BNO055 accelerometer, gyroscope, magnetometer with basic Adafruit library – 1

Spread the love

The BNO055 is a System in Package (SiP), integrating a triaxial 14-bit accelerometer, a triaxial 16-bit gyroscope with a range of ±2000 degrees per second, a triaxial geomagnetic sensor, and a 32-bit cortex M0+ microcontroller running Bosch Sensortec sensor fusion software, in a single package.

BNO055 accelerometer, gyroscope, magnetometer and orientation software
BNO055 accelerometer, gyroscope, magnetometer and orientation software

The BNO055 can output the following sensor data:

  • Absolute Orientation (Euler Vector, 100Hz) Three axis orientation data based on a 360° sphere
  • Absolute Orientation (Quatenrion, 100Hz) Four point quaternion output for more accurate data manipulation
  • Angular Velocity Vector (100Hz) Three axis of ‘rotation speed’ in rad/s
  • Acceleration Vector (100Hz) Three axis of acceleration (gravity + linear motion) in m/s^2
  • Magnetic Field Strength Vector (20Hz) Three axis of magnetic field sensing in micro Tesla (uT)
  • Linear Acceleration Vector (100Hz) Three axis of linear acceleration data (acceleration minus gravity) in m/s^2
  • Gravity Vector (100Hz) Three axis of gravitational acceleration (minus any movement) in m/s^2
  • Temperature (1Hz) Ambient temperature in degrees celsius

BNO055 pinouts

Exists a lot of module versions of this sensors, i choice the smallest and cheap.

Here the module Aliexpress

All these modules had the same features, but to enable Them you must do different operations.

This is the clone I use:

BNO055 pinout mischianti
BNO055 pinout mischianti

And here is the Adafruit one:

Adafruit bno055 pinout specs
Adafruit bno055 pinout specs

The sensor support a 3.3v logic level, but the module can be powered by 5v.

Can communicate via i2c (default option) and via UART. To activate the last modality you must desolder PS1.

PS1PS0Functionality
00Standard/Fast I2C Interface
01HID over I2C
10UART Interface
11Reserved

In standard i2c mode, you can select two address; by default, in this module, the address 0x29 is active; if you put to GND the ADD pin, the address become 0x28.

i2c configurationADDI2C address
SlaveHIGH0x29
SlaveLOW (default)0x28
HID-I2C0x40

INT is configured as an interrupt pin for signaling an interrupt to the host. The interrupt trigger is configured as a raising edge and is latched onto the INT pin. Once an interrupt occurs, the INT pin is set to high and will remain high until it is reset by the host.

Features

Magnetometer features

magnetometer is a device that measures magnetic field or magnetic dipole moment. Some magnetometers measure a magnetic field’s direction, strength, or relative change at a particular location.

I write some examples and additional information about magnetometers in this article, “GY-273 QMC5883L clone HMC5883L magnetometer for Arduino, esp8266 and esp32“.

  • Flexible functionality
    Magnetic field range typical ±1300µT (x-, y-axis);
    ±2500µT (z-axis)
    Magnetic field resolution of ~0.3µT
    • Operating modes:
      • Low power
      • Regular
      • Enhanced regular
      • High Accuracy
    • Power modes:
      • Normal
      • Sleep
      • Suspend
      • Force

Accelerometer features

An accelerometer is a tool that measures proper acceleration. Proper acceleration is the acceleration (the rate of change of velocity) of a body in its own instantaneous rest frame; this is different from coordinate acceleration, which is acceleration in a fixed coordinate system.

I have explained what it is in detail and written various practical application examples in this article, “GY-291 ADXL345 i2c spi accelerometer with interrupt for esp32, esp8266, stm32 and Arduino“.

  • Programmable functionality
    Acceleration ranges ±2g/±4g/±8g/±16g
    Low-pass filter bandwidths 1kHz – <8Hz

    Operation modes:
    • Normal
    • Suspend
    • Low power
    • Standby
    • Deep suspend
  • On-chip interrupt controller
    Motion-triggered interrupt-signal generation for
    • any-motion (slope) detection
    • slow or no motion recognition
    • high-g detection

