Reliably reloading the calibration data of IMU BNO055

Status
Not open for further replies.

frodojedi

Member
Hi all,
I am using the BNO055 IMU and the Adafruit Library.
I want to store the calibration data and load them after the microcontroller is powered off and repowered on.
The Adafruit Library provides an example for storing and restoring but, in actual facts, it does not work. It is always required to recalibrate the magnetometers, but even doing so, the library reperform the whole calibration including the accelerometers.

I would like to simply restore all the calibration data (including the magnetometers) so that no calibration needs to be performed when the IMU starts.

I have read a massive amount of posts on the argument, but I really could not figure out how to reliably load all the calibration data at boot and avoid recalibrating them.

Is there anyone who succeeded and can please share the code?
 
Take a look at the example sketch "restore_offsets.ino".

That example sketch stores the calibration data in the Teensy EEPROM if the calibration data is not already stored and if it is will reload it. Good place to start.
 
I am indeed using that. It does not work, you always need to reperform the whole calibration. If I load the saved calibration stored in the EEPROM then I get readings from the IMU which are noisy and random. I need to reperform the calibration, and I want to avoid this step. Can you share your code by any chance?
 
Well can you give me a bit more information. What Teensy are you using? You know it might not be the calibration but the environment you are in. Also not sure what you mean by noisy and random? Is the "noisy-random" from looking at data from the restore_offsets.ino sketch. One of the basic rules of the forum is to post your code, i.e., is the problem with the that particular sketch. The code I use is exactly what you see in that sketch. Are you getting the message back "Fully calibrated!" and data stored to EEPROM?
 
Well can you give me a bit more information. What Teensy are you using? You know it might not be the calibration but the environment you are in. Also not sure what you mean by noisy and random? Is the "noisy-random" from looking at data from the restore_offsets.ino sketch. One of the basic rules of the forum is to post your code, i.e., is the problem with the that particular sketch. The code I use is exactly what you see in that sketch. Are you getting the message back "Fully calibrated!" and data stored to EEPROM?

I am using a Teensy 3.6, but the same happens for Teensy 3.2 and Arduino Uno. There is no issue with magnetic interference in my environment, I am simply using the sensor on a wooden table for the moment. By noisy-random I mean that the data start to float randomly, without any reference to the calibrated values one should expect. Yes I get the message Fully Calibrated and the data stored in the EEPROM, but as I said, after power off and power on the Teensy, when restoring the calibration I get random values that do not certainly relate to the correct orientation from the IMU when was calibrated before power off.
 
I am using a Teensy 3.6, but the same happens for Teensy 3.2 and Arduino Uno.
Since it does the same thing on an Arduino Uno, if you have not already done so, you might try asking about this up on the Adafruit forum...

You might also mention things like, what version of Arduino you are using and on what... Likewise what version of Teensyduino?

