whobl.io
Wobble detection for electric unicycles.
An electric unicycle can wobble: a side-to-side roll and yaw oscillation that grows over a few cycles. The wheel cannot damp it — its one motor balances pitch and nothing else — so the rider is the only controller in that axis. Catch it early and it is coaching. Catch it late and you are narrating a crash.
This project puts an IMU on the wheel, watches how fast energy in the wobble band is growing rather than how loud it is, and aims to turn that into a tone the rider hears in time to act on it.
The first long ride found a candidate: a roll and yaw mode near 3 Hz that climbs with speed. Which of its swells a rider actually feels is the open question, and the next rides are for labelling them.
Where it stands
Phase 2 — Firmware (active)
10 of 18 done
Next up
- Port filter + RMS from Phase 1 — after road data says what the band is
- Orientation registration — the frame comes from the kickstand pickup, done analysis-side (
mount.py); on-device waits for the detector port.docs/algorithm.md - Growth-rate detection
- Buzzer output on A3
- Self-calibration workflow (baseline curve to flash)
Recently decided
- OTA firmware updates, if built, go through a guarded
ctlopcode (USB or stand only, file closed first), not Bluefruit'sBLEDfu, which reboots on write with no chance to refuse. - BLE contract v2:
BACKFILLnames aboot_idand may runTO_END; a range settles only when the replays counted matchBACKFILL_DONE.records; a run seals when head, tail and every recoverable hole are known. Changing any of it meansproto_ver3 on both sides. - Mount placement is free; mount orientation is not. One rigid body has one ω, so the yaw-rate detector is placement-invariant and a remount needs re-registration, not recalibration. That stops holding if an accelerometer joins the detection path, or across the suspension.
- Sample rate is
-DODR_SELand stays at 416 Hz: realigns scale linearly with rate so a slower rate is not immunity, and measured riding spectra put real energy well above a 52 Hz Nyquist at ~9000× the noise floor.
After that
- Phase 3 — Suspension tuning (parked)not scoped yet