Gyroscope features

gyroscope is used to measure or maintain orientation and angular velocity. In origin was a spinning wheel or disc in which the axis of rotation (spin axis) is free to assume any orientation by itself.

  • Programmable functionality
    Ranges switchable from ±125°/s to ±2000°/s
    Low-pass filter bandwidths 523Hz – 12Hz
    Operation modes:
    • Normal
    • Fast power up
    • Deep suspend
    • Suspend
    • Advanced power save
  • On-chip interrupt controller
    Motion-triggered interrupt-signal generation for
    • any-motion (slope) detection
    • high rate

Wiring

For basic i2c usage, you must only connect VCC, GND, SDA, and SCL.

Arduino UNO

The Adafruit version of the sensor is well documented and fully supports the 5v logic level.

Arduino UNO bno055 adafruit wiring breadboard
Arduino UNO bno055 adafruit wiring breadboard

The clone version was not clear if It fully supports the 5v logic level but surely supports the 5v power supply. I try to use Arduino UNO, and It’s works correctly without LLC.

Arduino UNO bno055 clone wiring breadboard
Arduino UNO bno055 clone wiring breadboard

esp32 wiring

ESP32 DOIT DEV KIT v1 pinout
ESP32 DOIT DEV KIT v1 pinout

esp32 work at 3.3v, so the wiring was without doubt.

esp32 bno055 adafruit wiring breadboard
esp32 bno055 adafruit wiring breadboard

And here is the clone.

esp32 bno055 clone wiring breadboard
esp32 bno055 clone wiring breadboard

esp8266 wiring

WeMos D1 mini esp8266 pinout mischianti low resolution
WeMos D1 mini esp8266 pinout low resolution

esp8266, like esp32, work at 3.3v, so the wiring is linear.

esp8266 WeMos D1 mini bno055 adafruit wiring
esp8266 WeMos D1 mini bno055 adafruit wiring

And now the clone.

esp8266 WeMos D1 mini bno055 clone wiring
esp8266 WeMos D1 mini bno055 clone wiring

Basic library

Adafruit (as usual) offers a beautiful and very simple to use library that needs the Adafruit Unified Sensors, but does not support interrupt and can be installed directly from the Arduino library manager.

Arduino IDE Adafruit bno055 sensor library manager
Arduino IDE Adafruit bno055 sensor library manager

You need to install Adafruit Unified Sensor library as dependencies.

Arduino IDE Adafruit unified sensor library manager
Arduino IDE Adafruit unified sensor library manager

Here the example sketch that show all values that you can grab from the sensor.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>

/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
   which provides a common 'type' for sensor data and some helper functions.

   To use this driver you will also need to download the Adafruit_Sensor
   library and include it in your libraries folder.

   You should also assign a unique ID to this sensor for use with
   the Adafruit Sensor API so that you can identify this particular
   sensor in any data logs, etc.  To assign a unique ID, simply
   provide an appropriate value in the constructor below (12345
   is used by default in this example).

   Connections
   ===========
   Connect SCL to analog 5
   Connect SDA to analog 4
   Connect VDD to 3.3-5V DC
   Connect GROUND to common ground

   History
   =======
   2015/MAR/03  - First release (KTOWN)
*/

/* Set the delay between fresh samples */
uint16_t BNO055_SAMPLERATE_DELAY_MS = 100;

// Check I2C device address and correct line below (by default address is 0x29 or 0x28)
//                                   id, address
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);

void setup(void)
{
  Serial.begin(115200);
  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);
  }

  delay(1000);
}