Is your library up to date with Adafruit? Are you using the Adafruit BNO055 (https://www.adafruit.com/product/2472)?

Have you looked at Adafruit's page on device calibration? https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/device-calibration

I have one sitting on my desk now, but I have not personally gone through all of the steps, as mainly had it to be able to test Wire library with T4, but...
 
Quick update: Did you look at the FAQ page for the device? https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/faqs


FAQs
by Kevin Townsend
Can I manually set the calibration constants?

Yes you can save and restore the calibration of the sensor, check out the restore_offsets example: https://github.com/adafruit/Adafruit_BN ... ffsets.ino

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.

For further details check out the datasheet and Bosch's info on the sensor for calibration info: https://www.bosch-sensortec.com/en/homepage/products_3/sensor_hubs/iot_solutions/bno055_1/bno055_4
 
Just tried the restore_offset sketch on the Teensy 4.0.

On initial calibration when calibration is completed I see this:
Code:
Fully calibrated!

--------------------------------

Calibration Results: 

Accelerometer: 9 -78 -5 
Gyro: 0 -1 -1 
Mag: -199 240 -39 
Accel Radius: 1000
Mag Radius: 660

Storing calibration data to EEPROM...

Data stored to EEPROM.
Now if I power off and power on again:
Code:
Orientation Sensor Test
Chip ID
Switch Mode
BNO055_SYS_TRIGGER_ADDR

Found Calibration for this sensor in EEPROM.

Accelerometer: 9 -78 -5 
Gyro: 0 -1 -1 
Mag: -199 240 -39 
Accel Radius: 1000
Mag Radius: 660

[COLOR="#FF0000"]Restoring Calibration data to the BNO055...[/COLOR]  //Ok data stored

[COLOR="#FF0000"]Calibration data loaded into BNO055[/COLOR]  // ok data transferred from EEPROM to BNO055
------------------------------------
Sensor:       BNO055

Driver Ver:   1
Unique ID:    55
Max Value:    0.00 xxx
Min Value:    0.00 xxx
Resolution:   0.01 xxx

------------------------------------

System Status: 0x5
Self Test:     0xF
System Error:  0x0

[COLOR="#FF0000"]Move sensor slightly to calibrate magnetometers[/COLOR]  //This is normal per the Adafruit API.
//See @KurtE's post on mag calibration

[COLOR="#FF0000"]Fully calibrated![/COLOR]   //Mag is recalibrated on each load. 

--------------------------------
Calibration Results: 

Accelerometer: 9 -78 -5 
Gyro: 0 -1 -1 
Mag: -199 240 -39 
Accel Radius: 1000
Mag Radius: 684

[COLOR="#FF0000"]Storing calibration data to EEPROM... [/COLOR]   //Resaves cal data to eeprom.  

Data stored to EEPROM.
--------------------------------
X: 125.0000	Y: 1.4375	Z: 2.6250	Sys:3 G:3 A:3 M:3
X: 125.0000	Y: 1.4375	Z: 2.6250	Sys:3 G:3 A:3 M:3
 
Hi, thanks. Of course the answer is yes to everything. With that code when you repower on the Teensy you need to redo the WHOLE calibration, not just the magnetometers. I am asking simply to have the data loaded from EEPROM that guarantee (in absence of any magnetic interference around the sensor) the same calibrated behaviour that happened before powering it off. I am using the latest version of Teensyduino and Adafruit library.
 
en you repower on the Teensy you need to redo the WHOLE calibration, not just the magnetometers.
What I posted showed that all its doing is recalibrating the magnetometer when you power up. Which is just moving the sensor slightly on power up.

As for your other question on stability data of the BNO055 after power up maybe that is a better question for the Adafruit forum.

For reference this is the function I am using to initial the BNO055 after I upload the calibration data to the BNO055. Its a modification of the their examples.

Code:
void BNO055_Init() {
  
    delay(1000);
    telem.println("Orientation Sensor Test"); telem.println("");

    /* Initialise the sensor */
    if (!bno.begin())
    {
        /* There was a problem detecting the BNO055 ... check your connections */
        telem.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
        while (1);
    }

    int eeAddress = 0;
    long bnoID;
    bool foundCalib = false;

    EEPROM.get(eeAddress, bnoID);

    adafruit_bno055_offsets_t calibrationData;
    sensor_t sensor;

    /*
    *  Look for the sensor's unique ID at the beginning oF EEPROM.
    *  This isn't foolproof, but it's better than nothing.
    */
    bno.getSensor(&sensor);
    if (bnoID != sensor.sensor_id)
    {
        telem.println("\nNo Calibration Data for this sensor exists in EEPROM");
        delay(500);
    }
    else
    {
        telem.println("\nFound Calibration for this sensor in EEPROM.");
        eeAddress += sizeof(long);
        EEPROM.get(eeAddress, calibrationData);

        displaySensorOffsets(calibrationData);

        telem.println("\n\nRestoring Calibration data to the BNO055...");
        bno.setSensorOffsets(calibrationData);

        telem.println("\n\nCalibration data loaded into BNO055");
        foundCalib = true;
    }

    delay(1000);

    /* Display some basic information on this sensor */
    displaySensorDetails();

    /* Optional: Display current status */
    displaySensorStatus();

    bno.setExtCrystalUse(true);

    sensors_event_t event;
    bno.getEvent(&event);
    if (foundCalib){
        telem.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }
    else
    {
        telem.println("Please Calibrate Sensor: ");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);

            telem.print("X: ");
            telem.print(event.orientation.x, 4);
            telem.print("\tY: ");
            telem.print(event.orientation.y, 4);
            telem.print("\tZ: ");
            telem.print(event.orientation.z, 4);

            /* Optional: Display calibration status */
            displayCalStatus();

            /* New line for the next sample */
            telem.println("");

            /* Wait the specified delay before requesting new data */
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }

    telem.println("\nFully calibrated!");
    telem.println("--------------------------------");
    telem.println("Calibration Results: ");
    adafruit_bno055_offsets_t newCalib;
    bno.getSensorOffsets(newCalib);
    displaySensorOffsets(newCalib);

    telem.println("\n\nStoring calibration data to EEPROM...");

    eeAddress = 0;
    bno.getSensor(&sensor);
    bnoID = sensor.sensor_id;

    EEPROM.put(eeAddress, bnoID);

    eeAddress += sizeof(long);
    EEPROM.put(eeAddress, newCalib);
    telem.println("Data stored to EEPROM.");

    telem.println("\n--------------------------------\n");
    delay(500);
    
}

