A BB sensor that publishes BB.Message.Sensor.Imu messages from a Bosch
BMI323 6-DoF inertial measurement unit (3-axis accelerometer + 3-axis
gyroscope) over I2C.
The BMI323 has no magnetometer, so this sensor cannot determine
orientation on its own — every published Imu carries
BB.Math.Quaternion.identity/0 for the orientation field. You
almost always want to pair this sensor with an orientation estimator
such as the ones in
bb_estimator_ahrs
(Madgwick, Mahony, Complementary). See
Pairing with an AHRS estimator.
Modes
Pick based on output data rate:
:polling— periodically callsBMI323.read_imu/1atpublish_rate. Low-overhead, low-jitter at modest rates. Use when ODR ≤ 200 Hz. Above ~200 Hz the BEAM scheduler starts to lose samples between polls.:interrupt— runsBMI323.Samplerwhich buffers samples in the chip's on-chip 2 KB FIFO and fires the host's INT1 GPIO when a configurable watermark is reached. Reliable up to the chip's 6.4 kHz ODR. Requires INT1 wired to a host GPIO.
In interrupt mode, samples arrive in bursts of watermark_frames at
once. With ODR 800 Hz and watermark 8, you'll see batches every 10 ms.
Downstream consumers should be designed to handle a burst (an estimator
like the AHRS filters integrates each sample with its own dt, so it
copes naturally).
Coordinate frame
Axes are the chip's own +X / +Y / +Z (see the BMI323 datasheet §3.2 for the silkscreen orientation). The BB topology entity this sensor attaches to is its coordinate frame — orient the IMU on the link as appropriate and apply a static transform in your downstream consumer if the chip mounting axes don't match the link axes.
Example DSL Usage
topology do
link :base do
sensor :imu, {BB.Sensor.BMI323,
bus: "i2c-1",
address: 0x68,
mode: :polling,
accelerometer_range: 8,
accelerometer_odr: 200,
gyroscope_range: 2000,
gyroscope_odr: 200,
publish_rate: ~u(100 hertz)
}
end
endOr in interrupt mode, with INT1 wired to GPIO 17:
sensor :imu, {BB.Sensor.BMI323,
bus: "i2c-1",
address: 0x68,
mode: :interrupt,
int1_pin: 17,
accelerometer_range: 8,
accelerometer_odr: 800,
gyroscope_range: 2000,
gyroscope_odr: 800,
watermark_frames: 8
}Pairing with an AHRS estimator
The BMI323 produces raw acceleration + angular-velocity samples; turning
those into an orientation needs sensor fusion. Attach an estimator from
bb_estimator_ahrs:
sensor :imu, {BB.Sensor.BMI323, bus: "i2c-1", ...} do
estimator :orientation, {BB.Estimator.Ahrs.Madgwick, beta: 0.1}
endThe estimator subscribes to this sensor's Imu messages, replaces the
identity quaternion with a fused orientation, and republishes. See
BB.Estimator.Ahrs.Madgwick, BB.Estimator.Ahrs.Mahony, and
BB.Estimator.Ahrs.Complementary for the algorithm choices.
Options
bus— I2C bus name (e.g."i2c-1") — required.address— I2C address (0x68or0x69, default0x68).mode—:pollingor:interrupt(default:polling).accelerometer_range—2 | 4 | 8 | 16g (default8).accelerometer_odr— output data rate in Hz (default200).accelerometer_mode—:disabled | :low_power | :normal | :high_performance(default:normal). Setting either axis to:disabledpowers it down — the IMU will publish constant / invalid values for that axis until the mode is changed back.gyroscope_range—125 | 250 | 500 | 1000 | 2000°/s (default2000).gyroscope_odr— output data rate in Hz (default200).gyroscope_mode— as for accelerometer (default:normal).publish_rate— polling rate (default~u(100 hertz)). Ignored in interrupt mode.int1_pin— GPIO pin number wired to BMI323's INT1. Required whenmode: :interrupt.watermark_frames— FIFO frames per interrupt (default8). Interrupt mode only.
Published Messages
BB.Message.Sensor.Imu published to [:sensor | path] where path is
the sensor's position in the topology. Fields:
angular_velocity— gyroscope reading asBB.Math.Vec3in rad/s.linear_acceleration— accelerometer reading asBB.Math.Vec3in m/s².orientation—BB.Math.Quaternion.identity/0(see above).
Runtime parameter changes
Options handled live (no restart):
publish_rate(polling mode) — interval is recomputed.accelerometer_range/accelerometer_odr/accelerometer_mode—BMI323.configure_accelerometer/2is re-issued.gyroscope_range/gyroscope_odr/gyroscope_mode—BMI323.configure_gyroscope/2is re-issued.
Options that trigger {:stop, :reconfigure} (supervisor restarts the
sensor with new params):
mode,bus,address,int1_pin,watermark_frames.
Error handling
A single failed read or reconfiguration is logged at warning level and does not crash the process — the polling loop or interrupt handler continues. Persistent failures will manifest as silence on the topic rather than a crash.
Troubleshooting
{:stop, {:chip_id_mismatch, got: id, expected: 0x43}}— the device at the configured I2C address is not a BMI323. Checkaddress(0x68when SDO is tied to GND,0x69when tied to VDDIO), the physical bus, and that the chip is actually powered.{:stop, :no_such_bus}fromWafer.Driver.Circuits.I2C.acquire/1— thebusstring doesn't match any/dev/i2c-*device. On Linux list available buses withi2cdetect -l.{:stop, :int1_pin_required_for_interrupt_mode}—mode: :interruptwas set without anint1_pin.- GPIO acquire failure in interrupt mode — the pin may already be exported, owned by another process, or not exist on this board.
- Constant / silently-wrong samples after changing
*_mode— check you didn't leave an axis on:disabled; that powers it down.