how to read multiple reports BNO085

General project help for Adafruit customers

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
sminogue
 
Posts: 46
Joined: Sun Oct 04, 2020 9:35 am

how to read multiple reports BNO085

Post by sminogue »

Hi,

I would like to read multiple reports from the BNO085. For example I want Linear Accel, Calibrated Gyroscope, and Calibrated Magnetometer

I am currently enabling the 3 reports:

Code: Select all

void setReports(){

  if (! bno08x.enableReport(SH2_LINEAR_ACCELERATION, 4000)) {
    Serial.println("Could not enable stabilized linear accel");
    handle_error(CONFIGURATION_ERROR);
  }

  if (! bno08x.enableReport(SH2_GYROSCOPE_CALIBRATED, 4000)) {
    Serial.println("Could not enable gyroscope");
    handle_error(CONFIGURATION_ERROR);
  }

  if (! bno08x.enableReport(SH2_MAGNETIC_FIELD_CALIBRATED, 4000)) {
    Serial.println("Could not enable magnetometer");
    handle_error(CONFIGURATION_ERROR);
  }

  Serial.println("Set Reports");
  
}
Then when I read from the sensor:

Code: Select all

void read_sensor(){

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

  accel.isset = 0;
  gyro.isset = 0;
  mag.isset = 0;

  while(!gyro.isset || !accel.isset || !mag.isset){

    if (bno08x.getSensorEvent(&sensorValue)) {

      switch(sensorValue.sensorId){
        case SH2_GYROSCOPE_CALIBRATED:
          gyro.isset = 1;
          gyro.x = sensorValue.un.gyroscope.x;
          gyro.y = sensorValue.un.gyroscope.y;
          gyro.z = sensorValue.un.gyroscope.z;
          break;
        case SH2_LINEAR_ACCELERATION:
          accel.isset = 1;
          accel.x = sensorValue.un.linearAcceleration.x;
          accel.y = sensorValue.un.linearAcceleration.y;
          accel.z = sensorValue.un.linearAcceleration.z;
          break;
        case SH2_MAGNETIC_FIELD_CALIBRATED:
          mag.isset = 1;
          mag.x = sensorValue.un.magneticField.x;
          mag.y = sensorValue.un.magneticField.y;
          mag.z = sensorValue.un.magneticField.z;
          break;
      }
      
    }
    
  }

    Serial.print(millis());             Serial.print("\t");
    Serial.print(gyro.x); Serial.print("\t");
    Serial.print(gyro.y); Serial.print("\t");
    Serial.print(gyro.z); Serial.print("\t");
    Serial.print(accel.x); Serial.print("\t");
    Serial.print(accel.y); Serial.print("\t");
    Serial.print(accel.z); Serial.print("\t");
    Serial.print(mag.x); Serial.print("\t");
    Serial.print(mag.y); Serial.print("\t");
    Serial.println(mag.z);
}
So the issue is that I keep looping until I have finally gotten a report from all 3... this is VERY slow. Like 554 reads the time averages out at 50ms for each call to the read_sensor function.

Thats slow to the point that I have to assume there is a better way? Also... what's the deal with the BNO085 sometimes resetting so I need to be ready to recall that setReports and the bno08x.getSensorEvent seems to return false a fair number of times...

Oh, I am using I2c for the wiring, if that could be related?

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

Hi again.
The BNO085 outputs magnetometer reports at a slower rate than most other reports, even if you request a fast rate. See datasheet section 6.9 Report Rates. It also likes to round-off requested report rates to a few fixed values. Could that be what you're seeing?

I don't understand this sentence, missing words?
"Like 554 reads the time averages out at 50ms for each call to the read_sensor function."

User avatar
sminogue
 
Posts: 46
Joined: Sun Oct 04, 2020 9:35 am

Re: how to read multiple reports BNO085

Post by sminogue »

Hey Gamma, thanks for taking the time to help me through all this.

