Calibrar MPU6050

Para que las medidas del MPU6050 sean totalmente precisas es necesario ajustar, realizar una calibración para ajustar los valores de offset. Para esto tenemos este programa, que nos proporciona los valores de offset de nuestro sensor. Es necesario ejecutarlo para cada MPU6050, ya que puede haber una gran variación de uno a otro.

Las librerías I2Cdev y MPU6050 deben estar instaladas.

#include «I2Cdev.h»
#include «MPU6050.h»
#include «Wire.h»

//////////////////////////////// CONFIGURACIÓN /////////////////////////////
///Cambia estas 3 variables para ajustar el programa a tus necesidades.

// Cantidad de lecturas utilizadas para promediar,  más alto para obtener más precisión, pero el programa será más lento (predeterminado: 1000)

int buffersize=1000;

// Error de acelerómetro permitido,  más bajo para obtener más precisión, pero es posible que el programa no converja (predeterminado: 8)

int acel_deadzone=8;

// Error de giro permitido,  más bajo para obtener más precisión, pero es posible que el boceto no converja (predeterminado: 1)

int giro_deadzone=1;

// la dirección por defecto de  I2C es 0x68
// si queremos pasar la dirección como parámetro
// AD0 low = 0x68
// AD0 high = 0x69

MPU6050 accelgyro(0x68);

int16_t ax, ay, az,gx, gy, gz;

int mean_ax,mean_ay,mean_az,mean_gx,mean_gy,mean_gz,state=0;
int ax_offset,ay_offset,az_offset,gx_offset,gy_offset,gz_offset;

/////////////////////////////////// SETUP ////////////////////////////////////
void setup() {
Wire.begin();
// COMMENT NEXT LINE IF YOU ARE USING ARDUINO DUE
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz). Leonardo measured 250kHz.

     // inicializamos comunicación serial
Serial.begin(115200);

    // inicializamos dispositivo
accelgyro.initialize();

// esperamos hasta que este preparado
while (Serial.available() && Serial.read()); // buffer vacío
while (!Serial.available()){
Serial.println(F(«Envia un caracter desde la consola serial»));
delay(1500);
}
while (Serial.available() && Serial.read()); // buffer vacío de nuevo

// mensajes de comienzo
Serial.println(«\nMPU6050 Programa de calibración»);
delay(2000);
Serial.println(«\nTu MPU6050 debe estar en posición horizontal,  \nNo lo toques hasta que veas un mensaje de finalización.\n»);
delay(3000);
// verifficar conexión
Serial.println(accelgyro.testConnection() ? «MPU6050 connection successful» : «MPU6050 connection failed»);
delay(1000);
// reset offsets
accelgyro.setXAccelOffset(0);
accelgyro.setYAccelOffset(0);
accelgyro.setZAccelOffset(0);
accelgyro.setXGyroOffset(0);
accelgyro.setYGyroOffset(0);
accelgyro.setZGyroOffset(0);
}

/////////////////////////////////// LOOP ////////////////////////////////////
void loop() {
if (state==0){
Serial.println(«\nLeyendo sensor por primera vez…»);
meansensors();
state++;
delay(1000);
}

if (state==1) {
Serial.println(«\nCalculando offsets…»);
calibration();
state++;
delay(1000);
}

if (state==2) {
meansensors();
Serial.println(«\nFINISHED!»);
Serial.print(«\nLeyendo sensor con offsets:\t»);
Serial.print(mean_ax);
Serial.print(«\t»);
Serial.print(mean_ay);
Serial.print(«\t»);
Serial.print(mean_az);
Serial.print(«\t»);
Serial.print(mean_gx);
Serial.print(«\t»);
Serial.print(mean_gy);
Serial.print(«\t»);
Serial.println(mean_gz);
Serial.print(«Tus  offsets:\t»);
Serial.print(ax_offset);
Serial.print(«\t»);
Serial.print(ay_offset);
Serial.print(«\t»);
Serial.print(az_offset);
Serial.print(«\t»);
Serial.print(gx_offset);
Serial.print(«\t»);
Serial.print(gy_offset);
Serial.print(«\t»);
Serial.println(gz_offset);
Serial.println(«\nDatos correspondes a: acelX acelY acelZ giroX giroY giroZ»);
Serial.println(«Check tu sensor leyendo  0 0 16384 0 0 0»);
Serial.println(«Si la calibración fue exitosa, anota tus compensaciones para que pueda sestablecerlas en tus proyectos usando algo similar a mpu.setXAccelOffset (youroffset)»);
while (1);
}
}

/////////////////////////////////// FUNCTIONS ////////////////////////////////////
void meansensors(){
long i=0,buff_ax=0,buff_ay=0,buff_az=0,buff_gx=0,buff_gy=0,buff_gz=0;

while (i<(buffersize+101)){
// read raw accel/gyro measurements from device
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

if (i>100 && i<=(buffersize+100)){ //First 100 measures are discarded
buff_ax=buff_ax+ax;
buff_ay=buff_ay+ay;
buff_az=buff_az+az;
buff_gx=buff_gx+gx;
buff_gy=buff_gy+gy;
buff_gz=buff_gz+gz;
}
if (i==(buffersize+100)){
mean_ax=buff_ax/buffersize;
mean_ay=buff_ay/buffersize;
mean_az=buff_az/buffersize;
mean_gx=buff_gx/buffersize;
mean_gy=buff_gy/buffersize;
mean_gz=buff_gz/buffersize;
}
i++;
delay(2); //Needed so we don’t get repeated measures
}
}

void calibration(){
ax_offset=-mean_ax/8;
ay_offset=-mean_ay/8;
az_offset=(16384-mean_az)/8;

gx_offset=-mean_gx/4;
gy_offset=-mean_gy/4;
gz_offset=-mean_gz/4;
while (1){
int ready=0;
accelgyro.setXAccelOffset(ax_offset);
accelgyro.setYAccelOffset(ay_offset);
accelgyro.setZAccelOffset(az_offset);

accelgyro.setXGyroOffset(gx_offset);
accelgyro.setYGyroOffset(gy_offset);
accelgyro.setZGyroOffset(gz_offset);

meansensors();
Serial.println(«…»);

if (abs(mean_ax)<=acel_deadzone) ready++;
else ax_offset=ax_offset-mean_ax/acel_deadzone;

if (abs(mean_ay)<=acel_deadzone) ready++;
else ay_offset=ay_offset-mean_ay/acel_deadzone;

if (abs(16384-mean_az)<=acel_deadzone) ready++;
else az_offset=az_offset+(16384-mean_az)/acel_deadzone;

if (abs(mean_gx)<=giro_deadzone) ready++;
else gx_offset=gx_offset-mean_gx/(giro_deadzone+1);

if (abs(mean_gy)<=giro_deadzone) ready++;
else gy_offset=gy_offset-mean_gy/(giro_deadzone+1);

if (abs(mean_gz)<=giro_deadzone) ready++;
else gz_offset=gz_offset-mean_gz/(giro_deadzone+1);

if (ready==6) break;
}
}

Mi resultado es:

01