The mpu gives me perfectly fine values for the yaw, pitch, and roll position of the chip, but when I use mpu.getRotation(&gx, &gy, &gz) to obtain the current angular velocity of the chip, the values returned are awful. I wrote a program in Processing to graph the data from my Arduino, and this is what it looks like:

Graph of angular velocity and angular position

I suggest you click on the picture and zoom in a bit because it's difficult to see. The green line represents zero (0), the Pink line represents the angular position of the mpu6050 chip, obtained from mpu.getYawPitchRoll..., and the Blue line represents the angular velocity on the same rotational axis.

A few extra things to note:

  • The scale between the Pink and the Blue lines is slightly off, but that shouldn't matter for this purpose.
  • The time-frame for this graph is about 16s.
  • Before being graphed, the raw gx value is divided by the gyro's sensitivity scale factor, 131, and then converted from radians to degrees. In addition to this, it is also put through a complementary filter, so the whole formula looks like this: rollRate = (0.7*rollRate) + (0.3*(-180 * gx / 131 / M_PI));

As you can see, the measurements for angular velocity (Blue) make almost no sense when graphed next to the angular position (Pink).

My question is this: What can I do to clean-up/filter these angular velocities and get rid of all the errors? I need these values to be accurate enough to be used in something like a drone PID.

Things I have tried:

  • Complementary filters of various proportions.
  • Adjusting the MPU's built in low-pass filter.

Thanks for any suggestions.

1 Answer 1


At last! I have discovered the solution.

Quick Solution for those who don't like reading: Amend the previous rollRate formula to rollRate = (0.7 * rollRate) + (-0.3 * gx / 16.4);. Or, if you don't want the filter, rollRate = -1 * gx / 16.4;

The problem starts with the function mpu.getRotation(&gx, &gy, &gz) which accepts int16_t types for gx, gy, and gz. Since int16_t is a 16 bit integer, it has a maximum range of -32,768...+32767. The reason this integer type is used is because the output range for the gyro is -32750...+32750, which fits nicely into the 16-bit integer's range.

The problem was that when I converted these values to a readable angular velocity (and complementarily filtered) using rollRate = (0.7*rollRate) + (0.3*(-180 * gx / 131 / M_PI)); , the gx value was multiplied by -180 in part of the calculation. This means that if gx was high enough initially, it would have rolled over to -32786 and ruined the whole calculation, causing the horrible spikes in the graph.

At the same time I discovered this problem, I also realized that converting from radians to degrees was unnecessary, as the gyro output was already in units of degrees (just scaled by a sensitivity factor). After that big face-palm, I revised my rate formula to the following: rollRate = (0.7 * rollRate) + (-0.3 * gx / 16.4);. You will notice the scale factor has changed from 131 to 16.4. That is because the gyro range is actually +/-2000 deg/s by default, not 250 deg/s. I tried to change it back to +/-250 with mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);, but after examining the graph, it appeares that mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); does not account for this setting change, and resulted in the ypr overshooting and then leveling out to its correct value after a delay. I decided not to mess around with the quaternion container, q, and just accepted the lower sensitivity.

Updated, bug free sketch Like the previous image, I suggest zooming in.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.