Skip to content

Commit 66d5b2e

Browse files
authored
Merge pull request #17 from sparkfun/Calibration_example
Calibration example
2 parents d2a757f + a4c2e17 commit 66d5b2e

File tree

3 files changed

+295
-70
lines changed

3 files changed

+295
-70
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
Using the BNO08x IMU
3+
4+
This example shows how to adjust settings of the dynamic calibration of the
5+
BNO08x.
6+
7+
The BNO08x allows you to turn on/off dynamic calibration for each sensor in
8+
the IMU (accel, gyro, or mag).
9+
10+
Please refer to the BNO08X data sheet Section 3 (page 37)
11+
https://docs.sparkfun.com/SparkFun_VR_IMU_Breakout_BNO086_QWIIC/assets/component_documentation/BNO080_085-Datasheet_v1.16.pdf
12+
13+
Note, by default, dynamic calibration is enabled for accel and mag.
14+
Some special use cases may require turning on all or any special combo of sensor
15+
dynamic calibration.
16+
17+
After the calibration settings are set, this example will output the
18+
x/y/z/accuracy of the mag and the i/j/k/real parts of the game rotation vector.
19+
https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
20+
21+
Note, the "simple calibration" feature, sh2_startCal(), is not available on
22+
the BNO08x. See this issue for more info:
23+
https://github.com/ceva-dsp/sh2/issues/11
24+
25+
By: Nathan Seidle
26+
SparkFun Electronics
27+
Date: December 21st, 2017
28+
SparkFun code, firmware, and software is released under the MIT License.
29+
Please see LICENSE.md for further details.
30+
31+
Originally written by Nathan Seidle @ SparkFun Electronics, December 28th, 2017
32+
33+
Adjusted by Pete Lewis @ SparkFun Electronics, June 2023 to incorporate the
34+
CEVA Sensor Hub Driver, found here:
35+
https://github.com/ceva-dsp/sh2
36+
37+
Also, utilizing code from the Adafruit BNO08x Arduino Library by Bryan Siepert
38+
for Adafruit Industries. Found here:
39+
https://github.com/adafruit/Adafruit_BNO08x
40+
41+
Also, utilizing I2C and SPI read/write functions and code from the Adafruit
42+
BusIO library found here:
43+
https://github.com/adafruit/Adafruit_BusIO
44+
45+
Hardware Connections:
46+
IoT RedBoard --> BNO08x
47+
QWIIC --> QWIIC
48+
A4 --> INT
49+
A5 --> RST
50+
51+
BNO08x "mode" jumpers set for I2C (default):
52+
PSO: OPEN
53+
PS1: OPEN
54+
55+
Serial.print it out at 115200 baud to serial monitor.
56+
57+
Feel like supporting our work? Buy a board from SparkFun!
58+
https://www.sparkfun.com/products/22857
59+
*/
60+
61+
#include <Wire.h>
62+
63+
#include "SparkFun_BNO08x_Arduino_Library.h" // CTRL+Click here to get the library: http://librarymanager/All#SparkFun_BNO08x
64+
BNO08x myIMU;
65+
66+
// For the most reliable interaction with the SHTP bus, we need
67+
// to use hardware reset control, and to monitor the H_INT pin.
68+
// The H_INT pin will go low when its okay to talk on the SHTP bus.
69+
// Note, these can be other GPIO if you like.
70+
// Define as -1 to disable these features.
71+
#define BNO08X_INT A4
72+
//#define BNO08X_INT -1
73+
#define BNO08X_RST A5
74+
//#define BNO08X_RST -1
75+
76+
#define BNO08X_ADDR 0x4B // SparkFun BNO08x Breakout (Qwiic) defaults to 0x4B
77+
//#define BNO08X_ADDR 0x4A // Alternate address if ADR jumper is closed
78+
79+
// variables to store all our incoming values
80+
81+
// mags
82+
float mx;
83+
float my;
84+
float mz;
85+
byte magAccuracy;
86+
87+
// quats
88+
float quatI;
89+
float quatJ;
90+
float quatK;
91+
float quatReal;
92+
93+
unsigned long previousDebugMicros = 0;
94+
#define DEBUG_INTERVAL_MICROSECONDS 10000
95+
96+
void setup() {
97+
Serial.begin(115200);
98+
99+
while(!Serial) delay(10); // Wait for Serial to become available.
100+
// Necessary for boards with native USB (like the SAMD51 Thing+).
101+
// For a final version of a project that does not need serial debug (or a USB cable plugged in),
102+
// Comment out this while loop, or it will prevent the remaining code from running.
103+
104+
Serial.println();
105+
Serial.println("BNO08x Calibration Example");
106+
107+
Wire.begin();
108+
109+
//if (myIMU.begin() == false) { // Setup without INT/RST control (Not Recommended)
110+
if (myIMU.begin(BNO08X_ADDR, Wire, BNO08X_INT, BNO08X_RST) == false) {
111+
Serial.println("BNO08x not detected at default I2C address. Check your jumpers and the hookup guide. Freezing...");
112+
while (1)
113+
;
114+
}
115+
Serial.println("BNO08x found!");
116+
117+
// Wire.setClock(400000); //Increase I2C data rate to 400kHz
118+
119+
// Enable dynamic calibration for desired sensors (accel, gyro, and mag)
120+
// uncomment/comment out as needed to try various options
121+
if (myIMU.setCalibrationConfig(SH2_CAL_ACCEL || SH2_CAL_GYRO || SH2_CAL_MAG) == true) { // all three sensors
122+
//if (myIMU.setCalibrationConfig(SH2_CAL_ACCEL || SH2_CAL_MAG) == true) { // Default settings
123+
//if (myIMU.setCalibrationConfig(SH2_CAL_ACCEL) == true) { // only accel
124+
Serial.println(F("Calibration Command Sent Successfully"));
125+
} else {
126+
Serial.println("Could not send Calibration Command. Freezing...");
127+
while(1) delay(10);
128+
}
129+
130+
setReports();
131+
132+
Serial.println("Reading events");
133+
delay(100);
134+
}
135+
136+
// Here is where you define the sensor outputs you want to receive
137+
void setReports(void) {
138+
Serial.println("Setting desired reports");
139+
140+
if (myIMU.enableMagnetometer(1) == true) {
141+
Serial.println(F("Magnetometer enabled"));
142+
Serial.println(F("Output in form x, y, z, in uTesla"));
143+
} else {
144+
Serial.println("Could not enable magnetometer");
145+
}
146+
147+
if (myIMU.enableGameRotationVector(1) == true) {
148+
Serial.println(F("Game Rotation vector enabled"));
149+
Serial.println(F("Output in form i, j, k, real"));
150+
} else {
151+
Serial.println("Could not enable game rotation vector");
152+
}
153+
}
154+
155+
void loop() {
156+
delayMicroseconds(10);
157+
158+
if (myIMU.wasReset()) {
159+
Serial.print("sensor was reset ");
160+
setReports();
161+
}
162+
163+
// Has a new event come in on the Sensor Hub Bus?
164+
if (myIMU.getSensorEvent() == true) {
165+
// is the event a report of the magnetometer?
166+
if (myIMU.getSensorEventID() == SENSOR_REPORTID_MAGNETIC_FIELD) {
167+
mx = myIMU.getMagX();
168+
my = myIMU.getMagY();
169+
mz = myIMU.getMagZ();
170+
magAccuracy = myIMU.getMagAccuracy();
171+
}
172+
// is the event a report of the game rotation vector?
173+
else if (myIMU.getSensorEventID() == SENSOR_REPORTID_GAME_ROTATION_VECTOR) {
174+
quatI = myIMU.getGameQuatI();
175+
quatJ = myIMU.getGameQuatJ();
176+
quatK = myIMU.getGameQuatK();
177+
quatReal = myIMU.getGameQuatReal();
178+
}
179+
}
180+
181+
// Only print data to the terminal at a user defined interval
182+
// Each data type (accel or gyro or mag) is reported from the
183+
// BNO086 as separate messages.
184+
// To allow for all these separate messages to arrive, and thus
185+
// have updated data on all axis/types,
186+
// The report intervals for each datatype must be much faster
187+
// than our debug interval.
188+
189+
// time since last debug data printed to terminal
190+
unsigned long microsSinceLastSerialPrint = (micros() - previousDebugMicros);
191+
192+
// Only print data to the terminal at a user deficed interval
193+
if(microsSinceLastSerialPrint > DEBUG_INTERVAL_MICROSECONDS)
194+
{
195+
Serial.print(mx, 2);
196+
Serial.print("\t\t");
197+
Serial.print(my, 2);
198+
Serial.print("\t\t");
199+
Serial.print(mz, 2);
200+
Serial.print("\t\t");
201+
printAccuracyLevel(magAccuracy);
202+
Serial.print("\t\t");
203+
204+
Serial.print(quatI, 2);
205+
Serial.print("\t\t");
206+
Serial.print(quatJ, 2);
207+
Serial.print("\t\t");
208+
Serial.print(quatK, 2);
209+
Serial.print("\t\t");
210+
Serial.print(quatReal, 2);
211+
Serial.print("\t\t");
212+
213+
Serial.print(microsSinceLastSerialPrint);
214+
Serial.println();
215+
previousDebugMicros = micros();
216+
}
217+
218+
if(Serial.available())
219+
{
220+
byte incoming = Serial.read();
221+
222+
if(incoming == 's')
223+
{
224+
// Saves the current dynamic calibration data (DCD) to memory
225+
// Note, The BNO08X stores updated Dynamic Calibration Data (DCD) to RAM
226+
// frequently (every 5 seconds), so this command may not be necessary
227+
// depending on your application.
228+
if (myIMU.saveCalibration() == true) {
229+
Serial.println(F("Calibration data was saved successfully"));
230+
} else {
231+
Serial.println("Save Calibration Failure");
232+
}
233+
}
234+
}
235+
}
236+
237+
//Given a accuracy number, print what it means
238+
void printAccuracyLevel(byte accuracyNumber)
239+
{
240+
if(accuracyNumber == 0) Serial.print(F("Unreliable"));
241+
else if(accuracyNumber == 1) Serial.print(F("Low"));
242+
else if(accuracyNumber == 2) Serial.print(F("Medium"));
243+
else if(accuracyNumber == 3) Serial.print(F("High"));
244+
}

