MPU6050 data reading issue on Arduino UNO

I'm using the mpu6050 to read the data from accel and gyros and use them together with a complementary filter to get roll, pitch and yaw. My problem is that the accel readings are wrong and I don't understand if the sensor is not working properly or something in my code is wrong. In standstill I have reasonable value but when I tilt my robot the gyros still gives me reasonable values whereas the accel value are always in the range [-1;1].

  • Robot standstill: aX: 0.06 - aY: 0.00 - aZ: 1.06 - gX: -0.11 - gY: 0.00 - gZ: -0.03 - Roll: -0.04 - Pitch: -0.00 - Yaw: -0.01
  • Tilt to the right: aX: 0.39 - aY: 0.92 - aZ: 1.12 - gX: 4.36 - gY: 0.73 - gZ: -1.35 - Roll: 8.29 - Pitch: 1.39 - Yaw: -2.62

As you can see the Accel readings remain in a range that's not correct. I hope to get some clarification.

Below the code:

#include <arduino.h>
#include <MPU6050.h>
#include <wire.h>
static double previousTime = 0;

struct accel_data{
  int16_t tmp_x = 0;
  int16_t tmp_y = 0;
  int16_t tmp_z = 0;
  int16_t ax = 0;
  int16_t ay = 0;
  int16_t az = 0;
};

struct gyros_data {
  int16_t gx = 0;
  int16_t gy = 0;
  int16_t gz = 0;
  int16_t tmp_x = 0;
  int16_t tmp_y = 0;
  int16_t tmp_z = 0;
};

struct accel_gyros{
  float gx = 0;
  float gy = 0;
  float gz = 0;
  float ax = 0;
  float ay = 0;
  float az = 0;
  float roll = 0;
  float pitch = 0;
  float yaw = 0;
};
class MPU6050_obj{
  public:
    accel_data a_data;
    gyros_data g_data;
    accel_gyros data;

    void calibration(const motor_setup&, accel_data& , gyros_data&, MPU6050&);
    void data_processing(const accel_data& ,const gyros_data&, accel_gyros&);
};
MPU6050_obj myMPU;
MPU6050 mpu_lib;
void setup() {
  Serial.begin(9600);
  Wire.begin();
  mpu_lib.initialize();
  myMPU.calibration(App_motor, myMPU.a_data, myMPU.g_data, mpu_lib);
}
void loop() {

  
  if(irrecv.decode(&results)){
    if(static_cast<button>(results.value) == button::unknown){
      Serial.println("Ignoring erroneous signal");
      irrecv.resume();
      return; 
    }
    switch (button_prs) {

      case button::three: //mpu
          myMPU.data_processing(myMPU.a_data, myMPU.g_data, myMPU.data);
      break;
       case button::five:
       //something
      break;
      default:
      break;
    }
      irrecv.resume();
  }

}
void MPU6050_obj::calibration(const motor_setup& App_motor, accel_data& a_data, gyros_data& g_data, MPU6050& mpu_lib){ //There are better ways to implement this fcn 

  int16_t accel_x, accel_y, accel_z, gyros_x, gyros_y, gyros_z;
  int n = 250, i = 0;
  // Set gyroscope sensitivity to ±250 dps (131) 
  mpu_lib.setFullScaleGyroRange(MPU6050_GYRO_FS_250); //I'm using ±250dps and ±2G because of my robot behaviour (small turns, flat ground mostly, no rapid accelerations)
  // Set accelerometer sensitivity to ±2 G (16384)
  mpu_lib.setFullScaleAccelRange(MPU6050_ACCEL_FS_4); 

  //reading_test();
  if(mpu_lib.testConnection() && App_motor.get_pin() == LOW){  //add this piece of code beacuse cal has to happen in standstill condition 
    for (i = 0; i < n ; i++){
      mpu_lib.getAcceleration(&accel_x, &accel_y, &accel_z);
      mpu_lib.getRotation(&gyros_x, &gyros_y, &gyros_z);
      a_data.tmp_x += accel_x;
      a_data.tmp_y += accel_y;
      a_data.tmp_z += accel_z;
      g_data.tmp_x += gyros_x;
      g_data.tmp_y += gyros_y;
      g_data.tmp_z += gyros_z;
      delay(10);
    }
    a_data.ax = a_data.tmp_x/n;
    a_data.ay = a_data.tmp_y/n;
    a_data.az = a_data.tmp_z/n;
    g_data.gx = g_data.tmp_x/n;
    g_data.gy = g_data.tmp_y/n;
    g_data.gz = g_data.tmp_z/n;
  }
  else Serial.print("MPU non identified");
}

