diff --git a/README.md b/README.md index a05a877..c634ef6 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ Thanks to all those who have helped improve the library: * Filimindji for AR/VR Stabilized RotationVector and AR/VR Stabilized GameRotationVector support - [PR 46](https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/pull/46) * ya-mouse for the getreadings improvements - [PR 55](https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/pull/55) * Guillaume for the read-multiple-values helper functions and the interrupt example - [PR56](https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/pull/56) & [PR59](https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/pull/59) +* aedancullen for the tap detector - [PR 64](https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/pull/64) +* mattbradford83 for the hasReset code and example - [PR 92](https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/pull/92) Repository Contents ------------------- diff --git a/examples/Example20-Sleep/Example20-Sleep.ino b/examples/Example20-Sleep/Example20-Sleep.ino index ca93525..bdf1b0a 100644 --- a/examples/Example20-Sleep/Example20-Sleep.ino +++ b/examples/Example20-Sleep/Example20-Sleep.ino @@ -26,6 +26,9 @@ #include "SparkFun_BNO080_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_BNO080 BNO080 myIMU; +unsigned long lastMillis = 0; // Keep track of time +bool lastPowerState = true; // Toggle between "On" and "Sleep" + void setup() { Serial.begin(115200); @@ -44,46 +47,51 @@ void setup() // Wire.setClockStretchLimit(4000); // //================================= + //myIMU.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + if (myIMU.begin() == false) { Serial.println("BNO080 not detected at default I2C address. Check your jumpers and the hookup guide. Freezing..."); while (1); } - Wire.setClock(400000); //Increase I2C data rate to 400kHz + // Enable the Rotation Vector packet ** while the I2C bus is set to 100kHz ** + myIMU.enableRotationVector(50); //Send RV data update every 50ms - myIMU.enableRotationVector(50); //Send data update every 50ms + Wire.setClock(400000); //Now increase I2C data rate to 400kHz Serial.println(F("Rotation vector enabled")); Serial.println(F("Output in form i, j, k, real, accuracy")); -} -unsigned long lastMillis = 0; // Keep track of time -bool lastPowerState = true; // Toggle between "On" and "Sleep" + lastMillis = millis(); // Keep track of time +} void loop() { - //Look for reports from the IMU - if (myIMU.dataAvailable() == true) + //Look for reports from the IMU - ** but only when not asleep ** + if (lastPowerState) // Are we "On"? (Comment this if you are interested in how it effects the sleep current) { - float quatI = myIMU.getQuatI(); - float quatJ = myIMU.getQuatJ(); - float quatK = myIMU.getQuatK(); - float quatReal = myIMU.getQuatReal(); - float quatRadianAccuracy = myIMU.getQuatRadianAccuracy(); - - Serial.print(quatI, 2); - Serial.print(F(",")); - Serial.print(quatJ, 2); - Serial.print(F(",")); - Serial.print(quatK, 2); - Serial.print(F(",")); - Serial.print(quatReal, 2); - Serial.print(F(",")); - Serial.print(quatRadianAccuracy, 2); - Serial.print(F(",")); - - Serial.println(); + if (myIMU.dataAvailable() == true) // Is fresh data available? + { + float quatI = myIMU.getQuatI(); + float quatJ = myIMU.getQuatJ(); + float quatK = myIMU.getQuatK(); + float quatReal = myIMU.getQuatReal(); + float quatRadianAccuracy = myIMU.getQuatRadianAccuracy(); + + Serial.print(quatI, 2); + Serial.print(F(",")); + Serial.print(quatJ, 2); + Serial.print(F(",")); + Serial.print(quatK, 2); + Serial.print(F(",")); + Serial.print(quatReal, 2); + Serial.print(F(",")); + Serial.print(quatRadianAccuracy, 2); + Serial.print(F(",")); + + Serial.println(); + } } //Check if it is time to change the power state @@ -102,4 +110,6 @@ void loop() lastPowerState ^= 1; // Invert lastPowerState (using ex-or) } + + delay(10); // Don't pound the bus too hard (Comment this if you are interested in how it effects the sleep current) } diff --git a/examples/Example21-ResetCheck/Example21-ResetCheck.ino b/examples/Example21-ResetCheck/Example21-ResetCheck.ino new file mode 100644 index 0000000..20bfbd0 --- /dev/null +++ b/examples/Example21-ResetCheck/Example21-ResetCheck.ino @@ -0,0 +1,90 @@ +/* + Using the BNO080 IMU hasReset() function + By: @mattbradford83 + Date: 1 August 2021 + SparkFun code, firmware, and software is released under the MIT License. + Please see LICENSE.md for further details. + + This example shows how check for a "Reset Complete" packet from the sensor, + which is helpful when used in tandem with resetReason(). The sensor will be + reset each time 25 readings are received to demonstrate. + +*/ + +#include + +#include "SparkFun_BNO080_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_BNO080 + +#define BNO08X_ADDR 0x4B // SparkFun BNO080 Breakout (Qwiic) defaults to 0x4B +//#define BNO08X_ADDR 0x4A // Alternate address if ADR jumper is closed + +BNO080 myIMU; + +int cyclecount = 0; + + +// After a reset, reports need to be re-enabled. +void enableReports() { + myIMU.enableGyro(50); //Send data update every 50ms +} + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println("BNO080 Read Example"); + + Wire.begin(); + Wire.flush(); + if (!myIMU.begin(BNO08X_ADDR)) { + Serial.println("Could Not Enable BNO Sensor! Check your I2C Address."); + return; + } + + enableReports(); + + Serial.println(F("Gyro enabled")); + Serial.println(F("Output in form x, y, z, in radians per second")); +} + +void loop() +{ + // One of these will appear at the very start because of the power on reset. + // Check resetReason() for the difference between different resets. + if (myIMU.hasReset()) { + Serial.println(" ------------------ BNO085 has reset. ------------------ "); + Serial.print(F(" Reason: ")); + Serial.println(myIMU.resetReason()); + enableReports(); // We'll need to re-enable reports after any reset. + } + + //Look for reports from the IMU + if (myIMU.dataAvailable()) + { + cyclecount++; + + Serial.print(F("[")); + if (cyclecount < 10) Serial.print(F("0")); + Serial.print(cyclecount); + Serial.print(F("] ")); + + float x = myIMU.getGyroX(); + float y = myIMU.getGyroY(); + float z = myIMU.getGyroZ(); + + Serial.print(x, 2); + Serial.print(F(",")); + Serial.print(y, 2); + Serial.print(F(",")); + Serial.print(z, 2); + Serial.print(F(",")); + + Serial.println(); + + if (cyclecount == 25) { + myIMU.softReset(); + cyclecount=0; + } + + } +} diff --git a/keywords.txt b/keywords.txt index 89dc28e..318ed33 100644 --- a/keywords.txt +++ b/keywords.txt @@ -19,6 +19,7 @@ enableDebugging KEYWORD2 softReset KEYWORD2 resetReason KEYWORD2 +hasReset KEYWORD2 modeOn KEYWORD2 modeSleep KEYWORD2 diff --git a/library.properties b/library.properties index 5615a31..357fe5d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun BNO080 Cortex Based IMU -version=1.1.10 +version=1.1.11 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=Library for the SparkFun Qwiic VR IMU - BNO080/BNO085 diff --git a/src/SparkFun_BNO080_Arduino_Library.cpp b/src/SparkFun_BNO080_Arduino_Library.cpp index 179f624..1ebdfe7 100644 --- a/src/SparkFun_BNO080_Arduino_Library.cpp +++ b/src/SparkFun_BNO080_Arduino_Library.cpp @@ -504,6 +504,18 @@ void BNO080::getQuat(float &i, float &j, float &k, float &real, float &radAccura float BNO080::getQuatI() { float quat = qToFloat(rawQuatI, rotationVector_Q1); + if (_printDebug == true) + { + if ((quat < -1.0) || (quat > 1.0)) + { + _debugPort->print(F("getQuatI: quat: ")); // Debug the occasional non-unitary Quat + _debugPort->print(quat, 2); + _debugPort->print(F(" rawQuatI: ")); + _debugPort->print(rawQuatI); + _debugPort->print(F(" rotationVector_Q1: ")); + _debugPort->println(rotationVector_Q1); + } + } return (quat); } @@ -511,6 +523,18 @@ float BNO080::getQuatI() float BNO080::getQuatJ() { float quat = qToFloat(rawQuatJ, rotationVector_Q1); + if (_printDebug == true) + { + if ((quat < -1.0) || (quat > 1.0)) // Debug the occasional non-unitary Quat + { + _debugPort->print(F("getQuatJ: quat: ")); + _debugPort->print(quat, 2); + _debugPort->print(F(" rawQuatJ: ")); + _debugPort->print(rawQuatJ); + _debugPort->print(F(" rotationVector_Q1: ")); + _debugPort->println(rotationVector_Q1); + } + } return (quat); } @@ -518,6 +542,18 @@ float BNO080::getQuatJ() float BNO080::getQuatK() { float quat = qToFloat(rawQuatK, rotationVector_Q1); + if (_printDebug == true) + { + if ((quat < -1.0) || (quat > 1.0)) // Debug the occasional non-unitary Quat + { + _debugPort->print(F("getQuatK: quat: ")); + _debugPort->print(quat, 2); + _debugPort->print(F(" rawQuatK: ")); + _debugPort->print(rawQuatK); + _debugPort->print(F(" rotationVector_Q1: ")); + _debugPort->println(rotationVector_Q1); + } + } return (quat); } @@ -999,6 +1035,16 @@ void BNO080::modeSleep(void) ; //delay(1); } +// Indicates if we've received a Reset Complete packet. Once it's been read, +// the state will reset to false until another Reset Complete packet is found. +bool BNO080::hasReset() { + if (_hasReset) { + _hasReset = false; + return true; + } + return false; +} + //Get the reason for the last reset //1 = POR, 2 = Internal reset, 3 = Watchdog, 4 = External reset, 5 = Other uint8_t BNO080::resetReason() @@ -1447,6 +1493,15 @@ boolean BNO080::receivePacket(void) getData(dataLength); } + // Quickly check for reset complete packet. No need for a seperate parser. + // This function is also called after soft reset, so we need to catch this + // packet here otherwise we need to check for the reset packet in multiple + // places. + if (shtpHeader[2] == CHANNEL_EXECUTABLE && shtpData[0] == EXECUTABLE_RESET_COMPLETE) + { + _hasReset = true; + } + return (true); //We're done! } diff --git a/src/SparkFun_BNO080_Arduino_Library.h b/src/SparkFun_BNO080_Arduino_Library.h index 025f9c8..0b1c811 100644 --- a/src/SparkFun_BNO080_Arduino_Library.h +++ b/src/SparkFun_BNO080_Arduino_Library.h @@ -100,6 +100,9 @@ const byte CHANNEL_GYRO = 5; #define FRS_RECORDID_MAGNETIC_FIELD_CALIBRATED 0xE309 #define FRS_RECORDID_ROTATION_VECTOR 0xE30B +// Reset complete packet (BNO08X Datasheet p.24 Figure 1-27) +#define EXECUTABLE_RESET_COMPLETE 0x1 + //Command IDs from section 6.4, page 42 //These are used to calibrate, initialize, set orientation, tare etc the sensor #define COMMAND_ERRORS 1 @@ -131,6 +134,7 @@ class BNO080 void enableDebugging(Stream &debugPort = Serial); //Turn on debug printing. If user doesn't specify then Serial will be used. void softReset(); //Try to reset the IMU via software + bool hasReset(); //Returns true if the sensor has reported a reset. Reading this will unflag the reset. uint8_t resetReason(); //Query the IMU for the reason it last reset void modeOn(); //Use the executable channel to turn the BNO on void modeSleep(); //Use the executable channel to put the BNO to sleep @@ -273,6 +277,8 @@ class BNO080 uint8_t _int; uint8_t _rst; + bool _hasReset = false; // Keeps track of any Reset Complete packets we receive. + //These are the raw sensor values (without Q applied) pulled from the user requested Input Report uint16_t rawAccelX, rawAccelY, rawAccelZ, accelAccuracy; uint16_t rawLinAccelX, rawLinAccelY, rawLinAccelZ, accelLinAccuracy;