src/SparkFun_BNO08x_Arduino_Library.cpp

+44-61
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,30 @@ uint8_t BNO08x::getQuatAccuracy()
328328
return _sensor_value->status;
329329
}
330330

331+
//Return the game rotation vector quaternion I
332+
float BNO08x::getGameQuatI()
333+
{
334+
return _sensor_value->un.gameRotationVector.i;
335+
}
336+
337+
//Return the game rotation vector quaternion J
338+
float BNO08x::getGameQuatJ()
339+
{
340+
return _sensor_value->un.gameRotationVector.j;
341+
}
342+
343+
//Return the game rotation vector quaternion K
344+
float BNO08x::getGameQuatK()
345+
{
346+
return _sensor_value->un.gameRotationVector.k;
347+
}
348+
349+
//Return the game rotation vector quaternion Real
350+
float BNO08x::getGameQuatReal()
351+
{
352+
return _sensor_value->un.gameRotationVector.real;
353+
}
354+
331355
//Gets the full acceleration
332356
//x,y,z output floats
333357
void BNO08x::getAccel(float &x, float &y, float &z, uint8_t &accuracy)
@@ -925,49 +949,18 @@ bool BNO08x::enableActivityClassifier(uint16_t timeBetweenReports, uint32_t acti
925949
return enableReport(SENSOR_REPORTID_PERSONAL_ACTIVITY_CLASSIFIER, timeBetweenReports, activitiesToEnable);
926950
}
927951

928-
// //Sends the commands to begin calibration of the accelerometer
929-
// void BNO08x::calibrateAccelerometer()
930-
// {
931-
// sendCalibrateCommand(CALIBRATE_ACCEL);
932-
// }
933-
934-
// //Sends the commands to begin calibration of the gyro
935-
// void BNO08x::calibrateGyro()
936-
// {
937-
// sendCalibrateCommand(CALIBRATE_GYRO);
938-
// }
939-
940-
// //Sends the commands to begin calibration of the magnetometer
941-
// void BNO08x::calibrateMagnetometer()
942-
// {
943-
// sendCalibrateCommand(CALIBRATE_MAG);
944-
// }
945-
946-
// //Sends the commands to begin calibration of the planar accelerometer
947-
// void BNO08x::calibratePlanarAccelerometer()
948-
// {
949-
// sendCalibrateCommand(CALIBRATE_PLANAR_ACCEL);
950-
// }
951-
952-
// //See 2.2 of the Calibration Procedure document 1000-4044
953-
// void BNO08x::calibrateAll()
954-
// {
955-
// sendCalibrateCommand(CALIBRATE_ACCEL_GYRO_MAG);
956-
// }
952+
// See 2.2 of the Calibration Procedure document 1000-4044
953+
// Set the desired sensors to have active dynamic calibration
954+
bool BNO08x::setCalibrationConfig(uint8_t sensors)
955+
{
956+
int status = sh2_setCalConfig(sensors);
957957

958-
// void BNO08x::endCalibration()
959-
// {
960-
// sendCalibrateCommand(CALIBRATE_STOP); //Disables all calibrations
961-
// }
958+
if (status != SH2_OK) {
959+
return false;
960+
}
962961

963-
// //See page 51 of reference manual - ME Calibration Response
964-
// //Byte 5 is parsed during the readPacket and stored in calibrationStatus
965-
// boolean BNO08x::calibrationComplete()
966-
// {
967-
// if (calibrationStatus == 0)
968-
// return (true);
969-
// return (false);
970-
// }
962+
return true;
963+
}
971964