So my use case: I want to "read the sensor" and pull back: Accelerometer data, gyroscope data, and either magnetometer data OR convert a rotation vector to Yaw,Pitch,Roll.

So I created a function "read_sensor" which will attempt to pull all 3 reports and write a single "line" to my output containing that information. It seems like getSensorEvent returns 1 report but there seems to be no rhyme or reason to which report. So I end up with like 4 Accelerometer reports followed by 2 gyroscope reports and then 1 magnetometer or RV report.

As you can see from the attached code I wrote a little loop which basically keeps polling getSensorEvent until I have pulled back 1 of each report.

Unfortunately what I am seeing is that a call to "read_sensor" can take anywhere from 36ms to 244ms and over the course of 30 seconds recording data my average is that every call to read_sensor takes about 66ms.

I am transmitting all these "reads" over BLE to a phone app which then makes use of them. Each "read" of data I send to the phone app should be GX, GY, GZ, AX, AY, AZ, and then either MX,MY,MZ or Yaw,Pitch,Roll. I use that information for motion analysis. My target rate and what I was able to achieve using the 9DOF precision breakout was 5ms between reads. On the 9DOF I was using Accelerometer, Gyroscope, and Magnetometer and using Madgewicks sensor fusion algorithm to get to my Yaw, Pitch, and Roll. With the BNO085 I am considering letting it do the sensor fusion for me.

Hopefully that makes it a little clearer what I am talking about in terms of reads?

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

If you have a choice between reading individual sensors and doing your own fusion math, or reading quaternions and converting to Euler angles (Yaw Pitch Roll), definitely read the quaternions and convert - that's much easier and probably better fusion results.

The BNO085 likes to output different reports at different rates. Those rates are not necessarily the rates that you may want. Also, if you request too many total reports per second, The BNO can't keep up and unpredictably drops some reports.

Rather than looping until all reports arrive, you could maintain "most recent value" variables for each report. Then use some type of timer to periodically send all the most recent values to your processing math. That would probably cause some values to be overwritten before they're used, or some values to be used multiple times, but it's a simple technique that may be acceptable.

Or you could do mathematical sample rate conversion (a DSP technique): for each BNO085 report type, you convert the report rate to whatever rate you need. That involves some fancy interpolation filtering math, similar to converting digital audio to a different sample rate. This inserts a time delay that may or may not be acceptable to you.

User avatar
sminogue
 
Posts: 46
Joined: Sun Oct 04, 2020 9:35 am

Re: how to read multiple reports BNO085

Post by sminogue »

I'm still struggling with read rate. I have implemented what you suggested where I just poll the bno085 and keep a copy of the latest report. Then periodically I am writing those reports to Serial. I have enabled the reports at 400hz (2500 microseconds) and I am writing to the Serial at 100hz (10ms) so I would expect for each line written to the Serial to have all 3 reports. I am using Linear Acceleration, Calibrated Gyroscope, and ARVR Rotation Vector.

Example data below. As you can see each row is ending up with only 1 report represented. Also as you can see from the time column the time between outputs is a lot more than the 10ms I expect. Also, the time between is inconsistent. Any idea what I am missing?

Oh, when I remove the actual reading report from the sensor it outputs a line every 10ms anticipated. So I dont think I have a flaw in my loop logic.
Screenshot 2023-03-13 at 3.13.32 PM.png
Screenshot 2023-03-13 at 3.13.32 PM.png (29.28 KiB) Viewed 1118 times

Code: Select all

struct reading_t {
  float x;
  float y;
  float z;
  int isset;
} accel, gyro;

struct quat_t {
  float real;
  float i;
  float j;
  float k;
  int isset;
} rotation;

Adafruit_BNO08x  bno08x(BNO08X_RESET);
sh2_SensorValue_t sensorValue;

uint32_t starttime = millis();

