找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 10165|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

MPU6050姿態(tài)解算方法分析與Arduino連接串口6050模塊的代碼分享

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:90084 發(fā)表于 2015-9-15 01:32 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
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)
數(shù)據(jù)內(nèi)容
含義
0
0x55
包頭
1
0x51
標(biāo)識(shí)這個(gè)包是加速度包
2
AxL
X軸加速度低字節(jié)
3
AxH
X軸加速度高字節(jié)
4
AyL
y軸加速度低字節(jié)
5
AyH
y軸加速度高字節(jié)
6
AzL
z軸加速度低字節(jié)
7
AzH
z軸加速度高字節(jié)
8
TL
溫度低字節(jié)
9
TH
溫度高字節(jié)
10
Sum
校驗(yàn)和
角速度輸出:
數(shù)據(jù)編號(hào)
數(shù)據(jù)內(nèi)容
含義
0
0x55
包頭
1
0x52
標(biāo)識(shí)這個(gè)包是角速度包
2
wxL
X軸角速度低字節(jié)
3
wxH
X軸加速度高字節(jié)
4
wyL
y軸加速度低字節(jié)
5
wyH
y軸加速度高字節(jié)
6
wzL
z軸加速度低字節(jié)
7
wzH
z軸加速度高字節(jié)
8
TL
溫度低字節(jié)
9
TH
溫度高字節(jié)
10
Sum
校驗(yàn)和
角度輸出:
數(shù)據(jù)編號(hào)
數(shù)據(jù)內(nèi)容
含義
0
0x55
包頭
1
0x53
標(biāo)識(shí)這個(gè)包是角度包
2
RollL
X軸角度低字節(jié)
3
RollH
X軸角度高字節(jié)
4
PitchL
y軸角度低字節(jié)
5
PitchH
y軸角度高字節(jié)
6
YawL
z軸角度低字節(jié)
7
YawH
z軸角度高字節(jié)
8
TL
溫度低字節(jié)
9
TH
溫度高字節(jié)
10
Sum
校驗(yàn)和

現(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

1.23 KB, 下載次數(shù): 45, 下載積分: 黑幣 -5

MPU6050資料V4.zip

4.28 MB, 下載次數(shù): 35, 下載積分: 黑幣 -5

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:810428 發(fā)表于 2020-8-2 10:01 | 只看該作者
為什么我arduino的顯示上傳出錯(cuò)
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表