James Harton James Harton

June 2026: Getting Our Bearings

The quiet core woke up loudly: a BB.Estimator behaviour, three AHRS filters, a BMI323 IMU driver and a URDF importer — plus a balance bot that finally knows which way is up, on real hardware and on screen.

Last month I called it the calm before the goat. The core had gone quiet, the bots were bumping dependencies, and I was quietly panicking about Sweden. Well, the calm is over. This month the framework learned something genuinely new: it figured out which way is up.

bb went from 0.15 to 0.20 — eleven releases — and the thread running through almost all of it is sensing and self-awareness. The robot can now read an IMU, fuse the readings into an orientation estimate, and tell you its attitude in real time. There's a video to prove it.

The Robot Knows Which Way It's Pointing

Here's the new estimation stack running on real hardware:

That's a Bosch BMI323 IMU talking to my laptop over a circuits_ft232h USB-to-I2C bridge, feeding a complementary AHRS filter in Beam Bots, with the resulting absolute orientation rendered live in a LiveView. Wave the chip around, the model on screen waves with it. No fudging, no pre-baked animation — that's a sensor fusion pipeline doing honest work, end to end, in Elixir.

This is also the first proper outing for the balance bot test platform I'm building for the Goatmire workshop. More on that at the bottom.

State Estimation, From Behaviour to Bottle

The demo above only works because three new pieces landed this month, and they slot together cleanly.

BB.Estimator (proposal 0018, shipped in bb 0.20.0) is a new behaviour and DSL entity for state estimators — the components that turn noisy sensor readings into something you can actually steer by. It arrived in two phases: the behaviour, DSL entity and runtime wiring first (along with Covariance3/Covariance6 math types, estimator payloads and error types), then health transitions and command dispatch. You declare one in your topology like anything else:

estimator :orientation, {BB.Estimator.Ahrs.Complementary, alpha: 0.98}

bb_estimator_ahrs is the first concrete implementation — a brand-new package with three 6-DOF IMU fusion algorithms, each a BB.Estimator:

  • BB.Estimator.Ahrs.Madgwick — gradient-descent filter, tuned with :beta
  • BB.Estimator.Ahrs.Mahony — PI-controller filter, tuned with :kp/:ki
  • BB.Estimator.Ahrs.Complementary — high-pass gyro plus low-pass accelerometer, tuned with :alpha

Pick the one whose trade-offs suit your robot and your patience.

I can't take credit for the maths here. The algorithm internals are ported, with his blessing, from Gus Workman's gworkman/ahrs — his original MIT-licensed work, with the unit conversion and dt tracking lifted out into the BB.Estimator framework boundary. Gus is doing the Nerves system and the carrier board and, it turns out, the sensor fusion. Thanks, Gus.

bb_sensor_bmi323 is the eyes — a driver for the Bosch BMI323 6-DoF IMU (accelerometer plus gyroscope) over I2C, running in either polling or interrupt mode. It's the sensor in the video.

Sensor → estimator → orientation. That's the whole point of having a framework: each piece is a declarative component, and they compose.

Bring Your Own Robot: mix bb.from_urdf

If you already have a robot described in URDF — and most of the robotics world does — you no longer have to hand-translate it. mix bb.from_urdf (in bb 0.18.0) imports a URDF model straight into the BB DSL, and it'll merge its output into your existing modules rather than clobbering them.

It also models URDF <transmission> blocks, which turned out to be the right home for a concept that was previously scattered: the relationship between joint-space and motor-space. Which brings us to a breaking change…

Breaking Changes You'll Want to Know About

The jump to bb 0.16 carried three breaking changes. There's a mix bb.upgrade Igniter task to smooth the path, but here's what moved:

  • BB.Message now carries wall-clock time and the originating node. Messages know when they were created and where they came from — essential once you're running across distributed nodes. This rippled out into bb_kino, bb_liveview and the new bb_mcp, all of which now surface real timestamps.
  • Force-disarm moved to the topology supervisor. The old auto_disarm_on_error flag is gone; safety shutdown now goes through the supervision tree itself, which is where a let-it-crash safety story belongs.
  • Units migrated from ex_cldr_units to localize — lighter, and one fewer heavyweight dependency to drag onto an embedded target.

Separately, reverse? has been removed from every servo package (Feetech, PCA9685, pigpio, Robotis). Reversing a joint is really a property of the transmission between motor and joint, so that's where it lives now. If you had reverse?: true on a servo, it moves into a transmission block — and mix bb.from_urdf will emit those for you.

Two New Packages, and One That Stopped Being a Placeholder

  • bb_mcp — a Model Context Protocol server for Beam Bots robots. List your robots at startup and AI agents (Claude Desktop, Claude Code, your own LLM agent) can drive them over standard MCP. Yes, you can now ask an LLM to move your robot. No, I'm not responsible for what it does next.
  • bb_so101 — installer and operator tooling for TheRobotStudio's SO-101, a 6-DOF desktop arm built on Feetech STS3215 servos. mix igniter.install bb_so101 scaffolds a complete robot module, supervisor wiring and SIMULATE-aware boot options in one command.
  • bb_jido — last month the README cheerfully admitted it was "a placeholder for future development." It is no longer. The initial implementation (proposal 0009, built on Jido 2.2) landed. Where bb_reactor answers "how do I execute this workflow?", bb_jido answers "what should I do next?" — goal-directed agents that observe the world via BB.PubSub and dispatch commands in response.

Power, Crashes, and Convenience

A few smaller things worth flagging:

  • BB.Message.Sensor.PowerState (in bb 0.19.0) is a generic voltage/current/power reading, and bb_sensor_ina219 now publishes it. Your robot can watch its own battery.
  • Sensors now crash on read failure instead of logging and carrying on. Both bb_sensor_bmi323 and bb_sensor_ina219 were quietly swallowing I2C errors; now they fall over and let the supervisor restart them. A sensor that's lying to you is worse than one that's honestly dead.
  • Application-environment config via set_robot_param_default/4, with sensors and servos writing their defaults into config.exs at install time. Less boilerplate, more "it just works."
  • Igniter installers nearly everywherebb_liveview.install, bb_pid_controller.install, and the servo packages all gained one-command setup.

Around the Ecosystem

Mauricio Cassola kept the terminal-UI side moving at his usual clip: ex_ratatui shipped 0.9 and 0.10 with cell sessions, in-terminal images, big text and syntax highlighting, and bb_tui gained a bb_tui.install Igniter task to match the rest of the ecosystem.

Gus Workman continued grinding on the Nerves Starter Kit system on the support-nsk branch of nerves_system_trellis — UART pin definitions, GPIO poweroff — with an Igniter installer for the Trellis target now open for review. That's the board the Goatmire workshop runs on, so every commit there is one fewer thing for me to worry about in September.

Goatmire Prep and the Balance Bot

Goatmire is still on in Varberg, Sweden, 28 September – 3 October, and my talk and balance bot workshop are still both happening. The workshop hardware is taking shape: the test platform is a Raspberry Pi Zero, a BMI323 IMU, a DRV8827 motor driver, and an 18650 cell managed by a TP4056 charger.

The one thing standing between me and writing workshop code is a DC-DC boost converter to lift the 3–4 V cell up to the 5 V the Pi and motors want. It's in the post. Once it lands I can start building and testing the code the workshop will actually teach — which, given the video above, is going to lean heavily on the new estimation stack.

A robot that balances is just a robot that's very good at knowing which way is up. This month, Beam Bots learned how.