void setReports(){

  if (! bno08x.enableReport(SH2_LINEAR_ACCELERATION, 2500)) {
    Serial.println("Could not enable stabilized linear accel");
    handle_error(CONFIGURATION_ERROR);
  }

  if (! bno08x.enableReport(SH2_GYROSCOPE_CALIBRATED, 2500)) {
    Serial.println("Could not enable gyroscope");
    handle_error(CONFIGURATION_ERROR);
  }

  if (! bno08x.enableReport(SH2_ARVR_STABILIZED_RV, 2500)) {
    Serial.println("Could not enable arvr RV");
    handle_error(CONFIGURATION_ERROR);
  }
  
  Serial.println("Set Reports");
  
}

void initialize_measure(){
  if (!bno08x.begin_I2C()) {
    Serial.println("Failed to find BNO08x chip");
    handle_error(CONFIGURATION_ERROR);
  }
  Serial.println("BNO08x Initialized!");

  setReports();
}

void reset_sensor_values(){
  accel.isset = 0;
  gyro.isset = 0;
  rotation.isset = 0;
}

void write_to_buffer(){
  //This is where we would actually write to the buffer... For now write to serial.
  if(!gyro.isset){
    gyro.x = 666;
    gyro.y = 666;
    gyro.z = 666;
  }
  
  if(!accel.isset){
    accel.x = 666;
    accel.y = 666;
    accel.z = 666;  
  }

  if(!rotation.isset){
    rotation.real = 666;
    rotation.i = 666;
    rotation.j = 666;
    rotation.k = 666;
  }
  
    Serial.print((millis() - starttime));             Serial.print("\t");
    Serial.print(gyro.x); Serial.print("\t");
    Serial.print(gyro.y); Serial.print("\t");
    Serial.print(gyro.z); Serial.print("\t");
    Serial.print(accel.x); Serial.print("\t");
    Serial.print(accel.y); Serial.print("\t");
    Serial.print(accel.z); Serial.print("\t");
    Serial.print(rotation.real); Serial.print("\t");
    Serial.print(rotation.i); Serial.print("\t");
    Serial.print(rotation.j); Serial.print("\t");
    Serial.print(rotation.k); Serial.print("\t");
    Serial.println("");
}

void read_sensor(){

  if (bno08x.wasReset()) {
    Serial.println("sensor was reset ");
    setReports();
  }

  if (bno08x.getSensorEvent(&sensorValue)) {
    switch(sensorValue.sensorId){
      case SH2_GYROSCOPE_CALIBRATED:
        gyro.isset = 1;
        gyro.x = sensorValue.un.gyroscope.x;
        gyro.y = sensorValue.un.gyroscope.y;
        gyro.z = sensorValue.un.gyroscope.z;
        break;
      case SH2_LINEAR_ACCELERATION:
        accel.isset = 1;
        accel.x = sensorValue.un.linearAcceleration.x;
        accel.y = sensorValue.un.linearAcceleration.y;
        accel.z = sensorValue.un.linearAcceleration.z;
        break;
      case SH2_ARVR_STABILIZED_RV:
        rotation.real = sensorValue.un.arvrStabilizedRV.real;
        rotation.i = sensorValue.un.arvrStabilizedRV.i;
        rotation.j = sensorValue.un.arvrStabilizedRV.j;
        rotation.k = sensorValue.un.arvrStabilizedRV.k;
        rotation.isset = 1;
        break;
      }
    }
}

void record_motion(){
  Serial.println("Recording...");
  starttime = millis();
  uint32_t currtime = starttime;
  uint32_t prevtime = starttime;
  uint32_t endtime = starttime + STROKE_LEN_MILLI; 

  //Clear out the write buffer
  //emptyWriteBuff();

  //Reset the sensor reads.
  reset_sensor_values();

  //Iterate for the length of the recording time
  while(currtime < endtime){

    //Read the sensor and update sensor read variables
    read_sensor();

    //Test if frequency has been met, if so add read variables to write buffer
    if((currtime - prevtime) >= FREQUENCY){
        //Update the prev time which will break us out of this loop until the next scheduled write
        prevtime = currtime;

        //Update the write buffer 
        write_to_buffer();

        //Reset the sensor reads.
        reset_sensor_values();
        
      }

    //Update currtime
    currtime = millis();
      
    }
    
}

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  initialize_measure();

  delay(100); //Delay I think to let reports be fully enabled.

  Serial.println("Initialization Completed");
  
}

