sparkfun / SparkFun_BNO080_Arduino_Library

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

dataAvailable() blocks the program #13

Closed Nate711 closed 5 years ago

Nate711 commented 6 years ago

Please correct me if I'm misinterpreting how the sensor polling works, but it appears that whenever you call dataAvailable(), it will block the program until the next data packet is read. This is a problem for me because I'm trying to log IMU data at 20Hz and do other stuff at 100Hz. But it looks like waitForSPI() will block the program for a maximum 50ms (or whatever the sensor polling period is), and thus the 100Hz loop will execute at 20Hz.

My suggestion is to change:

//Blocking wait for BNO080 to assert (pull low) the INT pin
//indicating it's ready for comm. Can take more than 104ms
//after a hardware reset
boolean BNO080::waitForSPI()
{
  for (uint8_t counter = 0 ; counter < 125 ; counter++) //Don't got more than 255
  {
    if (digitalRead(_int) == LOW) return (true);
    delay(1);
  }

  if (_printDebug == true) _debugPort->println(F("SPI INT timeout"));
  return (false);
}

to

//Blocking wait for BNO080 to assert (pull low) the INT pin
//indicating it's ready for comm. Can take more than 104ms
//after a hardware reset
boolean BNO080::waitForSPI()
{
  if (digitalRead(_int) == LOW) return (true);

  if (_printDebug == true) _debugPort->println(F("SPI INT timeout"));
  return (false);
}

and manually add blocking to line 93 like so

//Wait for first assertion of INT before using WAK pin. Can take ~104ms
long ts = millis()
while(millis() - ts < 125) {
    waitForSPI();
}

I've just been using the SPI interface because I want the read time to eventually go down to <1ms, so I haven't been looking to much at the I2C stuff, but it appears this is an issue there as well.

Let me know what you think and if I'm correct about this then I can make a pull request. Thanks for your time!

Nate711 commented 6 years ago

I'm also not sure why there is a waitForSPI() on line 1072. It was my understanding that the interrupt line only goes low when the BNO080 wants to talk to the host.

nseidle commented 6 years ago

Hi Nate711,

You are close, that function is blocking up to 125*delay(1) = 125ms.

Your solution is a good one but should be implemented in a dataAvailable() function rather than modifying the waitForSPI. To me, waitForSPI indicates a hard wait (ie blocking) whereas a dataAvailable() is a common function to many libs that offers a boolean return. If you want to submit a PR I'd be happy to look at it!

Also, did you know you can link to lines? Line 1072 does not contain waitForSPI so I'm not sure what you're talking about in your 2nd comment.

Nate711 commented 6 years ago

Hi nseidle,

Thanks for replying! The dataAvailable() function calls the receivePacket() function which then calls waitForSPI(). So either waitForSPI() or receivePacket() has to change in order to remove the blocking behavior of dataAvailable(). I ended up adding the amount of time to block as a parameter to both receivePacket() and waitForSPI(). https://github.com/Nate711/SparkFun_BNO080_Arduino_Library. My fork isn't so clean so I won't be submitting a PR, but I do think this is a very important fix. For most real-time applications, I'd consider the blocking behavior a bug!

Btw, I had mixed up the line numbers and was referring to https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/blob/d196c42a6c404c7efd92c4d1c0526969179f13e3/src/SparkFun_BNO080_Arduino_Library.cpp#L1076

ealkhatib commented 5 years ago

Hi Nate711 and nseidle,

I'm interested in real time applications. Did you fix the blocking of dataAvailable() ?

I tried Nate711 version from here " https://github.com/Nate711/SparkFun_BNO080_Arduino_Library" but I still have the same problem, it blocks the loop for about 10 ms. I'm using I2C communication, is yours only improve SPI method?

Is there a way to keep the sensor awake and keep sending the data? so we can read the data based on the interrupt. But without calling dataAvailable() the sensor doesn't send anything and No interrupt occurs.

Thank you.

nseidle commented 5 years ago

Ok, I think I have removed the blocking. Please have a look at this line in the commit. Also, I've extended the SPI->Ex1 a bit to run at 115200, and print the output rate.

image

In the image above, "Doing other things" has a 10ms delay with each print. So for 40ms we do nothing but burn cycles and then we have new data (which takes time to print).

So I think blocking has been reasonably removed for SPI. I'll roll these changes into a new lib version once I can address the other issues.

Please kick the tires on Ex1 and let me know if these changes are not enough for your real-time purposes. I'm closing but feel free to re-open if needed.

And thanks for reporting! We're always trying to make things better.

dxydas commented 4 years ago

Hi, I have the same issue but with the I2C bus. The waitForI2C() function doesn't seem to be checking the interrupt pin the same way waitForSPI() is. I tried modifying the code and using interrupt pin but with no luck. Does anyone know how this can be fixed? Thanks.