Bosch BNO055 with Adafruit Library - 1x Problem and Understanding

Hello everybody,

I have a few questions and a problem with the Bosch BNO055 sensor.
First, I do not find Adafruit’s introductions to the sensor / library very helpful. That’s why I researched and tested myself. I want to use the Sensor to get 9-axis absolute orientation.

Now i think i understand the most important thing about the sensor.

The sensor takes care of OnChip’s mathematical calculations and can process Accel, Mag and Gyro themselves. In order to process meaningful data, the chip permanently performs a calibration. one should wait for a complete calibration to use the results data. Since the calibration will be lost after a power out, it should be saved. The chip expects the “config” mode to save the calibration back. however, the Adafruit library does this automatically and sets the right modes.

I hope my knowledge is correct so far.

Since I currently use a MKR Zero without EEPROM, I save the calibration on an SD card instead of the EEPROM.

This brings me to my problem: After writing the calibration back to the Bosch BNO055, the calibration status for the magnetometer is discarded. I do not understand why. I checked the raw data twice.

I use this setup:

  Serial.println(" - Init BNO055");
  if(!bno.begin()){ Serial.println("   failed - check wiring or I2C ADDR!");  } else {
    delay(500);
    bno.setExtCrystalUse(false);
    bno.setMode(bno.OPERATION_MODE_NDOF);
  }

I use this function to save:

        if(bno.isFullyCalibrated()){
          File file = sd.open(sensorFileName, O_CREAT | O_WRITE | O_TRUNC);
          if(file){
            adafruit_bno055_offsets_t sensorOffsets;
            bno.getSensorOffsets(sensorOffsets);
            file.write((uint8_t)(sensorOffsets.accel_offset_x >> 8)); file.write((uint8_t)sensorOffsets.accel_offset_x);
            file.write((uint8_t)(sensorOffsets.accel_offset_y >> 8)); file.write((uint8_t)sensorOffsets.accel_offset_y);
            file.write((uint8_t)(sensorOffsets.accel_offset_z >> 8)); file.write((uint8_t)sensorOffsets.accel_offset_z);
            file.write((uint8_t)(sensorOffsets.gyro_offset_x  >> 8)); file.write((uint8_t)sensorOffsets.gyro_offset_x);
            file.write((uint8_t)(sensorOffsets.gyro_offset_y  >> 8)); file.write((uint8_t)sensorOffsets.gyro_offset_y);
            file.write((uint8_t)(sensorOffsets.gyro_offset_z  >> 8)); file.write((uint8_t)sensorOffsets.gyro_offset_z);
            file.write((uint8_t)(sensorOffsets.mag_offset_x   >> 8)); file.write((uint8_t)sensorOffsets.mag_offset_x);
            file.write((uint8_t)(sensorOffsets.mag_offset_y   >> 8)); file.write((uint8_t)sensorOffsets.mag_offset_y);
            file.write((uint8_t)(sensorOffsets.mag_offset_z   >> 8)); file.write((uint8_t)sensorOffsets.mag_offset_z);
            file.write((uint8_t)(sensorOffsets.accel_radius   >> 8)); file.write((uint8_t)sensorOffsets.accel_radius);
            file.write((uint8_t)(sensorOffsets.mag_radius     >> 8)); file.write((uint8_t)sensorOffsets.mag_radius);
            file.close();
            Serial.println("Offsets written to CONFIG:");
            SerialPrintLnBnoSensorOffsets(sensorOffsets);
          } else {
            Serial.println("Could not create file " + sensorFileName);
          }
        }else {
          Serial.println("ERROR: skipped because the sensor is not fully calibrated!!!");
        }