void loop() {  
    record_motion();
}

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

Whoa! Slow down those report rates. The BNO085 won't output thousands of messages per second. It should, but it won't. Requesting too many messages causes an internal logjam or constipation or something. Start with much slower report rates, confirm success, then work your way up in speed.

Maybe try printing a simple one-character message each time a report arrives, such as 'a' for accel, 'g' for gyro, 'v' for vector. That should help you visualize the BNO's actual report rates, and how they're interleaved.

Speed-up the I2C clock to 400 kHz. Your default is probably 100 kHz.

Be sure your microcontroller and/or serial port baud rate isn't bogging down printing too many numbers.

SPI would run somewhat faster than I2C. Not a lot, but somewhat.
I haven't measured UART throughput. Don't know if it would be faster or slower than I2C or SPI.

User avatar
jps2000
 
Posts: 811
Joined: Fri Jun 02, 2017 4:12 pm

Re: how to read multiple reports BNO085

Post by jps2000 »

Spec says 400kHz IIC clock rate max but I tried up to 1Mhz and it worked flawlessly. (Short wires and pullups of 2k2-4k7 requested.
Hig data rate is crucial for the BNO to vomit all data generated. If it is too slow it can not finish reporting and restart from the beginning . If you can monitor the INTN with a scope. L means attention of the host is required H means nothing to report. If this line is always L than this tells that data rate is not sufficient for the requested amount.

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

Hi jps2000,
With this example project, I'm seeing decreased report rate at 1 MHz I2C clock compared to 400 kHz. My hypothesis: Adafruit's library polls the BNO (no interrupts) to see if a report is available. At 1 MHz, it polls more often, and that's probably eating up more BNO CPU bandwidth, so it can't output as many reports. Just guessing.

At both 400 kHz and 1 MHz, the BNO085 breakout's INT pin is high about 98% of the time, and briefly pulses low twice for each report. The pulses become more erratic and less frequent when it's dropping more reports.

I'm guessing this project would run better using interrupts rather than polling. I've never tried doing that.

I just now tried polling the INT pin by waiting until it goes low at the beginning of read_sensor(). That reduces the I2C polling and helps read reports faster at 1 MHz I2C clock. However, nothing I've ever tried helps me read more that about 600 total reports per second. Have you seen better speed?

By the way, right now I'm using a QT Py ESP32-S2 (Adafruit 5348).

As we notice more and more weird symptoms, I can almost visualize the clumsy I/O programming inside the BNO.

User avatar
jps2000
 
Posts: 811
Joined: Fri Jun 02, 2017 4:12 pm

Re: how to read multiple reports BNO085

Post by jps2000 »

Hi gammaburst.
I never used reports other than quats and 400Hz data rate. Quats and Linacc is sufficient I think.
For other applications I do not use the BNO.

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

Hi sminogue,
Your example sketch attempts to read three reports at certain data rates.
Are those your actual project requirements, or are they merely experimental values for troubleshooting?
Which reports and data rates does your project require? Or maybe you haven't decided yet?

I am successfully reading your three messages at 200 Hz, but not at 400 Hz.
The significant changes that I made to your sketch:
- Increased I2C clock rate to 400 kHz.
- Added the aforementioned wait-until-INT-low loop at the beginning of read_sensor().
- Replaced all of your output messages with a simple one-character message for each report type.

Here's my over-simplified experimental sketch:

Code: Select all

#include <Adafruit_BNO08x.h>

#define PIN_SCL      SCL            // SCL pin
#define PIN_INT      A3             // INT pin, from BNO085 breakout
#define BNO08X_RESET -1             // RST pin, to BNO085 breakout, -1 unused

Adafruit_BNO08x bno08x(BNO08X_RESET);

void setup()
{
  Serial.begin(115200);
  Serial.println("\nSerial port running");

  delay(300);                       // allow BNO085 time to finish booting

  for (int n=0; n<10; n++)          // clear I2C bus, in case a slave is holding SDA low
  {
    digitalWrite(PIN_SCL,LOW);
    pinMode(PIN_SCL,OUTPUT);        // clock low
    delayMicroseconds(10);
    pinMode(PIN_SCL,INPUT);         // clock high
    delayMicroseconds(10);
  }
  bno08x.begin_I2C();
  Wire.setClock(400000);

  bno08x.enableReport(SH2_LINEAR_ACCELERATION,  1000000/200);
  bno08x.enableReport(SH2_GYROSCOPE_CALIBRATED, 1000000/200);
  bno08x.enableReport(SH2_ARVR_STABILIZED_RV,   1000000/200);

  pinMode(PIN_INT, INPUT);          // so we can read BNO's INT pin

  Serial.println("setup() done");
}

void loop()
{
  while (digitalRead(PIN_INT));     // wait until INT low

  sh2_SensorValue_t sensorValue;
  if (bno08x.getSensorEvent(&sensorValue))
  {
    switch(sensorValue.sensorId)
    {
      case SH2_GYROSCOPE_CALIBRATED:
        Serial.print("g");
        break;
      case SH2_LINEAR_ACCELERATION:
        Serial.print("a");
        break;
      case SH2_ARVR_STABILIZED_RV:
        Serial.print("r");
        break;
    }
  }
}

User avatar
sminogue
 
Posts: 46
Joined: Sun Oct 04, 2020 9:35 am

Re: how to read multiple reports BNO085

Post by sminogue »

Hey can you guys point me at any documentation or example code for doing UART? Everything I am finding searching is UART-RVC... kinda driving me nuts.

In the more_reports example there is this little block of code:

Code: Select all

if (!bno08x.begin_I2C()) {
    // if (!bno08x.begin_UART(&Serial1)) {  // Requires a device with > 300 byte
    // UART buffer! if (!bno08x.begin_SPI(BNO08X_CS, BNO08X_INT)) {
    Serial.println("Failed to find BNO08x chip");
    while (1) {
      delay(10);
    }
  }
Which kind of implies that I can change that if statement to switch between I2C, SPI, and UART... But when I make the change it doesn't work. Also While I declared a new Serial1.begin(115200)... That comment about a device with > 300 byte uart buffer gives me pause.

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

Some BNO085 reports are hundreds of bytes long, and UART mode is fixed at 3000000 baud, so that's probably why it advised a buffer of several hundred bytes.

I haven't used (or looked for) a library that supports BNO085 UART mode. Sorry.

The BNO085 is over-complicated and poorly documented. Few people have attempted to figure out how to fully use it.

In this forum discussion viewtopic.php?p=953477#p953477 I connected a BNO085 in UART mode to Windows through a USB-Serial adapter (no microcontroller). It was merely a minimal feasibility test. It doesn't use any BNO085 library, it shortcuts the BNO's messaging protocol, it requests some reports, but it doesn't decode the reports. Maybe you could use it as a starting point for a project, or use it to see how fast the BNO outputs reports in UART mode:

User avatar
sminogue
 
Posts: 46
Joined: Sun Oct 04, 2020 9:35 am

Re: how to read multiple reports BNO085

Post by sminogue »

Hi again,
Thanks for all the help on this... I am still struggling with the report rate. I have implemented a lot of what we have discussed and still performance is not what I would hope for.

The timing I am seeing was inconsistent so I made a couple changes to the below program to just print how long the getSensorEvent is taking. No joke I am getting times over 10 milliseconds to just get a report. I honestly dont know how the UART_RVC manages to get accelerometer and rotation vector data consistently at 100hz because trying to do that just reading the sensor I am coming nowhere near.

I have adjusted the speed I am reading the sensor (right now in the below code it's 2000 microseconds) but I have had it at 750 microseconds without it seeming to impact the timing.

I know the call to Serial.println will add some overhead... and the 2 calls to micros() as well... but I wouldn't expect them to add whole milliseconds of time.

What am I doing wrong? I am rapidly reaching the point where I decide the BNO085 simply cannot perform at a level I need. Sadly the now discontinued Precision 9-DOF sensor Adafruit carried was more than capable of meeting my needs. I was able to read Accel, Gyro, and Mag from it at 200hz (5 milliseconds) without any issues.

Code: Select all

#include <Wire.h>
#include <Adafruit_BNO08x.h>

// Config constants used by sensor
#define BNO08X_RESET -1

Adafruit_BNO08x  bno08x(BNO08X_RESET);
sh2_SensorValue_t sensorValue;

struct reading_t {
  float x;
  float y;
  float z;
  int isset;
} accel, gyro;

struct quat_t {
  float real;
  float i;
  float j;
  float k;
  int isset;
} rotation;

unsigned long prevmicros_read = 0;
unsigned long prevmicros_write = 0;
unsigned long currmicros = 0;


#define SENSOR_READ_INTERVAL 2000 //Read the sensors at 500hz
#define SENSOR_WRITE_INTERVAL 13000 //Write output at 100hz

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

  Wire.begin();
  Wire.setClock(400000L); //Set clock speed to fast 
  
  while (!Serial) delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  initialize_measure();
 
}

void write_readings(){
    Serial.print(millis());
    Serial.print("\t");
    if(gyro.isset){
      Serial.print("G\t");
      //Serial.print(gyro.x);
      //Serial.print("\t");
      //Serial.print(gyro.y);
      //Serial.print("\t");
      //Serial.print(gyro.z);
      //Serial.print("\t");
    }else{
      //Serial.print("-\t-\t-\t");
      Serial.print("-\t");
    }
    if(accel.isset){
      Serial.print("A\t");
      //Serial.print(accel.x);
      //Serial.print("\t");
      //Serial.print(accel.y);
      //Serial.print("\t");
      //Serial.print(accel.z);
      //Serial.print("\t");
    }else{
      //Serial.print("-\t-\t-\t");
       Serial.print("-\t");
    }
    if(accel.isset){
      Serial.print("R\t");
      //Serial.print(rotation.real);
      //Serial.print("\t");
      //Serial.print(rotation.i);
      //Serial.print("\t");
      //Serial.print(rotation.j);
      //Serial.print("\t");
      //Serial.print(rotation.k);
    }else{
      //Serial.print("-\t-\t-\t-");
      Serial.print("-\t");
    }
    Serial.println("");
    accel.isset = 0;
    gyro.isset = 0;
    rotation.isset = 0;
}

void loop() {
  record_data();
}

void initialize_measure(){
  if (!bno08x.begin_I2C(BNO08x_I2CADDR_DEFAULT,&Wire)) {
    Serial.println("Failed to find BNO08x chip");
    while (true) delay(10);
  }
  Serial.println("BNO08x Initialized!");

  setReports();
}
void setReports(){

  if (! bno08x.enableReport(SH2_LINEAR_ACCELERATION, 2000)) {
    Serial.println("Could not enable stabilized linear accel");
    while (true) delay(10);
  }

  if (! bno08x.enableReport(SH2_GYROSCOPE_CALIBRATED, 2500)) {
    Serial.println("Could not enable gyroscope");
    while (true) delay(10);
  }

  if (! bno08x.enableReport(SH2_ROTATION_VECTOR, 2500)) {
    Serial.println("Could not enable arvr RV");
    while (true) delay(10);
  }

  Serial.println("Set Reports");
  
}

void record_data(){

  currmicros = micros();
  prevmicros_read = currmicros;
  prevmicros_write = currmicros;

  while(true){
    currmicros = micros();

    if((currmicros - prevmicros_read) >= SENSOR_READ_INTERVAL){
      //Serial.print(millis());
      //Serial.println("\tReading");
      Serial.print(millis());
      Serial.print("\t");
      read_sensor();
      Serial.println(millis());
      prevmicros_read = currmicros;
    }

    if((currmicros - prevmicros_write) >= SENSOR_WRITE_INTERVAL){
   //   Serial.print(millis());
    //  Serial.println("\tWriting");
      //write_readings();
     prevmicros_write = currmicros;
    }
    
  }
  
}

void read_sensor(){

  if (bno08x.wasReset()) {
    //Serial.println("sensor was reset ");
    setReports();
  }
  //Serial.print((millis() - prevtime));
  if (bno08x.getSensorEvent(&sensorValue)) {
    switch(sensorValue.sensorId){
      case SH2_GYROSCOPE_CALIBRATED:
        gyro.isset = 1;
        gyro.x = sensorValue.un.gyroscope.x;
        gyro.y = sensorValue.un.gyroscope.y;
        gyro.z = sensorValue.un.gyroscope.z;
        break;
      case SH2_LINEAR_ACCELERATION:
        accel.isset = 1;
        accel.x = sensorValue.un.linearAcceleration.x;
        accel.y = sensorValue.un.linearAcceleration.y;
        accel.z = sensorValue.un.linearAcceleration.z;
        break;
      case SH2_ROTATION_VECTOR:
        rotation.real = sensorValue.un.rotationVector.real;
        rotation.i = sensorValue.un.rotationVector.i;
        rotation.j = sensorValue.un.rotationVector.j;
        rotation.k = sensorValue.un.rotationVector.k;
        rotation.isset = 1;
        break;
      }
    }  
}

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

I'll try your code a little later today.
Which microcontroller are you using? I may have a similar one to try.
Which reports does your project need, and what report rate?
My above example reads the three reports at 200 Hz, using a QT Py ESP32-S2 (Adafruit 5348).

UPDATE

Again, slow down those report rates. The BNO085 probably won't output 500+400+400=1300 reports per second.
Start with much slower report rates, confirm success, then work your way up in speed.
If you can get 600 total reports per second, that's about as fast as I've ever seen the BNO085 go.

Don't print so much stuff to the serial port. That could be slowing things down.
I changed your print code to this calculation, and it prints many 1, some 0, occasional 2:

Code: Select all

unsigned t0 = millis();
read_sensor();
unsigned t1 = millis();
Serial.print(t1-t0);
Serial.print(" ");

User avatar
gammaburst
 
Posts: 1016
Joined: Thu Dec 31, 2015 12:06 pm

Re: how to read multiple reports BNO085

Post by gammaburst »

I just noticed these two lines add-up to 600 Hz:
- #define SENSOR_READ_INTERVAL 2000 //Read the sensors at 500hz
- #define SENSOR_WRITE_INTERVAL 13000 //Write output at 100hz
Maybe you're thinking those numbers control the speed problem, but they merely control your loop rate, and that's not the main problem.

The main problem is you asked the BNO to generate 500 + 400 + 400 = 1300 reports per second:
- bno08x.enableReport(SH2_LINEAR_ACCELERATION, 2000)
- bno08x.enableReport(SH2_GYROSCOPE_CALIBRATED, 2500)
- bno08x.enableReport(SH2_ROTATION_VECTOR, 2500)
By the way, 2000 (500 Hz) is too fast for that report, I think the BNO will limit it to 2500 (400 Hz).

Remember BNO085 datasheet section 6.9:
"Each individual sensor can operate at its maximum rate; however, all sensors cannot operate at their maximum rate simultaneously ... the user will need to find a balance ..."
That's why I suggest starting with a slow report rates, confirm success, then work your way up in speed.

I hope that helps clarify things!

Locked
Please be positive and constructive with your questions and comments.

Return to “General Project help”