|
MPU6050模塊是InvenSense公司推出的一款低成本的6軸傳感器模塊,包括三軸加速度,三軸角速度。其體積小巧,用途非常廣。做平衡小車(chē),四軸飛行器,飛行鼠標(biāo)等等,都是必不可少而且是最優(yōu)的傳感器解決方案。本人根據(jù)自己的一些實(shí)際工作經(jīng)驗(yàn)和使用體會(huì)來(lái)談?wù)凪PU6050的相關(guān)問(wèn)題吧,拋磚引玉,如有不當(dāng)之處,歡迎大家批評(píng)指正。
不論是做平衡還是四軸飛行器,關(guān)鍵的問(wèn)題在于兩方面,一是模塊姿態(tài)的確定,通常需要用到積分運(yùn)算與卡爾曼濾波算法,需要較強(qiáng)的數(shù)學(xué)功底與編程能力,二是穩(wěn)定控制,方法比較單一,就是經(jīng)典的PID控制算法,難點(diǎn)在于需要根據(jù)實(shí)際情況調(diào)整PID的參數(shù),需要做實(shí)驗(yàn)確定,不難,只是費(fèi)時(shí)間。因此以下主要分析姿態(tài)確定問(wèn)題。
雖然6050模塊能夠輸出三軸加速度和三軸角速度的數(shù)據(jù),但實(shí)際應(yīng)用的時(shí)候,直接使用的確不是這些量,而是需要根據(jù)這些數(shù)據(jù)解算出三軸的角度數(shù)據(jù)。比如平衡小車(chē),需要算出
模塊的俯仰角,然后控制算法根據(jù)角度大小控制小車(chē)輪子的移動(dòng)。四軸飛行器需要根據(jù)俯仰角度、滾轉(zhuǎn)角度,和飛行指令來(lái)調(diào)節(jié)四個(gè)電機(jī)的轉(zhuǎn)速。
從6軸的原始數(shù)據(jù)得到三軸的角度計(jì)算是一個(gè)比較復(fù)雜的運(yùn)動(dòng)學(xué)解算過(guò)程,有的童鞋可能會(huì)說(shuō),不就是三軸角速度積分不就行了嗎?這就是沒(méi)有實(shí)踐,想當(dāng)然的說(shuō)法。有三點(diǎn)需要注意的問(wèn)題:
1.三軸姿態(tài)的解算不能直接積分。因?yàn)槿S是有耦合的,只有在三軸角度為小角度的時(shí)候可以這么算,角度大了以后,比如60度了,這么算的誤差就很大。標(biāo)準(zhǔn)的做法是用四元數(shù)的方法做姿態(tài)解算,積分的方法可以用4階龍格-庫(kù)塔法,或者4階Gill法。詳情請(qǐng)參考:航空航天器運(yùn)動(dòng)的建!w行動(dòng)力學(xué)的理論基礎(chǔ) 肖業(yè)倫著 北京航空航天大學(xué)出版社。
2.積分運(yùn)算的累積誤差。角速度積分運(yùn)算是有累積誤差的,累積誤差在短時(shí)間內(nèi)表現(xiàn)不明顯,只要零點(diǎn)漂移處理得好了,1分鐘以?xún)?nèi)的漂移都不大,但時(shí)間長(zhǎng)了,就會(huì)有累積誤差,5分鐘就漂到不知道哪里去了。
3.角速率零點(diǎn)漂移。所謂零點(diǎn)漂移就是模塊靜止的時(shí)候,我們認(rèn)為正常的輸出應(yīng)該是0,或者均值為0的數(shù)據(jù),但是實(shí)際上6050的輸出不是,可能在2°/s或者其他,而且每次都不一樣,如果不校準(zhǔn),別說(shuō)1分鐘了,10秒鐘誤差就有20度。
根據(jù)上面的分析,似乎要獲得角度非常困難呀。又有些聰明的朋友會(huì)想,用角速率積分這么麻煩,我不怎么算好了,條條大路通羅馬,為啥非得用這個(gè)方法。6050不是能輸出加速度嗎?我用重力在3軸的分量的反正切值,作為滾轉(zhuǎn)角和俯仰角不久行了。
用加速度計(jì)算的確也是一種方法,但使用加速度也有三方面的問(wèn)題:
1.無(wú)法在動(dòng)態(tài)情況下使用,使用重力的來(lái)解算姿態(tài)的前提條件是模塊本身沒(méi)有加速度,因此模塊輸出的三軸加速度值,正好是重力在模塊本體坐標(biāo)系下的分量,從而能夠求出俯仰和滾轉(zhuǎn)的姿態(tài)角度。一旦模塊運(yùn)動(dòng)起來(lái),這種方法就傻了,因?yàn)槟K無(wú)法分辨出哪些是重力的分量,那些是模塊本身的加速度引起的。目前市面上很多傾角儀就是這種思路,但問(wèn)題就是沒(méi)法在動(dòng)態(tài)情況下使用,最簡(jiǎn)單的測(cè)試方法就是把模塊水平放置桌面上,緩慢運(yùn)動(dòng),發(fā)現(xiàn)X,Y軸的角度基本不變化,都在0度左右,一旦快速運(yùn)動(dòng)起來(lái),X,Y軸就顯示有很大的角度了。而實(shí)際上模塊一直水平,沒(méi)有變化。
2.精度差。6050模塊的加速度本身的精度不高,就算是在靜態(tài)情況下,角度測(cè)量的精度也只能到1°左右。
3.三軸耦合問(wèn)題。利用加速度求解姿態(tài)的時(shí)候,也會(huì)有三軸耦合的問(wèn)題,因?yàn)樽藨B(tài)表示與坐標(biāo)旋轉(zhuǎn)順序有關(guān),這樣只有一種一個(gè)軸能用反正切值計(jì)算,另一個(gè)軸不能用反正切值計(jì)算。
那么怎么才能得到高精度不漂移的三軸角度呢?陀螺儀精度高,但時(shí)間長(zhǎng)了會(huì)有漂移,加速度動(dòng)態(tài)精度差,但沒(méi)有長(zhǎng)期漂移。能否綜合利用陀螺儀和加速度計(jì)的特點(diǎn),優(yōu)勢(shì)互補(bǔ)獲得準(zhǔn)確的姿態(tài)角度呢?答案是肯定的,方法就是用卡爾曼濾波做數(shù)據(jù)融合。大致的思路是將模塊的姿態(tài)用四元素表示,作為系統(tǒng)的狀態(tài)量,模塊的姿態(tài)運(yùn)動(dòng)學(xué)方程作為濾波的狀態(tài)轉(zhuǎn)移方程,加速度信息作為濾波的觀察量信息,然后利用卡爾曼濾波的計(jì)算方法迭代計(jì)算更新,詳細(xì)的過(guò)程可以參考慣性導(dǎo)航方面的書(shū)籍。不過(guò)卡爾曼濾波算法比較復(fù)雜,需要用到矩陣運(yùn)算等等,數(shù)學(xué)功底和編程基礎(chǔ)要求都較高,不是初學(xué)者能夠快速掌握的。而且MPU6050模塊是IIC接口輸出的,也給初學(xué)者帶來(lái)了不少障礙與困難。
難道不會(huì)卡爾曼濾波,就不能做出高精度的東西了嗎?好在萬(wàn)能的淘寶上面,已經(jīng)有專(zhuān)業(yè)的團(tuán)隊(duì)已經(jīng)為我們處理好了這些問(wèn)題,已經(jīng)有成熟的高精度串口6050模塊面世了。模塊不僅能夠輸出6050原始的三軸加速度,三軸角速度信息,在模塊內(nèi)部還集成了高精度的卡爾曼濾波算法,輸出濾波融合以后的角度數(shù)據(jù),而且是串口接口的,能夠直接與計(jì)算機(jī)對(duì)接,查看數(shù)據(jù)。目前該串口6050模塊已經(jīng)量產(chǎn),大家可以以非常低廉的價(jià)格獲得此款模塊了,不用把時(shí)間和精力花在姿態(tài)的求解與計(jì)算上面了。大家可以集中精力解決產(chǎn)品的其他調(diào)試問(wèn)題。地址:
http://item點(diǎn)taobao點(diǎn)com/item.htm?id=19785706431
目前以及有網(wǎng)友用這款模塊配合arduino uno R3做出了平衡小車(chē),用料簡(jiǎn)單,效果很好。借用幾張圖:
平衡車(chē)靜態(tài)展示:

