I recently got an MPU6050 and I noticed the accelerometer data was a bit off, especially on the Z axis.
I'm running it on a Teensy 4.0 with Adafruit's MPU6050 library and basic example code: https://github.com/adafruit/Adafruit_MPU6050/blob/master/examples/basic_readings/basic_readings.ino
While stable on a flat surface (+Z up), it's reading ~8.5 m/s^2 and when flipped over (-Z up), ~11.6 m/s^2:
+Z:
Acceleration X: -0.06, Y: 0.00, Z: 8.44 m/s^2
-Z:
Acceleration X: -0.01, Y: -0.07, Z: -11.57 m/s^2
Aligning the other axes vertically gives me:
+X:
Acceleration X: 10.16, Y: -0.16, Z: -0.03 m/s^2
-X:
Acceleration X: -9.27, Y: -0.10, Z: -0.18 m/s^2
+Y:
Acceleration X: 0.07, Y: 9.55, Z: -0.10 m/s^2
-Y:
Acceleration X: 0.04, Y: -9.93, Z: -0.05 m/s^2
The X and Y readings could be adjusted fairly close to 9.81 m/s^2 with just an offset, but it seems like the Z axis would also require some scaling.
My question, is there a standard method of calibrating it in code?
3 Answers 3
I had this exact issue, where when I flipped the sensor to different orientations I would measure gravity as being anywhere between 7 m/s^2 to 10.5 m/s^2. I came to the same solution that st2000 is describing. I'm a little late to this conversation but I figured I can still share my solution to help anyone else who's experiencing the same issue.
First, I flipped the sensor on all 6 sides to record the approximate maximum and minimum acceleration I got for each axis due to gravity (each axis should read somewhere around 16,000 to 17,000 assuming the sensitivity is set to 2G).
My readings at this point were:
Minimum | Maximum
X | -15,700 | 17,000
Y | -16,650 | 16,250
Z | -16,600 | 16,800
Then I derived a linear correction formula that would take the raw readings from the accelerometer and output the acceleration in m/s^2. I first calculated the "center offset" of each axis by just averaging the minimum and maximum readings for each axis.
axis_min + axis_max
Center = ---------------------
2
Then I scaled the output according to its range so that when the axis reading was at the maximum, the output would be 9.8, and when the raw reading was around the minimum it would output -9.8.
G = 9.80665 (Acceleration due to gravity)
Range = axis_max - axis_min
G
----------- 2 * G 2 * G
Scale = Range = ------- = ---------------------
------- Range axis_max - axis_min
2
Now putting it all together we get the following linear equation to calculate the acceleration on each axis:
2 * G z_min + z_max
A(x) = Scale * (x - Center) = --------------------- * (x - ---------------)
axis_max - axis_min 2
The function in actual code looks like this:
float axis_correction(float raw_reading, float axis_min, float axis_max, float grav_accel) {
return (float)(2.f * grav_accel * (raw_reading - (axis_min + axis_max) / 2.f)) / (axis_max - axis_min);
}
Now, with this I get a consistent 9.75 to 9.88 m/s^2, I'm guessing with more tuning I can get this variation down further but this is already much better than the readings I was getting using any of the libraries out there. For reference, here's the plot for the accelerometer readings I got.
Plot for the processed accelerometer readings
The plot shows us the processed readings. The red line is the total magnitude of the acceleration the sensor is experiencing. The purple line plots the nominal acceleration due to gravity. The other three lines are the individual accelerations on each axis. As we can see, the magnitude of acceleration is sticking very close the nominal acceleration due to gravity of 9.8 (except for the spikes and fluctuations from me flipping the sensor).
The ability to reliably measure gravity from various orientations was very important in my specific application and this calibration technique should work very well for me and hopefully others having the same issue!
Yes an accelerometer can be calibrated. An offset for each of the 3 accelerometers can be found such that the absolute value of the maximum and minimum values of any given accelerometer axis are equal. The maximum and minimum values can be found by rotating the accelerometer such that each axes is pointed directly toward and directly away from the earth. Once each axes is normalized each axes needs a magnitude adjustment value such that the maximum value of all axes equal one another. It may be convenient the product of the maximum of any given axes and that axes' magnitude adjustment value is 9.8 (meters per second * second).
-
Would you have an article or link you can share so we can have a look. I understand what you're saying but have no idea how to actually do it.Zhelyazko Grudov– Zhelyazko Grudov2021年08月07日 12:10:23 +00:00Commented Aug 7, 2021 at 12:10
-
1It's a little difficult to find an appropriate article. This NIST article goes way overboard assuming the 3 accelerometers may not even be orthogonal. And other articles skip over accelerometer calibration (to be honest, accelerometers are usually good out of the box for most Arduino applications). Try this Adafruit article it sounds like what you are after.st2000– st20002021年08月08日 16:39:40 +00:00Commented Aug 8, 2021 at 16:39
-
Thank you for your commentZhelyazko Grudov– Zhelyazko Grudov2021年08月20日 10:55:29 +00:00Commented Aug 20, 2021 at 10:55
Yes. Jeff Rowberg's library performs the calibration for you when you power on. You'll need to make sure the module is lying level and still and then send a character over serial to trigger the calibration. A version based on Jeff's library, called Electronic Cats, can be downloaded directly using the Arduino IDE.
Note that Jeff's library is a bit overwhelming/intimidating for new users. If you'd like to learn more about hiding its complexity behind a simple and easy to use interface, or about being able to save the calibration results to persistent memory so that you don't have to perform the calibration every time you power on, or just want to learn more about this topic in general, please consult the following tutorial: