MPU-9250 Teensy Library

To what extent does the accuracy of calibrateAccel depend on how well/accurately I position the IMU relative to the true vertical, and for each of the 6 axis positions? This strikes me as the achilles heel, but maybe your routine is smarter than I realise.
 
Hi Brian, of course I noticed the terminal messages. A couple of times telling me "switch". I coded a calibration routine for the 9250 as well - quite dumb with instructions how to position the sensor. I suspected in your calibration must be some magic that does the calibration without positioning the sensor. Have the impression just switching the light on and off does the trick. (please don't take my comment too serious).

By the way - why six times ? x-axis positive/negative etc ? I did three measurements - one for each axis, positive or negative did not matter.

You won't be able to estimate both a bias and a scale factor unless you do both the positive and negative direction for each axis; you would only be able to estimate one of those by either attributing all error as a bias or all error as a scale factor. By adding the extra information through doing both directions for each axis, you're able to use the higher order error model.
 
To what extent does the accuracy of calibrateAccel depend on how well/accurately I position the IMU relative to the true vertical, and for each of the 6 axis positions? This strikes me as the achilles heel, but maybe your routine is smarter than I realise.

My code isn't that smart. Eventually, I'd like to do something like a gauss newton sphere fitting model, but I was running into other error sources for that, so for now I'm just using the min and max values measured in each axis. So error in orientation during calibration leads to error in the output value.

If we consider vertical to 0, the error in terms of m/s/s would then be:
Code:
9.807*sin(angle, rad)

The bias in each axis is estimated as:
Code:
(min + max) / 2

And the scale factor in each axis is estimated as:
Code:
9.807/((abs(min) + abs(max)) / 2)
 
Last edited:
Hi Brian,

Eventually, I'd like to do something like a gauss newton sphere fitting model, but I was running into other error sources for that, so for now I'm just using the min and max values measured in each axis.

I have a windows app that was converted from python that does exactly what you want. It is essentially Fabio Versano wrote for his FreeIMU. Had to make a couple of minor modifications though. If you want it is posted at: https://github.com/mjs513/FreeIMU-Updates/tree/master/FreeIMU_GUI, sources and exe version. There is an option to save to eeprom - never tried it though.

Mike
 
mjs513 / brtaylor:
To get my onehorse bottom mounted i2c MPU9250 to work on T_3.6 it uses Wire and works with: MPU9250 IMU(Wire,0x69, 47, 48); // Set scl=47 and sda=48 { he just restocked these so they are in production }

I edited the MPU9250 to allow this : MPU9250(TwoWire &bus,uint8_t address,uint8_t sclPin=255,uint8_t sdaPin=255);

Since that works on Wire with setSCl and setSDA I have working changes and was going to offer a pull request.

Then I saw the mjs513 fork that changes to i2c_t3 for Teensy - this likely would be better in long run.

Brian - do you anticipate altering your 'master' branch one way or another - or should I fork mjs513?

I've got the GPS PPS on interrupt giving cycle counter resolution for TIME_STAMP for GPS Serial start bit and was going to do the same for the MPU9250 i2c interrupt - now that I found my T_3.6 with the 9250 soldered on.

As long as (typically unused) cycle counter is not zeroed elsewhere - it is perhaps 99.8% in +/- 13 cpu ticks (in 55 hr run) - and the math/return is over 6X faster than micros
 
@degragster:
My 9250 fork/pull request was actually against Brian's old MPU9250 library that used the i2c_t3 library. He recently changed to use just wire/spi so the library could be used on other boards besides the teensies. The library has also changed a bit since the original implementation so my fork has actually been obe'd. So don't fork my version, its not the latest version. Probably should have closed it. Think you might be using an older version of the 9250 library if it is still using i2c_t3?

PS. I've been using Onehorse's MPU-9250 breakout board exclusively for these tests. Great little board.
 
mjs513 / brtaylor:
To get my onehorse bottom mounted i2c MPU9250 to work on T_3.6 it uses Wire and works with: MPU9250 IMU(Wire,0x69, 47, 48); // Set scl=47 and sda=48 { he just restocked these so they are in production }

I edited the MPU9250 to allow this : MPU9250(TwoWire &bus,uint8_t address,uint8_t sclPin=255,uint8_t sdaPin=255);

Since that works on Wire with setSCl and setSDA I have working changes and was going to offer a pull request.

Then I saw the mjs513 fork that changes to i2c_t3 for Teensy - this likely would be better in long run.

Brian - do you anticipate altering your 'master' branch one way or another - or should I fork mjs513?

I've got the GPS PPS on interrupt giving cycle counter resolution for TIME_STAMP for GPS Serial start bit and was going to do the same for the MPU9250 i2c interrupt - now that I found my T_3.6 with the 9250 soldered on.

As long as (typically unused) cycle counter is not zeroed elsewhere - it is perhaps 99.8% in +/- 13 cpu ticks (in 55 hr run) - and the math/return is over 6X faster than micros

You should be able to use the following with the most current version of the MPU-9250 library:

https://github.com/bolderflight/MPU9250

Code:
MPU9250 IMU(Wire,0x68);

void setup() {
  Wire.setSCL(47);
  Wire.setSDA(48);
  IMU.begin();
}

As Mike pointed out, I switched from i2c_t3 to Wire a few months ago to enable the library to be used on other Arduino devices. Thankfully, for Teensy LC and 3.x, the Wire.setSCL and Wire.setSDA functionality is still present.

Brian
 
Indeed as shown in setup() - "Wire.setSCL(47); and Wire.setSDA(48);" - works since the pins are native to Wire.

I went in expecting to add i2c_t3 to get underpins - when I was looking in WIRE source and reminded of the setSDA/SCL - so put that into class .begin as suggested above. Then gIthUb stole some life from me as I wandered around seeing and not seeing i2c_t3 between old branch and Mike's fork - and indeed I saw that was an old fork.
 
H Brian,
First, thanks for your excellent library...

I'm finalizing a wireless system ( teensy 3.6 / esp8266 combo ) for medical study (ergonomics / fatigue) that has besides a 9250 a whole bunch of other sensors. Currently I'm looking into methods to prevent magnetic jamming.
( quite a bit of devices with magnets around :rolleyes: )

Got some questions.
Do you have any plans to incorporate a magnetic anti jamming filter?
> mjs513 suggested a UKF filter > relevant thread here: https://forum.pjrc.com/threads/33902-Prop-Shield-NXPSensorFusion-observations

more reading : Accurate Orientation Estimation Using AHRS under Conditions of Magnetic Distortion / Unscented Kalman Filter and Magnetic Angular Rate Update (MARU) for an Improved Pedestrian Dead-Reckoning
> macaba has a working anti jamming filter > forked from Paul's MadgwickAHRS > https://github.com/macaba/MadgwickAHRS

I've made a couple of modifications to your library, that allows it to
A.) compile it for an esp8266
B.) disable SPI dependencies entirely, > I'm using SPI slave mode on the teensy...
What I'm actually doing is, using a bunch of esp8266's to gather data send it to another esp8266 that offloads it to a teensy over SPI for number crunching.

