Arduino讀取MPU6050陀螺儀數據——卡爾曼濾波算法實踐

01 簡介:Why MPU6050?

MPU 6050等IMU傳感器用於自平衡機器人,無人機,智能手機等。IMU傳感器幫助我們在三維空間中獲得連接到傳感器的物體的位置。這些值通常是角度,以幫助我們確定其位置。它們用於檢測智能手機的方向,或者用於Fitbit等可穿戴設備,它使用IMU傳感器跟蹤運動。

MPU6050 它是全球首例整合性 6 軸運動處理組件,俗稱的六軸陀螺儀x y z 三軸的傾斜角度三軸方向的加速度)。它集成了陀螺儀和加速度計於一體的芯片,它極大程度上免除了獨立使用的陀螺儀和加速度計在時間上的誤差,而且減少了佔用 PCB 板的空間。(圖1 爲實物圖)

MPU6050具體參數:

MPU-60X0 對陀螺儀和加速度計分別用了三個 16 位的 ADC將其測量的模擬量轉化爲可輸出的數字量。爲了精確跟蹤快速和慢速的運動,傳感器的測量範圍都是用戶可控的,陀螺儀可測範圍爲±250,±500,±1000,±2000°/秒(dps),加速度計可測範圍爲±2,±4,±8,±16g。 一個片上 1024 字節的 FIFO,有助於降低系統功耗。和所有設備寄存器之間的通信採用400kHzI2C接口1MHz的SPI接口(SPI 僅 MPU-6000 可用)。對於需要高速傳輸的應用,對寄存器的讀取和中斷可用 20MHz 的 SPI。另外,片上還內嵌了一個溫度傳感器和在工作環境下僅有±1%變動的振盪器。 芯片尺寸 4×4×0.9mm,採用 QFN 封裝(無引線方形封裝),可承受最大 10000g 的衝擊,並有可編程的低通濾波器。 關於電源,MPU-60X0 可支持 VDD範圍 2.5V±5%3.0V±5%,或 3.3V±5%。另外 MPU-6050 還有一個 VLOGIC 引腳,用來爲 I2C 輸出提供邏輯電平。VLOGIC 電壓可取 1.8±5%或者 VDD。(圖 2 爲 MPU6050 三軸示意圖。)
 

MPU6050作爲價格低廉、功能強大、開源的硬件,其廣泛應用於通用場景的移動嵌入書開發,諸如四軸無人機,平衡車,機器人等作品, 以智能平衡小車爲例,其融合了 Z 軸和 Y 軸夾角實現小車平衡。 

電路原理圖

MPU6050 模塊內部自帶穩壓電路,可兼容 3.3V/5V 的供電電壓,採用先進的數字濾波技術,提高精度同時抑制了測量噪聲。通訊方面,MPU6050 保留了 IIC 接口,高級用戶能夠採樣底層測量數據。值得一提的是,芯片集成了 DMP (Digital Motion Processor數字動態處理器(以後會用到,實現平衡小車姿體平衡)從陀螺儀、加速度計以及外接的傳感器接收並處理數據,處理結果可以從 DMP 寄存器讀出,或通過 FIFO(First In First Out) 緩衝。圖4爲模塊的原理圖,圖5爲Arduino連接原理圖。

IMU工作原理

IMU傳感器通常由兩個或多個部件組成。按優先級列出它們,它們是加速度計,陀螺儀,磁力計和高度計。MPU 6050是6 DOF(自由度)或六軸IMU傳感器,這意味着它提供六個值作爲輸出:來自加速度計的三個值來自陀螺儀的三個值。MPU 6050是基於MEMS(微機電系統)技術的傳感器。加速度計和陀螺儀都嵌入在單個芯片內。該芯片使用I2C(內部集成電路)I2C (inter-integrated circuit) 協議進行通信

一個加速度計適用於壓電效應原理。想象一個立方體盒子,裏面有一個小球,如上圖所示。這個盒子的牆壁是用壓電晶體制成的。每當您傾斜盒子時,球都會因重力而沿傾斜方向移動。球碰撞的壁產生微小的壓電電流。長方體中有三對相對的牆。每對對應於3D空間中的軸:X,Y和Z軸。根據壓電壁產生的電流,我們可以確定傾斜方向及其大小。

 

連接到Arduino

MPU 6050通過I2C協議與Arduino通信。MPU 6050連接到Arduino,如下圖所示。如果MPU 6050模塊具有5V引腳,則可以將其連接到Arduino的5V引腳。如果沒有,則必須將其連接到3.3V引腳。接下來,Arduino的GND連接到MPU 6050的GND。

                                     Arduino MPU 6050連接圖

我們將在這裏運行的程序也利用了Arduino的中斷引腳。將Arduino的數字引腳2(中斷引腳0)連接到MPU 6050上標記爲INT的引腳。

接下來,我們需要設置I2C線路。爲此,將MPU 6050上標有SDA的引腳連接到Arduino的模擬引腳4(SDA),將MPU 6050上標記爲SCL的引腳連接到Arduino的模擬引腳5(SCL)。至此,已完成了Arduino MPU 6050的接線。

  • 要測試Arduino MPU 6050,首先要下載由Jeff Rowberg開發的MPU 6050的Arduino library- >>>>>here
  • Arduino與6050之間的通信I2C (inter-integrated circuit) 協議進行通信,加載IIC通信協議庫文件- >>>>>here.

02 卡爾曼濾波

 

濾波原理

 

讀取MPU6050數據

 

 

分析:

代碼:

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"

MPU6050 accelgyro;

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軸卡爾曼變量

void setup()
{
    Wire.begin();
    Serial.begin(115200);

    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()
{
    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;
        aazs[i-1] = aazs[i];
        aaz_sum += aazs[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;
    aazs[n_sample-1] = aaz; 
    aaz_sum += aaz * n_sample;
    aaz = (aaz_sum / (11*n_sample/2.0)) * 9 / 7.0;

    float gyrox = - (gx-gxo) / GyroRatio * dt; //x軸角速度
    float gyroy = - (gy-gyo) / GyroRatio * dt; //y軸角速度
    float gyroz = - (gz-gzo) / GyroRatio * dt; //z軸角速度
    agx += gyrox;                             //x軸角速度積分
    agy += gyroy;                             //x軸角速度積分
    agz += gyroz;
    
    /* 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_z[i-1] = a_z[i];
        Sz += a_z[i];
    
    }
    
    a_x[9] = aax;
    Sx += aax;
    Sx /= 10;                                 //x軸加速度平均值
    a_y[9] = aay;
    Sy += aay;
    Sy /= 10;                                 //y軸加速度平均值
    a_z[9] = aaz;
    Sz += aaz;
    Sz /= 10;

    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;                        
    Rz = Rz / 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;
  
    Pz = Pz + 0.0025;
    Kz = Pz / (Pz + Rz);
    agz = agz + Kz * (aaz - agz); 
    Pz = (1 - Kz) * Pz;

    /* kalman end */

    Serial.print(agx);Serial.print(",");
    Serial.print(agy);Serial.print(",");
    Serial.print(agz);Serial.println();
    
}
© 2019 GitHub, Inc.

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章