工作狀況展示,弱光拍攝,曝光時(shí)間長(zhǎng),得益于穩(wěn)定的控制效果,小車(chē)紋絲不動(dòng)。

以下再來(lái)說(shuō)是串口6050模塊如何連接arduino。
代碼分為兩個(gè)部分,一是中斷接收,當(dāng)收到6050串口發(fā)送過(guò)來(lái)的數(shù)據(jù)以后,找到數(shù)據(jù)頭,將數(shù)據(jù)放入數(shù)據(jù)緩沖區(qū)內(nèi)。二是數(shù)據(jù)解析與處理,將數(shù)據(jù)緩沖區(qū)的數(shù)據(jù)取出,解析成對(duì)應(yīng)的角速度,角速度和角度數(shù)據(jù)。
先看數(shù)據(jù)協(xié)議:
模塊發(fā)送每幀數(shù)據(jù)分為3個(gè)數(shù)據(jù)包,分別為加速度包,角速度包和角度包,3個(gè)數(shù)據(jù)包順序輸出。波特率115200時(shí)每隔10ms輸出1幀數(shù)據(jù),波特率9600時(shí)每隔50ms輸出一幀數(shù)據(jù)。
加速度輸出:
數(shù)據(jù)編號(hào) | | | | | | | | 標(biāo)識(shí)這個(gè)包是加速度包 | | | | | | | | | | | | | | | | | | | | | | | | | | | |
角速度輸出: 數(shù)據(jù)編號(hào) | | | | | | | | 標(biāo)識(shí)這個(gè)包是角速度包 | | | | | | | | | | | | | | | | | | | | | | | | | | | |
角度輸出:
現(xiàn)在開(kāi)始處理串口數(shù)據(jù):
ARDUINO 代碼復(fù)制打印下載
- /*
- This code is used for connecting arduino to serial mpu6050 module, and test in arduino uno R3 board.
- connect map:
- arduino mpu6050 module
- VCC 5v/3.3v
- TX RX<-0
- TX TX->1
- GND GND
- note:
- because arduino download and mpu6050 are using the same serial port, you need to un-connect 6050 module when you want to download program to arduino.
- Created 14 Nov 2013
- by Zhaowen
-
- serial mpu6050 module can be found in the link below:
- http://item.taobao.com/item.htm?id=19785706431
- */
- unsigned char Re_buf[11,counter=0;
- unsigned char sign=0;
- float a[3,w[3,angle[3,T;
- void setup() {
- // initialize serial:
- Serial.begin(115200);
- }
- void loop() {
- if(sign)
- {
- sign=0;
- if(Re_buf[0==0x55) //檢查幀頭
- {
- switch(Re_buf [1)
- {
- case 0x51:
- a[0 = (short(Re_buf [3<<8| Re_buf [2))/32768.0*16;
- a[1 = (short(Re_buf [5<<8| Re_buf [4))/32768.0*16;
- a[2 = (short(Re_buf [7<<8| Re_buf [6))/32768.0*16;
- T = (short(Re_buf [9<<8| Re_buf [8))/340.0+36.25;
- break;
- case 0x52:
- w[0 = (short(Re_buf [3<<8| Re_buf [2))/32768.0*2000;
- w[1 = (short(Re_buf [5<<8| Re_buf [4))/32768.0*2000;
- w[2 = (short(Re_buf [7<<8| Re_buf [6))/32768.0*2000;
- T = (short(Re_buf [9<<8| Re_buf [8))/340.0+36.25;
- break;
- case 0x53:
- angle[0 = (short(Re_buf [3<<8| Re_buf [2))/32768.0*180;
- angle[1 = (short(Re_buf [5<<8| Re_buf [4))/32768.0*180;
- angle[2 = (short(Re_buf [7<<8| Re_buf [6))/32768.0*180;
- T = (short(Re_buf [9<<8| Re_buf [8))/340.0+36.25;
- Serial.print("a:");
- Serial.print(a[0);Serial.print(" ");
- Serial.print(a[1);Serial.print(" ");
- Serial.print(a[2);Serial.print(" ");
- Serial.print("w:");
- Serial.print(w[0);Serial.print(" ");
- Serial.print(w[1);Serial.print(" ");
- Serial.print(a[2);Serial.print(" ");
- Serial.print("angle:");
- Serial.print(angle[0);Serial.print(" ");
- Serial.print(angle[1);Serial.print(" ");
- Serial.print(angle[2);Serial.print(" ");
- Serial.print("T:");
- Serial.println(T);
- break;
- }
- }
- }
- }
- void serialEvent() {
- while (Serial.available()) {
- //char inChar = (char)Serial.read(); Serial.print(inChar); //Output Original Data, use this code
- Re_buf[counter=(unsigned char)Serial.read();
- if(counter==0&&Re_buf[0!=0x55) return; //第0號(hào)數(shù)據(jù)不是幀頭
- counter++;
- if(counter==11) //接收到11個(gè)數(shù)據(jù)
- {
- counter=0; //重新賦值,準(zhǔn)備下一幀數(shù)據(jù)的接收
- sign=1;
- }
- }
- }
說(shuō)了這么半天,無(wú)圖無(wú)真相,斗膽上一個(gè)軟件效果圖:

串口打印效果:
|
-
-
Arduino-MPU6050.zip
2015-9-15 01:31 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
1.23 KB, 下載次數(shù): 45, 下載積分: 黑幣 -5
-
-
MPU6050資料V4.zip
2015-9-15 01:31 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
4.28 MB, 下載次數(shù): 35, 下載積分: 黑幣 -5
|