Hi everyone. I'm recently trying to write a mahony filter for use with a MPU6050 + QMC5883L. at the moment (with some uncertainty) I have written a code to extrapolate the raw data of the sensors. then on the MPU6050 I average the bias to be subtracted and then through an algorithm on matlab I calibrate the QMC5883L sensor.
Now I'm wondering two things:
-
do you think the calibration of the MPU6050 is correct? I have doubts looking at the serial data based on how I rotate the sensor I have higher values ​​in some axes than 9.81 as an average. so I'm wondering if there already exists a file that correctly calibrates the mpu6050.
-
inserting the mahony filter, after having done the calibration correctly, what and how to fine-tune the filter? according to what criteria?
#include <Wire.h>
#include <math.h>
#define MPU6050_ADDRESS 0x68
#define MPU6050_REG_ACCEL_XOUT_H 0x3B
#define MPU6050_REG_GYRO_XOUT_H 0x43
#define QMC5883L_ADDRESS 0x0D
#define QMC5883L_REG_X_LSB 0x00
#define QMC5883L_REG_Y_LSB 0x02
#define QMC5883L_REG_Z_LSB 0x04
float accBiasX = 0, accBiasY = 0, accBiasZ = 0;
float gyroBiasX = 0, gyroBiasY = 0, gyroBiasZ = 0;
void setup() {
Wire.begin();
Serial.begin(115200);
pinMode(2, OUTPUT);
// Inizializza il MPU6050
Wire.beginTransmission(MPU6050_ADDRESS);
Wire.write(0x6B); // Power Management register
Wire.write(0); // Accendi il dispositivo (wakes up the MPU-6050)
Wire.endTransmission(true);
// Inizializza il sensore QMC5883L
Wire.beginTransmission(QMC5883L_ADDRESS);
Wire.write(0x09); // Registri di controllo
Wire.write(0x1D); // ModalitĂ continuativa con 50Hz
Wire.endTransmission();
// Calibra l'MPU6050
calibrateMPU6050();
// Lampeggia il buzzer due volte
}
void loop() {
int16_t accX, accY, accZ;
int16_t gyroX, gyroY, gyroZ;
int16_t magX, magY, magZ;
// Leggi i dati dell'accelerometro dal MPU6050
Wire.beginTransmission(MPU6050_ADDRESS);
Wire.write(MPU6050_REG_ACCEL_XOUT_H);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDRESS, 6);
if (Wire.available() >= 6) {
accX = Wire.read() << 8 | Wire.read();
accY = Wire.read() << 8 | Wire.read();
accZ = Wire.read() << 8 | Wire.read();
}
// Leggi i dati del giroscopio dal MPU6050
Wire.beginTransmission(MPU6050_ADDRESS);
Wire.write(MPU6050_REG_GYRO_XOUT_H);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDRESS, 6);
if (Wire.available() >= 6) {
gyroX = Wire.read() << 8 | Wire.read();
gyroY = Wire.read() << 8 | Wire.read();
gyroZ = Wire.read() << 8 | Wire.read();
}
// Leggi i dati del magnetometro dal QMC5883L
Wire.beginTransmission(QMC5883L_ADDRESS);
Wire.write(QMC5883L_REG_X_LSB);
Wire.endTransmission(false);
Wire.requestFrom(QMC5883L_ADDRESS, 6);
if (Wire.available() >= 6) {
magX = Wire.read() | (Wire.read() << 8);
magY = Wire.read() | (Wire.read() << 8);
magZ = Wire.read() | (Wire.read() << 8);
}
// Calibra e converte i dati dell'MPU6050
float accX_calibrated = ((float)accX - accBiasX) / 16384.0 * 9.81;
float accY_calibrated = ((float)accY - accBiasY) / 16384.0 * 9.81;
float accZ_calibrated = ((float)accZ - accBiasZ) / 16384.0 * 9.81;
float gyroX_calibrated = ((float)gyroX - gyroBiasX) / 131.0;
float gyroY_calibrated = ((float)gyroY - gyroBiasY) / 131.0;
float gyroZ_calibrated = ((float)gyroZ - gyroBiasZ) / 131.0;
// Creazione della stringa di output
char output[100]; // Assicurati che la dimensione sia sufficiente per contenere la stringa
sprintf(output, "&,%f,%f,%f,%f,%f,%f,%d,%d,%d$", accX_calibrated, accY_calibrated, accZ_calibrated, gyroX_calibrated, gyroY_calibrated, gyroZ_calibrated, magX, magY, magZ);
// Stampa la stringa su Serial
Serial.println(output);
delay(10); // Aggiorna ogni 10 ms
}
void calibrateMPU6050() {
unsigned long startTime = millis();
unsigned long duration = 11000; // Acquisizione dei dati per 5 secondi
long accX_sum = 0, accY_sum = 0, accZ_sum = 0;
long gyroX_sum = 0, gyroY_sum = 0, gyroZ_sum = 0;
int count = 0;
while (millis() - startTime < duration) {
int16_t accX, accY, accZ;
int16_t gyroX, gyroY, gyroZ;
// Leggi i dati dell'accelerometro dal MPU6050
Wire.beginTransmission(MPU6050_ADDRESS);
Wire.write(MPU6050_REG_ACCEL_XOUT_H);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDRESS, 6);
if (Wire.available() >= 6) {
accX = Wire.read() << 8 | Wire.read();
accY = Wire.read() << 8 | Wire.read();
accZ = Wire.read() << 8 | Wire.read();
accX_sum += accX;
accY_sum += accY;
accZ_sum += accZ;
}
// Leggi i dati del giroscopio dal MPU6050
Wire.beginTransmission(MPU6050_ADDRESS);
Wire.write(MPU6050_REG_GYRO_XOUT_H);
Wire.endTransmission(false);
Wire.requestFrom(MPU6050_ADDRESS, 6);
if (Wire.available() >= 6) {
gyroX = Wire.read() << 8 | Wire.read();
gyroY = Wire.read() << 8 | Wire.read();
gyroZ = Wire.read() << 8 | Wire.read();
gyroX_sum += gyroX;
gyroY_sum += gyroY;
gyroZ_sum += gyroZ;
}
count++;
delay(100); // Acquisisce i dati ogni 10 ms
}
// Calcola il bias error per l'accelerometro e il giroscopio
accBiasX = (float)accX_sum / count;
accBiasY = (float)accY_sum / count;
accBiasZ = ((float)accZ_sum / count) - 16384.0; // 16384 è il valore medio quando l'MPU6050 è fermo
gyroBiasX = (float)gyroX_sum / count;
gyroBiasY = (float)gyroY_sum / count;
gyroBiasZ = (float)gyroZ_sum / count;
for (int i = 0; i < 2; i++) {
digitalWrite(2, HIGH);
delay(100);
digitalWrite(2, LOW);
delay(100);
}
}