← BlogBlog

Going open, and letting AI take the Wheel

The Modular Motor Controller is now open source, at github.com/rhobic/mmc. This post covers what’s in the repository, a back-EMF sensing experiment on the bench, and a change to the milestone order that followed from it.

The code is public

The repository is what every write-up in the Learn series points at. It’s a Rust workspace built simulation-first: the control core is allocation-free and no_std, so the same code that runs in the 20 kHz ISR on the STM32G474 also runs on a PC against a virtual motor. The host tooling talks to the simulator (over a TCP socket) and to real silicon (over serial) through the same COBS-framed, CRC-checked protocol. cargo test runs the simulation regression suite; cargo run -p mmc-host -- suite regenerates the Results dashboard.

Development is AI-driven — most of the implementation is written by Claude, working against the simulator and the bench. Opening the repository makes that process legible: the commit history and the in-repo progress log are the record of how it was built.

A back-EMF sensing experiment

The bench power stage, an X-NUCLEO-IHM16M1, has a divider network on the motor terminals for sensing back-EMF that the firmware wasn’t using. The intent was to read actual phase voltage while driving and feed it to the flux observer in place of the commanded voltage, removing the roughly 8% error from the inverter’s switch and dead-time drops and letting the observer work closer to standstill.

The wiring was straightforward: a second ADC reads the divider outputs, injected on the same timer trigger as the current sense, in parallel, so it costs the control loop nothing in the timing budget. Three telemetry channels, a panel chart. The pin mapping wasn’t usable from the schematic and was resolved on hardware — one channel sat railed at 18.3 V, which identified it as the board’s speed potentiometer rather than a phase.

It does not work as a live voltage sense on this shield, for two reasons:

  • Schottky clamp diodes rectify the signal, so it reads zero-to-peak rather than the bipolar waveform.
  • Under PWM the signal follows the switched rail and averages to about 1.7 V, which is unusable.

Feeding the observer measured phase voltage is therefore not achievable on this hardware; that would need filtered or in-line terminal sensing the shield doesn’t provide.

The same network does work for what it was designed for. Spinning the motor, putting the bridge into high-impedance, and letting it coast, all three phases show a back-EMF sine that scales with speed — 4.3 to 5.3 V peak-to-peak at 150 rad/s electrical, 9.5 to 10.0 V at 300. The coast-down amplitude backs out a flux linkage within about 11% of the profiled value, consistent with the diode drop, which makes a usable cross-check. It is also the zero-cross detector that six-step commutation needs.

Milestone order

The next milestone was MS7: add an encoder as a second angle source, calibrate its offset against the observer, and stack a position loop on top. It’s blocked — no rotor-angle sensor is wired to this hardware, and neither an encoder nor the motor’s hall sensors reach the shield’s connector.

Six-step commutation needs nothing new. Its back-EMF zero-cross front end is now wired and characterized, and the firmware change it requires — floating one phase at a time — is a small change to the existing enable handling. So the order swaps: six-step (MS8) first, position control (MS7) once there is an angle sensor on the bench.

Where things stand

Next is six-step commutation. Position control waits on an angle sensor. The Results page has the traces, and the repository has the code and the progress log.