MPU6050 drift

hey there
I've recently used MPU6050 Accelerometer/Gyroscope sensor to measure rotation angle. I've used complementary filters as explained here

but every time I turn on MPU6050, it has a -20degree offset! so for example at the beginning when I started reading the angles, it was ok(0 degrees) after a while it had -20degrees when was still and had no rotation. and yesterday, the offset was -40degrees(each time around -20degrees as I've said).
I don't know why this happens!
any help?

And dude, your link wants me to subscribe before I can read the thing.

I bet you did not read about how to do a programming question? It's a link you had to skip past to get to the point of posting.

Did you calibrate the MPU, each and every time the MPU is energized or reset?

That internet thingy search thingy on the words 'arduino mpu6050 calibration', may net a result or 2.


Also, do you actually think that a MPU6050 sitting on a table top is, actually, sitting still?

dear Idahowalker

Also, do you actually think that a MPU6050 sitting on a table top is, actually, sitting still?

yes, actually! or it isn't?

so here is a snippet code

float last_x_angle; //these are the filtered angle
float last_y_angle;
float last_z_angle;
float last_gyro_x_angle;//store gyro angle to compare drift
float last_gyro_y_angle;
float last_gyro_z_angle;

void set_last_read_angle_data(unsigned long time;float x, float y, float z, float x_gyro, float y_gyro, float z_gyro){
last_read_time=time;
last_x_angle=x;
last_y_angle=y;
last_z_angle=z;
last_gyro_x_angle=x_angle;
last_gyro_y_angle=y_angle;
last_gyro_z_angle=z_angle;	
}
inline unsigned long get_last_time(){return last_read_time}
inline float get_last_x_angle(){return last_x_angle;}
inline float get_last_y_angle(){return last_y_angle;}
inline float get_last_z_angle(){return last_z_angle;}
inline float get_last_gyro_x_angle(){return last_gyro_x_angle;}
inline float get_last_gyro_y_angle(){return last_gyro_y_angle;}
inline float get_last_gyro_z_angle(){return last_gyro_z_angle;}

GYRO_FACTOR=131.0;
const float RADIANS_TODEGREES=57.2958;//180/3.14159

set_last_read_angle_data(millis(),0,0,0,0,0,0);

t_last=t_now;
		TM_MPU6050_ReadAll(&MPU6050_Data0);//get Raw data of Accelerometer and Gyro
		t_now=millis();
		
		float gyro_x=(MPU6050_Data0.Gyroscope_X)/GYRO_FACTOR;
		float gyro_y=(MPU6050_Data0.Gyroscope_Y)/GYRO_FACTOR;
		float gyro_z=(MPU6050_Data0.Gyroscope_Z)/GYRO_FACTOR;
		
		float accel_x=MPU6050_Data0.Accelerometer_X;
		float accel_y=MPU6050_Data0.Accelerometer_Y;
		float accel_z=MPU6050_Data0.Accelerometer_Z;
		
		float accel_angle_y=atan(-1*accel_x/sqrt(pow(accel_y,2)+pow(accel_z,2)))*RADIANS_TODEGREES;
		float accel_angle_x=atan(accel_y/sqrt(pow(accel_x,2)+pow(accel_z,2)))*RADIANS_TODEGREES;
		float accel_angle_z=0; //Accelerometer doesn't give z-angle

    //compute the (filtered) gyro angles
		dt=(t_now-get_last_time())/1000.0;
		
		float gyro_angle_x=gyro_x*dt+get_last_x_angle();
		float gyro_angle_y=gyro_y*dt+get_last_y_angle();
		
		float gz_threshold1=0.2;//gyro z raw data fluctuation threshold value when gyro doesn't move. It is up to your MPU6050.
		float gz_threshold2=1.0;
		if(gyro_z<gz_threshold1 && gyro_z > -gz_threshold2)//when gyro stands ignore the gyro z small fluctuations to prevent z angle irregular 
			gyro_z=0;
		
		float gyro_angle_z=gyro_z*dt + get_last_z_angle();
		
		//Compute the drifting gyro angles
		float unfiltered_gyro_angle_x=gyro_x*dt + get_last_gyro_x_angle();
		float unfiltered_gyro_angle_y=gyro_y*dt + get_last_gyro_y_angle();
		float unfiltered_gyro_angle_z=gyro_z*dt + get_last_gyro_z_angle();
		
		//Apply the complimentary filter to figure out the change in angles-choice of alpha is 
		/*estimated now. Alpha depends on the sampling rate...*/
		const float alpha=0.96;
		float angle_x=alpha*gyro_angle_x + (1.0-alpha)*accel_angle_x;
		float angle_y=alpha*gyro_angle_y + (1.0-alpha)*accel_angle_y;
		float angle_z=gyro_angle_z; //Accelerometer doesn't give z-angle
		
		//Update the saved data with the latest value
		set_last_read_angle_data(t_now, angle_x, angle_y, angle_z, unfiltered_gyro_angle_x, unfiltered_gyro_angle_y, unfiltered_gyro_angle_z);

also, besides the offset, it is really slowww...

alaa72:
dear Idahowalker
yes, actually! or it isn't?

When you set the MPU on the table top what does accel Z axis read? Why?
Using all those floats, what is the MCU you are using? Using an Uno and lots of floatties, slow is to be expected.
Complementary filter, taken from my python code.
lastX = K * ( lastX + ( Gx * tDiff ) ) + ( K1 * AxRot )
lastY = K * lastY + ( Gy * tDiff ) ) + ( K1 * ayRot ) )

K = 0.93
K1 = 1 - K

I found K < .70 does a terrible job. You may find lowering the K to the lower 90's may give better results. Learn to use the graphing display in monitor to observe the oscillations and tune K to get the range of oscillations you want

I compute tDiff using microSeconds instead of milliSeconds, otherwise I get 0's for time. 0's in a multiplication result in 0's. Using a Complementary or a Kalman (GitHub - denyssene/SimpleKalmanFilter: A basic implementation of Kalman Filter for single variable models. filter requires an accurate time count.

For me calibration is 100 averaged readings with .1S between each reading, then doing the calibration math, storing the calibration data. I apply calibration data for accel during Ax, Ay, Az calculations:

preScaled = AxRaw
AxRaw = AxRaw/ACCEL_SCALE
Ax = (prescaled * AX_OFFSET )

I do not apply gyro offsets before calculating the scaled reading. Apply gyro offsets one step before the filter: Gx += ( GX_OFFSET - X_Rotation_Offest )

Most people determine the gyro offsets every time at startup, by averaging several hundred raw measurements taken while the sensor is held still.

After startup, subtract the average offsets from the raw readings, then apply scale factors. Yaw angles will always be relative to the starting sensor orientation.

Because gyro offsets are temperature and time dependent, the IMU output will still drift, but much more slowly.

hey guys!
it worked!

First: I've accidently put the configuration part in the loop, so it took a lot of time to process this config part every time.
Second: I set K=0.69! and this responded around 1-2sec! whereas K=0.96(which is recommended) responds within 10sec!

that was my experience! and thanks all for sharing their great help!