void loop(void)
{
  //could add VECTOR_ACCELEROMETER, VECTOR_MAGNETOMETER,VECTOR_GRAVITY...
  sensors_event_t orientationData , angVelocityData , linearAccelData, magnetometerData, accelerometerData, gravityData;
  bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
  bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
  bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
  bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
  bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
  bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);

  printEvent(&orientationData);
  printEvent(&angVelocityData);
  printEvent(&linearAccelData);
  printEvent(&magnetometerData);
  printEvent(&accelerometerData);
  printEvent(&gravityData);

  int8_t boardTemp = bno.getTemp();
  Serial.println();
  Serial.print(F("temperature: "));
  Serial.println(boardTemp);

  uint8_t system, gyro, accel, mag = 0;
  bno.getCalibration(&system, &gyro, &accel, &mag);
  Serial.println();
  Serial.print("Calibration: Sys=");
  Serial.print(system);
  Serial.print(" Gyro=");
  Serial.print(gyro);
  Serial.print(" Accel=");
  Serial.print(accel);
  Serial.print(" Mag=");
  Serial.println(mag);

  Serial.println("--");
  delay(BNO055_SAMPLERATE_DELAY_MS);
}

void printEvent(sensors_event_t* event) {
  double x = -1000000, y = -1000000 , z = -1000000; //dumb values, easy to spot problem
  if (event->type == SENSOR_TYPE_ACCELEROMETER) {
    Serial.print("Accl:");
    x = event->acceleration.x;
    y = event->acceleration.y;
    z = event->acceleration.z;
  }
  else if (event->type == SENSOR_TYPE_ORIENTATION) {
    Serial.print("Orient:");
    x = event->orientation.x;
    y = event->orientation.y;
    z = event->orientation.z;
  }
  else if (event->type == SENSOR_TYPE_MAGNETIC_FIELD) {
    Serial.print("Mag:");
    x = event->magnetic.x;
    y = event->magnetic.y;
    z = event->magnetic.z;
  }
  else if (event->type == SENSOR_TYPE_GYROSCOPE) {
    Serial.print("Gyro:");
    x = event->gyro.x;
    y = event->gyro.y;
    z = event->gyro.z;
  }
  else if (event->type == SENSOR_TYPE_ROTATION_VECTOR) {
    Serial.print("Rot:");
    x = event->gyro.x;
    y = event->gyro.y;
    z = event->gyro.z;
  }
  else if (event->type == SENSOR_TYPE_LINEAR_ACCELERATION) {
    Serial.print("Linear:");
    x = event->acceleration.x;
    y = event->acceleration.y;
    z = event->acceleration.z;
  }
  else {
    Serial.print("Unk:");
  }

  Serial.print("\tx= ");
  Serial.print(x);
  Serial.print(" |\ty= ");
  Serial.print(y);
  Serial.print(" |\tz= ");
  Serial.println(z);
}

And here is the serial output.

temperature: 26

Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient:	x= 12.75 |	y= -33.44 |	z= 30.75
Rot:	x= -37.00 |	y= -15.81 |	z= -15.88
Linear:	x= 0.30 |	y= -0.06 |	z= -0.25
Mag:	x= 26.69 |	y= -11.50 |	z= -23.06
Accl:	x= -5.10 |	y= -4.24 |	z= 6.77
Accl:	x= -5.41 |	y= -4.18 |	z= 7.02

temperature: 26

Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient:	x= 11.81 |	y= -31.56 |	z= 34.44
Rot:	x= -21.81 |	y= -14.81 |	z= -19.62
Linear:	x= -0.21 |	y= -0.23 |	z= -0.53
Mag:	x= 27.75 |	y= -9.75 |	z= -24.25
Accl:	x= -5.47 |	y= -4.80 |	z= 6.72
Accl:	x= -5.10 |	y= -4.77 |	z= 6.88

temperature: 26

Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient:	x= 12.69 |	y= -29.25 |	z= 38.69
Rot:	x= -36.44 |	y= -7.81 |	z= -18.81
Linear:	x= 0.08 |	y= 0.13 |	z= -0.35
Mag:	x= 27.50 |	y= -8.69 |	z= -25.75
Accl:	x= -4.52 |	y= -5.23 |	z= 6.08
Accl:	x= -4.76 |	y= -5.40 |	z= 6.64