I use this function to read / restore:

        File file = sd.open(sensorFileName, O_READ);
        if(file){
          Serial.println("openend with " + (String)file.size() + " bytes");
          adafruit_bno055_offsets_t sensorOffsets;
          int i = 0;
          while(file.available()){
            byte fileByte = file.read();
            if(i== 0){ sensorOffsets.accel_offset_x = ((uint16_t)fileByte) << 8; } if(i== 1){ sensorOffsets.accel_offset_x += fileByte; }
            if(i== 2){ sensorOffsets.accel_offset_y = ((uint16_t)fileByte) << 8; } if(i== 3){ sensorOffsets.accel_offset_y += fileByte; }
            if(i== 4){ sensorOffsets.accel_offset_z = ((uint16_t)fileByte) << 8; } if(i== 5){ sensorOffsets.accel_offset_z += fileByte; }
            if(i== 6){ sensorOffsets.gyro_offset_x  = ((uint16_t)fileByte) << 8; } if(i== 7){ sensorOffsets.gyro_offset_x  += fileByte; }
            if(i== 8){ sensorOffsets.gyro_offset_y  = ((uint16_t)fileByte) << 8; } if(i== 9){ sensorOffsets.gyro_offset_y  += fileByte; }
            if(i==10){ sensorOffsets.gyro_offset_z  = ((uint16_t)fileByte) << 8; } if(i==11){ sensorOffsets.gyro_offset_z  += fileByte; }
            if(i==12){ sensorOffsets.mag_offset_x   = ((uint16_t)fileByte) << 8; } if(i==13){ sensorOffsets.mag_offset_x   += fileByte; }
            if(i==14){ sensorOffsets.mag_offset_y   = ((uint16_t)fileByte) << 8; } if(i==15){ sensorOffsets.mag_offset_y   += fileByte; }
            if(i==16){ sensorOffsets.mag_offset_z   = ((uint16_t)fileByte) << 8; } if(i==17){ sensorOffsets.mag_offset_z   += fileByte; }
            if(i==18){ sensorOffsets.accel_radius   = ((uint16_t)fileByte) << 8; } if(i==19){ sensorOffsets.accel_radius   += fileByte; }
            if(i==20){ sensorOffsets.mag_radius     = ((uint16_t)fileByte) << 8; } if(i==21){ sensorOffsets.mag_radius     += fileByte; }
            i++;
          }
          file.close();
          Serial.println("Offsets in CONFIG:");
          SerialPrintLnBnoSensorOffsets(sensorOffsets);
          
          bno.setSensorOffsets(sensorOffsets);
          Serial.println("Offsets on BNO055:");
          adafruit_bno055_offsets_t sensorOffsetsOnChip;
          bno.getSensorOffsets(sensorOffsetsOnChip);
          SerialPrintLnBnoSensorOffsets(sensorOffsetsOnChip);
        } else {
          Serial.println("Could not open file " + sensorFileName);
        }

This is my output: ::slight_smile:

X: 4.4375	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
X: 4.4375	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
X: 4.4375	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
X: 4.4375	Y: 70.8750	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
[bno save] ###################################################
Saving offsets...

Offsets written to CONFIG:
Accel: 65521 65524 9 
Gyro:  65535 2 0 
Mag:   65208 189 496 
Accel Radius: 1000
Mag   Radius: 957
##############################################################
X: 3.8750	Y: 70.8750	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
X: 3.0000	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
X: 2.1875	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
[bno load] ###################################################
Loading offsets...
openend with 22 bytes

Offsets in CONFIG:
Accel: 65521 65524 9 
Gyro:  65535 2 0 
Mag:   65208 189 496 
Accel Radius: 1000
Mag   Radius: 957

->Written to BNO055

Offsets on BNO055:
Accel: 65521 65524 9 
Gyro:  65535 2 0 
Mag:   65208 189 496 
Accel Radius: 1000
Mag   Radius: 947
##############################################################
X: 0.0000	Y: 0.0000	Z: 0.0000	Calibration: 3 system, 3 gyro, 3 accel, 3 mag	Is fully calibrated!!!
X: 2.1250	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 0 mag	Is not fully calibrated
X: 2.1250	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 0 mag	Is not fully calibrated
X: 2.1250	Y: 70.9375	Z: 5.8125	Calibration: 3 system, 3 gyro, 3 accel, 0 mag	Is not fully calibrated

The Output shows, that i have calibrated the sensor correct (manually moved the chip, …), than saved the Data to SD Card, than read the Data from SD Card (like i would do after power off) and write it to the Sensor. After the last step, the calibration for the magnetometer was discarded and set to 0!

I dont know why! The Output shows that the Offset’s are fine so far (after reading, saving, …).

I would be very happy if someone with bno055 experience could see if I made a mistake somewhere or the behavior is correct (and I misunderstood something about the calibration).

One thing I still do not understand:
Where should be magnetic north (x=0) if I put the chip flat on the table?
Please see atteched image.

Always post ALL the code, using code tags. Snippets are useless.

After the last step, the calibration for the magnetometer was discarded and set to 0!

What this means is that the BNO055 no longer believes the magnetometer to be calibrated, but the sensor developers do not explain what those calibration flags signify.

Edit: There is a comment suggesting that the magnetometer calibration is in fact not fixed by writing the offsets on this page: Device Calibration | Adafruit BNO055 Absolute Orientation Sensor | Adafruit Learning System

If you do not intend to do the calibration often, it is much easier and safer to put the offsets in the program as constants, rather than read/write the SD card. (I don’t use Adafruit’s bloated and clumsy library and wrote my own functions).

If the sensor is properly calibrated in the local environment, the yaw angle is measured from magnetic North. You must add an additional offset in yaw, possibly as another program constant, if you want the measurement to be relative to true North.

First of all, thank you for your answer. I did not post everything because I wanted to simplify reading. The rest of the code deals almost exclusively with the output and a few unimportant features. If the code is still interesting, I like to post the code here.

you wrote:

There is a comment suggesting that the magnetometer calibration is in fact not fixed by writing the offsets on this page

I could not find this comment. The link leads directly to the Adafruit calibration page. There are no comments.

If you have written your own library, have you also recognized the problem? maybe I can ignore the discard and use the data without mag calibration.

By the way. The system is intended to be used in different environments and therefore has to work with different calibrations. Therefore, I can not write the calibration directly into the code. on the productive system the eeprom is used (Arduino Due). other configurations are read from different files on the sd card.

