<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MPU6050陀螺儀與Processing和上位機飛控聯動實錄

      簡而言之,MPU6050 = 三軸MEMS陀螺儀 + 三軸MEMS加速度計 + 可擴展數字運動處理器DMP ,它可進行姿態解算(Pitch、Yaw、Roll角),我們還可以外接Processing IDE,或外接匿名上位機(V7),實時繪制系統的飛行姿態,下面講一下整個聯調過程以及遇到的坑。
       
      0
      圖0 單片機與上位機(V7)飛行姿態聯動

      一,MPU6050簡介

      MPU6050是InvenSense推出的集成6軸運動處理組件,即三軸MEMS(注1)陀螺儀傳感器和三軸MEMS加速度傳感器,相較于多組件方案,集成模塊可以免除各個組件時間軸之差的問題,還能大大減小封裝的空間。它含有一個副IIC接口,可用于連接外部磁力傳感器,利用自帶數字運動處理器(DMP,Digital Motion Processor的縮寫)硬件加速引擎,通過主IIC接口,可以向應用端輸出完整的9軸姿態融合演算數據。
      注1:MEMS是微機電系統(Micro Electro Mechanical System)的英文縮寫。 它是指可批量制作的,集微型機構、微型傳感器、微型執行器以及信號處理和控制電路、通信和電源于一體的系統。 比較成熟的MEMS傳感器有三種:加速度計、壓力傳感器和陀螺儀。
      有了DMP,我們可以使用InvenSense提供的運動處理資料庫,非常方便地實現姿態解算,降低了運動處理運算對操作系統的負荷,同時大大降低了開發難度 。
       

      二,MUP6050特點

      MPU6050 的特點有:
      ① 以數字形式輸出 6 軸或 9 軸(需外接磁傳感器)(注2)的旋轉矩陣、四元數(quaternion)、歐拉角格式(Euler Angle forma)的融合演算數據(需 DMP 支持)。
      ② 具有 131 LSBs/°/sec 敏感度與全格感測范圍為±250、±500、±1000 與±2000°/sec 的 3 軸角速度感測器(陀螺儀)。
      ③ 集成可程序控制,范圍為±2g、±4g、±8g 和±16g 的 3 軸加速度傳感器。
      ④ 移除加速器與陀螺儀軸間敏感度,降低設定給予的影響與感測器的飄移。
      ⑤ 自帶數字運動處理引擎可減少MCU復雜的融合演算數據、感測器同步化、姿勢感應等的負荷。
      ⑥ 內建運作時間偏差與磁力感測器校正演算技術,免除了客戶須另外進行校正的需求。
      ⑦ 自帶一個數字溫度傳感器。
      ⑧ 帶數字輸入同步引腳(Sync pin)支持視頻電子影相穩定技術與 GPS。
      ⑨ 可程序控制的中斷(interrupt),支持姿勢識別、搖攝、畫面放大縮小、滾動、快速下降中斷、high-G 中斷、零動作感應、觸擊感應、搖動感應功能。
      ⑩ VDD 供電電壓為 2.5V±5%、3.0V±5%、3.3V±5%;VLOGIC 可低至 1.8V± 5%。
      ? 陀螺儀工作電流:5mA。
      ? 自帶 1024 字節 FIFO,有助于降低系統功率。
      ? 400Khz 的 IIC 通信接口。
      注2:三軸 = 3軸陀螺儀
      六軸 = 3軸加速度計 + 3軸陀螺儀
      九軸 = 3軸加速度計 + 3軸陀螺儀 + 3軸磁力計
       

      三,原理說明

      3.1.MEMS陀螺儀

      MEMS陀螺儀與傳統的陀螺儀原理不同。 傳統陀螺儀是一個不停轉動的物體即轉子,由于慣性其旋轉軸的指向不會隨著承載它的支架旋轉而改變方向,如下圖所示,三軸即橫滾軸、俯仰軸和航向軸,通俗點說也就是X Y Z三軸,當三軸發生旋轉時,旋轉軸是不會隨之變化的。 顯然,將這樣一個不停旋轉的裝置用微機技術在硅片襯底上加工是非常難的事情。
      0
      圖1 傳統陀螺儀示意
      為此,MEMS陀螺儀基于陀螺儀的特性利用科里奧利力來實現。 科里奧利力即科氏力,它是對旋轉體系中進行直線運動的質點由于慣性相對于旋轉體系產生的直線運動的偏移的一種描述。
      以MEMS陀螺儀常見的微機械音叉式陀螺結構為例,陀螺儀中間有一個懸在空中的質量塊,它可以在兩個互相垂直的平面內振動。在一般狀態下,陀螺儀通過加震蕩電壓迫使質量塊在其中一個平面做振動,如下圖藍色箭頭所示,也就是提供了科里奧利力中的徑向運動。在陀螺儀發生旋轉時,質量塊受到與它運動方向垂直的科里奧利力,產生了另一個平面的振動,如下圖黃色箭頭所示,根據振動產生的電容變化便可以測量科里奧利力的大小,又因為科里奧利力正比于角速度,所以我們可以通過電容變化計算得到角速度。
       
      0
      圖2 科里奧利力示意

      3.2.MEMS加速度計

      技術成熟的MEMS加速度計分為三種:壓電式、容感式和熱感式。
      壓電式:在其內部有一個剛體支撐的質量塊,在運動的情況下質量塊會產生壓力,剛體產生應變,從而轉換為電信號輸出。
      容感式:它是標準的平行板電容器,加速度的變化帶來質量塊的移動從而改變電容兩級的間距以及面積,通過計算即可得到相應的加速度。
      熱感式:內部無任何質量塊,它的中央有加熱體,周邊是溫度傳感器,里面是密閉的氣腔。工作時在加熱體的作用下,氣體在內部形成一個熱氣團,熱氣團的比重和周圍的冷氣是有差異的,通過慣性熱氣團的移動形成的質量塊,熱場變化讓感應器感應到加速度值。
      附錄A:
      陀螺儀歷史發展和原因參考資源:https://zhuanlan.zhihu.com/p/610287151
       

      四,模塊初始化工作

      4.1.初始化 IIC 接口

      MPU6050 采用 IIC 與開發板通信,所以我們需要先初始化與 MPU6050 連接的 SDA 和 SCL 數據線。

      4.2.復位 MPU6050

      這一步讓 MPU6050 內部所有寄存器恢復默認值,通過對電源管理寄存器 1(0x6B)的bit7 寫 1 實現。 復位后,電源管理寄存器 1 恢復默認值(0x40),然后必須設置該寄存器為0x00,以喚醒 MPU6050,進入正常工作狀態。
      const uint8_t MPU6050_REGISTER_PWR_MGMT_1 = 0x6B;
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_1, 0x01);

      4.3.設置角速度傳感器(陀螺儀)和加速度傳感器的滿量程范圍

      這一步,我們設置兩個傳感器的滿量程范圍(FSR)(注3),分別通過陀螺儀配置寄存器(0X1B)和加速度傳感器配置寄存器(0X1C)設置。我們一般設置陀螺儀的滿量程范圍為 ±2000dps(注4),加速度傳感器的滿量程范圍為 ±2g。
      注3:量程是度量工具的測量范圍,也就是儀器設備所能測量的物理量的最大值。
      注4:dps是角速度單位,即degree per second的縮寫。
      (1)陀螺儀配置
      寄存器地址:0X1B(英文對應于Gyroscope Configuration)
      寫入數據 :0X00,選擇量程為:±250dps,視情況而定,可以為±250、±500、±1000、±2000(°/sec)
      mpu.setGyroRange(MPU6050_RANGE_250_DEG);//Adafruit_MPU6050庫的寫法
      (2)加速度計配置
      寄存器地址:0X1C(英文對應于Accelerometer Configuration)
      寫入數據 :0X00,選擇量程為:±2g(視情況而定)
      mpu.setAccelerometerRange(MPU6050_RANGE_2_G);//Adafruit_MPU6050庫的寫法

      4.4.設置其他參數

      我們還需要配置的參數有:
      • 關閉中斷
      • 關閉 AUX IIC 接口
      • 禁止 FIFO
      • 設置陀螺儀采樣率
      • 設置數字低通濾波器(DLPF)等。
      我們不用中斷方式讀取數據,所以可以關閉中斷。也沒用到 AUX IIC 接口外接其他傳感器,所以也關閉這個接口。如下所示,分別通過中斷使能寄存器(0x38)和用戶控制寄存器(0x6A)控制。
      const uint8_t MPU6050_REGISTER_INT_ENABLE = 0x38; 
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_INT_ENABLE, 0x01); 
      const uint8_t MPU6050_REGISTER_USER_CTRL = 0x6A; 
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_USER_CTRL, 0x00);
      MPU6050 可以使用 FIFO 存儲傳感器數據,不過我們也可以不用,所以關閉所有 FIFO 通道。如下所示,通過 FIFO 使能寄存器(0x23)控制,默認都是 0(即禁止 FIFO),所以用默認值就可以了。
      const uint8_t MPU6050_REGISTER_FIFO_EN = 0x23; 
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_FIFO_EN, 0x00);
      閱讀寄存器說明手冊可知,MPU6050的陀螺輸出頻率可達8kHz,加速度計為1kHz,而且可以通過分頻來降低頻率。采樣頻率就是通過陀螺儀輸出頻率分頻得到的。陀螺儀采樣率通過采樣率分頻寄存器(0x19)控制。如果要得到200Hz的采樣率,那么分頻值就是39。只要設置寄存器25的值為39,就可以使得DMP以200Hz來更新寄存器中的數據,只要按時讀取寄存器就可以了(注5)。
      const uint8_t MPU6050_REGISTER_SMPLRT_DIV = 0x19; 
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SMPLRT_DIV, 0x07);
      注5:采樣頻率分頻解釋參考 https://zhuanlan.zhihu.com/p/21670600
      數字低通濾波器(DLPF)則通過配置寄存器(0x1A)設置,一般設置 DLPF 為帶寬的 1/2 即可。
      const uint8_t MPU6050_REGISTER_CONFIG = 0x1A; 
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_CONFIG, 0x00);
       

      4.5.配置系統時鐘源并使能角速度傳感器和加速度傳感器

      可選的時鐘源有三種:內部8MHz晶振、基于陀螺儀的時鐘和外部時鐘源。 默認為內部晶振,強烈建議選擇其中一個陀螺儀(或者外部時鐘源)作為時鐘源,以提高穩定性。
      系統時鐘源同樣是通過電源管理寄存器 1(0X6B)來設置,該寄存器的最低三位用于設置系統時鐘源選擇,默認值是 0(內部晶振),不過我們一般設置為 1,即選擇 X 軸陀螺 PLL 作為時鐘源,以獲得更高精度的時鐘。
      寄存器地址:0x6B(英語對應于Power Management 1)
      寫入數據 :0x01,選擇陀螺儀的 X 軸作為時鐘源
      同時,使能角速度傳感器和加速度傳感器,這兩個操作通過電源管理寄存器 2(0x6C)來設置,設置對應位為 0 即可開啟,如下所示。
      const uint8_t MPU6050_REGISTER_PWR_MGMT_2 = 0x6C; 
      I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_2, 0x00);
       
      至此,MPU6050 的初始化就完成了,可以正常工作了(其他未設置的寄存器全部采用默認值即可)。那么當代碼燒錄后,MPU的參考點是什么呢?參考點其實就是MPU6050初始化之后一開始的位置,沒有規定說哪一個方向就是基準點,所以初始化之后的初始位置就是(0,0,0)點。
      接下來,我們就可以讀取相關寄存器,來得到加速度傳感器、角速度傳感器和溫度傳感器的數據了。
       

      五,數據處理

      5.1.原始數據格式

      我們感興趣的數據位于 0X3B 到 0X48 這14個字節的寄存器當中。這些數據會被動態更新,下面是相關的寄存器地址與數據名稱。注意每個數據都是2個字節,高位在前低位在后。
      0x3B,加速度計的X軸分量ACC_X
      0x3D,加速度計的Y軸分量ACC_Y
      0x3F,加速度計的Z軸分量ACC_Z
      0x41,當前溫度TEMP
      0x43,繞X軸旋轉的角速度GYR_X
      0x45,繞Y軸旋轉的角速度GYR_Y
      0x47,繞Z軸旋轉的角速度GYR_Z
      關于模塊的坐標系定義如下圖所示,將模塊面朝自己,此時水平方向即為X軸,豎直方向為Y軸,指向自己的方向為Z軸。
       
      0
      圖3 可根據右手螺旋定則確定方向

      5.2.DMP處理成歐拉角

      MPU6050 自帶了數字運動處理器,即 DMP。而且 InvenSense 提供了一個運動驅動庫,結合 DMP,可以將我們的加速度傳感器和角速度傳感器的原始數據,直接轉換成四元數輸出,而得到四元數之后,就可以很方便地計算出歐拉角:航向角(yaw,也叫偏航角)、橫滾角(roll)和俯仰角(pitch)(注6)。
      注6:歐拉角就是物體繞坐標系三個坐標軸(x,y,z軸)的旋轉角度。這三個角的動畫解釋參考:https://zhuanlan.zhihu.com/p/228805569
      DMP 輸出的四元數是 q30 格式的,也就是浮點數放大了 2 的 30 次方倍。在換算成歐拉角之前,必須先將其轉換為浮點數,也就是除以 2 的 30 次方,然后再進行計算,計算公式為:
      q0=quat[0] / q30;//q30格式轉換為浮點數 
      q1=quat[1] / q30; 
      q2=quat[2] / q30; 
      q3=quat[3] / q30; //計算得到ypr:pitch俯仰角/roll橫滾角/yaw航向角 
      pitch=asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3;//俯仰角 
      roll=atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3;//橫滾角 
      yaw=atan2(2*(q1q2 + q0q3),q0q0+q1q1-q2q2-q3q3) * 57.3;//航向角
      上面代碼中,quat[0]~quat[3]是 MPU6050 的 DMP 解算后的四元數,q30 格式,所以要除以一個2 的 30 次方。其中 q30 是一個常量:1073741824,即 2 的 30 次方,然后帶入公式,計算出歐拉角。上述計算公式的 57.3 是弧度轉換為角度,即 180/π,這樣得到的結果就是以度(°)為單位的。關于四元數與歐拉角的公式推導,此處不再贅述。
      需要注意的是,單靠 MPU6050 無法準確得到 yaw 角,需要和地磁傳感器結合使用,具體原因請看下一節。

      5.3.Yaw角的問題

      因為沒有參考量,所以無法求出當前的Yaw角的絕對角度,只能得到Yaw的變化量,也就是角速度GYR_Z。當然,我們可以通過對GYR_Z積分的方法來推算當前Yaw角(以初始值為準),但由于測量精度的問題,推算值會發生漂移,一段時間后就完全失去意義了。如果必須要獲得絕對的Yaw角,那么應當選用MPU9250這款九軸運動跟蹤芯片,它可以提供額外的三軸羅盤數據,這樣我們就可以根據地球磁場方向來計算Yaw角了。

      5.4.數據校準和濾波

      MPU6050提供的數據夾雜著較嚴重的噪音,在芯片處理靜止狀態時數據擺動都可能超過2%。除了噪音,各項數據還會有偏移的現象,也就是說數據并不是圍繞靜止工作點擺動,因此要先對數據偏移進行校準 ,再通過濾波算法消除噪音。
      (一)校準
      校準是比較簡單的工作,我們只需要找出擺動的數據圍繞的中心點即可。以GRY_X為例,在芯片處理靜止狀態時,這個讀數理論上講應當為0,但它往往會存在偏移量,比如我們以10ms的間隔讀取了10個值如下:
      -158.4, -172.9, -134.2, -155.1, -131.2, -146.8, -173.1, -188.6, -142.7, -179.5
      這10個值的均值,也就是讀數的偏移量為-158.25。在獲取偏移量后,每次的讀數都減去偏移量就可以得到校準后的讀數了。當然這個偏移量只是估計值,比較準確的偏移量要對大量的數據進行統計才能獲知,數據量越大越準,但統計的時間也就越慢。一般校準可以在每次啟動系統時進行,我們應當在準確度和啟動時間之間做一個權衡。
      三個角速度讀數GYR_X、GYR_Y和GYR_Z均可通過統計求平均的方法來獲得,但三個加速度分量就不能這樣簡單的完成了,因為芯片靜止時的加速度并不為0。
      加速度值的偏移來自兩個方面,一是由于芯片的測量精度,導至它測得的加速度向量并不垂直于大地;二是芯片在整個系統(如無人機)上安裝的精度是有限的,系統與芯片的座標系很難達到完美重合。前者我們稱為讀數偏移,后者我們稱為角度偏移。
      由于校準角度偏移需要專業設備,且對于一般應用來說,兩步校準帶來的精度提升并不大,因此通常只進行讀數校準即可。讀數校準辦法如下所示。
      首先將MPU6050牢牢地固定在系統底座上,并使二者座標系盡可能地重合。其次將系統置于水平、堅固的平面上,并充分預熱。此時,我們認為芯片的加速度方向應當與Z軸負方向重合,且加速度向量的模長為g,因此ACC_X和ACC_Y的理論值應為0,ACC_Z的理論值應為-16384(假設我們設定2g的倍率,1g的加速度的讀數應為最大值-32768的一半),即在統計偏移量的過程中,ACC_Z每次讀數都要加上16384,再進行統計均值校準,如下代碼所示。
        float valSums[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0};
        //先求和
        for (int i = 0; i < nCalibTimes; ++i) {
          int mpuVals[nValCnt];
          ReadAccGyr(mpuVals);
          for (int j = 0; j < nValCnt; ++j) {
            valSums[j] += mpuVals[j];
          }
        }
        //再求平均
        for (int i = 0; i < nValCnt; ++i) {
          calibData[i] = int(valSums[i] / nCalibTimes);
        }
        calibData[2] += 16384;
      (二)卡爾曼濾波
      對于夾雜了大量噪音的數據,卡爾曼濾波器的效果無疑是最好的。如果不想考慮算法細節,可以直接使用Arduino的Klaman Filter庫完成(注7)。在我們的模型中,一個卡爾曼濾波器接受一個軸上的角度值、角速度值以及時間增量,估計出一個消除噪音的角度值。跟據當前的角度值和上一輪估計的角度值,以及這兩輪估計的間隔時間,我們還可以反推出消除噪音的角速度。
      注7:Klaman源代碼中文注釋參見:https://blog.csdn.net/acktomas/article/details/89087174
       

      六、接線方式

      不需要都接。一般只需要這幾個:
      模塊 : 開發板
      VCC : 5V電源
      GND : GND
      SCL : 主IIC時鐘線(如下圖所示,一般接NodeMCU的D6)——C代表Clock,控制數據發送的時序。
      SDA : 主IIC數據線(如下圖所示,一般接NodeMCU的D7)——D代表Data,用來傳輸數據的。
      AD0 : 從機地址最低位。模塊電路中將AD0下拉接地,所以不接其他外部信號。I2C從機地址(手冊可以查看到),對于MPU6050來說固定為0x68(某些批次可能為0x98),所以可以用于驗證I2C讀出協議是否正常。也可以調整AD0引腳電壓就可以改變其從機地址:AD0接3V的時候(AD0=1),從機地址為0x69。
      0
      圖4 一種接線方式
      上述接線方式能用下述簡單實驗代碼燒錄成功和跑通:
      #include <Wire.h>
      
      // MPU6050 Slave Device Address
      const uint8_t MPU6050SlaveAddress = 0x68;//MPU6050的I2C地址
      
      // Select SDA and SCL pins for I2C communication 
      const uint8_t scl = D6;
      const uint8_t sda = D7;
      
      // sensitivity scale factor respective to full scale setting provided in datasheet 
      const uint16_t AccelScaleFactor = 16384;
      const uint16_t GyroScaleFactor = 131;
      
      // MPU6050 few configuration register addresses
      const uint8_t MPU6050_REGISTER_SMPLRT_DIV   =  0x19;
      const uint8_t MPU6050_REGISTER_USER_CTRL    =  0x6A;
      const uint8_t MPU6050_REGISTER_PWR_MGMT_1   =  0x6B;
      const uint8_t MPU6050_REGISTER_PWR_MGMT_2   =  0x6C;
      const uint8_t MPU6050_REGISTER_CONFIG       =  0x1A;
      const uint8_t MPU6050_REGISTER_GYRO_CONFIG  =  0x1B;
      const uint8_t MPU6050_REGISTER_ACCEL_CONFIG =  0x1C;
      const uint8_t MPU6050_REGISTER_FIFO_EN      =  0x23;
      const uint8_t MPU6050_REGISTER_INT_ENABLE   =  0x38;
      const uint8_t MPU6050_REGISTER_ACCEL_XOUT_H =  0x3B;//我們感興趣的數據位于 0X3B 到 0X48 這14個字節的寄存器當中
      const uint8_t MPU6050_REGISTER_SIGNAL_PATH_RESET  = 0x68;
      
      int16_t AccelX, AccelY, AccelZ, Temperature, GyroX, GyroY, GyroZ;
      
      void setup() {
        Serial.begin(115200);
        Wire.begin(sda, scl);
        MPU6050_Init();
      }
      
      void loop() {
        double Ax, Ay, Az, T, Gx, Gy, Gz;
        
        Read_RawValue(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H);
        
        //divide each with their sensitivity scale factor
        Ax = (double)AccelX/AccelScaleFactor;
        Ay = (double)AccelY/AccelScaleFactor;
        Az = (double)AccelZ/AccelScaleFactor;
        T = (double)Temperature/340+36.53; //temperature formula
        Gx = (double)GyroX/GyroScaleFactor;
        Gy = (double)GyroY/GyroScaleFactor;
        Gz = (double)GyroZ/GyroScaleFactor;
      
        Serial.print("Ax: "); Serial.print(Ax);
        Serial.print(";Ay: "); Serial.print(Ay);
        Serial.print(";Az: "); Serial.print(Az);
        Serial.print(";T: "); Serial.print(T);
        Serial.print(";Gx: "); Serial.print(Gx);
        Serial.print(";Gy: "); Serial.print(Gy);
        Serial.print(";Gz: "); Serial.println(Gz);
      
        delay(100);
      }
      
      void I2C_Write(uint8_t deviceAddress, uint8_t regAddress, uint8_t data){
        Wire.beginTransmission(deviceAddress);
        Wire.write(regAddress);
        Wire.write(data);
        Wire.endTransmission();
      }
      
      // read all 14 register
      void Read_RawValue(uint8_t deviceAddress, uint8_t regAddress){
        Wire.beginTransmission(deviceAddress);
        Wire.write(regAddress);
        Wire.endTransmission();
        Wire.requestFrom(deviceAddress, (uint8_t)14);
        AccelX = (((int16_t)Wire.read()<<8) | Wire.read());
        AccelY = (((int16_t)Wire.read()<<8) | Wire.read());
        AccelZ = (((int16_t)Wire.read()<<8) | Wire.read());
        Temperature = (((int16_t)Wire.read()<<8) | Wire.read());
        GyroX = (((int16_t)Wire.read()<<8) | Wire.read());
        GyroY = (((int16_t)Wire.read()<<8) | Wire.read());
        GyroZ = (((int16_t)Wire.read()<<8) | Wire.read());
      }
      
      //configure MPU6050
      void MPU6050_Init(){
        delay(150);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SMPLRT_DIV, 0x07);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_1, 0x01);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_2, 0x00);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_CONFIG, 0x00);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_GYRO_CONFIG, 0x00);//set +/-250 degree/second full scale
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_CONFIG, 0x00);// set +/- 2g full scale
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_FIFO_EN, 0x00);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_INT_ENABLE, 0x01);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SIGNAL_PATH_RESET, 0x00);
        I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_USER_CTRL, 0x00);
      }
      但是需要注意,這時候我們常用來遍歷打印I2C設備地址的Scanning-I2C-Device程序就報告找不到I2C設備。
      所以為了找到I2C設備,為了能使用Adafruit_MPU6050開源庫,我們采用了下面這種NodeMCU+MPU6050的接線方式:
      VCC VU (5V USB) Not available on all boards so use 3.3V if needed.
      GND G Ground
      SCL D1 (GPIO05) I2C clock
      SDA D2 (GPIO04) I2C data
      XDA not connected
      XCL not connected
      AD0 not connected
      INT D8 (GPIO15) Interrupt pin
      只有按上述方式接線,Scanning-I2C-Device程序才會打印說找到了I2C設備:
      Scanning...
      I2C device found at address 0x68 !
      Adafruit_MPU6050庫的樣例代碼也才能找到芯片。
      附錄B:
      引腳講解和簡單示例代碼可參考:https://docs.wokwi.com/parts/wokwi-mpu6050
      通常我們為了方便把IIC設備分為主設備和從設備,基本上誰控制時鐘線(即控制SCL的電平高低變換)誰就是主設備。
       

      七,外接Processing實驗

      Processing IDE是一款強大的,能與其他軟件尤其是硬件如Arduino、STM32和ESP32直接交互的編程語言和開發環境。
      為了能讓MPU6050+NodeMCU的串口輸出能夠控制Processing軟件里的小飛機模型,我們需要準備好以下庫:
      1)Arduino IDE需要安裝如下庫或者直接把庫文件復制到你的文件夾下直接引用:
      2)Processing IDE需要安裝如下庫:
      接下來開始運行。
      在Arduino IDE中打開 MPU6050_DMP6 的示例,注釋掉其他選項,只保留下面這一個選項:
      #define OUTPUT_READABLE_YAWPITCHROLL
      燒錄之后,你會看到串口打印了yaw、pitch、roll三個角的實時變化:
      MPU6050 connection successful
      Send any character to begin DMP programming and demo:
      Initializing DMP...
      .****************.***....>......-972.00000, -429.00000, 4374.00000, 96.00000, 16.00000, -34.00000
      Enabling DMP...
      DMP ready! Waiting for first interrupt...
      ypr 24.96 -0.83 -11.36
      ypr 23.79 -0.54 -9.71
      ypr 23.21 -0.22 -8.21
      ypr 22.98 -0.17 -6.86
      ypr 22.87 -0.41 -5.73
      ypr 22.63 -0.72 -4.76
      ypr 21.65 -1.02 -3.73
      ypr 20.10 -1.19 -2.59
      ypr 18.38 -1.10 -1.33
      接下來我們要與Processing IDE配合了。
      MPU6050_DMP6 中注釋掉其他選項,只保留下面這一個選項:
      #define OUTPUT_TEAPOT
      燒錄上傳。同時用Processing IDE打開 MPUTeapot.pde,運行起來,Teapot程序會自動給串口發送一個字符讓MPU6050跑起來。此時,正值MPU初始化階段,你的MPU模塊一定要水平地平放在穩固的平面上,如下圖所示,MPU平放在你面前,亮燈的地方就是機尾,機頭方向就是X軸,垂直于模塊向上就是Z軸。放得不平,或者方向不對,小飛機就會飛得奇奇怪怪。
      0
      圖5 模塊的機頭機尾方向
      初始化成功后,模塊的機頭向上,Processing IDE里的小飛機也機頭向上了,如下圖所示。
      0
      圖6 MPU+Processing第一次聯動
      如果用 MPUplane.pde 配合,還可以繪制出3D小飛機的飛行姿態效果,并解算出歐拉角和ypr,可以直觀地對比它倆的區別,如下圖所示。
      0
      圖7 MPU+Processing第二次聯動
      附錄C:
      MPU6050_DMP6 中有一行代碼,可能會引發ESP8266不斷重啟,如下所示:
      attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
      mpuIntStatus = mpu.getIntStatus();
      ESP8266不斷重啟的同時,串口會一直重復打印如下堆棧信息和ISR not in IRAM的報錯:
      Initializing I2C devices...
      Testing device connections...
      MPU6050 connection successful
       
      Send any character to begin DMP programming and demo:
      Initializing DMP...
      >*......>......-1632.00000, 667.00000, 3960.00000, 65.00000, 22.00000, -17.00000
       
      Enabling DMP...
      Enabling interrupt detection (Arduino external interrupt 2)...
      ISR not in IRAM!
       
      User exception (panic/abort/assert)
      --------------- CUT HERE FOR EXCEPTION DECODER ---------------
       
      Abort called
      我只好把這段代碼注釋掉。
       

      八,外接匿名上位機(V7)

      在單片機開發領域里,什么是上位機?
      上位機指的是可以直接發送操作指令的計算機或者單片機,一般提供用戶操作交互界面并向用戶展示反饋數據。單片機主動發送狀態信息或者報警信息給上位機。只要通信協議可以建立,上位機軟件可以是任意開發語言和任意平臺,下位機可以是單片機。
      什么是匿名上位機?
      匿名指的是匿名科創,主頁地址:http://anotc.com/。
      這個團隊公布的上位機可以完成基本收發(類似于串口調試助手)、高級收發收碼(實現比較復雜的自定義接收和發送)、同時顯示20條波形圖(用于調試PID等)、調試無人機(可以監視無人機的飛控狀態以及調試PID),最新的版本號為V7.2.5。我們可以在匿名資料匯總頁面下載匿名助手、匿名上位機等軟件。
      一定要注意下面講的是MPU6050模塊+NodeMCU開發板與匿名上位機V7的聯調,再強調一遍,是V7!一定要匹配V7飛控通信協議!不是V2.6,不是V4.5,是V7!

      8.1.單片機上報靈活格式幀給上位機

      第一步:單片機一側
      將MPU6050獲取到的六軸參數(xyz三個方向的加速度值和xyz三個方向的陀螺儀值)組裝成一幀,功能碼設置為0XF1。這個0XF1對應于協議里定義的靈活格式幀的功能碼ID,如下圖所示。
      0
      圖8 靈活格式幀說明
      由于每一幀的數據長度最大可以是40,所以我們可以在這個長度范圍內把一些相關的數據打包放在一起,組成本幀,如下面代碼所示。
      注意,此時的目標地址碼為0XFF,指的是廣播型輸出。
      void Ano_Init(void) 
      {
        MyAno.Head = FRAME_HEADER;//0XAA是幀頭
        MyAno.Addr = GENERAL_OUTPUT_ADDR;//地址碼為0xFF,指的是無特定目標,用于數據廣播型輸出
        MyAno.Lenth = 0;
      }
      //-----------------與匿名上位機通訊-----------------------------
      /**  發送靈活格式幀,幀ID為0xF1~0xFA
        *  功能:發送加速度傳感器和陀螺儀傳感器數據給匿名上位機(V7)
        *  入口參數:第一個參數accel,它的三個元素是xyz三個方向的加速度值
        *           第二個參數gyro,它的三個元素是xyz三個方向的陀螺儀值     
        *  返回值:無
        *  注:數據格式:幀頭0xAA+目標地址0xFF+功能碼0xF1+數據長度LEN+DATA+和校驗SC+附加校驗AC
        */
      void mpu6050_send_data2ano(VectorInt16 *accel,VectorInt16 *gyro)
      { 
        uint8_t nul = 0;
        Ano_Set_Mdata(0xF1,(int16_t*)&accel->x,sizeof(accel->x),1);
        Ano_Set_Mdata(0xF1,(int16_t*)&accel->y,sizeof(accel->y),2);
        Ano_Set_Mdata(0xF1,(int16_t*)&accel->z,sizeof(accel->z),3);
        Ano_Set_Mdata(0xF1,(int16_t*)&gyro->x,sizeof(gyro->x),4);
        Ano_Set_Mdata(0xF1,(int16_t*)&gyro->y,sizeof(gyro->y),5);
        Ano_Set_Mdata(0xF1,(int16_t*)&gyro->z,sizeof(gyro->z),6);
        Ano_Set_Mdata(0xF1,(uint8_t*)&nul,sizeof(nul),7);//加載數據到對應的數據位
        Ano_SendMdata();//發送數據
      }
      第二步:上位機一側
      上位機根據指定的波特率打開相應的串口連接,如下圖所示:
      0
      圖9 上位機連接設置
      第三步,打開上位機的“協議解析”界面,這時候應該已經收到了來自于MPU6050的上報信息。如下圖所示,注意看ID這一列,全都是F1。我們將點擊右下角的設置,來使能F1幀,并自定義用戶數據。
      0
      圖10 上位機協議解析界面
      第四步,首先,我們在“高級收碼設置”的“自定義幀數據配置”里勾選F1這一行的“使能該幀”,如下圖所示:
      0
      圖11 上位機自定義幀數據設置
      其次,我們繼續在“高級收碼設置”的“數據容器配置”里,依次修改容器的名稱、用戶幀和數據位。
      如下圖所示,因為我們在F1幀里傳入了六軸參數,所以用戶幀都選F1,數據位依次是1到6。為了方便顯示和理解,我們把容器名稱也都改一改。
      0
      圖12 上位機數據容器設置
      第五步,前面我們準備好了數據容器,就可以打開上位機的“波形分析”界面。默認它展示的是飛控基本波形的數據容器列表,沒有我們的。所以我們需要打開“設置”界面,點擊“用戶數據波形”,然后點擊“確定”,如下圖所示。
      0
      圖13 上位機波形設置
      到此,上位機配置完成。只需要我們的單片機按照靈活格式幀的協議格式將數據發送至上位機,即可觀察到自定義數據容器對應的數據值開始刷新,并繪制對應數據波形。
      現在回到“波形顯示”界面,左側“波形選擇”區域已經展示了我們剛才定義的六個數據容器,全部勾選之后,就可以看到右側區域開始繪制波形了。波形顯示的本質就是在一個固定的時間間隔內建立坐標然后進行連線,對于上位機的波形來說,這個時間取決于單片機發數據的頻率。
      上下左右搖動我們的MPU6050模塊,就可以看到波形有一些大幅度的變化。
      0
      圖14 上位機波形顯示
      到此,NodeMCU+MPU6050如何向匿名上位機(V7)發送串口數據,上位機如何配置使能該幀和數據容器,如何配置波形顯示,都演示完畢了。

      8.2.單片機上報飛行狀態數據給上位機

      畢竟如果MPU6050模塊是一個無人機,還是要看到無人機模型的動畫展示才更直觀,下面講一下配置流程。
      第一步:單片機一側
      上位機的飛控狀態至少需要單片機上報兩種數據幀。
      第一種是慣性傳感器數據,功能碼為0X01。我們把六軸參數逐一壓進去即可,震動狀態可以暫時置為零,如下圖所示。
      0
      圖15 上位機慣性數據說明
      第二種是歐拉角格式數據,功能碼為0X03。我們把算出來的角度乘以100,再壓進去,上位機在展示的時候會自己除以100,如下圖所示。
      0
      圖16 上位機歐拉角數據說明
      這么做的原因是為了提高數據傳輸的效率,當有浮點數類型數據需要傳輸時,根據數據類型的特點,適當截取小數點后固定幾位,比如保留歐拉角的小數點后兩位即可(即乘以100),將浮點數轉化成整數類型進行傳輸,可縮短數據長度,并且避免浮點數傳輸時發生異 常,解析成非法浮點數。
      此時的目標地址碼仍然是0XFF(廣播型輸出)。
      好,現在飛控相關的基本信息類幀就組裝完畢了,如下面的代碼所示:
      //-----------------與匿名上位機通訊-----------------------------
      /**  發送基本信息類幀,功能碼ID為0x01~0x04之間,在飛控通信協議里屬于飛控相關信息類
        *  功能:發送慣性傳感器、歐拉角等數據給匿名上位機(V7)
        *  入口參數:第一個參數accel,它的三個元素是xyz三個方向的加速度值
        *           第二個參數gyro,它的三個元素是xyz三個方向的陀螺儀值
        *           第三個參數ypr,這是一個float[]數組,分別是yaw/pitch/roll angles原始值
        *  返回值:無
        *  注:數據格式:幀頭0xAA+目標地址0xFF+功能碼+數據長度LEN+DATA+和校驗SC+附加校驗AC
        *  注:為了提高數據傳輸的效率,當有浮點數類型數據需要傳輸時,根據數據類型的特點,適當截取小數點后固定幾
              位,比如飛控姿態數據,保留角度的小數點后兩位即可(即乘以100)。
              將浮點數轉化成整數類型進行傳輸,可縮短數據長度,并且避免浮點數傳輸時發生異
              常,解析成非法浮點數。
        */
      void mpu6050_send_flydata2ano(VectorInt16 *accel,VectorInt16 *gyro,float *ypr)
      { 
        uint8_t nul = 0;
        //ID:0x01:慣性傳感器數據
        //DATA 區域內容:
        //ACC、GYR:依次為加速度、陀螺儀傳感器數據。
        //SHOCK_STA:震動狀態
        Ano_Set_Mdata(0x01,(int16_t*)&accel->x,sizeof(accel->x),1);
        Ano_Set_Mdata(0x01,(int16_t*)&accel->y,sizeof(accel->y),2);
        Ano_Set_Mdata(0x01,(int16_t*)&accel->z,sizeof(accel->z),3);
        Ano_Set_Mdata(0x01,(int16_t*)&gyro->x,sizeof(gyro->x),4);
        Ano_Set_Mdata(0x01,(int16_t*)&gyro->y,sizeof(gyro->y),5);
        Ano_Set_Mdata(0x01,(int16_t*)&gyro->z,sizeof(gyro->z),6);
        Ano_Set_Mdata(0x01,(uint8_t*)&nul,sizeof(nul),7);
        Ano_SendMdata();//發送數據
        //ID:0x03:飛控姿態:歐拉角格式
        //DATA 區域內容:
        //ROL、PIT、YAW:姿態角,依次為橫滾、俯仰、航向,精確到 0.01。
        //FUSION _STA:融合狀態
        //注意:角度最終要乘以100,上位機那邊會除以100做展示
        int16_t rol = (int16_t)(ypr[2] * 180 * 100.00 / M_PI);
        int16_t pit = (int16_t)(ypr[1] * 180 * 100.00 / M_PI);
        int16_t yaw = (int16_t)(ypr[0] * 180 * 100.00 / M_PI);
        Ano_Set_Mdata(0x03,(int16_t*)&rol,sizeof(rol),1);
        Ano_Set_Mdata(0x03,(int16_t*)&pit,sizeof(pit),2);
        Ano_Set_Mdata(0x03,(int16_t*)&yaw,sizeof(yaw),3);
        Ano_Set_Mdata(0x03,(uint8_t*)&nul,sizeof(nul),4);
        Ano_SendMdata();//發送數據
      }
      第二步,上位機一側
      在上位機里打開連接后,我們就會發現已經有數據進來了。打開“飛行狀態”界面(如下圖所示),點擊下方的“數據顯示”按鈕。
      0
      圖17 上位機飛行狀態界面
      我們就會看到飛控通信協議里的基本信息類幀都在這里羅列了,如下圖所示。我們點開單片機本次上報的“Frame ID: 0x01”和“Frame ID: 0x03”,就會看到兩個要點:
      第一,數據值這一列一直在變化,說明數據都能被正確地解析;
      第二,傳輸縮放這一列里,慣性傳感器數據都沒有做縮放,而歐拉角則做了100(即1.0E+2)的倍數縮放。
      0
      圖18 上位機數據顯示界面
      第三步,我們打開上位機的“波形顯示”畫面,在它的設置項里選“飛控基本波形”并確定,就會看到波形顯示的左側區域展示了慣性傳感器和歐拉角等預定義數據項,勾選之后就會看到波形在實時變化,隨著你搖動旋轉MPU6050模塊。
      0
      圖19 上位機波形設置
      第四步,MPU6050與上位機飛行狀態聯動的效果如下圖所示:
      0
      圖20 單片機與上位機飛行姿態聯動
      到此,單片機按照匿名公司的飛控通信協議V7(注意版本號哦),將MPU6050模塊啟用自帶的DMP計算出來的歐拉角等數據,以基本信息類幀的數據格式,通過串口上報給電腦端的匿名上位機(V7),從而可以讓MPU6050的運動姿態聯動上位機的無人機模型。
       
      最后,我們總結一下:
      0x01:【元器件基礎】學習了如何基于Adafruit_MPU6050和Kalman_Filter_Library庫,利用MPU6050模塊,獲得六軸參數,并進一步計算俯仰角和橫滾角。
      0x02:【元器件進階】學習MPU6050如何對接Processing IDE,在電腦端實時繪制模型的飛行姿態。
      0x03:【元器件進階】學習MPU6050如何對接匿名上位機(V7),在上位機里收碼、波形顯示和實時飛行姿態。
       
      -END-
      posted @ 2023-04-04 15:13  老兵筆記  閱讀(2562)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲午夜精品国产电影在线观看| 无码日韩做暖暖大全免费不卡| 最近中文字幕完整版2019| 四虎成人在线观看免费| 国产亚洲精品一区二区不卡| 国产精品成人久久电影| 女人下边被添全过视频的网址| 婷婷四虎东京热无码群交双飞视频| 成年午夜无码av片在线观看| 粗大挺进朋友人妻淑娟| 宁夏| 在线播放国产精品三级网| 亚洲情A成黄在线观看动漫尤物| 亚洲欧美国产精品专区久久| 国产极品美女高潮无套| 四虎精品永久在线视频| 亚洲午夜成人精品电影在线观看| 熟妇人妻中文a∨无码| 亚洲女人天堂成人av在线| 99久久er热在这里只有精品99| 国产在线观看网址不卡一区 | 超碰成人人人做人人爽 | 廊坊市| 精品午夜福利短视频一区| 亚洲精品日韩在线观看| 无码av免费毛片一区二区| 国产一区二区三区九九视频| 国产高清在线不卡一区| 欧美人禽杂交狂配| 极品蜜桃臀一区二区av| 无码人妻斩一区二区三区| 色老板精品视频在线观看| av高清无码 在线播放| 国产亚洲一在无在线观看| 超碰人人超碰人人| 国产熟睡乱子伦午夜视频| 久久精品道一区二区三区| 日日猛噜噜狠狠扒开双腿小说| 国产地址二永久伊甸园| 国产自拍在线一区二区三区| 亚洲欧美一区二区成人片|