temperature: 26

Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient:	x= 13.25 |	y= -27.19 |	z= 42.06
Rot:	x= -21.94 |	y= -8.81 |	z= -14.63
Linear:	x= 0.30 |	y= 0.02 |	z= -0.77
Mag:	x= 28.25 |	y= -4.19 |	z= -26.87
Accl:	x= -4.15 |	y= -5.85 |	z= 5.68
Accl:	x= -4.45 |	y= -5.87 |	z= 6.46

temperature: 26

Constructor

In the example, you can identify the constructor for the i2c connection.

Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);

the complete declaration is:

Adafruit_BNO055(int32_t sensorID = -1, uint8_t address = BNO055_ADDRESS_A, TwoWire *theWire = &Wire);

The first parameter is an arbitrary unique identify of the sensor, the second is the address, by default is BNO055_ADDRESS_A or 0x28, the last one is the Wire declaration.

Begin

In the begin method, you can specify with the type of operation you want to manage:

  bool begin(adafruit_bno055_opmode_t mode = OPERATION_MODE_NDOF);

There are a lot of options, and they are self-explained:

    OPERATION_MODE_CONFIG = 0X00,
    OPERATION_MODE_ACCONLY = 0X01,
    OPERATION_MODE_MAGONLY = 0X02,
    OPERATION_MODE_GYRONLY = 0X03,
    OPERATION_MODE_ACCMAG = 0X04,
    OPERATION_MODE_ACCGYRO = 0X05,
    OPERATION_MODE_MAGGYRO = 0X06,
    OPERATION_MODE_AMG = 0X07,
    OPERATION_MODE_IMUPLUS = 0X08,
    OPERATION_MODE_COMPASS = 0X09,
    OPERATION_MODE_M4G = 0X0A,
    OPERATION_MODE_NDOF_FMC_OFF = 0X0B,
    OPERATION_MODE_NDOF = 0X0C

The table explains what happens when you select a specified option.

Non-fusionmodes (generated only from sensors)

Operating ModeAccelMagnGyroRel. orient.
Fusion
Absol. orient.
Fusion
CONFIGMODE
ACCONLYX
MAGONLYX
GYROONLYX
ACCMAGXX
ACCGYROXX
MAGGYROXX
AMGXXX

Fusion modes

Operating ModeAccelMagnGyroRel. orient.
Fusion
Absol. orient.
Fusion
IMUXXX
COMPASSXXX
M4GXX X
NDOF_FMC_OFFXXXX
NDOFXXXX

Retrieve data

Then we can get data selectively like in the example.

  //could add VECTOR_ACCELEROMETER, VECTOR_MAGNETOMETER,VECTOR_GRAVITY...
  sensors_event_t orientationData , angVelocityData , linearAccelData, magnetometerData, accelerometerData, gravityData;
  bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
  bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
  bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
  bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
  bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
  bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);

Or you can get all data in one shot like so.

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

Vector events type

Acceleration data

  bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
[...]
  if (event->type == SENSOR_TYPE_ACCELEROMETER) {
    Serial.print("Accl:");
    x = event->acceleration.x;
    y = event->acceleration.y;
    z = event->acceleration.z;
  }

In non-fusion mode uncompensated acceleration data for each axis X/Y/Z.

In fusion mode the fusion algorithm output offset compensated acceleration data for each axis X/Y/Z.

Linear Acceleration

  bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
[...]
  else if (event->type == SENSOR_TYPE_LINEAR_ACCELERATION) {
    Serial.print("Linear:");
    x = event->acceleration.x;
    y = event->acceleration.y;
    z = event->acceleration.z;
  }

Linear acceleration output is only available in fusion operating modes.

The fusion algorithm outputs linear acceleration data for each axis x/y/z.

Magnetic Field Strength

  bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
[...]
  else if (event->type == SENSOR_TYPE_MAGNETIC_FIELD) {
    Serial.print("Mag:");
    x = event->magnetic.x;
    y = event->magnetic.y;
    z = event->magnetic.z;
  }

