Hello, I am using MPU 5060 IMU to find the roll angle (x direction) by implementing Complementary filter. I have included calibration for accelomter abd gyro but When I run my code , it works but doesn’t feel right, the angle as I rotates starts to drift then starting to stable after few seconds.and using goniometer there is a about 9 degrees difference .
Can you explain why this happens and what could be the solution to make it accurate ?
Thanks
Code:
#include <Wire.h>
float Ax, Ay, Az; // Accelerometer readings
float KneeAngleA, TwistAngleA; // Angles calculated from accelerometer
float GyroX, GyroY, GyroZ; // Gyroscope readings
float AngularX, AngularY, AngularZ; // Angular velocities
float CalibrationX, CalibrationY, CalibrationZ; // Gyroscope calibration values
int CalibrationValue; // calibration average
uint32_t Duration; // Duration since start
const float alpha = 0.89; // Complementary filter weight
const long T = 10; // Sample time in microseconds
float Theta; // Angle
void Config() {
// I2C communication and Low Pass Filter
Wire.beginTransmission(0x68);
Wire.write(0x1A);
Wire.write(0x05);
Wire.endTransmission();
// Accelerometer Data Output
Wire.beginTransmission(0x68);
Wire.write(0x1C);
Wire.write(0x10);
Wire.endTransmission();
// Accelerometer Measurements Output
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
// Sensitivity of the Accelerometer
Wire.requestFrom(0x68, 6);
int16_t AxLSB = Wire.read() << 8 | Wire.read();
int16_t AyLSB = Wire.read() << 8 | Wire.read();
int16_t AzLSB = Wire.read() << 8 | Wire.read();
// Gyroscope Measurements Output
Wire.beginTransmission(0x68);
Wire.write(0x43);
Wire.endTransmission();
Wire.requestFrom(0x68, 6);
int16_t GyroX = Wire.read() << 8 | Wire.read();
int16_t GyroY = Wire.read() << 8 | Wire.read();
int16_t GyroZ = Wire.read() << 8 | Wire.read();
// Converting the Accelerometer Measurements to m/s^2
Ax = ((float)AxLSB / 4096 + 0.03) * 9.81; // Convert from g to m/s^2
Ay = (float)AyLSB / 4096 * 9.81; // Convert from g to m/s^2
Az = ((float)AzLSB / 4096 - 0.02) * 9.81; // Convert from g to m/s^2
// Convert Gyroscope Measurements to radians/s
AngularX = ((float)GyroX / 65.5) * (PI / 180); // Convert from degrees/s to radians/s
AngularY = ((float)GyroY / 65.5) * (PI / 180); // Convert from degrees/s to radians/s
AngularZ = ((float)GyroZ / 65.5) * (PI / 180); // Convert from degrees/s to radians/s
// Calculate the Angle from Accelerometer
KneeAngleA = atan(Ay / sqrt(Ax * Ax + Az * Az)) * (180 / PI); // Convert from radians to degrees
TwistAngleA = -atan(Ax / sqrt(Ay * Ay + Az * Az)) * (180 / PI); // Convert from radians to degrees
}
void setup() {
Serial.begin(57600);
Wire.setClock(400000);
Wire.begin();
delay(200);
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
for (CalibrationValue = 0; CalibrationValue < 3000; CalibrationValue++) {
Config();
CalibrationX += AngularX;
CalibrationY += AngularY;
CalibrationZ += AngularZ;
delayMicroseconds(500);
}
CalibrationX /= 3000;
CalibrationY /= 3000;
CalibrationZ /= 3000;
Duration = micros();
}
void loop() {
Config();
AngularX -= CalibrationX;
AngularY -= CalibrationY;
AngularZ -= CalibrationZ;
// Complementary filter to calculate The Angle
Theta = alpha * (Theta + T * AngularX) + (1 - alpha) * KneeAngleA;
Serial.print("Theta [°]= ");
Serial.println((int)Theta); // Convert to integer for printing
delay(90);
}