Beam Bots integration for the Bosch BMI323 6-DoF inertial measurement unit (accelerometer + gyroscope) over I2C.

Operates the chip in either polling mode (periodic register reads) or interrupt mode (FIFO watermark on INT1) and publishes BB.Message.Sensor.Imu messages with angular velocity (rad/s) and linear acceleration (m/s²).

The BMI323 has no magnetometer, so orientation is published as the identity quaternion. You almost always want to pair this sensor with an orientation estimator such as bb_estimator_ahrs.

Choosing a mode

ODR ≤ 200 HzODR > 200 Hz
mode: :polling — simple, no GPIOmode: :interrupt — needs INT1 wired
Low jitter, low overheadReliable up to the chip's 6.4 kHz ODR
No FIFO, samples read one at a timeFIFO-buffered, samples arrive in bursts of watermark_frames

In interrupt mode, a watermark_frames: 8 setting at ODR 800 Hz means batches every 10 ms. Downstream consumers (AHRS estimators, kinematics filters) typically cope with bursts naturally since each sample's dt is read from its own monotonic timestamp.

Usage

Polling mode

defmodule MyRobot do
  use BB

  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
  end
end

Interrupt mode

Wire the chip's INT1 pin to a GPIO and let the on-chip FIFO buffer samples:

topology do
  link :base do
    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
    }
  end
end

Pairing with an AHRS estimator

The whole point of the identity orientation field is that an estimator fills it in:

topology do
  link :base do
    sensor :imu, {BB.Sensor.BMI323, bus: "i2c-1", ...} do
      estimator :orientation, {BB.Estimator.Ahrs.Madgwick, beta: 0.1}
    end
  end
end

The estimator subscribes to the sensor's Imu messages, replaces the identity quaternion with a fused orientation, and republishes. See bb_estimator_ahrs for the three available algorithms (Madgwick, Mahony, Complementary) and their tuning options.

Subscribe to the final stream:

BB.subscribe(MyRobot, [:sensor, :base, :imu])

Coordinate frame

Axes are the chip's own +X / +Y / +Z silkscreen (see the BMI323 datasheet §3.2). 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 downstream if the chip mounting doesn't match link axes.

Options

OptionDefaultDescription
busrequiredI2C bus name (e.g. "i2c-1")
address0x68I2C address (0x68 SDO→GND, 0x69 SDO→VDDIO)
mode:polling:polling or :interrupt
accelerometer_range8g (2, 4, 8, 16)
accelerometer_odr200Hz (12.5..6400)
accelerometer_mode:normal:normal, :low_power, :high_performance, :disabled
gyroscope_range2000°/s (125, 250, 500, 1000, 2000)
gyroscope_odr200Hz
gyroscope_mode:normalas for accelerometer
publish_rate~u(100 hertz)Polling rate (polling mode only)
int1_pinrequired if mode: :interruptGPIO pin number wired to BMI323 INT1
watermark_frames8FIFO frames per interrupt (interrupt mode only)

Setting accelerometer_mode or gyroscope_mode to :disabled powers that axis down — the IMU will publish constant / invalid values for it until the mode is changed back.

Runtime parameter changes

Live (no restart):

  • publish_rate (polling mode) — interval is recomputed.
  • accelerometer_* / gyroscope_* — chip is reconfigured.

Triggers {:stop, :reconfigure} (supervisor restarts with new params):

  • mode, bus, address, int1_pin, watermark_frames.

Troubleshooting

  • {:chip_id_mismatch, got: id, expected: 0x43} — the device at the configured I2C address isn't a BMI323. Check address (0x68 SDO→GND, 0x69 SDO→VDDIO), the bus, and that the chip is powered.
  • :no_such_bus — the bus string doesn't match any /dev/i2c-* device. On Linux: i2cdetect -l.
  • :int1_pin_required_for_interrupt_modemode: :interrupt was set without an int1_pin.
  • GPIO acquire failure in interrupt mode — pin may already be exported, owned by another process, or not exist on this board.
  • Constant / silently-wrong samples after changing *_mode — make sure you didn't leave an axis on :disabled.

See BB.Sensor.BMI323 for full module documentation.