user37223: Board: ESP32
Script: restore_offsets.ino from Adafruit's BNO055 library
The only difference is I am storing the information in ESP's NVS using the Preferences Library
Code
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
#include <Preferences.h>


/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (1000)

Adafruit_BNO055 bno = Adafruit_BNO055(1390);

Preferences Calibration;

/**************************************************************************/
/*
    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 Serial Monitor */
    Serial.println("");
    Serial.print("System Status: 0x");
    Serial.println(system_status, HEX);
    Serial.print("Self Test:     0x");
    Serial.println(self_test_results, HEX);
    Serial.print("System Error:  0x");
    Serial.println(system_error, HEX);
    Serial.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 */
    Serial.print("\t");
    if (!system)
    {
        Serial.print("! ");
    }

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

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

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

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

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

    Serial.print("\nMag Radius: ");
    Serial.print(calibData.mag_radius);
}


/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
    */
/**************************************************************************/
void setup(void)
{
    Wire.begin(13, 16, 400000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("Orientation Sensor Test"); Serial.println("");

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

    Calibration.begin("offsets", false);
    adafruit_bno055_offsets_t calibrationData;
    sensor_t sensor;

    int32_t bnoID = Calibration.getInt("bnoID");
     bool foundCalib = false;
    /*
    *  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)
    {
        Serial.println("\nNo Calibration Data for this sensor exists in NVS");
        delay(500);
    }
    else
    {
        Serial.println("\nFound Calibration for this sensor in NVS.");

        // Accelerometer offsets
        calibrationData.accel_offset_x = Calibration.getInt("acc_off_x");
        calibrationData.accel_offset_y = Calibration.getInt("acc_off_y");
        calibrationData.accel_offset_z = Calibration.getInt("acc_off_z");

        // Gyroscrope offsets
        calibrationData.gyro_offset_x = Calibration.getInt("gyr_off_x");
        calibrationData.gyro_offset_y = Calibration.getInt("gyr_off_y");
        calibrationData.gyro_offset_z = Calibration.getInt("gyr_off_z");

        // Magnetometer offsets
        calibrationData.mag_offset_x = Calibration.getInt("mag_off_x");
        calibrationData.mag_offset_y = Calibration.getInt("mag_off_y");
        calibrationData.mag_offset_z = Calibration.getInt("mag_off_z"); 

        displaySensorOffsets(calibrationData);

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

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

    delay(1000);

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

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

   //Crystal must be configured AFTER loading calibration data into BNO055.
    bno.setExtCrystalUse(true);

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

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

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

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

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

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

    Serial.println("\n\nStoring calibration data to NVS...");

    bno.getSensor(&sensor);
    bnoID = sensor.sensor_id;
    // enter the Sensor ID
    Calibration.putInt("bnoID", bnoID);

    // store new Accelerometer offsets
    Calibration.putInt("acc_off_x", newCalib.accel_offset_x);
    Calibration.putInt("acc_off_y", newCalib.accel_offset_y);
    Calibration.putInt("acc_off_z", newCalib.accel_offset_z);

    // store new Gyroscope offsets
    Calibration.putInt("gyr_off_x", newCalib.gyro_offset_x);
    Calibration.putInt("gyr_off_y", newCalib.gyro_offset_y);
    Calibration.putInt("gyr_off_z", newCalib.gyro_offset_z);

    // store new Magnetometer offsets
    Calibration.putInt("mag_off_x", newCalib.mag_offset_x);
    Calibration.putInt("mag_off_y", newCalib.mag_offset_y);
    Calibration.putInt("mag_off_z", newCalib.mag_offset_z);
    Serial.println("Data stored to NVS..");

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

void loop() {
    /* Get a new sensor event */
    sensors_event_t event;
    bno.getEvent(&event);

    /* Display the floating point data */
    Serial.print("X: ");
    Serial.print(event.orientation.x, 4);
    Serial.print("\tY: ");
    Serial.print(event.orientation.y, 4);
    Serial.print("\tZ: ");
    Serial.print(event.orientation.z, 4);

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

    /* Optional: Display sensor status (debug only) */
    displaySensorStatus();

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

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

The only difference in the code is instead of passing the offset struct I save information individually using putInt method
steps

I calibrate the sensor connected via I2C
Once the calibration is done store it into NVS
Observe values for a bit
Restart the node and retreive the offsets from NVS

Problem
The calibration offsets are stored into the BNO and it takes hella time in the following block:
   if (foundCalib){
        Serial.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&event);
            displayCalStatus();
            Serial.println("");
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }

I added the displayCalStatus to see the values of the accelerometer, gyroscope and magnetometer and all values within the block are Zero.
Doesn't this defy the whole idea of storing offsets in the first place if the values are all zero?
Output from board
Found Calibration for this sensor in NVS.
Accelerometer: 19 -10 4 
Gyro: -3 -4 9 
Mag: 589 986 1473 
Accel Radius: 0
Mag Radius: 0

Restoring Calibration data to the BNO055...


Calibration data loaded into BNO055

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

Move sensor slightly to calibrate magnetometers
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0

As you can observe the calibration are all set to 0 and I have to do the whole thing again. why ?

user37622: The displayCalStatus() function shows the status of the calibration, not the offsets or current sensor values. With calibration in progress the status is zero. Once the calibration of a sensor is complete, the status is 3. The sensor starts the calibration itself with first movements after power up.
The set offsets are used after power-up only until the initial automatic calibration finished.
from datasheet:

Once  the  device  is  calibrated,  the  calibration  profile  can  be  reused  to  get  the 
  correct  orientation  data  immediately  after  ‘Power  of  Reset’.  However,  once  the  sensor  enters  the  internal 
  calibration  routine,  the  calibration  profile  is  overwritten 
  with  the  newly  obtained  sensor  offsets  and  sensor radius.


37223: <p>Board: <strong>ESP32</strong></p>

<p>Script: <a href="https://github.com/adafruit/Adafruit_BNO055" rel="nofollow noreferrer">restore_offsets.ino from Adafruit's BNO055 library</a></p>

<p>The only difference is I am storing the information in ESP's <strong>NVS</strong> using the <code>Preferences</code> Library</p>

<h3>Code</h3>

<pre><code>#include &lt;Wire.h&gt;
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_BNO055.h&gt;
#include &lt;utility/imumaths.h&gt;
#include &lt;Preferences.h&gt;


/* Set the delay between fresh samples */
#define BNO055_SAMPLERATE_DELAY_MS (1000)

Adafruit_BNO055 bno = Adafruit_BNO055(1390);

Preferences Calibration;

/**************************************************************************/
/*
    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(&amp;system_status, &amp;self_test_results, &amp;system_error);

    /* Display the results in the Serial Monitor */
    Serial.println("");
    Serial.print("System Status: 0x");
    Serial.println(system_status, HEX);
    Serial.print("Self Test:     0x");
    Serial.println(self_test_results, HEX);
    Serial.print("System Error:  0x");
    Serial.println(system_error, HEX);
    Serial.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(&amp;system, &amp;gyro, &amp;accel, &amp;mag);

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

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

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

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

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

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

    Serial.print("\nMag Radius: ");
    Serial.print(calibData.mag_radius);
}


