Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hangman

Assembled prototype P1.0 unit

Hangman is a Bluetooth-enabled crane scale. It's intended use is as a climbing training and rehab tool, but it can be used anywhere that requires measuring force or weight.

The hardware retrofits a cheap (~$23) 150kg crane scale from Amazon with a custom PCB based around a Nordic nRF52 microcontroller and a differential ADC. The firmware uses Embassy, an embedded async framework written in Rust, as well as Nordic's SoftDevice Bluetooth stack.

Why?

Crane scales have become popular in the climbing community as a means to train and rehab fingers. This is a fun project to learn and practice various concepts I was unfamiliar or rusty with: BLE 101, async Rust on embedded, nRF52 development, SMT soldering and PCB design, etc. Maybe it'll even help my fingers get stronger.

Status

The scale is feature-complete. Weight measurement works great with the Progressor API and compatible tools. Battery life is guesstimated to be in the range of several months to a couple of years depending on usage.

Disclaimer

This is not an officially supported Google product. Wouldn't that be funny though?

This has no affiliation with Tindeq.

Assembly

How to assemble the boards into the housings

Instructions

  • Test the scale to make sure that it generally works
  • Disassemble fully, keep the screws

Partially disassembled scale

  • Swap over the wires to the new, already populated PCB
  • Screw the new PCB back in

Soldered and semi-assembled scale

  • Measure the voltage input pins for shorts (to prevent stupid errors)
  • Power on the board with batteries or a lab bench power supply
  • Do the Bringup
  • Close the housing and screw it shut, don't pinch any wires or strip any screws
  • Do the Calibration
  • Done!

Bringup

How to get the board from being assembled to being functional, using Windows, WSL and a ST-Link

Requirements on Windows

  • Working WSL2
  • ST-Link, with installed drivers (I used a ST-Link V2-1, borrowed from a Nucleo Board)
  • Install usbipd-win on windows: run winget install --interactive --exact dorssel.usbipd-win in a windows terminal
  • Install required packages in wsl: sudo apt install build-essential
  • Install rust: https://rustup.rs/
  • Install probe-rs: https://probe.rs/
  • Install OpenOCD in WSL: sudo apt install openocd in wsl
  • Download the SoftDevice for the chip from NRF (I used s113_nrf52_7.3.0_softdevice.hex)

Flashing on Windows

  • Connect the ST-Link
  • Follow these instructions to get the ST-Link connected to WSL: https://learn.microsoft.com/de-de/windows/wsl/connect-usb
  • usbipd list
  • usbipd bind --busid <busid>
  • usbipd attach --wsl --busid <busid>
  • Connect the board to the ST-Link correctly
  • Power the board
  • Run openocd -f /usr/share/openocd/scripts/interface/stlink.cfg -f /usr/share/openocd/scripts/target/nrf52.cfg
  • In a seperate terminal run telnet localhost 4444
  • Use targets you can check that you can see the nrf52 target
  • Run init, halt, nrf5 mass_erase, program /full/path/.../s113_nrf52_7.3.0_softdevice.hex verify
  • Run exitin telnet shell
  • Exit OpenOCD with CTRL+C
  • Build and flash the code with cargo run --bin proto1_0 --release
  • Done! Further flashing etc. should not require reflashing the SoftDevice

Notes:

  • If you just want to flash the softdevice in one command you can do it like this: openocd -f /usr/share/openocd/scripts/interface/stlink.cfg -f /usr/share/openocd/scripts/target/nrf52.cfg -c "init; halt; nrf5 mass_erase; program /full/path/.../s113_nrf52_7.3.0_softdevice.hex preverify verify; shutdown"

Sources:

  • https://www.jentsch.io/nrf51822-flashen-mit-st-link-v2-und-openocd/
  • https://github.com/seemoo-lab/openhaystack/wiki/Flashing-nRF-with-OpenOCD---ST-Link
  • https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/nrf52/scripts/nrf52/flash-boot.sh
  • https://www.youtube.com/watch?v=R5wub5ywzTU&t=197s
  • https://www.reddit.com/r/embedded/comments/1k9v4vr/stm32_cmake_stlinkv3pwr_on_windows_in_2025/?show=original
  • https://github.com/dorssel/usbipd-win/wiki/WSL-support
  • https://discuss.ardupilot.org/t/help-setting-up-openocd-with-st-link-in-wsl2/112271
  • https://hackmd.io/@aeefs2Y8TMms-cjTDX4cfw/r1fqAa_Da
  • https://learn.microsoft.com/de-de/windows/wsl/connect-usb

Calibration

Hangman uses a two-point calibration routine where one of the points is zero. Calibration needs to be run once before use. The generated calibration constants are saved across power cycles so there shouldn't be a need to be calibrate multiple times, but you can re-calibrate at any time if you feel like the scale is inaccurate.

Instructions

  1. Install the nRF Connect app or any similar tool that can be used to connect to BLE devices and write data to GATT characteristics.
  2. Wake up Hangman by pressing the power button.
  3. Connect to Hangman using nRF Connect. It'll be named something starting with Progressor.
  4. Hang "zero" weight from the scale. It's okay if this isn't actually zero. What's important is that you know the difference in weight between this stage and the second calibration point. Any deviation from zero at this point will be tared out later.
  5. Write the ByteArray 6900000000 to the 7e4e1703-1ea6-40c9-9dcc-13d34ffead57 GATT characteristic. This should be the only writable characteristic. This sends the 0x69 (AddCalibrationPoint) opcode along with 0.0 as a 32-bit float.
  6. Add a known reference weight to the scale, ideally something that's at or more than the expected maximum weight but less than 150kg, the maximum capacity of the scale.
  7. Convert the known weight, in kg, to a 32-bit floating point number in little-endian format. Write 69 <your hex bytes here> to the same characteristic as earlier. As an example, if your known weight were 120.0 kg, you would send 690000f042.
  8. If you mess up entering in either meaurement, feel free to resend the corresponding command.
  9. Once you're set, write 0x6A to the same characteristic to save the calibration.
  10. At this point, disconnect from Hangman and test it out using the Tindeq mobile app or something compatible.

Tips

  • If the measurements are wildly off after calibration, try re-calibrating and using a big-endian float. Different programs disagree on how these bytes should be entered 🤷
  • The two calibration points can be written in any order. However, it's probably a little better to write the zero point first, in case there is some hysteresis.
  • 0x69 is the AddCalibrationPoint opcode.
  • 0x6A is the SaveCalibration opcode.