Skip to content

Calibration example #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
/*
Using the BNO08x IMU

This example shows how to adjust settings of the dynamic calibration of the
BNO08x.

The BNO08x allows you to turn on/off dynamic calibration for each sensor in
the IMU (accel, gyro, or mag).

Please refer to the BNO08X data sheet Section 3 (page 37)
https://docs.sparkfun.com/SparkFun_VR_IMU_Breakout_BNO086_QWIIC/assets/component_documentation/BNO080_085-Datasheet_v1.16.pdf

Note, by default, dynamic calibration is enabled for accel and mag.
Some special use cases may require turning on all or any special combo of sensor
dynamic calibration.

After the calibration settings are set, this example will output the
x/y/z/accuracy of the mag and the i/j/k/real parts of the game rotation vector.
https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation

Note, the "simple calibration" feature, sh2_startCal(), is not available on
the BNO08x. See this issue for more info:
https://github.com/ceva-dsp/sh2/issues/11

By: Nathan Seidle
SparkFun Electronics
Date: December 21st, 2017
SparkFun code, firmware, and software is released under the MIT License.
Please see LICENSE.md for further details.

Originally written by Nathan Seidle @ SparkFun Electronics, December 28th, 2017

Adjusted by Pete Lewis @ SparkFun Electronics, June 2023 to incorporate the
CEVA Sensor Hub Driver, found here:
https://github.com/ceva-dsp/sh2

Also, utilizing code from the Adafruit BNO08x Arduino Library by Bryan Siepert
for Adafruit Industries. Found here:
https://github.com/adafruit/Adafruit_BNO08x

Also, utilizing I2C and SPI read/write functions and code from the Adafruit
BusIO library found here:
https://github.com/adafruit/Adafruit_BusIO

Hardware Connections:
IoT RedBoard --> BNO08x
QWIIC --> QWIIC
A4 --> INT
A5 --> RST

BNO08x "mode" jumpers set for I2C (default):
PSO: OPEN
PS1: OPEN

Serial.print it out at 115200 baud to serial monitor.

Feel like supporting our work? Buy a board from SparkFun!
https://www.sparkfun.com/products/22857
*/

#include <Wire.h>

#include "SparkFun_BNO08x_Arduino_Library.h" // CTRL+Click here to get the library: http://librarymanager/All#SparkFun_BNO08x
BNO08x myIMU;

// For the most reliable interaction with the SHTP bus, we need
// to use hardware reset control, and to monitor the H_INT pin.
// The H_INT pin will go low when its okay to talk on the SHTP bus.
// Note, these can be other GPIO if you like.
// Define as -1 to disable these features.
#define BNO08X_INT A4
//#define BNO08X_INT -1
#define BNO08X_RST A5
//#define BNO08X_RST -1

#define BNO08X_ADDR 0x4B // SparkFun BNO08x Breakout (Qwiic) defaults to 0x4B
//#define BNO08X_ADDR 0x4A // Alternate address if ADR jumper is closed

// variables to store all our incoming values

// mags
float mx;
float my;
float mz;
byte magAccuracy;

// quats
float quatI;
float quatJ;
float quatK;
float quatReal;

unsigned long previousDebugMicros = 0;
#define DEBUG_INTERVAL_MICROSECONDS 10000

void setup() {
Serial.begin(115200);

while(!Serial) delay(10); // Wait for Serial to become available.
// Necessary for boards with native USB (like the SAMD51 Thing+).
// For a final version of a project that does not need serial debug (or a USB cable plugged in),
// Comment out this while loop, or it will prevent the remaining code from running.

Serial.println();
Serial.println("BNO08x Calibration Example");

Wire.begin();

//if (myIMU.begin() == false) { // Setup without INT/RST control (Not Recommended)
if (myIMU.begin(BNO08X_ADDR, Wire, BNO08X_INT, BNO08X_RST) == false) {
Serial.println("BNO08x not detected at default I2C address. Check your jumpers and the hookup guide. Freezing...");
while (1)
;
}
Serial.println("BNO08x found!");

// Wire.setClock(400000); //Increase I2C data rate to 400kHz

// Enable dynamic calibration for desired sensors (accel, gyro, and mag)
// uncomment/comment out as needed to try various options
if (myIMU.setCalibrationConfig(SH2_CAL_ACCEL || SH2_CAL_GYRO || SH2_CAL_MAG) == true) { // all three sensors
//if (myIMU.setCalibrationConfig(SH2_CAL_ACCEL || SH2_CAL_MAG) == true) { // Default settings
//if (myIMU.setCalibrationConfig(SH2_CAL_ACCEL) == true) { // only accel
Serial.println(F("Calibration Command Sent Successfully"));
} else {
Serial.println("Could not send Calibration Command. Freezing...");
while(1) delay(10);
}

setReports();

Serial.println("Reading events");
delay(100);
}