Forking your library will just add Yet Another 9250 lib tm , become obsolete etc... while it's really just a couple of defines, maybe you can commit them yourself, I'll contact you on github for that...

Thanks
 
H Brian,
First, thanks for your excellent library...

I'm finalizing a wireless system ( teensy 3.6 / esp8266 combo ) for medical study (ergonomics / fatigue) that has besides a 9250 a whole bunch of other sensors. Currently I'm looking into methods to prevent magnetic jamming.
( quite a bit of devices with magnets around :rolleyes: )

Got some questions.
Do you have any plans to incorporate a magnetic anti jamming filter?
> mjs513 suggested a UKF filter > relevant thread here: https://forum.pjrc.com/threads/33902-Prop-Shield-NXPSensorFusion-observations

more reading : Accurate Orientation Estimation Using AHRS under Conditions of Magnetic Distortion / Unscented Kalman Filter and Magnetic Angular Rate Update (MARU) for an Improved Pedestrian Dead-Reckoning
> macaba has a working anti jamming filter > forked from Paul's MadgwickAHRS > https://github.com/macaba/MadgwickAHRS

I've made a couple of modifications to your library, that allows it to
A.) compile it for an esp8266
B.) disable SPI dependencies entirely, > I'm using SPI slave mode on the teensy...
What I'm actually doing is, using a bunch of esp8266's to gather data send it to another esp8266 that offloads it to a teensy over SPI for number crunching.

Forking your library will just add Yet Another 9250 lib tm , become obsolete etc... while it's really just a couple of defines, maybe you can commit them yourself, I'll contact you on github for that...

Thanks

WRT the anti-jamming filter. Yes, eventually. My plan is to incorporate things like anti-jamming and real-time gyro bias estimation into a set of "compensated" outputs, while still leaving uncompensated outputs available. No guarantees on a time frame though.

For your library modifications, please, I'd love to see them. With me opening up the library to Arduino devices other than Teensy, I'm seeing a lot of the little differences and non-standard things that different boards are doing. The more fixes I can incorporate for these different boards, the better it is for everyone.
 
...........With me opening up the library to Arduino devices other than Teensy, I'm seeing a lot of the little differences and non-standard things that different boards are doing. The more fixes I can incorporate for these different boards, the better it is for everyone......

exactly....
Give me a couple of days to review your latest commits > got some test subjects over ... hence no coding for me today.

WRT = ?
 
