毕业设计2- MPU6050传感器调试记录(STM32CubeMX+STM32F103C8T6)
文章目錄
- 一、前情提要
- 二、STM32CubeMX配置
- 三、寄存器介紹
- 四、Keil代碼介紹
- 總結(jié)
本次調(diào)試的傳感器是正點(diǎn)原子的MPU6050(三軸陀螺儀+三軸加速度)。因?yàn)槲业漠呍O(shè)中并不要求解算出歐拉角,只是用來反映風(fēng)電機(jī)組(demo)的振動(dòng)情況即可。為了簡化, 所以我只使用了三軸加速度計(jì),但是在這篇介紹中,采用了硬件I2C來讀取了硬件傳感器原始數(shù)據(jù),并對這些數(shù)據(jù)進(jìn)行了 卡爾曼濾波。
一、前情提要
這部分的問題是我在剛接觸這個(gè)傳感器的幾個(gè)問題,通過自己查閱資料有了個(gè)大致的了解。因此在這里想分享一下。感謝各位大佬們的分享,讓我不斷地可以學(xué)習(xí)。
我看了1個(gè)博客和1個(gè)小破站上的視頻,感覺博主和UP主講的很好
小破站視頻: https://www.bilibili.com/video/BV1sL411F7fu?spm_id_from=333.337.search-card.all.click
知乎博客: https://zhuanlan.zhihu.com/p/195683958
代碼參考視頻: https://www.bilibili.com/video/BV1qf4y1r73k?spm_id_from=333.337.search-card.all.click
這些問題也是我自己的理解,僅供參考,有不正確之處,歡迎大家指出,我的郵箱:2802433362@qq.com
1.你能解釋一下這種N軸IMU常見的一些概念嗎?
(1)笛卡爾坐標(biāo)系:
在下面實(shí)際中的這張圖好像跟上面的不太一樣啊,其實(shí)我們旋轉(zhuǎn)一下就好了,我說這個(gè)的目的是在姿態(tài)解算的時(shí)候,我們經(jīng)常會(huì)旋轉(zhuǎn)坐標(biāo)系,注意XYZ軸的位置關(guān)系千萬不要搞混了,有時(shí)候我自己也是多旋轉(zhuǎn)就亂了,所以可以借助右手坐標(biāo)系來幫助我們理解。
(2)歐拉角:我們常說的歐拉角指的是ROLL(橫滾角)、偏航角(Yaw)、俯仰角(Pitch)。具體的大家可以根據(jù)下面的模型來進(jìn)行理解。知乎博主“碼農(nóng)愛學(xué)習(xí)”寫的真的不錯(cuò),簡單易懂,很適合我們這種小白。“https://zhuanlan.zhihu.com/p/195683958”,我敢我再寫下去也是照搬人家的東西,博主概括的真的很全。
(3)四元素:他是表示旋轉(zhuǎn)的另一種方式,可以與歐拉角進(jìn)行轉(zhuǎn)化,具體的話可以參考CSDN的另外一個(gè)博主的文章:https://blog.csdn.net/xiaoma_bk/article/details/79082629
(4)陀螺儀傳感器:這個(gè)是涉及到很多物理方面的東西,我們可以簡單的認(rèn)為它可以X、Y、Z軸的角速度。
(5)加速度計(jì)傳感器:測量的是X、Y、Z的加速度。
(6)磁力計(jì)傳感器:測量的3軸磁場強(qiáng)度(這個(gè)目前我也不是很熟,后面要慢慢用起來的)
2. 我在網(wǎng)上查閱的資料看到有3軸、6軸、9軸、10軸傳感器你能解釋一下有什么區(qū)別嗎?
(1) 3軸傳感器是指3軸陀螺儀。 它測量的是3個(gè)軸(XYZ)的角速度,其實(shí)通過這三個(gè)數(shù)據(jù)也能進(jìn)行姿態(tài)解算得到三個(gè)歐拉角(俯仰角、橫滾角、偏航角),因此他也是可以獨(dú)立工作的,出現(xiàn)了市面上常見的3軸傳感器。但是這個(gè)傳感器存在的問題是:
(a)因?yàn)樗挠?jì)算方式的角度=角速度*dt,大家學(xué)過高數(shù)和大學(xué)物理,當(dāng)dt很小時(shí),我們可以把物體看成勻速運(yùn)動(dòng),但是這樣造成的問題是不太符合實(shí)際情況,我們只是假設(shè)這樣子,會(huì)有較大的累積誤差;
(b)之前看那個(gè)博主說,只使用3軸陀螺儀會(huì)出現(xiàn)相位差的問題(這部分我不是很懂,后面需要去補(bǔ)充一些知識)。
偉大的前輩們也知道這個(gè)問題,所以一個(gè)神奇的想法就產(chǎn)生了,能不能用兩個(gè)傳感器,相互校正一下,然后取個(gè)平均啥的(傳感器融合當(dāng)然沒這么簡單,此處只是舉個(gè)栗子),應(yīng)該能精確很多吧。但是從兩個(gè)角度來做效果應(yīng)該更好,因?yàn)樵偌右粋€(gè)3軸陀螺儀,就沒多大必要(此處我也不知道解釋比較好,就是那種本來這個(gè)誤差就大,換個(gè)角度去測量會(huì)更好,而不是疊羅漢。),于是6軸加速度就產(chǎn)生了。
(2)6軸傳感器是指3軸陀螺儀+3軸加速度計(jì)。 3軸加速度計(jì)測量的就是XYZ軸上的加速度g的一個(gè)分量。當(dāng)這個(gè)坐標(biāo)系很正的時(shí)候,三軸的數(shù)值應(yīng)該為aacx=0g、aacy=0g、aacz=1*g,其中9為重力加速度,9.8m/s2。當(dāng)這個(gè)傳感器有一個(gè)傾斜的話,g在x軸和y軸上就會(huì)有個(gè)分量,有可能就變成了aacx=0.3g、aacy=0.2g、aacz=0.7g,我們其實(shí)可以根據(jù)這些數(shù)據(jù)得到三個(gè)歐拉角,所有單獨(dú)用加速度計(jì)也可以進(jìn)行姿態(tài)結(jié)算,但是如果單獨(dú)用的話我們是無法解算出偏航的角的。可以參考下面的推導(dǎo)公式,我們通過傳感器得到的是ax、ay、az但是我們通過推導(dǎo)發(fā)現(xiàn)y沒了(p代表pitch俯仰角、r表示raw橫滾角、y表示yaw偏航角),數(shù)學(xué)就是這么神奇,哈哈,想不到吧,所以3軸加速度計(jì)只能解算出pitch角和raw角,所以6軸傳感器的yaw(偏航角會(huì)一直漂移),而pitch(俯仰角)和raw(橫滾角)通過數(shù)據(jù)融合算法可以得到較為穩(wěn)定的值。,目前常用的數(shù)據(jù)融合算法是DMP和卡爾曼濾波。卡爾曼濾波不得不說是一個(gè)很神奇的東西,此處強(qiáng)烈感謝卡爾曼前輩能研究出這么優(yōu)秀又通用的算法。
(3)9軸傳感器是指3軸陀螺儀+3軸加速度計(jì)+3軸磁力計(jì)。加3軸磁力計(jì)的目的大家可能可以猜到的啦,可以把偏航角也給校準(zhǔn)了,這樣可以得到較為穩(wěn)定的3個(gè)歐拉角(或者穩(wěn)定的四元組),具體的解算過程大家可以參考上面推薦的知乎博客,大佬寫的真的不錯(cuò),當(dāng)然小破站上的小哥哥的那個(gè)視頻講的也很清楚,再次感謝大佬們。我這次沒有選用類似MPU9250的9軸傳感器,一是因?yàn)槲也⒉恍枰M(jìn)行姿態(tài)計(jì)算,二是因?yàn)槲业恼麄€(gè)系統(tǒng)存在電機(jī)和鋼軸,會(huì)對磁力計(jì)的校準(zhǔn)影響很大,不能起到相應(yīng)的效果。因此大家在使用的時(shí)候應(yīng)該主要有磁場校準(zhǔn)影響的情況。
9軸傳感器不是已經(jīng)很完美了嗎?可以完全把姿態(tài)計(jì)算出來,10軸傳感器又是啥哩
(4)10軸傳感器是指3軸陀螺儀+3軸加速度計(jì)+3軸磁力計(jì)+1個(gè)氣壓計(jì),這個(gè)可以把氣壓高度計(jì)算出來,我認(rèn)為這個(gè)是錦上添花的作用。 ,當(dāng)然存在即是合理,自然有它的應(yīng)用場景。
3. 網(wǎng)上說的DMP算法和卡爾曼濾波你能簡要說一下他們是什么嗎?
(1)對于DMP算法:可以參考知乎博主“碼農(nóng)愛學(xué)習(xí)”的這篇文章:https://zhuanlan.zhihu.com/p/165156300
復(fù)制他的一段話:DMP就是MPU6050內(nèi)部的運(yùn)動(dòng)引擎,全稱Digital Motion Processor,直接輸出四元數(shù),可以減輕外圍微處理器的工作負(fù)擔(dān)且避免了繁瑣的濾波和數(shù)據(jù)融合。 就我們使用的諸如MPU6050、MPU9250等來說,DMP是硬件融合,就是商家已經(jīng)做了硬件的嵌入,我們只需要調(diào)用相應(yīng)的驅(qū)動(dòng)庫即可,這樣可以很方便的,具體的一些驅(qū)動(dòng)程序可以參考正點(diǎn)原子的驅(qū)動(dòng)程序。
(2)對于卡爾曼濾波算法: 利用加速度計(jì)采集的3軸加速度計(jì)進(jìn)行姿態(tài)融合成的pitch、roll作為觀測值, 利用陀螺儀采集的3軸角度值進(jìn)行的姿態(tài)融合成的pitch,yaw,raw作為測量值。所以利用卡爾曼濾波可以實(shí)現(xiàn)pitch(俯仰角)、roll(橫滾角)的穩(wěn)定輸出。
(3)下面還是引用知乎博主“碼農(nóng)愛學(xué)習(xí)”中的內(nèi)容:這部分其實(shí)反映的是卡爾曼濾波的思想,K其實(shí)指的是卡爾曼增益,這部分我們可以這樣理解:每個(gè)傳感器都可以進(jìn)行姿態(tài)解算,得到自己的三個(gè)歐拉角,而我們希望把這些融合(直接取平均的方式顯然太low)了。因?yàn)槊總€(gè)傳感器都有自己的優(yōu)缺點(diǎn),我們應(yīng)該把每個(gè)傳感器的優(yōu)點(diǎn)利用起來會(huì)使結(jié)果更加地準(zhǔn)確,因此前輩們提取了每個(gè)傳感器權(quán)重不同的方法來進(jìn)行融合,至于這個(gè)權(quán)重到底是多少,卡爾曼老先生在自己的論文中有明確的推導(dǎo)(卡爾曼濾波最經(jīng)典的那5個(gè)方程:2個(gè)預(yù)測方程,3個(gè)更新方程)。此處不再多做介紹,大家如果對卡爾曼濾波原理什么的想要有更深的了解,可以自行搜索,后面我也會(huì)自己出一期我自己對卡爾曼濾波的理解。
二、STM32CubeMX配置
有了上面的一些基礎(chǔ)概念和了解,我們下面開始配置STM32CubeMX
(1) 在“SYS”設(shè)置為“SW”調(diào)試模式;
(2)我們在“RCC”中選擇外部晶振模式;
(3) 因?yàn)镸PU6050采用的通信協(xié)議是I2C,而我們又想采用硬件I2C去開發(fā),所以必須進(jìn)行勾選。
(4)因?yàn)槲覀兿氚褦?shù)據(jù)打印到電腦的“串口調(diào)試助手”,所以我們需要開一路串口,波特率為115200;
(5)我們下面配置時(shí)鐘樹;
(6)將這個(gè)工程存放在文件夾中,整個(gè)目錄最好不要有中文,因?yàn)楹竺孀詣?dòng)生成代碼的時(shí)候并不能直接打開,不過問題也不大,需要自己去相關(guān)文件夾中的找到工程文件打開;
(7)我們勾選一下我們希望生成文件的配置。
到此為止,我們的配置就已經(jīng)完成了。
三、寄存器介紹
對于傳感器而言,寄存器是很重要的東西,所以我們想要使用一個(gè)傳感器,一定要清楚他的寄存器怎樣配置,數(shù)據(jù)存儲(chǔ)在哪個(gè)寄存器中
(其實(shí)我在學(xué)習(xí)的時(shí)候也不喜歡看手冊,但是咱們都是搞這個(gè)的,datasheet肯定要看的,后面我們能形成屬于自己的一套看datasheet的流程和經(jīng)驗(yàn),會(huì)很舒服的)。我這里只是介紹一下我再這次調(diào)試中用到的寄存器,具體的每一個(gè)比特位到底表示什么大家自己查手冊就好了。
四、Keil代碼介紹
這部分是參考小破站上的視頻講解:https://www.bilibili.com/video/BV1qf4y1r73k?spm_id_from=333.337.search-card.all.click(俺是妥妥自己搬運(yùn)工具人,同時(shí)加上自己的一點(diǎn)理解)。關(guān)于我們應(yīng)該對I2C通信有個(gè)簡單的了解吧(不了解的話,小破綻也有很多資源,我比較推薦的是創(chuàng)客學(xué)院的武老師的講解)。對于I2C設(shè)備,都有一個(gè)自己的設(shè)備地址,我們首先要做的知道設(shè)備地址。
(1)首先我們進(jìn)行多串口重映像,在“usart.h”文件中添加以下代碼;
#include "stdarg.h" #include "string.h" #include "stdio.h"(2)在“usart.c”文件中添加下面的代碼;
#define TXBUF_SIZE_MAX 100 void usart2_printf(const char *format, ...) {va_list args;uint32_t length;uint8_t txbuf[TXBUF_SIZE_MAX] = {0};va_start(args, format);length = vsnprintf((char *)txbuf, sizeof(txbuf), (char *)format, args);va_end(args);HAL_UART_Transmit(&huart2, (uint8_t *)txbuf, length, HAL_MAX_DELAY);memset(txbuf, 0, TXBUF_SIZE_MAX); }(3)對于類似樹莓派的Linux系統(tǒng)中我們可以通過I2C查詢的指令即可實(shí)現(xiàn),當(dāng)然,STM32也有相應(yīng)的程序可以查看:
for (uint8_t i=0; i<255;i++) {if(HAL_I2C_IsDeviceReady(&hi2c1, i ,1, 1000) == HAL_OK) //尋找設(shè)備地址,I2C原裝函數(shù) { usart2_printf("%d\r\n",i);break;}. }我們在串口中可以看到返回值,我返回的是208,轉(zhuǎn)換成16進(jìn)制數(shù)據(jù)為0xD0,所以我們的I2C設(shè)備地址為0xD0。
(4)下面我們在“main.c”文件中 添加宏定義:
(5)進(jìn)行MPU6050初始化,配置一些寄存器;
void MPU6050_Init(void ) {/*HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);第1個(gè)參數(shù)為I2C操作句柄第2個(gè)參數(shù)為從機(jī)設(shè)備地址第3個(gè)參數(shù)為從機(jī)寄存器地址第4個(gè)參數(shù)為從機(jī)寄存器地址長度第5個(gè)參數(shù)為發(fā)送的數(shù)據(jù)的起始地址第6個(gè)參數(shù)為傳輸數(shù)據(jù)的大小第7個(gè)參數(shù)為操作超時(shí)時(shí)間 */uint8_t check,Data;// check device ID WHO_AM_I//檢查設(shè)備ID HAL_I2C_Mem_Read (&hi2c1 ,MPU6050_ADDR,WHO_AM_I_REG,1,&check ,1,1000);if(check == 104) //if the device is present,寄存器地址默認(rèn)0x68{//power management register 0x6B we should write all 0's to wake the sensor up//電源管理寄存器,我們應(yīng)該在0x6B中寫入所有0來喚醒傳感器Data = 0;HAL_I2C_Mem_Write (&hi2c1 ,MPU6050_ADDR ,PWR_MGMT_1_REG ,1,&Data ,1,1000);//Set DATA RATE of 1KHz by writing SMPLRT_DIV register//通過寫入SMPLRT_DIV寄存器設(shè)置1KHz的數(shù)據(jù)速率Data = 0x07;HAL_I2C_Mem_Write (&hi2c1 ,MPU6050_ADDR ,SMPLRT_DIV_REG ,1 ,&Data,1,1000);// Set accelerometer configuration in ACCEL_CONFIG Register// XA_ST=0,YA_ST=0,ZA_ST=0, FS_SEL=0 ->±2g//在加速度寄存器中修改配置Data = 0x00;HAL_I2C_Mem_Write (&hi2c1 ,MPU6050_ADDR, ACCEL_CONFIG_REG, 1, &Data, 1, 1000);// Set Gyroscopic configuration in GYRO_CONFIG Register// XG_ST=0,YG_ST=0, FS_SEL=0 ->± 250 °/s//修改重力加速計(jì)配置Data = 0x00;HAL_I2C_Mem_Write (&hi2c1 ,MPU6050_ADDR, GYRO_CONFIG_REG, 1, &Data, 1, 1000);} }(6)進(jìn)行數(shù)據(jù)讀取函數(shù):加速度數(shù)據(jù)讀取、陀螺儀數(shù)據(jù)讀取、溫度數(shù)據(jù)讀取;
//************************************加速度傳感器讀取*************************************// void MPU6050_Read_Accel(void) {uint8_t Rec_Data[6];//Read 6 BYTES of data starting from ACCEL_XOUT_H registerHAL_I2C_Mem_Read (&hi2c1 ,MPU6050_ADDR ,ACCEL_XOUT_H_REG ,1,Rec_Data ,6,1000);Accel_X_RAW = (int16_t )(Rec_Data [0] <<8 | Rec_Data [1]);Accel_Y_RAW = (int16_t )(Rec_Data [2] <<8 | Rec_Data [3]);Accel_Z_RAW = (int16_t )(Rec_Data [4] <<8 | Rec_Data [5]);Ax = Accel_X_RAW/16384.0;Ay = Accel_Y_RAW/16384.0;Az = Accel_Z_RAW/16384.0; } //*********************************陀螺儀數(shù)據(jù)讀取*****************************************// void MPU6050_Read_Gyro(void ) {uint8_t Rec_Data[6];// Read 6 BYTES of data staring from GYRO_XOUT_H registerHAL_I2C_Mem_Read (&hi2c1, MPU6050_ADDR ,GYRO_XOUT_H_REG ,1,Rec_Data ,6 ,1000);Gyro_X_RAW = (int16_t )(Rec_Data [0] << 8 | Rec_Data [1]);Gyro_Y_RAW = (int16_t )(Rec_Data [2] << 8 | Rec_Data [3]);Gyro_Z_RAW = (int16_t )(Rec_Data [4] << 8 | Rec_Data [5]);Gx = Gyro_X_RAW/131.0;Gy = Gyro_Y_RAW/131.0;Gz = Gyro_Z_RAW/131.0; } //***********************************芯片溫度讀取************************************// void MPU6050_Read_Temp(void ) {uint8_t Rec_Data[2];HAL_I2C_Mem_Read (&hi2c1 ,MPU6050_ADDR ,TEMP_OUT_H_REG ,1 ,Rec_Data ,2 ,1000);Temp_RAW = (int16_t )(Rec_Data [0]<<8)|Rec_Data [1];Temp = 36.53 + (Temp_RAW )/340; }(7) 在主函數(shù)中調(diào)用這些函數(shù)即可;
(8)我們將這些代碼編譯,燒錄到我們單片機(jī)中即可。
總結(jié)
通過本次實(shí)驗(yàn),我學(xué)會(huì)了:
(1)了解了陀螺儀進(jìn)行姿態(tài)計(jì)算的原理;
(2)大致了解卡爾曼濾波的基本過程,同時(shí)怎么樣將卡爾曼應(yīng)用到卡爾曼濾波;
(3)通過單片機(jī)實(shí)現(xiàn)了MPU6050原始數(shù)據(jù)的讀取。
后面還需要學(xué)習(xí)的:
(1)陀螺儀、加速度計(jì)、磁力計(jì)他們的工作原理是什么,誤差到底來自于那些方面;
(2)利用這些原始數(shù)據(jù)進(jìn)行姿態(tài)解算的具體怎么操作;
(3)在草稿本上認(rèn)真推導(dǎo)姿態(tài)解算的過程,并把它記錄下來。
總結(jié)
以上是生活随笔為你收集整理的毕业设计2- MPU6050传感器调试记录(STM32CubeMX+STM32F103C8T6)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32 磁场传感器HMC5883
- 下一篇: bim 水利枢纽 运维_BIM——运维专