MPU6050 Arduino Due Problem

Hi,

I made a code using arduino mega. It’s ok but when I try on arduino due I have a problem.

Below the code where I made a average (bias) of gyro and accel.

The problem is Gyro_raw_error_x average. See this

Arduino Mega
Gyro_raw_error_x = -3

Arduino Due
Gyro_raw_error_x = -2000

Other average values are very similar, but GyroX is not.

for(int j=0; j<=samples; j++)
    {
      Wire.beginTransmission(0x68);
      Wire.write(0x3B);                       //Ask for the 0x3B register- correspond to AcX
      Wire.endTransmission(false);
      Wire.requestFrom(0x68,12,1); 
      
      Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ; 
      Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;
      temp=Wire.read()<<8|Wire.read(); 
      Gyr_rawX=Wire.read()<<8|Wire.read();     
      Gyr_rawY=Wire.read()<<8|Wire.read();

      Acc_angle_error_x = Acc_angle_error_x + ((atan((Acc_rawY)/sqrt(pow((Acc_rawX),2) + pow((Acc_rawZ),2)))*rad_to_deg));
      Acc_angle_error_y = Acc_angle_error_y + ((atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawZ),2)))*rad_to_deg)); 

      Gyro_raw_error_x = Gyro_raw_error_x + (Gyr_rawX/32.8); 
      Gyro_raw_error_y = Gyro_raw_error_y + (Gyr_rawY/32.8);      

    }


Acc_angle_error_x = Acc_angle_error_x/samples;
Acc_angle_error_y = Acc_angle_error_y/samples;
Gyro_raw_error_x = Gyro_raw_error_x/samples;
Gyro_raw_error_y = Gyro_raw_error_y/samples;

Some MPU6050 modules have a 5V regulator and will not run on 3.3V, due to the regulator dropout voltage. If that is the case, you will need to remove the regulator and/or bypass the connection to it.

@jremington

Thank you for the feedback. So I think the problem is not voltage because I used 3V3 and Arduino Mega it works, but on Due The result is different.

Have you checked for differences in default variable sizes, integer overflow and the like?

Post ALL your code. The snippet is useless.

All code below

The result when I print average on Serial Monitor:

#include <Wire.h>

int samples = 2000;
int temperature=0;

// Gyro Variables
float Gyr_rawX, Gyr_rawY, Gyr_rawZ;     //Here we store the raw data read 
float Gyro_angle_x, Gyro_angle_y;         //Here we store the angle value obtained with Gyro data
float Gyro_raw_error_x, Gyro_raw_error_y; //Here we store the initial gyro data error
//Acc Variables
float rad_to_deg = 180/3.141592654;      //This value is for pasing from radians to degrees values
float Acc_rawX, Acc_rawY, Acc_rawZ;    //Here we store the raw data read 
float Acc_angle_x, Acc_angle_y;          //Here we store the angle value obtained with Acc data
float Acc_angle_error_x, Acc_angle_error_y; //Here we store the initial Acc data error


void setup()
{  
  Serial.begin(115200); // baudrate 115200 bits per second
  Serial.println("Init");

  Wire.setClock(400000l);    //increases I2C frequency to 400kHz
  Wire.begin();                           //begin the wire comunication  
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68)              
  Wire.write(0x6B);                       //make the reset (place a 0 into the 6B register)
  Wire.write(0x00);
  Wire.endTransmission(true);             //end the transmission
  //Gyro config
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68) 
  Wire.write(0x1B);                       //We want to write to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                       //Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);             //End the transmission with the gyro
  //Acc config
  Wire.beginTransmission(0x68);           //Start communication with the address found during search.
  Wire.write(0x1C);                       //We want to write to the ACCEL_CONFIG register
  Wire.write(0x10);                       //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true); 

  Wire.beginTransmission(0x68);
  Wire.write(0x1A);  // the config address
  Wire.write(0x06);  // the config value
  Wire.endTransmission(true);

for(int j=0; j<=samples; j++)
    {
      Wire.beginTransmission(0x68);
      Wire.write(0x3B);                       //Ask for the 0x3B register- correspond to AcX
      Wire.endTransmission(false);
      Wire.requestFrom(0x68,12,1); 
      
      Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ; //each value needs two registres
      Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;
      temperature=Wire.read()<<8|Wire.read(); 
      Gyr_rawX=Wire.read()<<8|Wire.read();     //Once again we shif and sum
      Gyr_rawY=Wire.read()<<8|Wire.read();

       // Sum 
      Acc_angle_error_x = Acc_angle_error_x + ((atan((Acc_rawY)/sqrt(pow((Acc_rawX),2) + pow((Acc_rawZ),2)))*rad_to_deg));
      Acc_angle_error_y = Acc_angle_error_y + ((atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawZ),2)))*rad_to_deg)); 
      
      Gyro_raw_error_x = Gyro_raw_error_x + (Gyr_rawX/32.8); 
      Gyro_raw_error_y = Gyro_raw_error_y + (Gyr_rawY/32.8);      

    }  
// Average
Acc_angle_error_x = Acc_angle_error_x/samples;
Acc_angle_error_y = Acc_angle_error_y/samples;
Gyro_raw_error_x = Gyro_raw_error_x/samples;
Gyro_raw_error_y = Gyro_raw_error_y/samples;        

// Debugger
Serial.print("Acc_angle_error_x: ");
Serial.println(Acc_angle_error_x);
Serial.print("Acc_angle_error_y: ");
Serial.println(Acc_angle_error_y);
Serial.print("Gyro_raw_error_x: ");
Serial.println(Gyro_raw_error_x);
Serial.print("Gyro_raw_error_y: ");
Serial.println(Gyro_raw_error_y);
     
}//end of setup void



void loop()
{

}

Screenshots posted properly:
screenshots.png

What happens when you repeat both tests?

screenshots.png

When I repeat this code the average value change but very little.

These values are degree, so running on Arduino Due gyroX average is very different, other values are similar.

On arduino Mega my robot is great, but when I try run on Arduino Due it's crazy because average GyroX is incorrect.

I personally think it is a bad idea to leave the initialization of variables up to the compiler and linker. Try setting all these to zero before using them as accumulators.

float Gyro_raw_error_x, Gyro_raw_error_y; //Here we store the initial gyro data error

Makes sense. I initialized the variables…but not sucess yet. :confused:

I tried double type instead float, but also not sucess.

#include <Wire.h>

int samples = 2000;
int temperature=0;

// Gyro Variables
float Gyr_rawX=0;
float Gyr_rawY=0;
float Gyr_rawZ=0;     //Here we store the raw data read 

float Gyro_angle_x=0;
float Gyro_angle_y=0;         //Here we store the angle value obtained with Gyro data
float Gyro_raw_error_x=0;
float Gyro_raw_error_y=0; //Here we store the initial gyro data error
//Acc Variables

float rad_to_deg = 180/3.141592654;      //This value is for pasing from radians to degrees values
float Acc_rawX=0;
float Acc_rawY=0;
float Acc_rawZ=0;    //Here we store the raw data read 
float Acc_angle_x=0;
float Acc_angle_y=0;          //Here we store the angle value obtained with Acc data
float Acc_angle_error_x=0;
float Acc_angle_error_y=0; //Here we store the initial Acc data error


void setup()
{  
  Serial.begin(115200); // baudrate 115200 bits per second
  Serial.println("Init");

  Wire.setClock(400000l);    //increases I2C frequency to 400kHz
  Wire.begin();                           //begin the wire comunication  
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68)              
  Wire.write(0x6B);                       //make the reset (place a 0 into the 6B register)
  Wire.write(0x00);
  Wire.endTransmission(true);             //end the transmission
  //Gyro config
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68) 
  Wire.write(0x1B);                       //We want to write to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                       //Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);             //End the transmission with the gyro
  //Acc config
  Wire.beginTransmission(0x68);           //Start communication with the address found during search.
  Wire.write(0x1C);                       //We want to write to the ACCEL_CONFIG register
  Wire.write(0x10);                       //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true); 

  Wire.beginTransmission(0x68);
  Wire.write(0x1A);  // the config address
  Wire.write(0x06);  // the config value
  Wire.endTransmission(true);

for(int j=0; j<=samples; j++)
    {
      Wire.beginTransmission(0x68);
      Wire.write(0x3B);                       //Ask for the 0x3B register- correspond to AcX
      Wire.endTransmission(false);
      Wire.requestFrom(0x68,12,1); 
      
      Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ; //each value needs two registres
      Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;
      temperature=Wire.read()<<8|Wire.read(); 
      Gyr_rawX=Wire.read()<<8|Wire.read();     //Once again we shif and sum
      Gyr_rawY=Wire.read()<<8|Wire.read();

       // Sum 
      Acc_angle_error_x = Acc_angle_error_x + ((atan((Acc_rawY)/sqrt(pow((Acc_rawX),2) + pow((Acc_rawZ),2)))*rad_to_deg));
      Acc_angle_error_y = Acc_angle_error_y + ((atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawZ),2)))*rad_to_deg)); 
      
      Gyro_raw_error_x = Gyro_raw_error_x + (Gyr_rawX/32.8); 
      Gyro_raw_error_y = Gyro_raw_error_y + (Gyr_rawY/32.8);      

    }  
// Average
Acc_angle_error_x = Acc_angle_error_x/samples;
Acc_angle_error_y = Acc_angle_error_y/samples;
Gyro_raw_error_x = Gyro_raw_error_x/samples;
Gyro_raw_error_y = Gyro_raw_error_y/samples;        

// Debugger
Serial.print("Acc_angle_error_x: ");
Serial.println(Acc_angle_error_x);
Serial.print("Acc_angle_error_y: ");
Serial.println(Acc_angle_error_y);
Serial.print("Gyro_raw_error_x: ");
Serial.println(Gyro_raw_error_x);
Serial.print("Gyro_raw_error_y: ");
Serial.println(Gyro_raw_error_y);
     
}//end of setup void



void loop()
{

}

InitVariables.jpg

Except to suggest that you compare the raw data coming out of the X and Y gyro axes during calibration, for each host processor, I’m out of ideas. Strange problem, that it seems to affect only one axis!

Coming back to this, though, if the 3.3V voltage on the Due is even slightly lower than on the Mega, that could make a critical difference. If the module has a regulator, try powering it with 5V while connected to the Due (separate power supply, grounds connected of course).

So I think the problem is not voltage because I used 3V3 and Arduino Mega it works, but on Due The result is different.

It's ok. Module MPU6050 works 5 volts / 3V3 .... but if I powering module 5V it can damage I2C pins of Due, or not ?

Arduino Due I2C pins works only 3V3, I'm afraid to try it.

If the module has a regulator, try powering it with 5V

if I powering module 5V it can damage I2C pins of Due, or not

It should not. The regulator functions to supply 3.3V power to the MPU6050.

As I indicated before, if the regulator is powered by 3.3V input, the voltage applied to the MPU6050 will be too low for for proper operation.

It is best to remove the regulator if you are using the module with the Due. I use a solder pencil to "swipe" them off.

If you really want to solve this problem, use a MUCH better IMU module, like this one, which is designed to operate properly on any voltage between 2.5 and 5.0.

Print the raw values, that way you can be certain whether the problem is with the data you're getting from the MPU6050.

If they are the same, then the math would be behaving differently, and you could write a sketch with constant values, and get different results - then pull intermediate calculations out and print the results until you found which operation was giving different results.

This is weird - if the MPU6050 is not giving the same values for the X axis, it is strange indeed that it is giving the same values for the other axes, this seems unlikely. But so does getting different results for mathematical operations, even all those trig functions - floats are different size on the due vs mega, but that alone doesn't explain this, and I think we would know if one of the math functions was straight up broken. Neither possible explanation seems particularly plausible - but instead of trying to fix problems with the the voltage supplied to the MPU6050, we should perform the simple test of confirming that we are indeed getting a different value back from it, and see what exactly that different value is!

@DrAzzy I print the raw values. See that are not same.

Arduino Due

Gyr_rawX 65284.00
Gyr_rawY 109.00
Gyr_rawX 65298.00
Gyr_rawY 109.00
Gyr_rawX 65312.00
Gyr_rawY 108.00
Gyr_rawX 65321.00

Arduino Mega

Gyr_rawX -124.00
Gyr_rawY 96.00
Gyr_rawX -124.00
Gyr_rawY 96.00
Gyr_rawX -124.00
Gyr_rawY 96.00
Gyr_rawX -124.00
Gyr_rawY 95.00
Gyr_rawX -124.00

@jremington

I tried 5V. I used external power supply. I can't believe, same result here. Really really weird.

What about Due microcontrollers ? It's 32 bit, is it can be a size register probem ?

Arduino Mega (atmega 2560) is a 8 bit microcontroller.

@jremington

I tried 5 volts, but same response. I can't believe, it's really really weird.

What about Due microcontroller ? It's 32 bits.

Arduino mega there is Atmega 2560, it's a 8 bit microcontroller. Is it can be a size register problem ?

My project is something like this:

I wanna try Due cause frequency clock is better. He built his own arduino uno. I don't give up.

@DrAzzy I print the raw values. See that are not same.

The problem is clearly confusion over the default integer size on the Due versus the Mega. See reply #4.

This won’t work if the default integer size is 32 bits and the 16 bit raw value is signed and negative.

     Gyr_rawX=Wire.read()<<8|Wire.read();     //Once again we shif and sum

Instead, on the Due, try something like this (I don’t have a Due to test):

int16_t xh = Wire.read()<<8;
int16_t xl = Wire.read();
int16_t rawx = xh|xl;

@jremington

Makes sense. I did as you said using bitwise operator.

You rock, you’re a master of the bit. It works very well !!! Thank you so much.