Question: T_3.6 Compiled beyond 'FAST' my i2c MPU9250 only works (fails init) at 240 MHz when I hacked the core F_BUS from 60 to 120 MHZ (noted here). Is anyone else running at 240 MHz with i2c MPU?

It may be my onehorse unit - or it's use of ALT i2c pins. I can see perhaps SPI in any case would not be affected the same.

[and that I've been using 240 MHz no issues since T_3.6 beta, and often changing to F_BUS 120 with good effect]
 
Question: T_3.6 Compiled beyond 'FAST' my i2c MPU9250 only works (fails init) at 240 MHz when I hacked the core F_BUS from 60 to 120 MHZ (noted here). Is anyone else running at 240 MHz with i2c MPU?

It may be my onehorse unit - or it's use of ALT i2c pins. I can see perhaps SPI in any case would not be affected the same.

[and that I've been using 240 MHz no issues since T_3.6 beta, and often changing to F_BUS 120 with good effect]

Had no problems at 400mhz. If I remember well it even worked at 800mhz.
 
Question: T_3.6 Compiled beyond 'FAST' my i2c MPU9250 only works (fails init) at 240 MHz when I hacked the core F_BUS from 60 to 120 MHZ (noted here). Is anyone else running at 240 MHz with i2c MPU?

It may be my onehorse unit - or it's use of ALT i2c pins. I can see perhaps SPI in any case would not be affected the same.

[and that I've been using 240 MHz no issues since T_3.6 beta, and often changing to F_BUS 120 with good effect]

Whoa, I can reproduce that issue with the emsensor breakout board and the default I2C Wire pins (18 and 19). Like you said, works great except for:
CPU speed set to 240 MHz
default F_BUS (60 MHz)
optimization of faster or faster with LTO

I'm getting a return code of -5, which means it's failing the WHOAMI check.
 
Whoa, I can reproduce that issue with the emsensor breakout board and the default I2C Wire pins (18 and 19). Like you said, works great except for:
CPU speed set to 240 MHz
default F_BUS (60 MHz)
optimization of faster or faster with LTO

I'm getting a return code of -5, which means it's failing the WHOAMI check.

That is what I was seeing! Changed the F_BUS in core file noted in the linked Post and no problem.

ALSO: bumped up to 1,000,000 on i2c and it is running fine - assuming the speed change took as I did it.
Code:
#define IMU_SPD 1000000
  status = Imu.begin();
  if ( 0 != IMU_SPD ) Wire.setClock(IMU_SPD);
 
Weird, I just tried this with i2c_t3 instead of the standard Wire library and, no issues.

Good to know. We'd have to write a short test to WHO_AM_I that can run on either Wire or i2c_t3 and post for Paul to resolve. I suppose you are using default pins, not an ALT like me? May be something off in the pin config in Wire?
 
Good to know. We'd have to write a short test to WHO_AM_I that can run on either Wire or i2c_t3 and post for Paul to resolve. I suppose you are using default pins, not an ALT like me? May be something off in the pin config in Wire?

Yes, I’m using default pins. If I comment the WHOAMI check, it’ll fail later. Almost like the clock is being set incorrectly. You’re right, need to setup a simple example for Paul.
 
Was doing a little digging into TWI. Think the problem is how i2c_t3 sets the rate versus wire/twi.c and the associated divisor. i2c_t3 looks like it explicitly allows you to change the bus freq and i2c frequency and then does the correct calculations for divisor etc. Check out the code for setClock in wire vs setRate in i2c_t3.
 
There was an oddity though - it depends on Compile Optimization FAST but NOT FASTEST. I'd expect that to be F_BUS math agnostic.

It works compiled FAST but not FASTEST at default F_BUS=60M. Setting kinetis.h F_BUS=120M it then works compiled FASTEST.

I made a sample - but it requires an i2c and Brian's MPU9250 library. That is tied to Wire, would take hacking to compare with i2c_t3.

I made #defines for Address and in case not on primary i2c pins. I put the setClock() to test - but that did not make it work after or then before the IMU.begin().

Here is the simple sketch and then it's output:
Code:
#include "MPU9250.h"

#define IMU_ADDR 0x69 // 0x68
#define IMU_SCL 0 // 47 // 0x255 to use default
#define IMU_SDA 0 // 48 // 0x255 to use default
#define IMU_SPD 0 // 1000000 // 0==NULL or other

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address IMU_ADDR
MPU9250 IMU(Wire, IMU_ADDR);
int status;

void setup() {
  Serial.begin(115200);
  while (!Serial) {}
  Serial.println("\n"__FILE__" "__DATE__" "__TIME__);
  Serial.print("F_CPU >> ");
  Serial.print(F_CPU);
  Serial.print("    F_BUS >> ");
  Serial.println(F_BUS);

  // start communication with IMU
  if ( 255 != IMU_SCL ) Wire.setSCL(IMU_SCL);
  if ( 255 != IMU_SDA ) Wire.setSDA(IMU_SDA);
  status = IMU.begin();
  if ( 0 != IMU_SPD ) {
    Wire.setClock(IMU_SPD);
    Serial.print("Wire Speed setClock  ");
    Serial.println(IMU_SPD);
  } else   Serial.println("Default Wire Speed");
  if (status < 0) {
    Serial.println("IMU initialization unsuccessful");
    Serial.println("Check IMU wiring or try cycling power");
    Serial.print("Status: ");
    Serial.println(status);
    while (1) {}
  }
}

void loop() {
  IMU.readSensor();
  Serial.print("TEMP == ");
  Serial.println(IMU.getTemperature_C(), 6);
  Serial.println("\n IT WORKED !!");
  delay(100);
  while (1) {}
}

Note: Status -5 is failure to get expected 'Who Am I' return value, that is after multiple other writes.
Note: I also got some Status -1 that is the first write after port setup: "// select clock source to gyro " after: _i2c->begin(); and _i2c->setClock(_i2cRate);

>>> COMPILED FAST
T:\tCode\Temp\T_i2c_Fail\T_i2c_Fail.ino Jan 25 2018 23:32:56
F_CPU >> 240000000 F_BUS >> 60000000
Default Wire Speed
TEMP == 35.266033

IT WORKED !!

>>> COMPILED FASTEST
T:\tCode\Temp\T_i2c_Fail\T_i2c_Fail.ino Jan 25 2018 23:34:54
F_CPU >> 240000000 F_BUS >> 60000000
Default Wire Speed
IMU initialization unsuccessful
Check IMU wiring or try cycling power
Status: -5

>>> COMPILED FASTEST
T:\tCode\Temp\T_i2c_Fail\T_i2c_Fail.ino Jan 25 2018 23:37:20
F_CPU >> 240000000 F_BUS >> 120000000
Default Wire Speed
TEMP == 34.888641

IT WORKED !!
 
Hi Brian

Know your busy but wanted to keep working on the uNAVAhrs code anyway. In post https://forum.pjrc.com/threads/48450-uNav-AHRS?p=169573&viewfull=1#post169573 in the other thread (uNAV INS). In going through the MotionDriver API for the MPU9250 I saw three functions of interest that actually relates to what I am seeing:

1. inv_enable_fast_nomot() - recal gyro at a specified frequency when zero motion is detected.
2. inv_enable_gyro_tc() - recal gyro on temperature change, and
3. inv_check_magnetic_disturbance() - pretty obvious.

For 1 and 2 I implemented something crude and put it into the example code I am working with and yaw drift seemed to have stabilized. Now for about 3-4 hours yaw varies about _/- 0.2 degrees (just eyeballed). I have to do the analysis on the data I dumped and will post later. I do have a mag disturbance routine and guess if it is detected just don't do a mag update. Right now I have it set to true (if not updated it just uses the previous values). This is on my to do list. But for the MPU-9250 we code we should do 1 and 2. 3 for uNavAHRS code.

There is another routine they have for periodically doing the accel but I have to think the best way to implement since they don't really say anything about the algorithm.

Mike

EDIT: Ok. Here is a simple chart. When the temp drops its when I opened the window so that the cold air is hitting it.
 

Attachments

  • gyroCorrection.png
    gyroCorrection.png
    7.4 KB · Views: 113
Last edited:
Brian.
Been playing with both the MPU9250 library and the uNavAHRS code. Kinda of gave up on the item 2 in the above list but been working on the 1st item, real-time gyro cal updates. It seems to be working but.. right now to collect the 15 points I use takes too much time (150ms) per update (400ms at an SRD of 4). Possible to use a MA so as we read the data we get the average of the past points - don't know still thinking about that one. Here is the test run. By the way at 28.6degrees I turn off the gyro updates. I did add a motion/nomotion function that works. Also, only updates gyro when there is no motion :)

Run444.jpg
 
Brian,

First off thanks for your effort, got the lib to work with Teensy 3.2 on SPI with little effort. Since I am new to the AHRS field, I had some questions:

1. Orientation, specifically the Accelerometer. I saw some of your example where the calibrateAccel() function was called 6 times with 5 second delays
in between each call, where you then output "Switch". I'll assume each call was for an bias and scale factor on each axis. However I am a bit confused
by physically what to do with the 9250, mine being breadboarded temporarily. I see section 9.1 of the InvenSense Product Spec how the axis are oriented
with respect to the chip (little dot in corner). Do I do +x, then -x, +y then -y... that is somewhat confusing.

2. Once we get the 9250 calibrated, I'll assume the scale and bias factors (x,y,z) can then be applied to the raw data from the sensor? Can you provide an example of such
an operation?

Thanks!
 
Back
Top