Do you think I should write adafruit about the problem?

Thank you first, Regards DrDooom

There are no comments.

The comment I was referring to is the following (on the FAQ page following the linked page):

One thing to keep in mind though is that the sensor isn't necessarily 'plug and play' with loading the calibration data, in particular the magnetometer needs to be recalibrated even if the offsets are loaded. The magnetometer calibration is very dynamic so saving the values once might not really help when they're reloaded and the EMF around the sensor has changed.

The latest version of the BNO055 documentation explains that the background calibration is never turned off, even if you preload the constants.

This means that by preloading a sensible set of calibration constants, you can skip the default power on calibration step. After that, the best you can do is to continuously monitor the calibration status variable and ignore orientations for which the system calibration status is zero.

Adafruit most likely won't be able to help with this "problem", it is a feature of the sensor. Furthermore, the BNO055 calibration could be vastly improved, as scale factors should be included to match up the sensitivities of the independent axes of the sensors.

If you want to roll your own sensor, use RTIMUlib for Arduino, the best open source AHRS available. Read about my experience implementing it here.

Thanks alot. Your response helped me a lot. I was offline for a few days because I'm still sick. :zipper_mouth_face:

I had not found the information. But the information in the FAQ correspond exactly to the behavior as in my development environment. That helps me alot.

So I will write the offsets (in case something changes), but check the readings according to "fully calibrated" and the system status 0-3. Great. Then I can continue with the project.

I looked at your link. Very interesting. I'll still put on the standard libraries first because I have much else to do. But I will prepare the code so that I can change later if necessary without problems.

Can you say anything more about the orientation of the chip (as described in my first post at the very end)? I think that the magnetic polar pole is in the direction of the connection cable.

I think that the magnetic polar pole is in the direction of the connection cable.

Correct.

You have to look at the BNO055 documentation to determine the axial directions, and then look at how the chip is soldered to the breakout board.

The axes can be remapped by software.

Super. I have allready checked the BNO055 Docu. But most of it I have read over because I assumed that it is not relevant for the use of the Adafruit IMU.
At the moment I do not want to get too deep in the task. Possibly. later in the project.

Thanks and regards DrDooom

for interested readers: the problem persists.

When the sensor is fully calibrated and offset data is loaded (as I did when I tested), the calibration status is 3 (ok), magnetometer is 0 (not ok) and valid orientation data is provided. The behavior would be good for me because I get the required data.

BUT: if the sensor was turned off and then turned on and offset data loaded, the calibration status is 0 (not ok), magnetometer is 0 (not ok) and NO valid data will be generated. only gyro and accelerometer is 3 (ok).

IMHO there must be a reason why the variable type adafruit_bno055_offsets_t also holds the offsets for magnetometer, but does not consider them.

I will write adafruit if the behavior can be changed.

BUT: if the sensor was turned off and then turned on

Are you obeying the timing restraints and setting fusion mode? There must be a delay of about 1 second after turn on, in order for the on board microprocessor to boot up, before sending commands. The sensor boots up in configuration mode.

You might try my test/calibration code, which includes an optional system reset to handle the power cycling/soft reboot situation, attached.

newbno.zip (3.26 KB)

Hey jremington,

sorry was sick and only checked the Thread in the Adafruit Forum: Adafruit-Forum Thread

I tried to run ur Project. But it is for AVR Boards. So my SAMD Board cant run it. In the BNO055_I2C.c the TWSR is unknown. I think it would be defined in avr/io.h which is not present on my SAMD Board / Environment. :o(

Do u / did u use the default Adafruit Library without problems?

The Lib uses the following addresses

          /* Magnetometer Offset registers */
          MAG_OFFSET_X_LSB_ADDR                                   = 0X5B,
          MAG_OFFSET_X_MSB_ADDR                                   = 0X5C,
          MAG_OFFSET_Y_LSB_ADDR                                   = 0X5D,
          MAG_OFFSET_Y_MSB_ADDR                                   = 0X5E,
          MAG_OFFSET_Z_LSB_ADDR                                   = 0X5F,
          MAG_OFFSET_Z_MSB_ADDR                                   = 0X60,

The Bosch Docu points to this addresses

MAG_OFFSET_X_LSB     0x5B
MAG_OFFSET_X_MSB    0x56C
MAG_OFFSET_Y_LSB     0x5D
MAG_OFFSET_Y_MSB    0x5E
MAG_OFFSET_Z_LSB     0x5F
MAG_OFFSET_Z_MSB    0x60

So MAG_OFFSET_X_MSB is not the same. But can this lead to the problem? Maybe its only another writing of the same address.

MAG_OFFSET_X_MSB 0x56C

Typo. Drop the "6". All the calibration parameters are sequential in addresses, so you can just read out 11 consecutive 16-bit integers.

My code is for a standard ATMega328-based Arduino.

Thanks jremington,

ok. So the addresses are correct. I wrote an email to bosch. I hope someone answers. I write here if there is news. :expressionless: