MPU-6050 Z-axis

Hi all, glad to finally register! I would like to begin with a little background to let you know where I’m coming from.

I purchased the Sparkfun MPU-6050 breakout board a while back to use on a quadcopter which got sidelined as the school year progressed. Recently however, a school project caused me to turn to it with a new use in mind. I would like mount it to a vehicle and measure its acceleration. Using this information, I intend to integrate this into velocity after running it through a simple filter. I am aware that the output will drift with time however this is only for short term applications and I begin with a reference so it shouldn’t pose any problems.

I initially tried Jeff Rowberg’s libraries on GitHub and got them running smoothly (thanks Jeff for the teapot demo - made me crack a huge grin!). As I played with the different outputs however I began noticing an issue.

The vehicle in question is a tractor configured for a pulling competition . I am attempting to measure its wheel slip as it travels in a straight line down the course. I am measuring the angular velocity of the drive wheels using a hall effect sensor. This will be compared with the ground speed of the vehicle. This scenario rules out other ground speed measurements such as GPS (indoor track), radar/optical methods (the vehicle catwalks at times - also ruling out another hall sensor on the front wheels), and a trailing spring-loaded wheel (uneven ground with abrupt transverse shocks require a robust system). See below for an example (not my team but you get the idea).

I run into issues when I start looking at data output options as seen below (from MPU6050_DMP6 - i2cdevlib/Arduino/MPU6050 at master · jrowberg/i2cdevlib · GitHub):

    // display initial world-frame acceleration, adjusted to remove gravity
    // and rotated based on known orientation from quaternion
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetAccel(&aa, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
    mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

The following is what I have come to understand about the underlying processes used to generate this output. I have spent a lot of time reading through Jeff’s libraries and have experimented with a number of different outputs (linear acceleration and gravity vector).

  • the attitude (as a quaternion) and the linear acceleration are combined to calculate the gravity vector
  • this is then scaled and subtracted from the linear acceleration to output acceleration solely due to motion
  • the linear acceleration along each of the axes are then rotated into the world reference frame (with gravity down)

I interpreted this from lines 533-633 of MPU6050_6Axis_MotionApps20.h found at i2cdevlib/Arduino/MPU6050 at master · jrowberg/i2cdevlib · GitHub.

The first indication I had that something might be out of the ordinary was that upon running MPU6050_DMP6 when configured to output readable world acceleration, both the x and y axes converged to zero after initial start-up (15 second), but the z-axis remain at a fairly constant output of ~2400. When I invert the accelerometer so that the z-axis is pointing downwards it reads ~6000, leading me to believe that it is not correctly calibrating when it starts. See below for sample output with the z-axis pointing upwards.

aworld	-3	8	2452
aworld	-3	4	2458
aworld	1	2	2463
aworld	3	2	2453
aworld	9	4	2454
aworld	7	2	2451
aworld	10	0	2448
aworld	11	-3	2447
aworld	11	-1	2445
aworld	5	2	2447
aworld	0	-2	2445
aworld	-2	0	2442

I modified the sketch (using the attached sketch) so that it displays linear acceleration. Experimenting with the x and y axes produced an output which ranged from approximately ±7500 to 8000 and they appeared similarly aligned with the physical axes of the sensor, however the z-axis ranged from +6400 to -10200 (not equally distributed).

I then changed the output to display the gravity vector’s x, y, and z components. When I oriented the sensor so that the x-axis go to zero (horizontal to the ground), the sensor appears flat as you would expect. Likewise with the y-axis. With the z-axis however, the board is inclined approximately 15 degrees from vertical, leading me to conclude that something is awry. I repeated the test again using the linear acceleration output and arrive at the same conclusion (this is not a problem with how the gravity vector is determined).

I then repeated the tests with Krodal’s sketch ( and arrived at the same conclusion, ruling out incorrect code.

My questions are:

  • can someone in possession of an MPU-6050 please run Jeff’s MPU6050_DMP6 sketch and please tell me if all their axes converge to zero as the sensor calibrates itself?
  • if you print the gravity vector (see code below) and move the chip so that each of the axes go to zero, does it look to be in close agreement with what you’d expect (physical x,y, and z axes printed on the breakout board)? My z-axis appears to be ~15 degrees out of alignment.

I have attached the sketch that I used to diagnose my problem.

Sorry if my explanation omitted any detail you require. Let me know and I’ll get back to you as soon as possible. I’m interested to hear all of your responses!

MPU6050_DMP6_DIAGNOSIS.ino (3.62 KB)

Hello cam_,

Incidentally I am also playing with MPU6050 using Jeff's code for the last few days . I see this output for 'aworld':

The second column is the time difference, in ms, between two consecutive readings (it's not in the original code). The x, y and z values are in the columns 3, 4, and 5.

aworld  18  -3  -2  3852
aworld  19  -7  0   3851
aworld  20  -8  -1  3851
aworld  21  -6  1   3852
aworld  18  -6  1   3852
aworld  18  -5  3   3854

So I also get some residual z-axis values.

I have another problem of my own. I frequently get FIFO overflow. Even if the IMU is at complete rest, once the FIFO overflow occurs, I get some random x, y and z values. So I modified the sampling rate to 100Hz by modifying MPU6050_6Axis_MotionApps20.h

//setRate(4); // 1khz / (1 + 4) = 200 Hz
setRate(9); // 1khz / (1 + 9) = 100 Hz - modified rate

I am not sure if this is the right way to accomplish that. I want the data at actually ~10Hz. It does the trick though. Let me know if you have another solution.

Thanks for your response. I'm sorry to hear you are also having the same problem. Did you try Krodal's code that I mentioned too? How modified is your code? When I run the sketch the time interval is approximately 1ms between readings (at the default sampling rate).

Your modification to the sampling rate appears to be correct from what I can tell, however I had not ventured that far yet. The time interval between your readings indicates a 50 Hz sampling rate though, am I right?

50 Hz = 1second / ~20 milliseconds (0.02 seconds)

So either your extra code is running too slowly and the buffer overflows before it is read again, causing the FIFO overflow, or you had the sampling rate set to something else when you recorded that output.

Does the sampling time make sense if you use setRate(99) (do you get 100 ms between samples)? The datasheet says that 4 Hz is the minimum.

I'm by no means a coding wiz but if you were unable to read the buffer in a timely manner you could check the size of the buffer and if it exceeded 1024. If so, reset it (using 'mpu.resetFIFO()') then return to the beginning of the loop without analyzing anything to read the next sample. Highly inefficient but it's an idea.

Hello, I registered a couple of minutes ago, just to say that I have exactly the same problem

in the worldaccel example, only x and y axis tend to zero during calibration (mpu6050 completely still), z remains with a constant value above 2000, that changes depending on which position was the mpu6050 resting.

I'll check the alignment of the gravity vector ASAP


Did you manage to make any progress?

I have the same problem with the z-axis. Not sure there is a flaw in the design of the chip or S/W related. I don't know how to compensate for it and I hope someone can isolate this to either the chip of the S/W.


What readings do you get from the chip when you put the board on its edge i.e. z-axis horizontal?

I bought another for a sideline project that I have and it also exhibits the same behaviour which is not encouraging.

When the z is placed horizontally it reads ~3600-4200 (little change from when z is directly up) while the x and z both tend to zero after being agitated.

Same observation here- did anybody care to check with jrowberg or the MotionApps forums?

Hey guys,

I just looked into this after a long time away, and it seems the DMP sensitivity is using +/- 2g instead of 4g, as I think it was when I originally put this stuff together. I can't be sure about that since I honestly don't really grasp a lot of the math involved, but that's what it looks like to me. When I added temp debug outputs for the "aa.z" component, my min/max range when the MPU was level in both normal and inverted orientations as [-8920, 7760] give or take a dozen. Adjusting the Z accel offset register with a new value results in a more or less correct range (though still a bit larger than exactly +/- 1g as I would expect), and then modifying the MPU6050::dmpGetLinearAccel() method in MPU6050_6Axis_MotionApps20.h to the following:

uint8_t MPU6050::dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity) {
    // get rid of the gravity component (+1g = +8192 in standard DMP FIFO packet, sensitivity is 2g)
    v -> x = vRaw -> x - gravity -> x*8192;
    v -> y = vRaw -> y - gravity -> y*8192;
    v -> z = vRaw -> z - gravity -> z*8192;
    return 0;

...then you get results for aaworld.z that are a lot more like what you would expect. This change has been pushed to the repo as of a moment ago.

By the way, I have very recently (i.e. a week ago) created a set of I2Cdevlib forums specifically for this kind of discussion, one forum for each device currently in the library. The MPU-6050 forum is here:

It's empty at the moment, but if you all want to keep that in mind for future I2Cdevlib-related discussions, it's there for you.

Excellent, thank you!