龙空技术网

Arduino 实例(四十一)MPU6050 测欧拉角(带卡尔曼滤波)

Snail先生 173

前言:

此时姐妹们对“卡尔曼滤波 arduino”可能比较注重,兄弟们都想要剖析一些“卡尔曼滤波 arduino”的相关知识。那么小编同时在网摘上搜集了一些有关“卡尔曼滤波 arduino””的相关资讯,希望你们能喜欢,姐妹们一起来了解一下吧!

1 连线图示

Arduino uno

MPU6050

5V端口

VCC

GND

GND

A5

SCL

A4

SDA

2 实物图片

3 程序

#include "Wire.h"#include "I2Cdev.h"#include "MPU6050.h" MPU6050 accelgyro;unsigned long time;unsigned long now, lastTime = 0;float dt;                                   //微分时间 int16_t ax, ay, az, gx, gy, gz;             //加速度计陀螺仪原始数据float aax=0, aay=0,aaz=0, agx=0, agy=0, agz=0;    //角度变量long axo = 0, ayo = 0, azo = 0;             //加速度计偏移量long gxo = 0, gyo = 0, gzo = 0;             //陀螺仪偏移量 float pi = 3.1415926;float AcceRatio = 16384.0;                  //加速度计比例系数float GyroRatio = 131.0;                    //陀螺仪比例系数 uint8_t n_sample = 8;                       //加速度计滤波算法采样个数float aaxs[8] = {0}, aays[8] = {0}, aazs[8] = {0};         //x,y轴采样队列long aax_sum, aay_sum,aaz_sum;                      //x,y轴采样和 float a_x[10]={0}, a_y[10]={0},a_z[10]={0} ,g_x[10]={0} ,g_y[10]={0},g_z[10]={0}; //加速度计协方差计算队列float Px=1, Rx, Kx, Sx, Vx, Qx;             //x轴卡尔曼变量float Py=1, Ry, Ky, Sy, Vy, Qy;             //y轴卡尔曼变量float Pz=1, Rz, Kz, Sz, Vz, Qz;             //z轴卡尔曼变量 const int MPU = 0x68; // MPU6050 I2C addressfloat AccX, AccY, AccZ;float GyroX, GyroY, GyroZ;float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;float roll, pitch, yaw;float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;float elapsedTime, currentTime, previousTime;int c = 0;int data1=0;void setup(){  time = millis();  Serial.begin(19200);    {      Serial.println();      Serial.print("please dont move ur mpu6050 in 5 secs");    }    Wire.begin();                      // Initialize comunication  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68  Wire.write(0x6B);                  // Talk to the register 6B  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register  Wire.endTransmission(true);        //end the transmission        accelgyro.initialize();                 //初始化     unsigned short times = 200;             //采样次数    for(int i=0;i<times;i++)    {        accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //读取六轴原始数值        axo += ax; ayo += ay; azo += az;      //采样和        gxo += gx; gyo += gy; gzo += gz;        }        axo /= times; ayo /= times; azo /= times; //计算加速度计偏移    gxo /= times; gyo /= times; gzo /= times; //计算陀螺仪偏移} void loop(){    float a;    float b;    time = millis();    unsigned long now = millis();             //当前时间(ms)    dt = (now - lastTime) / 1000.0;           //微分时间(s)    lastTime = now;                           //上一次采样时间(ms)     accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); //读取六轴原始数值     float accx = ax / AcceRatio;              //x轴加速度    float accy = ay / AcceRatio;              //y轴加速度    float accz = az / AcceRatio;              //z轴加速度     aax = atan(accy / accz) * (-180) / pi;    //y轴对于z轴的夹角    aay = atan(accx / accz) * 180 / pi;       //x轴对于z轴的夹角    aaz = atan(accz / accy) * 180 / pi;       //z轴对于y轴的夹角     aax_sum = 0;                              // 对于加速度计原始数据的滑动加权滤波算法    aay_sum = 0;    aaz_sum = 0;      for(int i=1;i<n_sample;i++)    {        aaxs[i-1] = aaxs[i];        aax_sum += aaxs[i] * i;        aays[i-1] = aays[i];        aay_sum += aays[i] * i;    }        aaxs[n_sample-1] = aax;    aax_sum += aax * n_sample;    aax = (aax_sum / (11*n_sample/2.0)) * 9 / 7.0; //角度调幅至0-90°    aays[n_sample-1] = aay;                        //此处应用实验法取得合适的系数    aay_sum += aay * n_sample;                     //本例系数为9/7    aay = (aay_sum / (11*n_sample/2.0)) * 9 / 7.0;     float gyrox = - (gx-gxo) / GyroRatio * dt; //x轴角速度    float gyroy = - (gy-gyo) / GyroRatio * dt; //y轴角速度    agx += gyrox;                             //x轴角速度积分    agy += gyroy;                             //x轴角速度积分    /* kalman start */    Sx = 0; Rx = 0;    Sy = 0; Ry = 0;    Sz = 0; Rz = 0;        for(int i=1;i<10;i++)    {                 //测量值平均值运算        a_x[i-1] = a_x[i];                      //即加速度平均值        Sx += a_x[i];        a_y[i-1] = a_y[i];        Sy += a_y[i];        }        a_x[9] = aax;    Sx += aax;    Sx /= 10;                                 //x轴加速度平均值    a_y[9] = aay;    Sy += aay;    Sy /= 10;                                 //y轴加速度平均值     for(int i=0;i<10;i++)    {        Rx += sq(a_x[i] - Sx);        Ry += sq(a_y[i] - Sy);        Rz += sq(a_z[i] - Sz);        }        Rx = Rx / 9;                              //得到方差    Ry = Ry / 9;                              Px = Px + 0.0025;                         // 0.0025在下面有说明...    Kx = Px / (Px + Rx);                      //计算卡尔曼增益    agx = agx + Kx * (aax - agx);             //陀螺仪角度与加速度计速度叠加    Px = (1 - Kx) * Px;                       //更新p值     Py = Py + 0.0025;    Ky = Py / (Py + Ry);    agy = agy + Ky * (aay - agy);     Py = (1 - Ky) * Py;  // === 读取加速度计数据 === //  Wire.beginTransmission(MPU);  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)  Wire.endTransmission(false);  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers  //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet  AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value  AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value  AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value  // Calculating Roll and Pitch from the accelerometer data  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)  // === 读取重力加速度计 === //  previousTime = currentTime;        // Previous time is stored before the actual time read  currentTime = millis();            // Current time actual time read  elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds  Wire.beginTransmission(MPU);  Wire.write(0x43); // Gyro data first register address 0x43  Wire.endTransmission(false);  Wire.requestFrom(MPU, 6, true);  GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;   GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;  GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;  GyroZ = GyroZ;  if (time<=3000){                      //获得第3秒的数据  yaw = yaw + GyroZ * elapsedTime;  a = yaw;  }  if (time<=2000){                     //获得第2秒的数据   b = yaw;  }  if (time>3000){  yaw = yaw + (GyroZ - (a-b)) * elapsedTime; //修正公式  Serial.print(agx,1);Serial.print("/");      //输出x轴数据  Serial.print(agy,1);Serial.print("/");      //输出y轴数据  Serial.println(yaw,1);                      //输出y轴数据  delay(50);  }  if (time>=2000, time<=3000){  Serial.print(a,5);  Serial.println(b,5);      //输出前3秒的数据  delay (5);  }  else{  }}//作者:MrPumpkinsss//代码前部分基于Techblog of HaoWANG修改的 >>> 

4 串口获取数据

标签: #卡尔曼滤波 arduino