IMU MPU-6050 help

Hello all!!

I am trying to measure acceleration by using GY-521 MPU6050 module.
I am following this tutorial: MPU6050 Interfacing With Arduino UNO | Arduino

This is the code I am using (this one comes as an example and is copied from the link above):

/*
    MPU6050 Triple Axis Gyroscope & Accelerometer. Simple Accelerometer Example.
    Read more: http://www.jarzebski.pl/arduino/czujniki-i-sensory/3-osiowy-zyroskop-i-akcelerometr-mpu6050.html
    GIT: https://github.com/jarzebski/Arduino-MPU6050
    Web: http://www.jarzebski.pl
    (c) 2014 by Korneliusz Jarzebski
*/

#include <Wire.h>
#include <MPU6050.h>

MPU6050 mpu;

void setup() 
{
  Serial.begin(115200);

  Serial.println("Initialize MPU6050");

  while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G))
  {
    Serial.println("Could not find a valid MPU6050 sensor, check wiring!");
    delay(500);
  }

  // If you want, you can set accelerometer offsets
  // mpu.setAccelOffsetX();
  // mpu.setAccelOffsetY();
  // mpu.setAccelOffsetZ();
  
  checkSettings();
}

void checkSettings()
{
  Serial.println();
  
  Serial.print(" * Sleep Mode:            ");
  Serial.println(mpu.getSleepEnabled() ? "Enabled" : "Disabled");
  
  Serial.print(" * Clock Source:          ");
  switch(mpu.getClockSource())
  {
    case MPU6050_CLOCK_KEEP_RESET:     Serial.println("Stops the clock and keeps the timing generator in reset"); break;
    case MPU6050_CLOCK_EXTERNAL_19MHZ: Serial.println("PLL with external 19.2MHz reference"); break;
    case MPU6050_CLOCK_EXTERNAL_32KHZ: Serial.println("PLL with external 32.768kHz reference"); break;
    case MPU6050_CLOCK_PLL_ZGYRO:      Serial.println("PLL with Z axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_YGYRO:      Serial.println("PLL with Y axis gyroscope reference"); break;
    case MPU6050_CLOCK_PLL_XGYRO:      Serial.println("PLL with X axis gyroscope reference"); break;
    case MPU6050_CLOCK_INTERNAL_8MHZ:  Serial.println("Internal 8MHz oscillator"); break;
  }
  
  Serial.print(" * Accelerometer:         ");
  switch(mpu.getRange())
  {
    case MPU6050_RANGE_16G:            Serial.println("+/- 16 g"); break;
    case MPU6050_RANGE_8G:             Serial.println("+/- 8 g"); break;
    case MPU6050_RANGE_4G:             Serial.println("+/- 4 g"); break;
    case MPU6050_RANGE_2G:             Serial.println("+/- 2 g"); break;
  }  

  Serial.print(" * Accelerometer offsets: ");
  Serial.print(mpu.getAccelOffsetX());
  Serial.print(" / ");
  Serial.print(mpu.getAccelOffsetY());
  Serial.print(" / ");
  Serial.println(mpu.getAccelOffsetZ());
  
  Serial.println();
}

void loop()
{
  Vector rawAccel = mpu.readRawAccel();
  Vector normAccel = mpu.readNormalizeAccel();

  Serial.print(" Xraw = ");
  Serial.print(rawAccel.XAxis);
  Serial.print(" Yraw = ");
  Serial.print(rawAccel.YAxis);
  Serial.print(" Zraw = ");

  Serial.println(rawAccel.ZAxis);
  Serial.print(" Xnorm = ");
  Serial.print(normAccel.XAxis);
  Serial.print(" Ynorm = ");
  Serial.print(normAccel.YAxis);
  Serial.print(" Znorm = ");
  Serial.println(normAccel.ZAxis);
  
  delay(10);
}

As the tutorial asks, I have downloaded the following github repo:https://github.com/jarzebski/Arduino-MPU6050

This is what I am getting on serial monitor (and here lies the problem):

Initialize MPU6050

 * Sleep Mode:            Disabled
 * Clock Source:          PLL with X axis gyroscope reference
 * Accelerometer:         +/- 2 g
 * Accelerometer offsets: -1086 / -4129 / 1966

 Xraw = 816.00 Yraw = 572.00 Zraw = 20172.00
 Xnorm = 0.53 Ynorm = 0.34 Znorm = 12.11
 Xraw = 784.00 Yraw = 612.00 Zraw = 20352.00
 Xnorm = 0.45 Ynorm = 0.39 Znorm = 12.11
 Xraw = 904.00 Yraw = 668.00 Zraw = 20176.00
 Xnorm = 0.54 Ynorm = 0.40 Znorm = 12.07
 Xraw = 768.00 Yraw = 540.00 Zraw = 20088.00
 Xnorm = 0.50 Ynorm = 0.33 Znorm = 11.99
 Xraw = 860.00 Yraw = 600.00 Zraw = 20188.00
 Xnorm = 0.53 Ynorm = 0.34 Znorm = 12.09
 Xraw = 824.00 Yraw = 632.00 Zraw = 20312.00
 Xnorm = 0.51 Ynorm = 0.35 Znorm = 12.09
 Xraw = 764.00 Yraw = 584.00 Zraw = 20208.00
 Xnorm = 0.49 Ynorm = 0.40 Znorm = 12.08
 Xraw = 844.00 Yraw = 640.00 Zraw = 20136.00
 Xnorm = 0.47 Ynorm = 0.40 Znorm = 12.03
 Xraw = 852.00 Yraw = 564.00 Zraw = 20128.00
 Xnorm = 0.51 Ynorm = 0.36 Znorm = 12.06
 Xraw = 804.00 Yraw = 640.00 Zraw = 20096.00
 Xnorm = 0.48 Ynorm = 0.42 Znorm = 12.08

The module is lying flat on a breadboard.

Isnt Znorm way out of track? For flat module it should be 1g? Also all readings must be between +/-2g.

Please help. Thanks!

Have you analyzed the code to determine what Xnorm, Ynorm and Znorm are supposed to represent? If not, that would be a great place to start.

The data sheet is also an excellent source of information.

How did you come up with these particular offset values?

* Accelerometer offsets: -1086 / -4129 / 1966

jremington:
Have you analyzed the code to determine what Xnorm, Ynorm and Znorm are supposed to represent? If not, that would be a great place to start.

Yes, I have and I cant understand it to be frank:

 Vector MPU6050::readNormalizeAccel(void)
{
    readRawAccel();

    na.XAxis = ra.XAxis * rangePerDigit * 9.80665f;
    na.YAxis = ra.YAxis * rangePerDigit * 9.80665f;
    na.ZAxis = ra.ZAxis * rangePerDigit * 9.80665f;

    return na;
}

Where rangePerDigit is determined as follows:

void MPU6050::setRange(mpu6050_range_t range)
{
    uint8_t value;

    switch (range)
    {
	case MPU6050_RANGE_2G:
	    rangePerDigit = .000061f;
	    break;
	case MPU6050_RANGE_4G:
	    rangePerDigit = .000122f;
	    break;
	case MPU6050_RANGE_8G:
	    rangePerDigit = .000244f;
	    break;
	case MPU6050_RANGE_16G:
	    rangePerDigit = .0004882f;
	    break;
	default:
	    break;
    }

    value = readRegister8(MPU6050_REG_ACCEL_CONFIG);
    value &= 0b11100111;
    value |= (range << 3);
    writeRegister8(MPU6050_REG_ACCEL_CONFIG, value);
}

This whole information is taken from MPU6050.cpp (the downloaded library from the github link above).
I know that when setting range at +/-2g, one needs to divide the raw value by 16384 to get the normalized value. I cant understand the author’s reasoning behind this logic. Perhaps this is wrong?

I cant understand the author's reasoning behind this logic. Perhaps this is wrong?

Evidently.

Why trust code that you don't understand and gives what appears to be the wrong answer?

When an accelerometer is motionless, with any axis in the vertical direction, the acceleration along that axis is +/- 1 g, by definition.

You can use that fact to calibrate an accelerometer properly, similar to the procedure described here: Programming and Calibration | ADXL345 Digital Accelerometer | Adafruit Learning System.

I was following the tutorial. That tutorial also has a video and everything is working fine it. I thought that maybe I am missing something very obvious so I inquired....

Seems arduino community isnt very welcoming.....

The tutorial you linked is incomplete, simplistic and seems to ignore the problem of device calibration.

You need to determine, at minimum, the six unique offsets and scale factors for the accelerometer.

Follow the procedure outlined in the link of reply #3 and let us know how that goes. There are other tutorials as well.

For a comprehensive overview and the most sophisticated approaches on calibration, see Tutorial: How to calibrate a compass (and accelerometer) with Arduino | Underwater Arduino Data Loggers

Looks like the norm values are the values with scale factors added.

Have you done your own calibration on your own unit to get offsets?

Be aware of when you code to apply scale factors to the bias offsets.

The code, I have to do the thing with MPU6050's is written in Python, on a Raspberry Pi across the room running SETI. I do have code to calibrate a MPU9250 that you could look at, the MPU9250 and MPU60X0 are nearly the same things, the MPU9250 has a Magnetometer. If you'd like to have a look at the calibration code I use, I'd be happy to post it. Though the code is written for an ESP32, the principle remains the same.

You can use your favorite search engine to search or you can click on this link https://os.mbed.com/users/onehorse/ for some great code that works quite well for the MPU60X0.

After a day of googling, searching and tinkering, I realized the importance of calibration and other stuff. I used the sketch by Luis Rodenas: AutoAero - Auto-Calibration MPU6050

I tried to keep my module as horizontal as possible and these were my offsets:

-1011 -4102 1554 110 3 -1

(In Ax, Ay, Az, Gx, Gy, Gz format).

I then ran MPU6050_raw.ino sketch from i2cdevlib library while making necessary offset adjustments. Here is the link to the sketch: // I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class// - Pastebin.com

What I would like to know is if I am getting sane accelerometer outputs. Here are the serial monitor outputs:

a/g: -56 10 2076 16 20 -2
a/g: -41 9 2062 -2 34 6
a/g: -44 16 2043 13 23 9
a/g: -56 16 2074 15 52 -19
a/g: -36 11 2061 8 29 -17
a/g: -44 17 2056 2 90 1
a/g: -45 20 2079 27 89 -8
a/g: -49 21 2045 22 104 -26
a/g: -46 11 2032 14 121 -1
a/g: -48 8 2050 3 74 3
a/g: -41 -3 2065 9 136 -27
a/g: -49 10 2063 23 86 0
a/g: -63 13 2044 15 114 7
a/g: -46 18 2070 12 119 -21
a/g: -49 11 2072 -16 138 -7
a/g: -48 20 2062 24 151 -2
a/g: -51 1 2047 14 131 -13
a/g: -43 19 2070 12 105 12

I am getting the above output when z axis of MPU6050 is perpandicular to earth surface, with all markings on top.

a/g: 2164 6 -63 16 25 9
a/g: 2144 10 -65 33 -13 -14
a/g: 2153 16 -69 -1 48 -6
a/g: 2160 14 -64 31 6 -16
a/g: 2175 8 -79 5 -14 -23
a/g: 2170 16 -55 19 15 1
a/g: 2158 11 -53 5 51 -5
a/g: 2161 18 -75 9 7 2
a/g: 2163 12 -65 -11 32 -21
a/g: 2158 15 -53 28 19 9
a/g: 2152 11 -61 -11 9 -11
a/g: 2173 14 -64 37 13 3
a/g: 2161 34 -65 15 12 1
a/g: 2162 0 -72 10 -17 9
a/g: 2171 15 -63 17 14 -16
a/g: 2164 6 -44 -20 10 23
a/g: 2144 26 -74 18 23 11
a/g: 2160 8 -67 27 1 -19
a/g: 2156 20 -67 -16 24 -5
a/g: 2149 14 -77 5 -4 6
a/g: 2163 7 -58 23 33 -7
a/g: 2159 20 -76 0 -11 11
a/g: 2160 7 -54 15 8 -14
a/g: 2160 12 -62 10 13 11
a/g: 2149 8 -85 17 -3 -16
a/g: 2159 24 -75 5 17 -24
a/g: 2153 21 -62 7 29 0
a/g: 2184 14 -71 0 -3 -21
a/g: 2140 19 -65 30 10 5
a/g: 2169 21 -73 16 5 3
a/g: 2159 14 -83 21 -11 -11
a/g: 2150 18 -67 20 37 -6
a/g: 2161 23 -69 8 -23 -15
a/g: 2157 19 -63 0 21 1
a/g: 2154 9 -63 8 13 1
a/g: 2164 19 -56 -5 46 -6
a/g: 2156 15 -66 13 -20 -3
a/g: 2168 19 -65 28 32 -16
a/g: 2157 17 -87 -2 -4 -29
a/g: 2163 11 -59 33 0 -4
a/g: 2161 20 -56 -2 -7 -16
a/g: 2167 12 -60 8 -7 -4
a/g: 2153 27 -85 22 34 -4
a/g: 2163 21 -64 -23 -15 1
a/g: 2153 7 -62 18 19 4
a/g: 2168 14 -62 34 -8 -18
a/g: 2157 18 -79 5 -9 -17
a/g: 2160 18 -81 4 -3 -19
a/g: 2172 26 -55 14 -10 13
a/g: 2168 28 -60 14 39 -1
a/g: 2153 24 -73 -2 5 -2
a/g: 2162 19 -69 17 -9 -19
a/g: 2157 19 -63 7 7 -6
a/g: 2151 23 -75 25 -5 -3
a/g: 2170 19 -70 6 -1 0

When positive x-axis is perpendicular to earth surface.

a/g: 90 2054 106 3 -75 10
a/g: 95 2056 93 25 -97 -11
a/g: 85 2057 93 -6 -113 14
a/g: 89 2065 106 5 -107 7
a/g: 85 2058 92 -17 -109 -19
a/g: 86 2050 89 -34 -91 -5
a/g: 92 2071 112 -42 -89 2
a/g: 87 2062 119 -40 -120 8
a/g: 96 2064 102 -31 -129 42
a/g: 100 2062 125 -31 -160 36
a/g: 86 2050 113 3 -157 17
a/g: 97 2059 110 8 -177 13
a/g: 99 2049 90 1 -177 5
a/g: 116 2065 83 34 -158 -24
a/g: 123 2057 101 -6 -163 -44
a/g: 119 2054 121 -4 -144 -98
a/g: 100 2048 121 17 -133 -86
a/g: 107 2046 134 17 -145 -128
a/g: 108 2055 114 42 -164 -146
a/g: 108 2074 99 29 -145 -150
a/g: 105 2050 113 48 -141 -197
a/g: 97 2055 119 36 -103 -177
a/g: 94 2051 89 13 -102 -176
a/g: 87 2066 116 9 -103 -171
a/g: 78 2063 102 15 -62 -182
a/g: 86 2060 118 10 -70 -143
a/g: 77 2065 116 -3 -17 -108
a/g: 82 2064 101 5 -20 -107
a/g: 67 2063 107 -11 46 -75
a/g: 77 2070 112 25 45 -73
a/g: 64 2061 91 33 52 -33
a/g: 75 2060 124 39 47 -24
a/g: 76 2057 127 0 66 -20
a/g: 84 2051 121 43 59 -28
a/g: 88 2064 106 19 69 -9
a/g: 95 2067 121 56 11 -24
a/g: 84 2057 115 23 64 -10
a/g: 98 2054 97 35 33 -31
a/g: 86 2068 109 25 38 -17
a/g: 86 2046 104 30 63 -27
a/g: 91 2047 128 38 36 -32
a/g: 102 2066 134 40 34 -73
a/g: 88 2071 121 46 41 -19
a/g: 80 2072 118 53 34 -37
a/g: 70 2033 114 40 35 -40
a/g: 90 2062 103 31 22 12
a/g: 81 2070 101 35 10 -17
a/g: 93 2054 105 27 -18 32
a/g: 86 2046 116 28 -4 49
a/g: 91 2046 98 15 -12 22
a/g: 82 2059 118 33 -22 73
a/g: 73 2047 123 31 -85 67
a/g: 91 2054 95 0 -117 93
a/g: 82 2055 110 17 -84 86
a/g: 73 2067 104 5 -135 137
a/g: 86 2062 93 -13 -117 133
a/g: 86 2055 109 10 -100 179
a/g: 75 2056 95 -5 -80 193
a/g: 74 2067 107 -8 -49 229
a/g: 88 2066 76 -22 8 223
a/g: 92 2055 72 -82 4 276
a/g: 77 2046 95 -70 4 254
a/g: 88 2057 113 -41 9 290
a/g: 100 2066 124 -36 12 271
a/g: 107 2053 128 -18 -9 258
a/g: 114 2068 126 13 -4 256
a/g: 104 2049 102 12 54 212
a/g: 127 2059 109 14 65 202
a/g: 106 2044 88 16 38 166
a/g: 127 2059 118 19 82 140
a/g: 122 2050 111 30 103 64
a/g: 118 2054 111 26 97 57
a/g: 111 2040 111 37 126 22

When positive y-axis is perpendicular to earth surface. All readings are in Ax,Ay,Az,Gx,Gy,Gz format.

Since +/-16g range is selected, it seems everything is working fine. If you spot any anomaly, please help. Also please recommend any other test to verify if everything is correct.

Thanks.

If the accelerometer is properly calibrated, all axes will return the same absolute value for g when vertical (plus or minus a few units).

Yours does not appear to pass that test.

jremington:
If the accelerometer is properly calibrated, all axes will return the same absolute value for g when vertical (plus or minus a few units).

Yours does not appear to pass that test.

You mean that when module is horizontal, Ax and Ay values must be approximately same? In my case its (-56,10), (-41,9) and all, are all wrong?

Should I try to calibrate it once again? Maybe module wasnt perfectly horizontal while calibrating?

Thanks.

Also please note that sketch is on +/-16g. Is it possible that since module is least sensitive at this range, I am getting these off values?
Also if you observe when x-axis is perpendicular to earth's surface, Ax and Az values are fairly same.
I am surely missing something :confused:

Ay and Ax should be their own unique values.

When I have the gyros and accelerometers moved into position, for calibration, I give about 30mS settle time before taking a reading. Taking 20 averaged readings per position has shown to be a good idea. For an inexpensive MMU you will not get flat lines from the units. I apply the scale factor to each measurement taken after averaging for the gyros and apply the bias calibration to the gyros, under operation, after the reading has been scaled. I do not scale the accelerometer calibration readings and apply the bias calibration corrections to the under operation accelerometer readings before the scaling.

Have a single operational reading, with calibration bias applied and have it serial printed, have the serial monitor closed. After about 2 minutes, open the serial plotter to watch the printed value displayed as a graphed line. Look to see if the graphed line, over time averages out or has a drift.

Frankly, when I do a MMU project, I buy three our four MMU's and test each one for the best performance. Some units work better then others.

You will need to filter the data, For a MMU without a magnetometer the complementary filter works great, Reading a IMU Without Kalman: The Complementary Filter | Pieter-Jan.com.

If you use a magnetometer the Madgwick / Mahony sensor fusion filters https://os.mbed.com/users/onehorse/ work even better. If you decide to use the MadgwickQuaternionUpdate, I highly recommend putting in a value for Kp other then 0.0f; 0.7f works well for the MPU9250. With a non-zero the error correction routine is enabled and, over time, works really well.

This is one of those threads were although I understand the individual words (well, most of them) I have nfc what the threads about. I do intend to play with a 6050 soon though, so bookmarking for future study, especially Idahowalker's reply right above this one.

Is is in English, yes? :wink:

I am surely missing something

Yes, you missed the point.

Reply #9 was about the values displayed for "g" on the vertical axis, which suggest that the accelerometer is still not properly calibrated.

Assuming that Y and Z are perpendicular to the Earth's surface, they report "g" to be 2060 +/-2 and 2058 +/-1 respectively, while X reports 2160 +/- 1, for a 5% difference.

X is probably not properly scaled with respect to Y and Z, but you need the "sensor flipped" values for -g to be certain.

After a day of googling, searching and tinkering

You could have studied the definitive overview and tutorial linked in reply #6 instead, and avoided this fundamental oversight.

@neiklot: Good intro to attitude and inertial sensors here: http://www.chrobotics.com/library

jremington:
Assuming that Y and Z are perpendicular to the Earth's surface, they report "g" to be 2060 +/-2 and 2058 +/-1 respectively, while X reports 2160 +/- 1, for a 5% difference.

How on earth can two mutually perpendicular axes be perpendicular to earth's surface? I am now getting blown away to bits.

How on earth can two mutually perpendicular axes be perpendicular to earth's surface?

One at a time, obviously. If this is too difficult for you, choose another hobby.

I'm out.

Ok, so, seems my local walk-in supplier has stock of the gy-521 so if I get one today, that’s the long weekend sorted :wink:

(Wondering why their Keyes version is almost 3x as expensive as the EIE one… maybe I’ll find out when the cheap one doesn’t work…)