This is a embedded-hal driver for Bosch's Absolute Orientation Sensor BNO055.
It is device-agnostic and uses embedded-hal's Write
/WriteRead
(for I2C)
and Delay
traits for its operation.
Uses and re-exports mint's Quaternion for quaternion reading and EulerAngles for Euler angles and Vector3 for sensor readings.
Add dependency to Cargo.toml
:
bash
cargo add bno055
Instantiate and init the device:
```rust // ... declare and configure your I2c and Delay implementations ... // let i2c = ...; // let delay = ...;
// Init BNO055 IMU let imu = bno055::Bno055::new(i2c);
imu.init(&mut delay)?;
// Enable 9-degrees-of-freedom sensor fusion mode with fast magnetometer calibration imu.set_mode(bno055::BNO055OperationMode::NDOF)?;
Ok(imu) ```
Read orientation data, quaternion or euler angles (roll, pitch, yaw/heading):
rust
let quat: mint::Quaternion<f32> = imu.quaternion()?;
// or:
let euler: mint::EulerAngles<f32, ()> = imu.euler_angles()?;
Due to the BNO055 firmware bugs, the Euler angles reading shouldn't be relied on. I recommend to stick with quaternion readings and convert them to the Euler angles later if needed.
To calibrate device's sensors for first time:
```rust use bno055::{BNO055Calibration, BNO055OperationMode, BNO055CALIBSIZE};
let bno055 = ...;
// Enter NDOF (absolute orientation) sensor fusion mode which is also performing // a regular sensors calibration bno055.set_mode(BNO055OperationMode::NDOF)?;
// Wait for device to auto-calibrate. // Please perform steps necessary for auto-calibration to kick in. // Required steps are described in Datasheet section 3.11 while !bno055.isfullycalibrated() {}
let calib = bno055.calibration_profile()?;
// Save calibration profile in NVRAM mcu.nvramwrite(BNO055CALIBADDR, calib.asbytes(), BNO055CALIBSIZE)?; ```
To load previously saved calibration profile:
```rust use bno055::{BNO055Calibration, BNO055OperationMode, BNO055CALIBSIZE};
let bno055 = ...;
// Read saved calibration profile from MCUs NVRAM let mut buf = [0u8; BNO055CALIBSIZE]; mcu.nvramread(BNO055CALIBADDR, &mut buf, BNO055CALIB_SIZE)?;
// Apply calibration profile let calib = BNO055Calibration::frombuf(buf); bno055.setcalibration_profile(calib)?; ```
BNO055 allows to change default axes to meet the chip orientation with actual physical device orientation, thus providing possibility to place BNO055 chip on PCB as suitable for a designer and to match chip's axes to physical axes in software later.
```rust use bno055::{AxisRemap, BNO055AxisConfig}; // ...
// Build remap configuration example with X and Y axes swapped: let remap = AxisRemap::builder() .swapxwith(BNO055AxisConfig::AXISASY) .build() .expect("Failed to build axis remap config");
bno055.setaxisremap(remap)?; ```
Please note that AxisRemap
(and the chip itself) builder doesn't allow invalid state to be constructed,
that is, when one axis is swapped with multiple of others.
For example, swapping axis X
with both Y
and Z
at the same time is not allowed:
rust
AxisRemap::builder()
.swap_x_with(BNO055AxisConfig::AXIS_AS_Y)
.swap_x_with(BNO055AxisConfig::AXIS_AS_Z)
.build()
.unwrap(); // <- panics, .build() returned Err
It is also possible to flip sign of either axis of the chip.
Example of flipping X and Y axes:
rust
bno055
.set_axis_sign(BNO055AxisSign::X_NEGATIVE | bno055::BNO055AxisSign::Y_NEGATIVE)
.expect("Unable to communicate");
For better performance, it is advised to connect and use external 32k quartz crystal.
User could enable or disable it by calling set_external_crystal
:
rust
bno055
.set_external_crystal(true)
.expect("Failed to set to external crystal");
BNO055 allows to change its I2C address from default 0x29
to alternative 0x28
by setting
COM3
pin LOW
.
To connect to device with alternative address, enable its use by calling with_alternative_address()
:
```rust // use default 0x29 address let mut bno = bno055::Bno055::new(i2c, delay);
// or:
// use 0x28 address let mut bno = bno055::Bno055::new(i2c, delay).withalternativeaddress(); ```
```rust use bno055::{Bno055, BNO055PowerMode}; // Normal mode bno055.setpowermode(BNO055PowerMode::NORMAL)?;
// Low-power mode (only accelerometer being awake) bno055.setpowermode(BNO055PowerMode::LOW_POWER)?;
// Suspend mode (all sensors and controller are sleeping) bno055.setpowermode(BNO055PowerMode::SUSPEND)?; ```
Temperature is specified in degrees Celsius by default.
rust
let temp: i8 = bno055.temperature()?;
What is done and tested and what is not yet: