This is a driver for the Adafruit Precision NXP 9-DOF Breakout Board - FXOS8700 + FXAS21002C. It is based on the libraries provided by Adafruit in C++ for the FXAS21002C and the FXOS8700.
embedded_hal
based driver with i2c access to the Adafruit chip.
It provides a basic interface to get raw and scaled data from the sensors.
All 3 sensors are separated in their own structure, respectively Accelerometer
, Magnetometer
and Gyroscope
.
You might need to calibrate and provide offset for the accelerometer and the gyroscope
-> check accel_gyro_calibration.rs
example code or the function calibration()
.
For the magnetometer, you might need to compute hard and soft iron correction.
If you want to learn more about those correction you can go here.
We won't provide any tool for those corrections.
However, you can follow this tutorial provided by Adafruit.
This crate allows for a full customization except for Fifo and hardware interruptions implementation. This is not plan in the near future.
To use this driver you must provide a concrete embedded_hal
implementation both for Delay and I2C.
You must be able to compute a delta time. e.g. the execution time of each loop. Most examples uses a Raspberry Pi for practicals reasons. NB: The more accurate the delta time, the more accurate the measurement.
A better ROS2 example might be provided in the future.
The example below uses rppal crates and runs on a Raspberry Pi.
use rppal::hal::Delay;
use rppal::i2c::I2c;
use embedded_hal::blocking::delay::*;
use nalgebra::{Vector3, Matrix3};
use adafruit::*;
fn main() -> -> Result<(), SensorError<rppal::i2c::Error>> {
// Init a delay used in certain functions and between each loop.
let mut delay = Delay::new();
// Setup the raspberry's I2C interface to create the sensor.
let i2c = I2c::new().unwrap();
// Create an Adafruit object.
let mut sensor = AdafruitNXP::new(0x8700A, 0x8700B, 0x0021002C, i2c);
// Check if the sensor is ready to go.
let ready = sensor.begin()?;
if !ready {
std::eprintln!("Sensor not detected, check your wiring!");
std::process::exit(1);
}
// If you don't want to use the default configuration.
sensor.set_accel_range(config::AccelMagRange::Range2g)?;
sensor.set_gyro_range(config::GyroRange::Range500dps)?;
sensor.set_accelmag_output_data_rate(config::AccelMagODR::ODR200HZ)?;
sensor.set_gyro_output_data_rate(config::GyroODR::ODR200HZ)?;
// If you need more precise results you might consider adding offsets. (Values are exemples)
sensor.accel_sensor.set_offset(-0.0526, -0.5145, 0.1439);
sensor.gyro_sensor.set_offset(0.0046, 0.0014, 0.0003);
let hard_iron = Vector3::new(-3.87, -35.45, -50.32);
let soft_iron = Matrix3::new(1.002, -0.012, 0.002,
-0.012, 0.974, -0.010,
0.002, -0.010, 1.025);
sensor.mag_sensor.set_hard_soft_iron(hard_iron, soft_iron);
loop {
sensor.read_data();
let acc_x = sensor.accel_sensor.get_scaled_x();
let acc_y = sensor.accel_sensor.get_scaled_y();
let acc_z = sensor.accel_sensor.get_scaled_z();
let gyro_x = sensor.gyro_sensor.get_scaled_x();
let gyro_y = sensor.gyro_sensor.get_scaled_y();
let gyro_z = sensor.gyro_sensor.get_scaled_z();
let mag_x = sensor.mag_sensor.get_scaled_x();
let mag_y = sensor.mag_sensor.get_scaled_y();
let mag_z = sensor.mag_sensor.get_scaled_z();
// Print data
std::println!("###############################################");
std::println!("Accel X: {}", acc_x);
std::print!(" Accel Y: {}", acc_y);
std::print!(" Accel Z: {}", acc_z);
std::println!("-----------------------------------------------");
std::println!("Gyro X: {}", gyro_x);
std::print!(" Gyro Y: {}", gyro_y);
std::print!(" Gyro Z: {}", gyro_z);
std::println!("-----------------------------------------------");
std::print!("Mag X: {}", mag_x);
std::print!(" Mag Y: {}", mag_y);
std::print!(" Mag Z: {}", mag_z);
delay.delay_ms(5_u8);
}
}