void MPU6050_obj::data_processing(const accel_data& a_data ,const gyros_data& g_data, accel_gyros& data){

  int s_a = 16384, s_g = 131; //accelerometer/gyroscope sensitivity
  float alpha = 0.98;//weight factor
  float a_roll = 0, a_pitch = 0, g_roll = 0, g_pitch = 0, yaw = 0;
  unsigned long currentTime = micros();  
  float dt = (currentTime - previousTime) / 1000000.0;  // Calculate dt in seconds
  int16_t accel_x, accel_y, accel_z, gyros_x, gyros_y, gyros_z;
  previousTime = currentTime; //PreviousTime is defined as static

  //Start measurements
  mpu_lib.getAcceleration(&accel_x, &accel_y, &accel_z);
  mpu_lib.getRotation(&gyros_x, &gyros_y, &gyros_z);

  //Subtracting the bias (calculated in calibration function) and dividing by sensitivy in order to convert raw values to dps and gravitation force (G)
  data.ax = (static_cast<float>(accel_x) -  static_cast<float>(a_data.ax))/s_a;
  data.ay = (static_cast<float>(accel_y) -  static_cast<float>(a_data.ay))/s_a;
  data.az = (static_cast<float>(accel_z) -  static_cast<float>(a_data.az))/s_a;
  data.gx = ((static_cast<float>(gyros_x) -  static_cast<float>(g_data.gx))/s_g) * (PI / 180.0);  //rad/s
  data.gy = ((static_cast<float>(gyros_y) -  static_cast<float>(g_data.gy))/s_g) * (PI / 180.0);  //rad/s
  data.gz = ((static_cast<float>(gyros_z) -  static_cast<float>(g_data.gz))/s_g) * (PI / 180.0);

  //Calculating roll and pitch from accel readings
  a_roll = atan2(data.ay, sqrt(pow(data.ax, 2) + pow(data.az, 2)));
  a_pitch = atan2(-data.ax, sqrt(pow(data.ay, 2) + pow(data.az, 2))); 

  //Integrate gyroscope data for angular velocity
  yaw += data.gz * dt; 
  g_roll += data.gx * dt;
  g_pitch += data.gy * dt;

  // Complementary filter
  data.roll = alpha * g_roll + (1 - alpha) * a_roll;
  data.pitch = alpha * g_pitch + (1 - alpha) * a_pitch;
  data.yaw = yaw;

}

Logic level shifters are required when connecting 5V and 3.3V devices. These ones work well.

If the MPU6050 module has a built in 5V to 3.3V voltage regulator, power the module with 5V. The Arduino 3.3V output may not be sufficient.

whereas the accel value are always in the range [-1;1].

Those look fine. The units are g values (acceleration due to gravity). The code for many of the complementary filters you find on the web is just plain wrong. Avoid them and use a modern Mahony or Madgwick filter.

The standstill readings look ok. They don't add up to exactly 1.0, but no sensor is perfect.

The "tilt" readings I'm not sure about. They add up to significantly more than 1.0. Is the sensor stationary but tilted away from horizontal? Or is it moving, performing a turn that requires a tilt like a banked corner on a racetrack or a aircraft flying in a turn?

Regarding the tilt readings, the sensor is moving that's why the gyros data, specifically gx increases. My problem is that, as you can see the accel data remain low.
Also, if the sensor is stationary but tilted away from horizontal I have the gyros data low (range [-1;1], which should be ok since there is no variation of the angular velocity being the sensor stationary) but the accel data keep being low ([-1;1]) as if the sensor doesn't read a variation on the g-force due to the tilt on the x-axis.
So, I'd like to understand if it's me that I'm not processing correctly the data from the accel or the sensor is not fully functional?

Sorry, I have no idea what you are asking.

The gyro measures rate of rotation about each axis and the accelerometer reads total acceleration along each axis (including acceleration due to gravity).

Those quantities are best thought of as unrelated to each other, so it makes no sense to compare them in any way.

No, it isn't. From the data you posted originally, in the "tilt" example, the total acceleration is 1.5g. but for the "stationary" example it is 1.0~1.1g

What kind of figure were you expecting?

When the robot tilt I would expect the sensor to read a variation regarding the gyros data (which I have) but I also would expect a more significant variation in the accel data.
Also, if during the tilt I read these values:
Roll: 8.29 - Pitch: 1.39 - Yaw: -2.62
If I want to calculate these angles again keeping the robot stationary but tilted (supposing in the same position that gave me the previous readings) I would expect the gyros data to be low because stationary and the accel data to be higher (due to g-force depending on the tilt) which would lead to a roll value close to the one of the previous reading. Whereas what I read is :
roll: -0.16 - pitch: -0.0 - yaw: -0.06.

Am I wrong thinking that I should read values that, being stationary and tilted, should be close to the values that I read during the tilt itself?

Again, I ask you, what values are you expecting? If the sensor is stationary but tilted, the total acceleration remains 1.0g. If the sensor is moving and tilted because it is turning on a curve, then the total acceleration will be more than 1.0g because of the additional centripetal force.

But if my robot is stationary and tilted and I read these values:
roll: -0.16 - pitch: -0.0 - yaw: -0.06
Isn't it wrong? Because I would expect the roll to be closer to the previous value (Roll: 8.29), telling me that the sensor is still tilted?

It's a good question. I'm not sure what roll, pitch, use readings you should expect.

But I know that if you want to measure the angle of tilt of a stationary sensor, only the accelerometer values are needed.

And I agree with you. But my question is (and I apologize if I haven't been clear so far): if I keep the robot in a stationary but tilted position, the values of Euler angles (roll,pitch,yaw) should depend on the accel data (not on the gyros data being the robot stationary). So why do I read a value (roll angle) close to zero while I would expect it to be such that it makes me understand that my robot is tilted?

This is my question, hopefully better formulated (and I apologize if I haven't been clear so far): if I keep the robot in a stationary but tilted position, the values of Euler angles (roll,pitch,yaw) should depend on the accel data (not on the gyros data being the robot stationary). So why do I read a value (roll angle) close to zero while I would expect it to be such that it makes me understand that my robot is tilted?

I doubt the complementary filter is working correctly, and you don't need it or the gyro to measure tilt.

Follow this tutorial to measure pitch and roll tilt angles: How_to_Use_a_Three-Axis_Accelerometer_for_Tilt_Sensing-DFRobot

You cannot measure yaw using the MPU-6050 as that requires a horizon reference, for example a magnetometer.