Hacking in raw IMU accelleration and mag values


Thank you! What is a standard deviation for ACC? Is it 4%? How can I calibrate LACC?
I have basic Kalman filter and it looks like this (LACCy):

And as a reminder - depth data error:


Hi frikksol.

Right now I’m working with a team in the Universidad Nacional de Colombia, and we are trying to do what you did. Could you please share whit us the code that you develope to make this changes? I mean, the Arduino code, and the Node.js code, or if you could show us the steps to do it. We are a little bit lost.

Thank you very much :slightly_smiling:


Do you have a current version of this code working for the BNO055 for the 30.0.3 version ?


The latest release of the code that is supported for 30.0.x versions can be found here:

It doesn’t include support for raw values, but it shouldn’t be too hard to add back in (sorry that the old github branch got deleted that had this implemented). The basic methodlogy for doing this is:

imu::Vector<3> mag;
imu::Vector<3> gyro;
imu::Vector<3> accel;

if( bno.GetVector( CAdaBNO055::VECTOR_MAGNETOMETER, mag ) )
           // Values are now stored in mag.x, mag.y, mag.z

if( bno.GetVector( CAdaBNO055::VECTOR_GYROSCOPE, gyro ) )
           // Values are now stored in gyro.x, gyro.y, gyro.z

if( bno.GetVector( CAdaBNO055::VECTOR_ACCELEROMETER, accel ) )
           // Values are now stored in accel.x, accel.y, accel.z

You can read CAdaBNO055.cpp to see how those were implemented and refer to the datasheet for all sorts of other functions you can perform with the chip.


I implemented all your suggestions in the last stable arduino software for the BNO055 sensor but I don´t have access to the hardware at the moment, which means I can´t test it.

These are my changes: https://github.com/noxxomatik/openrov-software-arduino-30.0.4-BNO055/commit/f1acfd4157a8b7fecd3510e797920fa1216219a7

I want to use these values in a plugin for the 31.0.0 version of the cockpit, but I don´t understand where the “mcu.status” event gets emitted. This event seems to transport the values.

// Arduino
deps.globalEventLoop.on('mcu.status', function (status)
  if ('depth_d' in status) {
    navdata.depth = decode( status.depth_d );
  if ('imu_p' in status) {
    navdata.pitch = decode( status.imu_p );
  if ('imu_r' in status) {
    navdata.roll = decode( status.imu_r );
  if ('imu_y' in status) {
    navdata.yaw = decode( status.imu_y );
    navdata.heading = decode( status.imu_y );
  if ('fthr' in status) {
    navdata.thrust = status.fthr;
  if ('imu_mode' in status) {
    self.state.imuMode = status.imu_mode==0?'gyro':'compass';
    deps.cockpit.emit('plugin.navigationData.state', self.state);                
  if ('imu_level:ack' in status) {
    navstate.imu_level_ack = Date.now();


Does the new cockpit already work with the older arduino software? Where can I adjust the mcu.status?



The Cockpit code that you referenced is from the 31.0.x release and corresponds to the firmware that exists in the master branch of openrov-software-arduino (it no longer supports firmware from the 30.0.x branches). The BNO055 code structure has changed significantly to achieve better performance by introducing a state machine for the sensor that uses no delay statements and does a better job of tracking sensor state and error conditions (and also uses a new I2C Master library).

The logic for the sensor is now contained in /opt/openrov/firmware/libraries/bno055/ and the code that sends the results to Cockpit over the serial line resides in /opt/openrov/firmware/sketches/OpenROV2x/CBNO055.h/cpp. Right now, the state machine is set up to constantly read the fused euler angles. You will want to add data structures for the raw values to the BNO055_Defs.h file and modify the sensor interface and state machine in BNO055.h/cpp to read and store the raw values, then modify CBNO055 to report the raw values to cockpit. Depending on how fast you want to read raw values, you may need to stop reading the fused results as each euler measurement takes ~2.3ms to complete because of the blocking nature of the I2C driver being used and the BNO’s tendency to stretch the I2C clock for long periods of time (nothing we can do about that). I believe the sensor has the ability to output raw accel/gyro data at 800 or 1000Hz, but you won’t be able to push that much data while reading fused results or while running the Serial Port at 115200 baud. We have not tested cranking the serial baud higher than that on the ATMega2560, and would not recommend doing so unless you modify the outgoing data strings to include a CRC check and also modify cockpit to perform a CRC check on the received data.

The mcu.status event is emitted in bridge.js, which for the Beaglebone + 2.X controllerboard can be found in:

Let me know if you have any additional questions and I’ll do my best to help. Unfortunately the existing communication architecture is not ideally set up for exercising the full capability of the sensor with regards to raw measurements.


Back of the hand calculations for bandwidth required on the I2C and UART buses to transmit the data:

Raw Bandwidth:
Each sensor has x, y, and z components, each 2 bytes long so:
Accel = {x,y,z} = 6 bytes @ 1000hz
Gyro = {x,y,z} = 6 bytes @ 1000hz
Mag = {x,y,z} = 6 bytes @ 30hz

Each new I2C transaction will have ~20 clock cycles required to transmit the initial address and register request, and each byte will have ~10 clock cycles overhead so:

1000 * 20 + 6 * 1000 * 10 = 80000 clock cycles

Accel + Gyro = 160000 clock cycles per second in I2C bandwidth

Mag data = 30 * 20 + 6 * 30 * 10 = 2400 clock cycles

So a total of ~162,400 clock cycles per second to read the BNO055’s raw data at max speed (I may have fudged a bit on this, it’s rather late so double check me). This means you will need to run the I2C bus at 400KHz and make sure that any other I2C sensors (like the depth sensor) aren’t eating too much more of your bandwidth. Though you will be clocking the bus at 400KHz, be aware that slave devices are allowed to hold the clock line for as long as they wish to prolong a transaction according to the I2C protocol, so you probably will not achieve anywhere near 400Kbits/second on the bus.

Next consideration is the Serial Port bandwidth required. Currently, we send the values as raw strings, so basically add up all of the characters that it takes to represent the messages and multiply by 10 bits (start, data, stop) to get an estimate of the required bandwidth. Back of the hand below:

If we call the message fields for the raw accel data “rax:[data];” (with messages also for the y and z axis for each sensor) and assume a worst case of a constant 6 characters per data field using 1K encoding (which is inefficient on the wire as well) we have:

Accel = 11 characters * 1000 * 10 bits * 3 axes= 330000 bits/s
Gyro = 330Kbit/s as well
Mag = 11 * 30 * 10 bits * 3 axes = 9900 bits/s

Total = 669900 bits/s

So you will need to either encode the messages more efficiently with a binary serialization or greatly increase the baud rate (brings with it increased error, requiring CRC checks for integrity).


Caveat to all of this: You can definitely just grab the raw values at a slower rate than the max to fit within the constraints of the hardware and software, depending on your needs.


@charlesdc Thank you for your reply! I definitely have to take a deeper look into it now. I think it try to grab them at a slower rate first.