Skip to content

BioroboticsLab/bb_mini_scales

Repository files navigation

bb_mini_scales

Read and save weight data from the M5Stack Unit Mini Scales (U177, I²C 0x26) to daily CSV files.

Hardware wiring (Raspberry Pi ↔︎ U177)

  • GND (black) → Pi GND (e.g. pin 6, 9, 14, …)
  • 5V (red) → Pi 5V (pin 2 or 4)
  • SDA (white) → Pi SDA1 (pin 3, GPIO2)
  • SCL (yellow) → Pi SCL1 (pin 5, GPIO3)

If i2cdetect does not show the device at 0x26, swap SDA/SCL (it's easy to mix those).
The U177 blue LED briefly lights at power-up.

Software setup (Raspberry Pi OS)

  1. Enable I2C
sudo raspi-config       # Interface Options → I2C → Enable
sudo reboot
  1. Install I2C tools (optional, for debugging) and Python deps
sudo apt update
sudo apt install -y i2c-tools python3-pip
pip3 install --upgrade smbus2
  1. Ensure your user can access I2C
sudo usermod -aG i2c $USER
# log out/in or reboot for group change to take effect
  1. Verify the device
i2cdetect -y 1
# Expect to see "26" in the table (address 0x26)
  1. Get the code
git clone https://github.com/BioroboticsLab/bb_mini_scales
cd bb_mini_scales
  1. Configure (optional)

Create a config.json (CLI flags override config values):

{
  "data_dir": "/home/pi/scale_data",
  "bus": 1,
  "addr": "0x26",
  "interval": 1.0,
  "name": "scaleA",
  "print": false,
  "tare_on_start": true,
  "gap": null,
  "set_filters": false,
  "lp_filter_enabled": 1,
  "avg_filter_level": 10,
  "ema_filter_alpha": 10,
  "sign": 1.0
}

Run

Basic

python3 mini_scale_logger.py

With config file

python3 mini_scale_logger.py -c config.json

Override config via CLI

python3 mini_scale_logger.py -c config.json --name scaleB --interval 1.0

Calibration

Tare vs GAP

The U177 has two independent adjustments:

  • Tare (offset reset): Zeroes out the current reading so an unloaded scale reads ~0 g. Volatile -- lost on power cycle. You need to tare every time the device powers up.
  • GAP (gain calibration): The ratio of ADC counts per gram, stored as a float in the device’s non-volatile memory (register 0x40). Survives power cycles. Only needs to be set once per load cell.

In practice: calibrate GAP once with a known weight, then tare whenever you power-cycle or reposition the scale.

Step-by-step calibration

  1. Remove all weight from the scale.
  2. Run the calibration tool:
    python3 test_and_calibrate_scale.py
  3. The script prints device info (firmware, address, current GAP, filter settings), then tares automatically.
  4. When prompted Calibrate GAP with known weight? [y/N], answer y.
  5. The script reads the raw ADC at 0 g.
  6. Place a known weight (e.g. a 200 g calibration mass) on the scale. Wait a few seconds for it to stabilize, then press Enter.
  7. The script reads the raw ADC under load, then asks you to type the known weight in grams.
  8. It computes GAP = (adc_0g - adc_weight) / weight_grams, writes it to the device, and reads it back for confirmation.
  9. The script then streams 30 samples so you can verify the displayed weight matches the known mass.

Verifying calibration

After calibrating, place one or two known weights and confirm weight_f32 matches within a few tenths of a gram. If readings drift over time, re-tare (not re-calibrate) -- GAP rarely needs to change unless the load cell is swapped.

Button-triggered tare

The logger (mini_scale_logger.py) always polls the physical button on the U177. Pressing it triggers scale.tare() immediately, with debounce. This is always active regardless of the tare_on_start config setting.

Useful for service mode: set tare_on_start: false so the service does not auto-tare on every restart, and use the physical button to tare when the scale is unloaded.

Configuration reference

The config fields (in config.json, all overridable via CLI flags):

Field Type Default Description
data_dir string "data" Directory for CSV output files
bus int 1 I2C bus number (1 on Raspberry Pi)
addr string/int "0x26" I2C address of the scale
interval float 1.0 Seconds between samples
name string "" Tag inserted into CSV filename (e.g. weight_data_scaleA_...)
print bool false Print readings to stdout (useful for debugging, omit in production)
tare_on_start bool true Tare when the logger starts. Set false for service mode
gap float/null null If set, writes this GAP to the device on startup
set_filters bool false If true, applies the filter settings below on startup
lp_filter_enabled 0/1 1 Enable device low-pass filter
avg_filter_level 0-50 10 Number of samples to average (higher = smoother, slower)
ema_filter_alpha 0-99 10 EMA smoothing factor (higher = more smoothing)
sign float 1.0 Multiply weight by this value. Use -1.0 if readings are inverted

Filter parameters

The U177 has three on-device digital filters (register 0x80):

  • lp_filter_enabled (0 or 1): Built-in low-pass filter. Recommended to leave enabled.
  • avg_filter_level (0--50): Moving average over N samples. Higher values give smoother but slower-responding readings. For static weights (e.g. beehive monitoring), 10--20 works well.
  • ema_filter_alpha (0--99): Exponential moving average smoothing. Higher = more smoothing.

To apply filters, set "set_filters": true in config.json along with the three filter values. They are written to the device on logger startup. For safety, set them on every startup rather than relying on persistence.

Running multiple scales

Each U177 ships at address 0x26. To run multiple scales on the same I2C bus, change the address of additional units using set_i2c_address() in the driver. Alternatively, use separate I2C buses.

  • Use --name scaleA, --name scaleB to differentiate CSV filenames.
  • Run one logger instance per scale with separate config files (and separate systemd service files if using services).

CSV output format

Daily CSV files are written to data/ by default (or data_dir from config):

weight_data_[name_]YYYY-MM-DD.csv

Columns:

Column Description
Time ISO 8601 timestamp with microseconds
Weight_g Float weight in grams (register 0x10). Primary measurement column.
Weight_x100_g Integer weight (register 0x60, value/100). Cross-check against Weight_g; if they diverge, investigate.
RawADC Raw 32-bit ADC count (register 0x00). Useful for debugging calibration or hardware issues.

A new file is created automatically at midnight.

Troubleshooting

  • i2cdetect does not show 0x26: Swap SDA/SCL wires. Verify 5V power (the unit needs 5V, not 3.3V). Check that I2C is enabled in raspi-config.
  • Readings are always 0.0 g: GAP may not be calibrated. Run test_and_calibrate_scale.py.
  • Readings have wrong sign: Set "sign": -1.0 in config.json.
  • Noisy/jumping readings: Increase avg_filter_level (e.g. 20) or ema_filter_alpha (e.g. 30). Ensure the scale is on a stable surface.
  • OSError: [Errno 121] Remote I/O error: Device not responding. Check wiring, check that nothing else is using the bus.
  • Service keeps restarting: Check journalctl -u mini_scale_logger.service -f. Common causes: wrong paths in the service file, I2C permission issue (user not in i2c group).
  • Weight drifts after power cycle: Expected -- tare is volatile. Press the button or set tare_on_start: true (only if the scale is guaranteed unloaded at boot).

Install as a system service

A sample unit file is included in the repo as mini_scale_logger.service:

# mini_scale_logger.service (example)
[Unit]
Description=MiniScale weight logger
After=network.target

[Service]
Type=simple
User=pi
Group=pi
WorkingDirectory=/home/pi/bb_mini_scales
ExecStart=/usr/bin/python3 /home/pi/bb_mini_scales/mini_scale_logger.py -c /home/pi/bb_mini_scales/config.json
Restart=always
RestartSec=2

[Install]
WantedBy=multi-user.target

Steps:

  1. Edit the file in the repo to match your paths, user, and Python:

    • User= / Group= (e.g., pi)
    • WorkingDirectory= (e.g., /home/pi/bb_mini_scales)
    • ExecStart= (ensure full paths to Python, script, and config)
  2. Install the service:

From the repo directory where mini_scale_logger.service lives:

sudo cp mini_scale_logger.service /etc/systemd/system/mini_scale_logger.service
sudo systemctl daemon-reload
  1. Enable on boot & start now:
sudo systemctl enable mini_scale_logger.service
sudo systemctl start mini_scale_logger.service
  1. Manage / inspect:
sudo systemctl status mini_scale_logger.service
sudo journalctl -u mini_scale_logger.service -f
sudo systemctl restart mini_scale_logger.service
sudo systemctl stop mini_scale_logger.service
sudo systemctl disable mini_scale_logger.service

Important: If you run the logger as a service and don’t want it to re-tare on every restart, set "tare_on_start": false in config.json. You can still tare manually (e.g., with test_and_calibrate_scale.py, or by pressing the unit’s button if your logger watches it).

About

Read and save mini scale data from m5stack scales

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages