MPU6050 angle problem

Hi,

I am using Jeff library to get DMP data from the MPU6050. I am reading the ypr (yaw, pitch and roll) and it works fine but there is a problem.

When I spin my mpu6050 in 80 degree in the X axis (or Y axis) the MPU6050 tells my arduino it has 80 degree, great! But when I spin my mpu6050 in 100 degree in the X axis (or Y axis) the MPU6050 also tells my arduino it has 80 degree!

I mean, when the value of the angle (ypr[1] ypr[2]) pass 90 degree the result is the same as if it was before 90 degree. This problem doesnt allow me to know if my project is after or before the 90 degree.

This is a generic problem, it happens with the MPU6050 using the Jeff library and has nothing to do with some wrong code of mine. I just would like to know if someone smarter into this can help me know if the angle that I am reading of the MPU6050 is before or after the 90 degree.

4 Words: Please post your code

Here is the code. It's the sample code of every MPU6050. It's standard. If you run it and move your sensor around the X axis you will see it increases when you get close to 90 degrees, but when you past the 90 degrees the values decrease! They should keep increasing. So a reading of 80 degree will mean 80 degrees or 100 degrees! That's not good for a widely used sensor like this.

//Código do MPU6050.
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
MPU6050 mpu;
uint8_t mpuIntStatus;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
volatile bool mpuInterrupt = false;
void dmpDataReady() {mpuInterrupt = true;}

void setup() {

	//Código do MPU6050.
    Wire.begin();
    TWBR = 24;
    mpu.initialize();
    mpu.dmpInitialize();
    mpu.setDMPEnabled(true);
    attachInterrupt(0, dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
    packetSize = mpu.dmpGetFIFOPacketSize();

	//Por algum motivo se utilizar "9600" aparece erro "FIFO overflow!".
    //COMENTAR_OFICIAL
    Serial.begin(115200);

}

void loop() {

    while (!mpuInterrupt && fifoCount < packetSize) {






    }

	//Código do MPU6050.
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        mpu.resetFIFO();
        //COMENTAR_OFICIAL
        Serial.println(F("FIFO overflow!"));
    }
    else if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        
        //COMENTAR_OFICIAL
        Serial.print("ypr\t");
        Serial.print(ypr[0]*180/M_PI);
        Serial.print("\t");
        Serial.print(ypr[1]*180/M_PI);
        Serial.print("\t");
        Serial.print(ypr[2]*180/M_PI);
        Serial.println();

    }

}

Can you please attach the library, I have tried using a different library and it works fine, but I cannot find an easy download for yours

Thank you so much! I am using this library i2cdevlib/Arduino/MPU6050 at master · jrowberg/i2cdevlib · GitHub

Could you please tell me your library if it does not produce the error I reported?

It just uses the Wire library to directly communicate with it. The output is around -17000 to 17000, but you don't get that problem.

Anyway, there is no download button on that site and simply copy/pasting ALL of that code will take forever, just give me a download and I can test it out.

    // MPU-6050 Short Example Sketch
    // By Arduino User JohnChi
    // August 17, 2014
    // Public Domain
    #include <Wire.h>
    const int MPU=0x68;  // I2C address of the MPU-6050
    int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
    void setup(){
      Wire.begin();
      Wire.beginTransmission(MPU);
      Wire.write(0x6B);  // PWR_MGMT_1 register
      Wire.write(0);     // set to zero (wakes up the MPU-6050)
      Wire.endTransmission(true);
      Serial.begin(115200);
    }
    void loop(){
      Wire.beginTransmission(MPU);
      Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
      Wire.endTransmission(false);
      Wire.requestFrom(MPU,14,true);  // request a total of 14 registers
      GyX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
      GyY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
      GyZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
      Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
      AcX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
      AcY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
      AcZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
      Serial.print("AcX = "); Serial.print(AcX);
      Serial.print("\t | AcY = "); Serial.print(AcY);
      Serial.print("\t | AcZ = "); Serial.print(AcZ);
      Serial.print("\t | Tmp = "); Serial.print((Tmp / 340. + 36.53) * 1.8 + 32);  //equation for temperature in degrees C from datasheet
      Serial.print("\t | GyX = "); Serial.print(GyX);
      Serial.print("\t | GyY = "); Serial.print(GyY);
      Serial.print("\t | GyZ = "); Serial.println(GyZ);
      /*Serial.write(AcX >> 8);
      Serial.write(AcX & 255);
      Serial.write(AcY >> 8);
      Serial.write(AcY & 255);
      Serial.write(AcZ >> 8);
      Serial.write(AcZ & 255);*/
      delay(250);
    }

hI thank you! But I need to use that library cause it reads the DMP which is a series of precious infomration the module provides freeing my arduino from doing lots of computation.

But to test my case, please open GitHub - jrowberg/i2cdevlib: I2C device library collection for AVR/Arduino or other C++-based MCUs and click the DOWNLOAD ZIP on the right bottom. Extract the content on your /library direcotry of arduino and you are good to go!

I see it thanks, I will respond again when I decide to tinker with it

@Ps991 thank you so much. Have a nice week!

Before I look deeper into, are you sure this code even works?

I am getting random freezing and I notice that Pitch affects Roll as well, but Roll does not affect pitch, and Yaw makes no sense to me what so ever, seriously at 1 point I was holding it still and Yaw was counting up, like what!?...

But I can tell you that the reason you only get -90 to 90 is because the function uses inverse tangent which needs extra consideration to get that negative you are looking for (I think), working on it.

EDIT: Pretty sure I found a solution for you, but I need more time, kinda bored of messing with it right now

Fixed it :smiley:

I still have no idea how a gyroscope is supposed to measure yaw, so that I have not changed...

But I did manage to get the gyroscope pitch and roll to work, it measures 0 to 360. I used the chip facing upward as my reference point for pitch. Roll I used the little arrow on the PCB. Everything should be right, but give it a test first.

Just replace this function inside MPU6050_6Axis_MotionApps20.h at line 697 located in ~/Documents/Arduino/libraries/MPU6050/MPU6050_6Axis_MotionApps20.h (This is on my MAC, so yours may be different)

uint8_t MPU6050::dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity) {
    // yaw: (about Z axis)
    data[0] = atan2(2*q -> x*q -> y - 2*q -> w*q -> z, 2*q -> w*q -> w + 2*q -> x*q -> x - 1);
    
    // pitch: (nose up/down, about Y axis)
    float temp = atan(gravity->z / gravity->x);
    if(gravity->z < 0){
      if(gravity->x >= 0)
        data[1] = HALF_PI - temp; //quadrant 2
      else
        data[1] = TWO_PI - HALF_PI - temp; //quadrant 3
    }
    else if(gravity->x >= 0)
      data[1] = HALF_PI - temp; //quadrant 1
    else
      data[1] = TWO_PI - HALF_PI - temp; //quadrant 4
    
    // roll: (tilt left/right, about X axis)
    temp = atan(gravity->z / gravity->y);
    if(gravity->y < 0){
      if(gravity->z >= 0)
        data[2] = HALF_PI + temp; //quadrant 1
      else
        data[2] = HALF_PI + temp; //quadrant 2
    }
    else if(gravity->z >= 0)
      data[2] = TWO_PI - HALF_PI + temp; //quadrant 4
    else
      data[2] = TWO_PI - HALF_PI + temp; //quadrant 3
    
    return 0;
}

If you want it to go from -180 to 180, then simply remove the TWO_PI in 4 locations and you will be fine.

I just started working with the 6050 recently, so am no expert, and am using Jeff Rowberg's library. I didn't look at the code posted here, so cannot comment on it.

What I did find, similar to OP, is that both pitch and roll accelerometer readings go to 90 deg as you tilt the board from horizontal to vertical, and then start back down, and go all the way back to zero when the board is completely upside down. I may be wrong, but I figured that's just how these things work.

To determine whether the board normal vector is pointing upwards or downwards, I noticed the z-accelerometer reads >0 for the board right-side up, and <0 for right-side down. So it's easy to tell the absolute angle of the board. But you might check this.

Did you mean z-gyro? Because, if it isn't moving, there is no acceleration.

However, what OP wants is to tell the angle, he doesn't want 2 positions to have the same result. For example, 85 degrees and 95 degrees (according to a standard unit circle) both come out as 85 degrees from the Jeff library.

Ps991:
Did you mean z-gyro? Because, if it isn't moving, there is no acceleration.

However, what OP wants is to tell the angle, he doesn't want 2 positions to have the same result. For example, 85 degrees and 95 degrees (according to a standard unit circle) both come out as 85 degrees from the Jeff library.

No, I meant z-accelerometer, not gyro.

If you try it yourself, what you should find is that the z-accel reading will be >0 for one of those 2 readings, and should change sign to <0 for the other. I'm pretty sure, but am currently in the process of working on this myself.

Come to think about it, gravity is acceleration, so yes, you are right.

Ps991:
I am getting random freezing and I notice that Pitch affects Roll as well, but Roll does not affect pitch, and Yaw makes no sense to me what so ever, seriously at 1 point I was holding it still and Yaw was counting up, like what!?...

@Ps991 - Did you ever figure out the cause of the freezing? I just started working with this code and am having the same problem.

I never did figure it out :confused:

I feel like it has to be a programmer's error because I have used simpler code and it works, however, the code may just be accessing different parts of the sensor and that part of the sensor may be causing the freezing. Either way, it does need some looking into.

If you are not flying a craft its probably easier to keep the quaternion and do vector
operations on it as needed. No gimbal-lock to worry about then.

If you are flying a craft then you shouldn't be upside down!