// Here is where you define the sensor outputs you want to receive
void setReports(void) {
Serial.println("Setting desired reports");

if (myIMU.enableMagnetometer(1) == true) {
Serial.println(F("Magnetometer enabled"));
Serial.println(F("Output in form x, y, z, in uTesla"));
} else {
Serial.println("Could not enable magnetometer");
}

if (myIMU.enableGameRotationVector(1) == true) {
Serial.println(F("Game Rotation vector enabled"));
Serial.println(F("Output in form i, j, k, real"));
} else {
Serial.println("Could not enable game rotation vector");
}
}

void loop() {
delayMicroseconds(10);

if (myIMU.wasReset()) {
Serial.print("sensor was reset ");
setReports();
}

// Has a new event come in on the Sensor Hub Bus?
if (myIMU.getSensorEvent() == true) {
// is the event a report of the magnetometer?
if (myIMU.getSensorEventID() == SENSOR_REPORTID_MAGNETIC_FIELD) {
mx = myIMU.getMagX();
my = myIMU.getMagY();
mz = myIMU.getMagZ();
magAccuracy = myIMU.getMagAccuracy();
}
// is the event a report of the game rotation vector?
else if (myIMU.getSensorEventID() == SENSOR_REPORTID_GAME_ROTATION_VECTOR) {
quatI = myIMU.getGameQuatI();
quatJ = myIMU.getGameQuatJ();
quatK = myIMU.getGameQuatK();
quatReal = myIMU.getGameQuatReal();
}
}

// Only print data to the terminal at a user defined interval
// Each data type (accel or gyro or mag) is reported from the
// BNO086 as separate messages.
// To allow for all these separate messages to arrive, and thus
// have updated data on all axis/types,
// The report intervals for each datatype must be much faster
// than our debug interval.

// time since last debug data printed to terminal
unsigned long microsSinceLastSerialPrint = (micros() - previousDebugMicros);

// Only print data to the terminal at a user deficed interval
if(microsSinceLastSerialPrint > DEBUG_INTERVAL_MICROSECONDS)
{
Serial.print(mx, 2);
Serial.print("\t\t");
Serial.print(my, 2);
Serial.print("\t\t");
Serial.print(mz, 2);
Serial.print("\t\t");
printAccuracyLevel(magAccuracy);
Serial.print("\t\t");

Serial.print(quatI, 2);
Serial.print("\t\t");
Serial.print(quatJ, 2);
Serial.print("\t\t");
Serial.print(quatK, 2);
Serial.print("\t\t");
Serial.print(quatReal, 2);
Serial.print("\t\t");

Serial.print(microsSinceLastSerialPrint);
Serial.println();
previousDebugMicros = micros();
}

if(Serial.available())
{
byte incoming = Serial.read();

if(incoming == 's')
{
// Saves the current dynamic calibration data (DCD) to memory
// Note, The BNO08X stores updated Dynamic Calibration Data (DCD) to RAM
// frequently (every 5 seconds), so this command may not be necessary
// depending on your application.
if (myIMU.saveCalibration() == true) {
Serial.println(F("Calibration data was saved successfully"));
} else {
Serial.println("Save Calibration Failure");
}
}
}
}

//Given a accuracy number, print what it means
void printAccuracyLevel(byte accuracyNumber)
{
if(accuracyNumber == 0) Serial.print(F("Unreliable"));
else if(accuracyNumber == 1) Serial.print(F("Low"));
else if(accuracyNumber == 2) Serial.print(F("Medium"));
else if(accuracyNumber == 3) Serial.print(F("High"));
}
105 changes: 44 additions & 61 deletions src/SparkFun_BNO08x_Arduino_Library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,30 @@ uint8_t BNO08x::getQuatAccuracy()
return _sensor_value->status;
}

