SJ cartoon avatar

Embedded Invensense IMUs - What to Know

I’ve previously written about the MPU6050 here, and I have worked with a few of the Invensense offerings over the past while. The Invensense documentation is pretty good, however I’ve found and reported several errata to Invensense over the past couple of years. Some of the fixes have made it into their new SDK - others have not yet. I thought it might be handy to go over some of these errata I ran into, in case other people are struggling with them too like I did.

MPU6000, MPU6050, MPU6500, MPU6055, etc…

There are a lot of different products Invensense has for sale, and I ran into a lot of problems understanding the differences, as from the non-marketing material (e.g. datasheets), they’re very similar devices. At a high-level, the 6000 and 6050 are the same chip - with different communication protocols (SPI/I2C vs I2C). The MPU6055 (or MPU9255) is the one designed for use alongside the Automatic Activity Recognition (AAR) library. But what about the 6050 and 6500? Or the 9150 and 9250?

I emailed support at Invensense and received this response.

My email

I’m very familiar with the MPU6050, but I see the MPU6500 - and it appears to have the same cost as the 6050, and a smaller footprint. Is there anything else different about these two? We spoke a while ago, and I recall you said the 6500 had worse sensitivity. Will the code I wrote for a 6050 be directly portable to the 6500? Is this just a v2 of the 6050?

Similar question with the 9150 and 9250. Prices are same, form factors are different. Is there any appreciable difference in the chip outputs?"

Invensense reply

The MPU-6050 is higher power, lower noise, and larger package versus the MPU-6500. Most of your code should port over, but some low power features are different and will need to be recoded in. Basic data acquisitions shouldn’t have changed.

The MPU-9150 contains the MPU-6050 and an AK8975 magnetometer from AKM. The MPU-9250 contains a MPU-6500 and AK8963. The same differences between gyro/accel are the same you see with 6050 v. 6500. The magnetometer on the MPU-9250 is a little better across the board.

For the remainder of this post, I’ll focus on my experiences with the 6-axis series, but some of the same issues were/are likely in the 9-axis series as well.

Keep up to date

I can’t stress this one enough. Invensense support is really good at staying in communication while they are looking over issues, and I would usually have my answers or a workaround within a week. However, there are some bugs that require lower-level changes, and they get rolled into the new SDKs. So, as much as it sucks to upgrade SDKs and have to deal with the re-tests, odds are you’re getting more than you’re losing.

A perfect example is the Calibration issue that I’ll dig into in an email below. It’s a pretty critical bug that was fixed between MotionDriver 5.1.1 and 5.1.2… However, there were two small multiplier issues which weren’t corrected in that revision, so it’s not quite perfect.

Sensitivity problems

As I was using the IMU in a device that required a bit more precision than most, I spent a lot of time digging into the code whenever I found anomalies. A lot of these anomalies were discovered around calibration. Here is one that is STILL in the latest version of the MotionDriver SDK (5.1.2 at time of writing):

int mpu_get_accel_sens(unsigned short *sens)
...
  case INV_FSR_4G:
    sens[0] = 8092;
    break;
...

I verified this with their support, and that value should actually return 8192 to stay in line with the rest of the SDK, as below:

int mpu_get_accel_sens(unsigned short *sens)
...
  case INV_FSR_4G:
    sens[0] = 8192;
    break;
...

This only adds slightly more than 1% of error to a system, but when you’re directly comparing with external references, that 1% goes a surprisingly long way!

Calibration problems

Bar none, the biggest source of grief (frankly, almost the only source of grief) with the IMU was around calibration. Again, given that I was comparing with an external reference, the calibration had to be as close as possible and I spent a LOT of time tweaking to get this running. As it turned out, in a previous version of the MotionDriver, calibration was only applied to the fused output quaternion and had NO effect on the returned discrete accelerometer values!

This proved to be the source of about 5-10% error in my system, and all-around a sloppy mistake…

Here was my code, basically copied from the Invensense sample code:

long gyrBias[3];
long accBias[3];
int result;

result = mpu_run_self_test(gyrBias, accBias);

// Check for passing accelerometer
if ((result & 0x02) == 0x02)
{
  unsigned short accel_sens = 0;

  mpu_get_accel_sens(&accel_sens);
  accBias[0] *= accel_sens;
  accBias[1] *= accel_sens;
  accBias[2] *= accel_sens;

  dmp_set_accel_bias(accBias);
}

The problem was, this still returned steady-state accelerometer values that were way off (as though they’d never been calibrated). I verified with Invensense that this was, in fact, a bug.

It was fixed and detailed in an app note for MotionDriver 5.1.2, however there was still a bug with the multiplier they recommended to use. They recommended that we use 4096 as the base multiplier when we pass in sensitivities, however I noticed that when I calibrated multiple times in a row, my calibration numbers would diverge.

Instead, again talking to support, we figured out that the scale factor required for each product may be different. For the 6050 and 9150, the scale factor was 2048, but for the 9250, it was 4096.

I haven’t seen this reflected in documentation yet, but I haven’t really looked lately either. In any case, what I have below is what actually works for calibration. I had the MPU setup as +/-4g, and ended up not even using the mpu_get_accel_sens call. Please note that you’ll need to cache the calibration values and send them back to the MPU after every reset, as the MPU only has volatile memory.

long gyrBias[3];
long accBias[3];
int result;
int i;

result = mpu_run_self_test(gyrBias, accBias);

// Check for passing accelerometer
if ((result & 0x02) == 0x02)
{
  for (i=0; i<3; ++i) {
    // The accBias values are stored in +/-8g format
    accBias[i] *= 2048;
    accBias[i] = accBias[i] >> 16;
  }

  // Cache these bias values, as they're not persisted to MPU memory
  // Update the MPU bias registers (needs to be done on every reset)
  mpu_set_accel_bias_6050_reg(accBias);
}

Anything else?

Those were the main issues I have run into so far. If anyone else has come across something new, please let me know!

Feature Photo credit: SparkFunElectronics / Foter / CC BY