972965
bool BNO08x::tareNow(bool zAxis, sh2_TareBasis_t basis)
973966
{
@@ -1068,26 +1061,16 @@ bool BNO08x::clearTare()
10681061
// sendCommand(COMMAND_ME_CALIBRATE);
10691062
// }
10701063

1071-
// //This tells the BNO08x to save the Dynamic Calibration Data (DCD) to flash
1072-
// //See page 49 of reference manual and the 1000-4044 calibration doc
1073-
// void BNO08x::saveCalibration()
1074-
// {
1075-
// /*shtpData[3] = 0; //P0 - Reserved
1076-
// shtpData[4] = 0; //P1 - Reserved
1077-
// shtpData[5] = 0; //P2 - Reserved
1078-
// shtpData[6] = 0; //P3 - Reserved
1079-
// shtpData[7] = 0; //P4 - Reserved
1080-
// shtpData[8] = 0; //P5 - Reserved
1081-
// shtpData[9] = 0; //P6 - Reserved
1082-
// shtpData[10] = 0; //P7 - Reserved
1083-
// shtpData[11] = 0; //P8 - Reserved*/
1084-
1085-
// for (uint8_t x = 3; x < 12; x++) //Clear this section of the shtpData array
1086-
// shtpData[x] = 0;
1087-
1088-
// //Using this shtpData packet, send a command
1089-
// sendCommand(COMMAND_DCD); //Save DCD command
1090-
// }
1064+
//This tells the BNO08x to save the Dynamic Calibration Data (DCD) to flash
1065+
//See page 49 of reference manual and the 1000-4044 calibration doc
1066+
bool BNO08x::saveCalibration()
1067+
{
1068+
int status = sh2_saveDcdNow();
1069+
if (status != SH2_OK) {
1070+
return false;
1071+
}
1072+
return true;
1073+
}
10911074

10921075
/*! @brief Initializer for post i2c/spi init
10931076
* @param sensor_id Optional unique ID for the sensor set

0 commit comments

Comments
 (0)