sparkfun / SparkFun_MPU-9250-DMP_Arduino_Library

Arduino library for the MPU-9250 enabling its digital motion process (DMP) features.
Other
227 stars 152 forks source link

Timing #19

Closed DomFo closed 5 years ago

DomFo commented 6 years ago

Hi and thank you for this very handy library!

I'm currently getting into the basic example and I noticed that the timestamp (imu.time) it prints out isn't quite consistent. Despite a sample rate (imu.setSampleRate) of 10Hz the timestamp indicates a sample interval of 99ms instead of 100ms every 6 or 7 samples.

Is there a way to get very accurate measurements timewise? So that even if there's a delay in one update, the next will be in time again?

Thank you,

Regards Dom

oclyke commented 6 years ago

Hi @DomFo, as I was getting familiar with the library I learned some things that could help you find a solution. If you can tell me about your desired application (for example why you need precise timing) that would also be helpful. In the mean time here is my take on what you're seeing:

In the basic example we set the sensor's update rate to 10 Hz with the lines imu.setSampleRate(10); and imu.setCompassSampleRate(10);. Inside the sensor we have updated some registers that store information about the period between samples - in terms of a number of internal clock cycles. These internal clock cycles have a number of possible sources within the MPU9250 but what is important to know is that it is not the same clock source as the microcontroller you are using.

The next thing to consider is that the advanced DMP library that was provided by InvenSense required a couple of user-provided functions in order to work. These included

delay_ms(unsigned long num_ms);
get_ms(unsigned long *count);

which we chose to implement using the Arduino functions 'delay()' and 'millis' - you can see how we did that in the files src\util\arduino_mpu9250_clk.h and src\util\arduino_mpu9250_clk.c. millis() is used when we call imu.update() to update the value imu.time.

The last key is to know that the main loop of the basic example sketch operates by polling the 'dataReady' indicator within the MPU9250. So as soon as the MPU9250 says that new data is ready (shortly after taking a sample reading) the example sketch will print the latest values to the screen.

So those three facts stack up to produce the discrepancy that you see: The microcontroller you use and the MPU9250 may slightly disagree about exactly how long one ms is. Lets call the amount of time that the MPU thinks is 1 ms a 'MPUms' and a 'uCms' will be how long the microcontroller thinks is 1 ms... We've told the MPU9250 to wait 100 MPUms between each reading. Now at every reading we are asking the uC how many uCms have happened. Because MPUms =/= uCms then we are not guaranteed that the time difference will be 100 uCms.

Now as for a solution: This is where your application comes into play. As is noted in the datasheet:

Clock accuracy is important, since timing errors directly affect the distance and angle calculations performed by the Digital Motion Processor (and by extension, by any processor).

So if you are, for example, integrating the rates provided by the sensor then of course you will try to be as accurate as possible.

A simplistic solution is based on you trusting that one of the two timing sources is really accurate - in this case the microcontroller. Then I would set the update rate of the MPU9250 to some value that is, say, double or triple the actual rate you need (see nyquist sampling) and then calling imu.update() at a rate that is determined only by your microcontroller. Using a delay would work, but you'd have to tailor the delay to compensate for the time that other operations in your loop take. This is really hard to maintain. A better way to get a fixed output rate is to use an interrupt. Off hand I don't know what kinds of solutions are available for the SAMD21, or most uCs, but a great example is the intervalTimer that is included in the core for the Teensy development boards. Maybe you can find something similar to help in your case.

I hope that was helpful, and please feel free to keep up the commentary!