/**************************************************************************/
/*
    Arduino setup function (automatically called at startup)
    */
/**************************************************************************/
void setup(void)
{
    Wire.begin(13, 16, 400000);
    Serial.begin(115200);
    delay(1000);
    Serial.println("Orientation Sensor Test"); Serial.println("");

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

    Calibration.begin("offsets", false);
    adafruit_bno055_offsets_t calibrationData;
    sensor_t sensor;

    int32_t bnoID = Calibration.getInt("bnoID");
     bool foundCalib = false;
    /*
    *  Look for the sensor's unique ID at the beginning oF EEPROM.
    *  This isn't foolproof, but it's better than nothing.
    */
    bno.getSensor(&amp;sensor);
    if (bnoID != sensor.sensor_id)
    {
        Serial.println("\nNo Calibration Data for this sensor exists in NVS");
        delay(500);
    }
    else
    {
        Serial.println("\nFound Calibration for this sensor in NVS.");

        // Accelerometer offsets
        calibrationData.accel_offset_x = Calibration.getInt("acc_off_x");
        calibrationData.accel_offset_y = Calibration.getInt("acc_off_y");
        calibrationData.accel_offset_z = Calibration.getInt("acc_off_z");

        // Gyroscrope offsets
        calibrationData.gyro_offset_x = Calibration.getInt("gyr_off_x");
        calibrationData.gyro_offset_y = Calibration.getInt("gyr_off_y");
        calibrationData.gyro_offset_z = Calibration.getInt("gyr_off_z");

        // Magnetometer offsets
        calibrationData.mag_offset_x = Calibration.getInt("mag_off_x");
        calibrationData.mag_offset_y = Calibration.getInt("mag_off_y");
        calibrationData.mag_offset_z = Calibration.getInt("mag_off_z"); 

        displaySensorOffsets(calibrationData);

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

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

    delay(1000);

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

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

   //Crystal must be configured AFTER loading calibration data into BNO055.
    bno.setExtCrystalUse(true);

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

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

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

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

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

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

    Serial.println("\n\nStoring calibration data to NVS...");

    bno.getSensor(&amp;sensor);
    bnoID = sensor.sensor_id;
    // enter the Sensor ID
    Calibration.putInt("bnoID", bnoID);

    // store new Accelerometer offsets
    Calibration.putInt("acc_off_x", newCalib.accel_offset_x);
    Calibration.putInt("acc_off_y", newCalib.accel_offset_y);
    Calibration.putInt("acc_off_z", newCalib.accel_offset_z);

    // store new Gyroscope offsets
    Calibration.putInt("gyr_off_x", newCalib.gyro_offset_x);
    Calibration.putInt("gyr_off_y", newCalib.gyro_offset_y);
    Calibration.putInt("gyr_off_z", newCalib.gyro_offset_z);

    // store new Magnetometer offsets
    Calibration.putInt("mag_off_x", newCalib.mag_offset_x);
    Calibration.putInt("mag_off_y", newCalib.mag_offset_y);
    Calibration.putInt("mag_off_z", newCalib.mag_offset_z);
    Serial.println("Data stored to NVS..");

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

void loop() {
    /* Get a new sensor event */
    sensors_event_t event;
    bno.getEvent(&amp;event);

    /* Display the floating point data */
    Serial.print("X: ");
    Serial.print(event.orientation.x, 4);
    Serial.print("\tY: ");
    Serial.print(event.orientation.y, 4);
    Serial.print("\tZ: ");
    Serial.print(event.orientation.z, 4);

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

    /* Optional: Display sensor status (debug only) */
    displaySensorStatus();

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

    /* Wait the specified delay before requesting new data */
    delay(BNO055_SAMPLERATE_DELAY_MS);
}
</code></pre>

<p>The only difference in the code is instead of passing the offset struct I save information individually using <code>putInt</code> method</p>

<h3>steps</h3>

<ol>
<li>I calibrate the sensor connected via I2C</li>
<li>Once the calibration is done store it into NVS</li>
<li>Observe values for a bit</li>
<li>Restart the node and retreive the offsets from NVS</li>
</ol>

<h2>Problem</h2>

<p>The calibration offsets are stored into the BNO and it takes <em>hella time</em> in the following block:</p>

<pre><code>   if (foundCalib){
        Serial.println("Move sensor slightly to calibrate magnetometers");
        while (!bno.isFullyCalibrated())
        {
            bno.getEvent(&amp;event);
            displayCalStatus();
            Serial.println("");
            delay(BNO055_SAMPLERATE_DELAY_MS);
        }
    }
</code></pre>

<p>I added the <code>displayCalStatus</code> to see the values of the accelerometer, gyroscope and magnetometer and all values within the block are Zero.</p>

<p>Doesn't this defy the whole idea of storing offsets in the first place if the values are all zero?</p>

<h3>Output from board</h3>

<pre><code>Found Calibration for this sensor in NVS.
Accelerometer: 19 -10 4 
Gyro: -3 -4 9 
Mag: 589 986 1473 
Accel Radius: 0
Mag Radius: 0

Restoring Calibration data to the BNO055...


Calibration data loaded into BNO055

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

Move sensor slightly to calibrate magnetometers
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:0 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
    ! Sys:0 G:3 A:0 M:0
</code></pre>

<p>As you can observe the calibration are all set to 0 and I have to do the whole thing again. why ?</p>
 37622: <p>The displayCalStatus() function shows the status of the calibration, not the offsets or current sensor values. With calibration in progress the status is zero. Once the calibration of a sensor is complete, the status is 3. The sensor starts the calibration itself with first movements after power up.</p>

<p>The set offsets are used after power-up only until the initial automatic calibration finished.</p>

<p>from datasheet:</p>

<blockquote>
  <p>Once  the  device  is  calibrated,  the  calibration  profile  can  be  reused  to  get  the 
  correct  orientation  data  <strong>immediately  after  ‘Power  of  Reset’</strong>.  However,  once  the  sensor  enters  the  internal 
  calibration  routine,  the  calibration  profile  <strong>is  overwritten</strong> 
  with  the  newly  obtained  sensor  offsets  and  sensor radius.</p>
</blockquote>