void displaySensorDetails(void)
{
  sensor_t sensor;
  bno.getSensor(&sensor);
  telem.println("------------------------------------");
  telem.print  ("Sensor:       "); telem.println(sensor.name);
  telem.print  ("Driver Ver:   "); telem.println(sensor.version);
  telem.print  ("Unique ID:    "); telem.println(sensor.sensor_id);
  telem.print  ("Max Value:    "); telem.print(sensor.max_value); telem.println(" xxx");
  telem.print  ("Min Value:    "); telem.print(sensor.min_value); telem.println(" xxx");
  telem.print  ("Resolution:   "); telem.print(sensor.resolution); telem.println(" xxx");
  telem.println("------------------------------------");
  telem.println("");
  delay(500);
}

/**************************************************************************/
/*
    Display some basic info about the sensor status
*/
/**************************************************************************/
void displaySensorStatus(void)
{
  /* Get the system status values (mostly for debugging purposes) */
  uint8_t system_status, self_test_results, system_error;
  system_status = self_test_results = system_error = 0;
  bno.getSystemStatus(&system_status, &self_test_results, &system_error);

  /* Display the results in the telem Monitor */
  telem.println("");
  telem.print("System Status: 0x");
  telem.println(system_status, HEX);
  telem.print("Self Test:     0x");
  telem.println(self_test_results, HEX);
  telem.print("System Error:  0x");
  telem.println(system_error, HEX);
  telem.println("");
  delay(500);
}

/**************************************************************************/
/*
    Display sensor calibration status
*/
/**************************************************************************/
void displayCalStatus(void)
{
  /* Get the four calibration values (0..3) */
  /* Any sensor data reporting 0 should be ignored, */
  /* 3 means 'fully calibrated" */
  uint8_t system, gyro, accel, mag;
  system = gyro = accel = mag = 0;
  bno.getCalibration(&system, &gyro, &accel, &mag);

  /* The data should be ignored until the system calibration is > 0 */
  telem.print("\t");
  if (!system)
  {
    telem.print("! ");
  }

  /* Display the individual values */
  telem.print("Sys:");
  telem.print(system, DEC);
  telem.print(" G:");
  telem.print(gyro, DEC);
  telem.print(" A:");
  telem.print(accel, DEC);
  telem.print(" M:");
  telem.print(mag, DEC);
}

/**************************************************************************/
/*
    Display the raw calibration offset and radius data
    */
/**************************************************************************/
void displaySensorOffsets(const adafruit_bno055_offsets_t &calibData)
{
    telem.print("Accelerometer: ");
    telem.print(calibData.accel_offset_x); telem.print(" ");
    telem.print(calibData.accel_offset_y); telem.print(" ");
    telem.print(calibData.accel_offset_z); telem.print(" ");

    telem.print("\nGyro: ");
    telem.print(calibData.gyro_offset_x); telem.print(" ");
    telem.print(calibData.gyro_offset_y); telem.print(" ");
    telem.print(calibData.gyro_offset_z); telem.print(" ");

    telem.print("\nMag: ");
    telem.print(calibData.mag_offset_x); telem.print(" ");
    telem.print(calibData.mag_offset_y); telem.print(" ");
    telem.print(calibData.mag_offset_z); telem.print(" ");

    telem.print("\nAccel Radius: ");
    telem.print(calibData.accel_radius);

    telem.print("\nMag Radius: ");
    telem.print(calibData.mag_radius);
}
I think this will give you the idea.
 
I think this will give you the idea.

Hi, your code is basically identical to the one of the examples of Adafruit. Anyways I found the solution. It is enough to add a function that when reperfoming the calibration of the magnetometer, checks ONLY if the magnetometer is calibrated (while the calibration for the accelerometer and gyroscope is reloaded from the EEPROM).

Code:
void performMagCal(void) {
  
  uint8_t system, gyro, accel, mag;
  system = gyro = accel = mag = 0;
 
  while (mag != 3) {
    
    bno.getCalibration(&system, &gyro, &accel, &mag);
    displayCalStatus();
    Serial.println("");
  }
  
  Serial.println("\nMagnetometer calibrated!");
}
 
Status
Not open for further replies.
Back
Top