//Return the game rotation vector quaternion I
float BNO08x::getGameQuatI()
{
return _sensor_value->un.gameRotationVector.i;
}

//Return the game rotation vector quaternion J
float BNO08x::getGameQuatJ()
{
return _sensor_value->un.gameRotationVector.j;
}

//Return the game rotation vector quaternion K
float BNO08x::getGameQuatK()
{
return _sensor_value->un.gameRotationVector.k;
}

//Return the game rotation vector quaternion Real
float BNO08x::getGameQuatReal()
{
return _sensor_value->un.gameRotationVector.real;
}

//Gets the full acceleration
//x,y,z output floats
void BNO08x::getAccel(float &x, float &y, float &z, uint8_t &accuracy)
Expand Down Expand Up @@ -925,49 +949,18 @@ bool BNO08x::enableActivityClassifier(uint16_t timeBetweenReports, uint32_t acti
return enableReport(SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER, timeBetweenReports, activitiesToEnable);
}

// //Sends the commands to begin calibration of the accelerometer
// void BNO08x::calibrateAccelerometer()
// {
// sendCalibrateCommand(CALIBRATE_ACCEL);
// }

// //Sends the commands to begin calibration of the gyro
// void BNO08x::calibrateGyro()
// {
// sendCalibrateCommand(CALIBRATE_GYRO);
// }

// //Sends the commands to begin calibration of the magnetometer
// void BNO08x::calibrateMagnetometer()
// {
// sendCalibrateCommand(CALIBRATE_MAG);
// }

// //Sends the commands to begin calibration of the planar accelerometer
// void BNO08x::calibratePlanarAccelerometer()
// {
// sendCalibrateCommand(CALIBRATE_PLANAR_ACCEL);
// }

// //See 2.2 of the Calibration Procedure document 1000-4044
// void BNO08x::calibrateAll()
// {
// sendCalibrateCommand(CALIBRATE_ACCEL_GYRO_MAG);
// }
// See 2.2 of the Calibration Procedure document 1000-4044
// Set the desired sensors to have active dynamic calibration
bool BNO08x::setCalibrationConfig(uint8_t sensors)
{
int status = sh2_setCalConfig(sensors);

// void BNO08x::endCalibration()
// {
// sendCalibrateCommand(CALIBRATE_STOP); //Disables all calibrations
// }
if (status != SH2_OK) {
return false;
}

// //See page 51 of reference manual - ME Calibration Response
// //Byte 5 is parsed during the readPacket and stored in calibrationStatus
// boolean BNO08x::calibrationComplete()
// {
// if (calibrationStatus == 0)
// return (true);
// return (false);
// }
return true;
}

bool BNO08x::tareNow(bool zAxis, sh2_TareBasis_t basis)
{
Expand Down Expand Up @@ -1068,26 +1061,16 @@ bool BNO08x::clearTare()
// sendCommand(COMMAND_ME_CALIBRATE);
// }

// //This tells the BNO08x to save the Dynamic Calibration Data (DCD) to flash
// //See page 49 of reference manual and the 1000-4044 calibration doc
// void BNO08x::saveCalibration()
// {
// /*shtpData[3] = 0; //P0 - Reserved
// shtpData[4] = 0; //P1 - Reserved
// shtpData[5] = 0; //P2 - Reserved
// shtpData[6] = 0; //P3 - Reserved
// shtpData[7] = 0; //P4 - Reserved
// shtpData[8] = 0; //P5 - Reserved
// shtpData[9] = 0; //P6 - Reserved
// shtpData[10] = 0; //P7 - Reserved
// shtpData[11] = 0; //P8 - Reserved*/

// for (uint8_t x = 3; x < 12; x++) //Clear this section of the shtpData array
// shtpData[x] = 0;

// //Using this shtpData packet, send a command
// sendCommand(COMMAND_DCD); //Save DCD command
// }
//This tells the BNO08x to save the Dynamic Calibration Data (DCD) to flash
//See page 49 of reference manual and the 1000-4044 calibration doc
bool BNO08x::saveCalibration()
{
int status = sh2_saveDcdNow();
if (status != SH2_OK) {
return false;
}
return true;
}

/*! @brief Initializer for post i2c/spi init
* @param sensor_id Optional unique ID for the sensor set
Expand Down
Loading