MKR IMU Shield Can't go above 4Gs

Hi all,

I've got an MKR IMU Shield hooked up to the MKR 1010 and I can not figure out why the IMU wont read anything above 4Gs. I think it has something to do with the way the library is written but I'm not experienced enough in C++ to accurately edit the library.

I can't seem to find ANYTHING about this anywhere on the internet but I can't imagine I'm the only person that's ran into this problem. Any help would be greatly appriciated!

According to Arduino, that shield contains the BNO055 IMU, so check the data sheet on how to reconfigure the accelerometer.

I checked that datasheet and I found that you need to change the registers for the mode and the max G rating but I cant for the life of me actually figure out how to do it. With my limited C++ knowledge I tried to create a register and write to it to change the max G to 16 and then change the address for the mode but Its still hitting the 4G max.

Most likely, the code you forgot to post contains one or more mistakes.

For hints on how to post successfully on this forum, please read and follow the instructions in the "How to get the best out of this forum" post.

Sorry about that, just didn't want to be that person that post a huge chunk of code and just ask someone to fix it for them. But I've attached the Arduino library with my edits below. (I edited lines 99, 89, 47).

I've also attached the link to the original Arduino library and the Bosch sensor documentation for refrence. Again, I appreciate the help!

/*
  This file is part of the MKRIMU library.
  Copyright (c) 2018 Arduino SA. All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "IMU.h"

// from Table 3-14 in the datasheet
#define ACCELEROMETER_SAMPLE_RATE     100
#define ACCELEROMETER_PERIOD_MS       (1000 / ACCELEROMETER_SAMPLE_RATE)
#define GYROSCOPE_SAMPLE_RATE         100
#define GYROSCOPE_PERIOD_MS           (1000 / ACCELEROMETER_SAMPLE_RATE)
#define MAGNETOMETER_SAMPLE_RATE      20
#define MAGNETOMETER_PERIOD_MS        (1000 / MAGNETOMETER_SAMPLE_RATE)
#define EULER_ANGLES_SAMPLE_RATE      100
#define EULER_ANGLES_PERIOD_MS        (1000 / EULER_ANGLES_SAMPLE_RATE)

#define BNNO055_ADDRESS                0x28

#define BNNO055_CHIP_ID_REG            0x00
#define BNNO055_ACC_DATA_X_LSB_REG     0x08
#define BNNO055_MAG_DATA_X_LSB_REG     0x0e
#define BNNO055_GYR_DATA_X_LSB_REG     0x14
#define BNNO055_EUL_DATA_X_LSB_REG     0x1a
#define BNNO055_PAGE_ID_REG            0x07
#define BNNO055_TEMP_REG               0x34
#define BNNO055_SYS_STATUS_REG         0x39
#define BNNO055_UNIT_SEL_REG           0x3b
#define BNNO055_OPR_MODE_REG           0x3d
#define BNNO055_SYS_TRIGGER_REG        0x3f
#define BNNO055_AXIS_MAP_CONFIG_REG    0x41
#define BNNO055_AXIS_MAP_SIGN_REG      0x42
#define BNNO055_ACC_CONFIG_REG	       0x08  //MY ADDITION

IMUClass::IMUClass(TwoWire& wire, int irqPin) : 
  _wire(&wire),
  _irqPin(irqPin)
{
}

IMUClass::~IMUClass()
{
}

int IMUClass::begin()
{
  _lastAccelerationReadMillis  = 0;
  _lastGyroscopeReadMillis     = 0;
  _lastMagneticFieldReadMillis = 0;
  _lastEulerAnglesReadMillis   = 0;

  _wire->begin();

  if (readRegister(BNNO055_CHIP_ID_REG) != 0xa0) {
    end();

    return 0;
  }

  // enter config mode
  writeRegister(BNNO055_OPR_MODE_REG, 0x00);
  delay(19);

  // select page id 0
  writeRegister(BNNO055_PAGE_ID_REG, 0x00);

  // enable external clock
  writeRegister(BNNO055_SYS_TRIGGER_REG, 0x80);

  // set acceleration unit to mG's, and fusion data output mode to Android
  writeRegister(BNNO055_UNIT_SEL_REG, 0x81);
  
  // set accelerometer max to 16G
  
  writeRegister(BNNO055_ACC_CONFIG_REG, 0x0F );  //MY ADDITION
  

  // set X = X, Y = Y, Z = Z
  writeRegister(BNNO055_AXIS_MAP_CONFIG_REG, 0x24);

  // invert X and Y axis signs
  writeRegister(BNNO055_AXIS_MAP_SIGN_REG, 0x06);

  // enter NDOF mode
  writeRegister(BNNO055_OPR_MODE_REG, 0X04);      //Changed address per bosch doc
  delay(7);



  return 1;
}

void IMUClass::end()
{
  // try to set config mode
  writeRegister(BNNO055_OPR_MODE_REG, 0x00);
    delay(19);
  _wire->end();
}

int IMUClass::readAcceleration(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastAccelerationReadMillis = millis();

  if (!readRegisters(BNNO055_ACC_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert mg to G's
  x = data[0] / 1000.0;
  y = data[1] / 1000.0;
  z = data[2] / 1000.0;

  return 1;
}

int IMUClass::accelerationAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastAccelerationReadMillis) < ACCELEROMETER_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::accelerationSampleRate()
{
  return ACCELEROMETER_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readGyroscope(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastGyroscopeReadMillis = millis();

  if (!readRegisters(BNNO055_GYR_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert degrees per second
  x = data[0] / 16.0;
  y = data[1] / 16.0;
  z = data[2] / 16.0;

  return 1;
}

int IMUClass::gyroscopeAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastGyroscopeReadMillis) < GYROSCOPE_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::gyroscopeSampleRate()
{
  return GYROSCOPE_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readMagneticField(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastMagneticFieldReadMillis = millis();

  if (!readRegisters(BNNO055_MAG_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert uT
  x = data[0] / 16.0;
  y = data[1] / 16.0;
  z = data[2] / 16.0;

  return 1;
}

int IMUClass::magneticFieldAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastMagneticFieldReadMillis) < MAGNETOMETER_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::magneticFieldSampleRate()
{
  return MAGNETOMETER_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readEulerAngles(float& heading, float& roll, float& pitch)
{
  int16_t data[3];

  _lastEulerAnglesReadMillis = millis();

  if (!readRegisters(BNNO055_EUL_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    heading = NAN;
    roll = NAN;
    pitch = NAN;

    return 0;
  }

  // convert degrees
  heading = data[0] / 16.0;
  roll = data[1] / 16.0;
  pitch = data[2] / 16.0;

  return 1;
}

int IMUClass::eulerAnglesAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastEulerAnglesReadMillis) < EULER_ANGLES_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::eulerAnglesSampleRate()
{
  return EULER_ANGLES_SAMPLE_RATE; // fixed in fusion mode
}

float IMUClass::readTemperature()
{
  int temp = readRegister(BNNO055_TEMP_REG);

  if (temp == -1) {
    return NAN;
  }

  return (int8_t)temp;
}

int IMUClass::readRegister(uint8_t address)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  if (_wire->endTransmission(false) != 0) {
    return -1;
  }

  if (_wire->requestFrom(BNNO055_ADDRESS, 1) != 1) {
    return -1;
  }

  return _wire->read();
}

int IMUClass::readRegisters(uint8_t address, uint8_t* data, size_t length)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  if (_wire->endTransmission(false) != 0) {
    return -1;
  }

  if (_wire->requestFrom(BNNO055_ADDRESS, length) != length) {
    return 0;
  }

  for (size_t i = 0; i < length; i++) {
    *data++ = _wire->read();
  }

  return 1;
}

int IMUClass::writeRegister(uint8_t address, uint8_t value)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  _wire->write(value);
  if (_wire->endTransmission() != 0) {
    return 0;
  }

  return 1;
}

IMUClass IMU(Wire, 0);

You also need to explain what you tried to do, and what happened instead.

If all you need to do is measure acceleration, that can be done in about 10 lines of code.

Keep in mind that if you change the maximum acceleration, the 3D orientation firmware may not function correctly. It doesn't work very well anyway, so this may not be a great loss.

Edit: I just checked the data sheet, and you can't use fusion mode at all in high-g mode, as it has complete control of the accelerometer parameters. You would probably be better off using a different accelerometer entirely. Choose one with a library that allows complete control over the sensor.

So my primary goal is just to read accelerations of up to 10Gs (16G mode on the sensor). I don't need 3D orientation so that is okay. I tried changing the mode on line 99, to a non-fusion mode to allow for the 16G mode to work. Line 47 and 89 are me defining the accelerometer register and writing to it respectively to tell it to change to 16G mode.

In my testing I confirmed that the mode IS changing via my edits to line 99 because when I switch the mode to accelerometer only, none of Arduinos example code for magnometer etc. work and they did prior to me changing the mode but the accelerometer example code works as expected.

Select the ACCONLY non-fusion mode.

I did so by changing line 99 to:

  writeRegister(BNNO055_OPR_MODE_REG, 0X01);
  delay(7);

per ACCONLY non-fusion mode being 0000 0001 on page 22 of the documentation but am getting the same result. The way I read the documentation and the library is that the sensor needs to be put into CONFIG mode in order to change its properties which is what I THINK the library is doing yet it seems to change the mode but still not change the max of the accelerometer.

EDIT: just for context, this is what Im seeing when shaking the IMU around, the Arduino example is plotting X,Y,Z accel. You can see when I shake it it plateaus at +-4Gs and does this for X Y and Z.

You are on the right track, just not there yet.

I also just changed lines 87 and 88:

  // set accelerometer max to 16G
  writeRegister(BNNO055_ACC_CONFIG_REG, 0x1F );

per this part of the documentation but still stuck at 4Gs


I am so close I can feel it......

Still no luck, have any pointers at what I should be looking at?

From my little experience, I have some suggestions to be taken into account to configure BNO055:

  • BNO055 writtable registers can only be modified with the device in Config Mode (p. 23 of the datasheet), which means OPR_MODE = xxxx0000b

  • A note on setting values in registers: The bits reserved or marked with "x" should not be modified when writing to the registers. This means that before writing the new value, you should first read the register value, set to "0" or "1" the bits you want to change using bit-level AND or OR operations, and write the modified value in the register.

  • The ACC_Config register is in address 0x08 in PAGE 1 of the register bank. You should set the page_ID to 1 (register 0x07 in both Page 0 and Page 1) before writting the new value of this register.

  • Set the OPR_MODE to ACCONLY mode when you have made all desired changes in configuration. To make new configuration changes you have to set again the OPR_MODE to CONFIG_MODE

Thanks for the pointers!

From the code I posted on Post#5, I think I did the stuff you mentioned here apart from setting the ACC_Config register to 0x08 on Page 1, it looks like the library author did it on page 0 but I'm not sure how to do it in page 1 as well.

Please post the revised code, in a new post.

Here is the updated code with the changes mentioned in prior posts:

/*
  This file is part of the MKRIMU library.
  Copyright (c) 2018 Arduino SA. All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "IMU.h"

// from Table 3-14 in the datasheet
#define ACCELEROMETER_SAMPLE_RATE     100
#define ACCELEROMETER_PERIOD_MS       (1000 / ACCELEROMETER_SAMPLE_RATE)
#define GYROSCOPE_SAMPLE_RATE         100
#define GYROSCOPE_PERIOD_MS           (1000 / ACCELEROMETER_SAMPLE_RATE)
#define MAGNETOMETER_SAMPLE_RATE      20
#define MAGNETOMETER_PERIOD_MS        (1000 / MAGNETOMETER_SAMPLE_RATE)
#define EULER_ANGLES_SAMPLE_RATE      100
#define EULER_ANGLES_PERIOD_MS        (1000 / EULER_ANGLES_SAMPLE_RATE)

#define BNNO055_ADDRESS                0x28

#define BNNO055_CHIP_ID_REG            0x00
#define BNNO055_ACC_DATA_X_LSB_REG     0x08
#define BNNO055_MAG_DATA_X_LSB_REG     0x0e
#define BNNO055_GYR_DATA_X_LSB_REG     0x14
#define BNNO055_EUL_DATA_X_LSB_REG     0x1a
#define BNNO055_PAGE_ID_REG            0x07
#define BNNO055_TEMP_REG               0x34
#define BNNO055_SYS_STATUS_REG         0x39
#define BNNO055_UNIT_SEL_REG           0x3b
#define BNNO055_OPR_MODE_REG           0x3d
#define BNNO055_SYS_TRIGGER_REG        0x3f
#define BNNO055_AXIS_MAP_CONFIG_REG    0x41
#define BNNO055_AXIS_MAP_SIGN_REG      0x42
#define BNNO055_ACC_CONFIG_REG	       0x08

IMUClass::IMUClass(TwoWire& wire, int irqPin) : 
  _wire(&wire),
  _irqPin(irqPin)
{
}

IMUClass::~IMUClass()
{
}

int IMUClass::begin()
{
  _lastAccelerationReadMillis  = 0;
  _lastGyroscopeReadMillis     = 0;
  _lastMagneticFieldReadMillis = 0;
  _lastEulerAnglesReadMillis   = 0;

  _wire->begin();

  if (readRegister(BNNO055_CHIP_ID_REG) != 0xa0) {
    end();

    return 0;
  }

  // enter config mode
  writeRegister(BNNO055_OPR_MODE_REG, 0x00);
  delay(19);

  // select page id 0
  writeRegister(BNNO055_PAGE_ID_REG, 0x00);

  // enable external clock
  writeRegister(BNNO055_SYS_TRIGGER_REG, 0x80);

  // set acceleration unit to mG's, and fusion data output mode to Android
  writeRegister(BNNO055_UNIT_SEL_REG, 0x81);
  
  // set accelerometer max to 16G
  writeRegister(BNNO055_ACC_CONFIG_REG, 0x1F );
  

  // set X = X, Y = Y, Z = Z
  writeRegister(BNNO055_AXIS_MAP_CONFIG_REG, 0x24);

  // invert X and Y axis signs
  writeRegister(BNNO055_AXIS_MAP_SIGN_REG, 0x06);

  // enter NDOF mode
  writeRegister(BNNO055_OPR_MODE_REG, 0X01);
  delay(7);



  return 1;
}

void IMUClass::end()
{
  // try to set config mode
  writeRegister(BNNO055_OPR_MODE_REG, 0x00);
    delay(19);
  _wire->end();
}

int IMUClass::readAcceleration(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastAccelerationReadMillis = millis();

  if (!readRegisters(BNNO055_ACC_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert mg to G's
  x = data[0] / 1000.0;
  y = data[1] / 1000.0;
  z = data[2] / 1000.0;

  return 1;
}

int IMUClass::accelerationAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastAccelerationReadMillis) < ACCELEROMETER_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::accelerationSampleRate()
{
  return ACCELEROMETER_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readGyroscope(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastGyroscopeReadMillis = millis();

  if (!readRegisters(BNNO055_GYR_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert degrees per second
  x = data[0] / 16.0;
  y = data[1] / 16.0;
  z = data[2] / 16.0;

  return 1;
}

int IMUClass::gyroscopeAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastGyroscopeReadMillis) < GYROSCOPE_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::gyroscopeSampleRate()
{
  return GYROSCOPE_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readMagneticField(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastMagneticFieldReadMillis = millis();

  if (!readRegisters(BNNO055_MAG_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert uT
  x = data[0] / 16.0;
  y = data[1] / 16.0;
  z = data[2] / 16.0;

  return 1;
}

int IMUClass::magneticFieldAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastMagneticFieldReadMillis) < MAGNETOMETER_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::magneticFieldSampleRate()
{
  return MAGNETOMETER_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readEulerAngles(float& heading, float& roll, float& pitch)
{
  int16_t data[3];

  _lastEulerAnglesReadMillis = millis();

  if (!readRegisters(BNNO055_EUL_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    heading = NAN;
    roll = NAN;
    pitch = NAN;

    return 0;
  }

  // convert degrees
  heading = data[0] / 16.0;
  roll = data[1] / 16.0;
  pitch = data[2] / 16.0;

  return 1;
}

int IMUClass::eulerAnglesAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastEulerAnglesReadMillis) < EULER_ANGLES_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::eulerAnglesSampleRate()
{
  return EULER_ANGLES_SAMPLE_RATE; // fixed in fusion mode
}

float IMUClass::readTemperature()
{
  int temp = readRegister(BNNO055_TEMP_REG);

  if (temp == -1) {
    return NAN;
  }

  return (int8_t)temp;
}

int IMUClass::readRegister(uint8_t address)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  if (_wire->endTransmission(false) != 0) {
    return -1;
  }

  if (_wire->requestFrom(BNNO055_ADDRESS, 1) != 1) {
    return -1;
  }

  return _wire->read();
}

int IMUClass::readRegisters(uint8_t address, uint8_t* data, size_t length)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  if (_wire->endTransmission(false) != 0) {
    return -1;
  }

  if (_wire->requestFrom(BNNO055_ADDRESS, length) != length) {
    return 0;
  }

  for (size_t i = 0; i < length; i++) {
    *data++ = _wire->read();
  }

  return 1;
}

int IMUClass::writeRegister(uint8_t address, uint8_t value)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  _wire->write(value);
  if (_wire->endTransmission() != 0) {
    return 0;
  }

  return 1;
}

IMUClass IMU(Wire, 0);

Comments on your code.

  • To enter configuration mode you should:

    • Read the OPR_MODE_REG
    • Set its four LSB to 0.
    • Write the new value to OPR_MODE_REG

    The procedure above, that avoids overwritting reserved bits, should be used to modify values in registers that contain both reserved and read/write bits: read original value; modify desired bits; rewrite new value. (see page 54)

  • Before writing ACC_CONFIG_REG, PAGE_ID should be set to 1.

  • After writing the desired ACC_CONFIG value, PAGE_ID should be set again to 0, if the next registers to be read/modified are in Page 0.

Thanks! Pardon my ignorance, im not super experienced in C++, I was not sure what you meant by setting the OPR_MODE_REGs 4 LSB to 0. I made edits in lines 74-82 but left out setting the LSB to 0.

I also switched to page 1 and back to page 0 after writing to the ACC_CONFIG register in lines 95-100.

I've attached my code below, thanks for the help btw!

/*
  This file is part of the MKRIMU library.
  Copyright (c) 2018 Arduino SA. All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "IMU.h"

// from Table 3-14 in the datasheet
#define ACCELEROMETER_SAMPLE_RATE     100
#define ACCELEROMETER_PERIOD_MS       (1000 / ACCELEROMETER_SAMPLE_RATE)
#define GYROSCOPE_SAMPLE_RATE         100
#define GYROSCOPE_PERIOD_MS           (1000 / ACCELEROMETER_SAMPLE_RATE)
#define MAGNETOMETER_SAMPLE_RATE      20
#define MAGNETOMETER_PERIOD_MS        (1000 / MAGNETOMETER_SAMPLE_RATE)
#define EULER_ANGLES_SAMPLE_RATE      100
#define EULER_ANGLES_PERIOD_MS        (1000 / EULER_ANGLES_SAMPLE_RATE)

#define BNNO055_ADDRESS                0x28

#define BNNO055_CHIP_ID_REG            0x00
#define BNNO055_ACC_DATA_X_LSB_REG     0x08
#define BNNO055_MAG_DATA_X_LSB_REG     0x0e
#define BNNO055_GYR_DATA_X_LSB_REG     0x14
#define BNNO055_EUL_DATA_X_LSB_REG     0x1a
#define BNNO055_PAGE_ID_REG            0x07
#define BNNO055_TEMP_REG               0x34
#define BNNO055_SYS_STATUS_REG         0x39
#define BNNO055_UNIT_SEL_REG           0x3b
#define BNNO055_OPR_MODE_REG           0x3d
#define BNNO055_SYS_TRIGGER_REG        0x3f
#define BNNO055_AXIS_MAP_CONFIG_REG    0x41
#define BNNO055_AXIS_MAP_SIGN_REG      0x42
#define BNNO055_ACC_CONFIG_REG	       0x08

IMUClass::IMUClass(TwoWire& wire, int irqPin) : 
  _wire(&wire),
  _irqPin(irqPin)
{
}

IMUClass::~IMUClass()
{
}

int IMUClass::begin()
{
  _lastAccelerationReadMillis  = 0;
  _lastGyroscopeReadMillis     = 0;
  _lastMagneticFieldReadMillis = 0;
  _lastEulerAnglesReadMillis   = 0;

  _wire->begin();

  if (readRegister(BNNO055_CHIP_ID_REG) != 0xa0) {
    end();

    return 0;
  }

  // enter config mode
  readRegister(BNNO055_OPR_MODE_REG, 0x00);
  delay(19);
  
  //Set 4 LSB for OPR_MODE_REG to 0 ?????
  
  //writing new value(?)
  writeRegister(BNNO055_OPR_MODE_REG, 0x00);
  delay(19);


  // select page id 0
  writeRegister(BNNO055_PAGE_ID_REG, 0x0);

  // enable external clock
  writeRegister(BNNO055_SYS_TRIGGER_REG, 0x80);

  // set acceleration unit to mG's, and fusion data output mode to Android
  writeRegister(BNNO055_UNIT_SEL_REG, 0x81);


  // select page id 1
  writeRegister(BNNO055_PAGE_ID_REG, 0x01);  
  // set accelerometer max to 16G
  writeRegister(BNNO055_ACC_CONFIG_REG, 0x1F );
  // select page id 0
  writeRegister(BNNO055_PAGE_ID_REG, 0x0);  

  // set X = X, Y = Y, Z = Z
  writeRegister(BNNO055_AXIS_MAP_CONFIG_REG, 0x24);

  // invert X and Y axis signs
  writeRegister(BNNO055_AXIS_MAP_SIGN_REG, 0x06);

  // enter NDOF mode
  writeRegister(BNNO055_OPR_MODE_REG, 0X01);
  delay(7);



  return 1;
}

void IMUClass::end()
{
  // try to set config mode
  writeRegister(BNNO055_OPR_MODE_REG, 0x00);
    delay(19);
  _wire->end();
}

int IMUClass::readAcceleration(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastAccelerationReadMillis = millis();

  if (!readRegisters(BNNO055_ACC_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert mg to G's
  x = data[0] / 1000.0;
  y = data[1] / 1000.0;
  z = data[2] / 1000.0;

  return 1;
}

int IMUClass::accelerationAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastAccelerationReadMillis) < ACCELEROMETER_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::accelerationSampleRate()
{
  return ACCELEROMETER_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readGyroscope(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastGyroscopeReadMillis = millis();

  if (!readRegisters(BNNO055_GYR_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert degrees per second
  x = data[0] / 16.0;
  y = data[1] / 16.0;
  z = data[2] / 16.0;

  return 1;
}

int IMUClass::gyroscopeAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastGyroscopeReadMillis) < GYROSCOPE_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::gyroscopeSampleRate()
{
  return GYROSCOPE_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readMagneticField(float& x, float& y, float& z)
{
  int16_t data[3];

  _lastMagneticFieldReadMillis = millis();

  if (!readRegisters(BNNO055_MAG_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    x = NAN;
    y = NAN;
    z = NAN;

    return 0;
  }

  // convert uT
  x = data[0] / 16.0;
  y = data[1] / 16.0;
  z = data[2] / 16.0;

  return 1;
}

int IMUClass::magneticFieldAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastMagneticFieldReadMillis) < MAGNETOMETER_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::magneticFieldSampleRate()
{
  return MAGNETOMETER_SAMPLE_RATE; // fixed in fusion mode
}

int IMUClass::readEulerAngles(float& heading, float& roll, float& pitch)
{
  int16_t data[3];

  _lastEulerAnglesReadMillis = millis();

  if (!readRegisters(BNNO055_EUL_DATA_X_LSB_REG, (uint8_t*)data, sizeof(data))) {
    heading = NAN;
    roll = NAN;
    pitch = NAN;

    return 0;
  }

  // convert degrees
  heading = data[0] / 16.0;
  roll = data[1] / 16.0;
  pitch = data[2] / 16.0;

  return 1;
}

int IMUClass::eulerAnglesAvailable()
{
  unsigned long now = millis();

  if (abs((long)now - (long)_lastEulerAnglesReadMillis) < EULER_ANGLES_PERIOD_MS) {
    return 0;
  }

  return 1;
}

float IMUClass::eulerAnglesSampleRate()
{
  return EULER_ANGLES_SAMPLE_RATE; // fixed in fusion mode
}

float IMUClass::readTemperature()
{
  int temp = readRegister(BNNO055_TEMP_REG);

  if (temp == -1) {
    return NAN;
  }

  return (int8_t)temp;
}

int IMUClass::readRegister(uint8_t address)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  if (_wire->endTransmission(false) != 0) {
    return -1;
  }

  if (_wire->requestFrom(BNNO055_ADDRESS, 1) != 1) {
    return -1;
  }

  return _wire->read();
}

int IMUClass::readRegisters(uint8_t address, uint8_t* data, size_t length)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  if (_wire->endTransmission(false) != 0) {
    return -1;
  }

  if (_wire->requestFrom(BNNO055_ADDRESS, length) != length) {
    return 0;
  }

  for (size_t i = 0; i < length; i++) {
    *data++ = _wire->read();
  }

  return 1;
}

int IMUClass::writeRegister(uint8_t address, uint8_t value)
{
  _wire->beginTransmission(BNNO055_ADDRESS);
  _wire->write(address);
  _wire->write(value);
  if (_wire->endTransmission() != 0) {
    return 0;
  }

  return 1;
}

IMUClass IMU(Wire, 0);

I found a solution, all I needed to do was change the page ID to page 1 before trying to change the ACC_Config to 16Gs then change it back to page 0 after changing it.

  // select page id 1
  writeRegister(BNNO055_PAGE_ID_REG, 0x01);  
  // set accelerometer max to 16G
  writeRegister(BNNO055_ACC_CONFIG_REG, 0x1F );
  // select page id 0
  writeRegister(BNNO055_PAGE_ID_REG, 0x0); ```