In non-fusion mode, uncompensated field strength data for each axis X/Y/Z.

In fusion mode, the fusion algorithm output offset compensated magnetic field strength data for each axis X/Y/Z.

Orientation (Euler angles)

  bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
[...]
  else if (event->type == SENSOR_TYPE_ORIENTATION) {
    Serial.print("Orient:");
    x = event->orientation.x;
    y = event->orientation.y;
    z = event->orientation.z;
  }

Orientation output is only available in fusion operation modes.

The fusion algorithm output offset and tilt-compensated orientation data in Euler angles format for each DOF Heading/Roll/Pitch. Refer table below for information regarding the data types and the unit representation for the Euler angle format.

Gravity Vector

  bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);
[...]
  else if (event->type == SENSOR_TYPE_ROTATION_VECTOR) {
    Serial.print("Rot:");
    x = event->gyro.x;
    y = event->gyro.y;
    z = event->gyro.z;
  }

Gravity Vector output is only available in fusion operating modes.

The fusion algorithm output gravity vector data for each axis x/y/z.

Angular Velocity

  bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
[...]
  else if (event->type == SENSOR_TYPE_GYROSCOPE) {
    Serial.print("Gyro:");
    x = event->gyro.x;
    y = event->gyro.y;
    z = event->gyro.z;
  }

In non-fusion mode, uncompensated angular velocity (yaw rate) data for each axis X/Y/Z.

In fusion mode, the fusion algorithm output offset compensated angular velocity (yaw rate) data for each axis X/Y/Z.

Quaternion

The .getQuat function returns a Quaternion, which is often easier and more accurate to work with than Euler angles when doing sensor fusion or data manipulation with raw sensor data.

You can get a quaternion data sample via the following code:

imu::Quaternion quat = bno.getQuat();
 
/* Display the quat data */
Serial.print("qW: ");
Serial.print(quat.w(), 4);
Serial.print(" qX: ");
Serial.print(quat.y(), 4);
Serial.print(" qY: ");
Serial.print(quat.x(), 4);
Serial.print(" qZ: ");
Serial.print(quat.z(), 4);
Serial.println("");

Temperature

The .getTemp helper returns the current ambient temperature in degrees Celsius, and can be read via the following function call:

/* Display the current temperature */
int8_t temp = bno.getTemp();
 
Serial.print("Current Temperature: ");
Serial.print(temp);
Serial.println(" C");
Serial.println("");

Power saving

You can also enter in suspend mode and return to normal with these commands.

  /* Power managments functions */
  void enterSuspendMode();
  void enterNormalMode();

Move 3d bunny with WebGL and absolute position

A very interesting example given with the library is reading the serial data and converting it to a 3D rotation to do that in a simple way, the use Web Serial API for Chrome browser.

So first, you need Chrome.

Then you must enable WebSerial API, and do that, you must put in the browser input URL chrome://flags then search (with Ctrl+f) Experimental Web Platform features and enable It.

Chrome enable Experimental Web Platform features
Chrome enable Experimental Web Platform features

Then load the example given in the library webserial_3d, upload, and start It.

Now open this in the browser this url:

https://adafruit.github.io/Adafruit_WebSerial_3DModelViewer/

Select 9600 baud, click connect and select the correct device serial port.

The result is that you can change the orientation of the bunny with the movement of bno055.

This is a fantastic library, but I think it is appropriate to experiment with more complex management of the device with the help of interrupts. To do this, we will make use of another library in the next article.

Thanks

  1. BNO055 accelerometer, gyroscope, magnetometer with basic Adafruit library
  2. BNO055 for esp32, esp8266, and Arduino: wiring and advanced Bosch library
  3. BNO055 for esp32, esp8266, and Arduino: features, configuration, and axes remap
  4. BNO055: power modes, accelerometer, and motion interrupt
  5. BNO055 for esp32, esp8266, and Arduino: enable INT pin and accelerometer High G Interrupt
  6. BNO055 for esp32, esp8266, and Arduino: Gyroscope High Rate and Any Motion Interrupt


Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *