Closed jerabaul29 closed 3 years ago
PS: could you provide an estimate of how long providing something like this may take? I have a hard deadline for developing a BNO080-based solution, with only a few days left. If it is too short for you to push something I will come up with a "hacky user-side solution", but would prefer to have something a bit clean :) .
To illustrate this issue, a small script (that I run on Artemis RedBoard):
#include "Arduino.h"
#include <Wire.h>
#include "SparkFun_BNO080_Arduino_Library.h"
BNO080 bno080_imu;
//------------------------------------------------------------------------
// some parameters
constexpr unsigned long imu_output_period_millis = 100;
//------------------------------------------------------------------------
void setup() {
Serial.begin(230400);
delay(10);
Serial.println();
Serial.println("---------- booted ----------");
delay(10);
Wire.begin();
delay(50);
Wire.setClock(400000);
delay(50);
bno080_imu.begin();
delay(50);
bno080_imu.enableDebugging(Serial);
delay(50);
bno080_imu.enableAccelerometer(imu_output_period_millis);
bno080_imu.enableMagnetometer(imu_output_period_millis);
bno080_imu.enableGyro(imu_output_period_millis);
bno080_imu.enableRotationVector(imu_output_period_millis);
delay(5000);
Serial.println(F("sensor set up, start measuring"));
Serial.println(F("the first measurements may be a bit off, the filter needs time to converge"));
}
//------------------------------------------------------------------------
void loop() {
if (bno080_imu.dataAvailable() == true){
Serial.println();
Serial.print(F("ma: ")); // millis arrival
Serial.println(millis());
}
}
100 ms ie 10Hz output should be very much ok, far under what the datasheet mentions (should be possible to get down to 10ms i.e. 100 Hz on all these outputs according to Table 6-14 of the datasheet if I understand well).
However, the timing I get as output looks very confusing to me, see for example this small sample:
ma: 7324
ma: 7325
ma: 7344
ma: 7407
ma: 7409
ma: 7424
ma: 7425
ma: 7467
ma: 7506
ma: 7525
ma: 7526
ma: 7529
ma: 7592
ma: 7607
ma: 7624
ma: 7625
How should I understand that?
bno080_imu.dataAvailable() == true
per interval of 100ms most of the time; is there something I do not see / understand that is also turned on?bno080_imu.dataAvailable() == true
seem to be spread out quite evenly; how do I understand which one is which fit?Looking at the equivalent library examples but from Adafruit (though I have the Sparkfun version of it):
https://github.com/adafruit/Adafruit_BNO08x/blob/master/examples/more_reports/more_reports.ino
They do have a way to see which kind of data just arrived:
As everything should be the same from a connection / sensor point of view, I may try their library :) .
Just FYI: I have got the SF Artemis + SF BNO080 on Qwiic to work with the Adafruit library, just for playing around. For those interested, the recipe is:
My conclusions so far by looking a bit at the code and outputs:
So the best solution is still to me if you could produce an output indicating which kind of packet has been received :) . May have a look at it myself tonight.
Hi JR, If you have the time to look at this - and send us a pull request - we will be very happy to merge it. So long as it maintains backward compatibility. We try to help users and respond to their requests as quickly as we can, but we do have finite resources and it may be a long time before we are able to look at this. You are - I believe - the only person to have asked for this feature. The quickest way forward for you - for now - will be to use the Adafruit library. Best wishes, Paul
I perfectly understand limited resources :) .
Ok, I will look a bit into the code and see if I can find a simple way to get this done :) . I let you know :) .
PS: I got some help on the Adafruit library repo, it is actually possible there to set the update rate too. I have limited time for developing my device, so may rather use their library for now and come back to this later.
@PaulZC excellent news: there is a simple fix :) .
Basically the isAvailable
method is too coarse in which information it reports as discussed here (reports only that a packet has arrived, not what kind of packet), but it is just a thin wrapper around a function that does exactly what is needed: getReadings()
. See:
vs
which wraps:
which returns the code we need. Also, the comments may be slightly misleading: these functions only parse 1 packet at a time, i.e. we get fine granularity about what data has come in, which is great :) .
So the trick is just to use getReadings()
, and to check for the return code to know which data has arrived :) .
As a note, with this, my SF-code and quaternion-based recipe here: https://github.com/jerabaul29/Artemis_MbedOS_recipes/blob/main/recipes/recipe_IMU_quaternions/recipe_IMU_quaternions.ino seems to now work fine:
received data at ms: 190959 | type: gyro
received data at ms: 190961 | type: quat
received data at ms: 190963 | type: mag
received data at ms: 191072 | type: accel
millis start analysis: 191131
accel: -1.0859, 0.3008, 9.8594, pres: U | gyro: -0.0020, -0.0078, 0.0000, pres: U | mag: 11.1250, -12.8125, -26.5000, pres: M | quat: -0.0494, 0.0298, 0.9550, 0.2910, pres: H, 0.2175
quat: scal = 0.29 | vect = [ -0.05, 0.03, 0.95 ]
quat norm: 1.00
accel IMU frame of ref norm: 9.92
accel ENU frame of ref norm: 9.92
accel ENU: vect = [ -0.03, -0.00, 9.92 ]
IMU X-dir in ENU frame: vect = [ -0.83, 0.55, -0.11 ]
millis end: 191137 | analysis + print duration: 6
Truly in a hurry now, but when I am back from the ice (middle of March) we should discuss:
So feel free to either close, or keep open as a reminder that we may consider some addition to the examples and providing a few extra functionalities (maybe as an example too?).
Hi JR, This is good stuff - thank you. I'm very happy to leave this open until you have time to work on pull request. All the best, Paul
Hi JR, I think this issue has gone stale? Please do send us a separate Pull Request if you have the time. Best wishes, Paul
Yes, sorry, too much to do at work lately. It is on my todo list, but not sure when I will have time to fix it.
@PaulZC no pull request yet but what I have had time to do finally this WE is to clean a bit of my quaternion code and try to make it available as a standalone header-library that should be easy to use from Arduino. See: https://github.com/jerabaul29/kiss_clang_3d_utils . Given this library it should be a single function call to take care of the change of coordinates. I will try to find time for that next WE ^^ :) .
Thanks JR - best wishes, Paul
I end up in situations where I need to query several streams of information at the same time. For example, both quaternion orientation and acceleration, to get acceleration in an absolute (East North Up) frame of reference, see some of the other discussions I have had today (in particular #65 ).
For this, I need to enable several streams, something like:
However, I meet problems when using the way of checking for incoming data presented in the examples:
Indeed:
it looks like I get an
bno080_imu.dataAvailable() == true
each time an individual stream packet has arrived. So for example, if I ask for both quaternion and acceleration once per second,dataAvailable()
actually gets true twice per second (when each of the packets arrives).this also means that I can have some data corruption quite easily: if I just received an accelerometer packet, and I query all my data, both acceleration and quaternion (since I do not know what has just arrived), and if the quaternion packet is arriving just when the data is being queried, it looks like I can get a corrupt quaternion reading. I noticed this because these orientation quaternions must have norm unity, and they have most of the time, but now and then, when querying several streams of data, I get a quaternion that is non unitary. This never happens if I only query the quaternion stream alone.
So my questions are:
is there a high-level API solution on your BNO class for solving this problem for me? That would look like the class would need to "know" the list of packets that are expected, and provide (an additional?) API call
allDataAvailable()
or something like this to let me know that I can query all at once.another (possibly simpler for you to implement) solution may be that you provide a way of knowing "which kind of data" has just been received, so that I can query only acceleration if this is what has just been received, and wait for querying quaternion as it may be currently being updated.
I think it would be logical if this kind of logics belongs to your class. Of course I can as a user find some hacky workarounds, but I think that this is not a very good idea - better to have a clean solution provided by your class.