sparkfun / SparkFun_BNO08x_Arduino_Library

An Arduino Library for the BNO08x IMU combination triple axis accelerometer/gyro/magnetometer packaged with an ARM Cortex M0+ running powerful algorithms.
Other
14 stars 8 forks source link

Intermittent zeros issue fixed? #21

Open Nate711 opened 3 months ago

Nate711 commented 3 months ago

I saw many reviewers saying the BNO086 with this library would often report spurious values at irregular intervals. https://www.sparkfun.com/products/22857#reviews

Is this because the library does not correctly parse zero-length data packets, which the bno086 provides when it doesn't have new data?

From the datasheet

The BNO08X uses CEVA’s SHTP (Sensor Hub Transport Protocol) protocol to communicate. The BNO08X
application does not support the repeated start method for typical I2C register based interfaces. More details are
available in [2]. If the BNO085 is polled and it has no data to send it will stretch the clock until it has data to send.
If the BNO086 is polled and it has no data to send, it will send zero data packets. Host should read the length field
and ignore zero length packets.
lewispg228 commented 3 months ago

Hi @Nate711 , Thanks for reaching out. I've been digging into this for the past couple days.

I haven't found the root cause of the issue yet, but FWW I have found a solution for example 2. If you drop the Wire clock to 50KHz, and decrease the delay in the main loop to 1ms, then the spurious values no longer pop up.

It looks like the CEVA driver is correctly ignoring zero length packets, so something else must be causing spurious values.

I have been able to replicate the spurious values on both examples 1 and 2. I am using a MicroMod Machine Learning Carrier board with the Artemis Processor. This is what I'm randomly seeing:

image

I suspect the CEVA driver is failing somewhere when you don't read the incoming events frequently enough. I suspect this because as soon as the main loop delay is increased to 5 or 10 ms, then the spurious values come back.

Also, I have created a slightly modified example 2 (with time stamping debug using millis()), and it is showing that each report is coming in every 6-7 ms, with the occasional longer timegap (15ms+). I'm guessing that these are other messages on the SHTP bus that the driver is properly handling and our sketch is not looking for. Either way, the data looks clean.

I will continue to dig into what may be the root cause here, and keep you posted.

Here is the modified example 2 that is working for me. Note, you may have to adjust the INT and RST pins to your hardware.


/*
  Using the BNO08x IMU

  This example shows how to output accelerometer values.

  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  PWM1
//#define BNO08X_INT  -1
#define BNO08X_RST  PWM0
//#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

// time stamp variables
// used to monitor the time gaps between available reports (aka "events").
long previousTime;

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 Read 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(50000); //Decrease I2C data rate to 50kHz

  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.enableAccelerometer() == true) {
    Serial.println(F("Accelerometer enabled"));
    Serial.println(F("Output in form x, y, z, in m/s^2"));
  } else {
    Serial.println("Could not enable accelerometer");
  }
}

void loop() {
  delay(1); // decreasing this delay to 1ms seems to eliminate spurious acel data

  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 it the correct sensor data we want?
    if (myIMU.getSensorEventID() == SENSOR_REPORTID_ACCELEROMETER) {
      long timeSinceLastReport = millis() - previousTime;

      float x = myIMU.getAccelX();
      float y = myIMU.getAccelY();
      float z = myIMU.getAccelZ();

      Serial.print(x, 2);
      Serial.print(F(","));
      Serial.print(y, 2);
      Serial.print(F(","));
      Serial.print(z, 2);
      Serial.print(F("\t"));
      Serial.print(timeSinceLastReport);

      Serial.println();
      previousTime = millis();
    }
  }
}