Final code below.

#include <Wire.h>

int samples = 2000;
long temperature=0;

// Gyro Variables
float Gyr_rawX=0;
int16_t Gyr_rawX_L=0;
int16_t Gyr_rawX_H=0;

float Gyr_rawY=0;
int16_t Gyr_rawY_L=0;
int16_t Gyr_rawY_H=0;

int16_t Gyr_rawZ=0;     //Here we store the raw data read 

float Gyro_angle_x=0;
float Gyro_angle_y=0;         //Here we store the angle value obtained with Gyro data
float Gyro_raw_error_x=0;
float Gyro_raw_error_y=0; //Here we store the initial gyro data error
//Acc Variables

float rad_to_deg = 180/3.141592654;      //This value is for pasing from radians to degrees values
float Acc_rawX=0;
float Acc_rawY=0;
float Acc_rawZ=0;    //Here we store the raw data read 
float Acc_angle_x=0;
float Acc_angle_y=0;          //Here we store the angle value obtained with Acc data
float Acc_angle_error_x=0;
float Acc_angle_error_y=0; //Here we store the initial Acc data error


void setup()
{  
  Serial.begin(115200); // baudrate 115200 bits per second
  Serial.println("Init");

  Wire.setClock(400000l);    //increases I2C frequency to 400kHz
  Wire.begin();                           //begin the wire comunication  
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68)              
  Wire.write(0x6B);                       //make the reset (place a 0 into the 6B register)
  Wire.write(0x00);
  Wire.endTransmission(true);             //end the transmission
  //Gyro config
  Wire.beginTransmission(0x68);           //begin, Send the slave adress (in this case 68) 
  Wire.write(0x1B);                       //We want to write to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                       //Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);             //End the transmission with the gyro
  //Acc config
  Wire.beginTransmission(0x68);           //Start communication with the address found during search.
  Wire.write(0x1C);                       //We want to write to the ACCEL_CONFIG register
  Wire.write(0x10);                       //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true); 

  Wire.beginTransmission(0x68);
  Wire.write(0x1A);  // the config address
  Wire.write(0x06);  // the config value
  Wire.endTransmission(true);

for(int j=0; j<=samples; j++)
    {
      Wire.beginTransmission(0x68);
      Wire.write(0x3B);                       //Ask for the 0x3B register- correspond to AcX
      Wire.endTransmission(false);
      Wire.requestFrom(0x68,12,1); 

      
      Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;
      temperature=Wire.read()<<8|Wire.read(); 
 
      Gyr_rawX_L=Wire.read()<<8;     //Once again we shif and sum
      Gyr_rawX_H=Wire.read();
      Gyr_rawX = Gyr_rawX_H | Gyr_rawX_L;
          
      Gyr_rawY_L=Wire.read()<<8;
      Gyr_rawY_H=Wire.read();
      Gyr_rawY = Gyr_rawY_H | Gyr_rawY_L;      
      
       
       // Sum 
      Acc_angle_error_x = (double) Acc_angle_error_x + ((atan((Acc_rawY)/sqrt(pow((Acc_rawX),2) + pow((Acc_rawZ),2)))*rad_to_deg));
      Acc_angle_error_y = (double) Acc_angle_error_y + ((atan(-1*(Acc_rawX)/sqrt(pow((Acc_rawY),2) + pow((Acc_rawZ),2)))*rad_to_deg)); 
      
      Gyro_raw_error_x = (double) Gyro_raw_error_x + (Gyr_rawX/32.8); 
      Gyro_raw_error_y = (double) Gyro_raw_error_y + (Gyr_rawY/32.8);      

    }  
// Average
Acc_angle_error_x = (double) Acc_angle_error_x/samples;
Acc_angle_error_y = (double) Acc_angle_error_y/samples;
Gyro_raw_error_x = (double) Gyro_raw_error_x/samples;
Gyro_raw_error_y = (double) Gyro_raw_error_y/samples;        

// Debugger
Serial.print("Acc_angle_error_x: ");
Serial.println(Acc_angle_error_x);
Serial.print("Acc_angle_error_y: ");
Serial.println(Acc_angle_error_y);
Serial.print("Gyro_raw_error_x: ");
Serial.println(Gyro_raw_error_x);
Serial.print("Gyro_raw_error_y: ");
Serial.println(Gyro_raw_error_y);
     
}//end of setup void



void loop()
{

}

Glad that the fix worked!

On the Due, you will have the same problem with the accelerometer data, unless you fix these too:

      Acc_rawX=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawY=(Wire.read()<<8|Wire.read())/4096.0 ;
      Acc_rawZ=(Wire.read()<<8|Wire.read())/4096.0 ;