1. 程式人生 > >第四章 PX4-Pixhawk-MPU6000感測器驅動解析

第四章 PX4-Pixhawk-MPU6000感測器驅動解析

第四章MPU6000感測器驅動解析

         Mpu6000是一個3軸加速度和3軸陀螺儀感測器,這一章節我們將對MPU6000這個感測器進行解析,依照這個解析步驟同樣可以對L3GD203軸陀螺儀)、HMC58833軸磁力計)、MS5611(氣壓高度計)程式進行閱讀理解,應為這幾個感測器同樣都是採用SPI協議,這個可以檢視硬體圖,待會我們也會貼出來。

 首先我們當然是找到驅動的入口,這個我們很容易找到驅動的入口就是

這個函式。至於這個函式我們可以檢視到初始化這個幾個引數是這個,這裡我們對他進行分析一下,busid就是說明是哪個匯流排協議,可以看到這個列舉型是有5個數的都是關於內部SPI,外部SPI,內部

IIC,外部IIC,這裡的外部內部的意思是板上的感測器和自己外加的感測器,這個要理解清楚哦。Device_type是裝置型別,external就是定義是內部V2硬體的感測器還自己外接的感測器,旋轉角度其實就是跟感測器的擺放位置相關,加速度範圍是8G,即為+-4G


然後就是這個函數了

這個其實就是解析了啟動感測器的判斷了,還記得


這些就是在這裡解析了,這裡說明一下前面是對照找這個引數,然後接個冒號就是找這個引數值,比如我們來對照mpu6000 –X –R 4 start這個就是首先解析到-X就是

然後找到-R 然後找到這個引數後是4就是rotation4也就是yaw旋轉180°,接著獲取start

引數

,這個介紹完了,我們來查詢我們V2硬體的mpu6000的啟動吧。我們找到rc.sensors中有

這裡就是啟動了,如果不知道怎麼找,那就去仔細閱讀RCS那一章節了,然後再仔細閱讀rc.sensors了。這裡可以看得出不會進入該函數了

接著進入到函式

這裡的引數是,這裡我不妨貼出來這個函式實際執行的就是進入到start中這裡就會對驅動去迴圈查詢然後執行

,這裡我們不對這個做詳細說明,有興趣的可以去看看,這裡我們知道V2的硬體板就是使用的內部板載感測器。然後我們對start_bus說明,這個函式是啟動匯流排協議了。這些個引數是進入函式

這裡就是對函式協議的控制了。這裡我們先找到裝置匯流排的選擇,針對

MPU6000我們選擇的是

看到沒這裡我們選擇的是


這個函式哦bus.busnum這個引數我們到


中去找發現是

device_type引數是6000external還是0

 進入到函式MUP6000_SPI_interfaceexternal=0我們進入到else中,由於我們在板子的配置中並沒有定義PX4_SPIDEV_ICM,所以cs=PX4_SPIDEV_MPU=4。現在進入到

注:,這裡是一個建構函式,C++中的new其實就是類似於C語言中的初始化。


看到沒這裡就開始對SPI的配置進行說明了,這裡SPI的進行選擇了哦,這裡的bus=1了哦注意。Device變成了cs=4哦,然後就是模式和速率了。


這裡對SPI的選擇模式和配置就完成了。然後回到mpu6000.cpp中的下一步就是

初始化協議了,這裡用到了虛擬函式的概念哦,這裡不懂也沒關係,最好是瞭解一下這些概念,應為這個系統會有很多都用到了虛擬函式,這裡告訴你這個虛擬函式的就是SPI的初始化了。這裡我們要找的就是SPI.ccp了,你可以檢視到SPI的初始化了。這裡我們就與剛才協議的驅動對接上了,

剛才說到這裡的_bus=1,返回的值_dev=1,_device=cs=4


追蹤到這裡就是這個函數了,至於為什麼開始是SPI_SELECT到後面變成了STM32_spi1selectspi驅動篇去看看。這裡選擇的執行時


,好了我們在來看看硬體圖,看到沒現在都對應起來了吧,spi選擇的是SPI1cs選擇的是PC2引腳


再回到mpu6000.cpp中接下來就該

這裡就開始對mpu6000的相關設定和配置,這裡我們不對它進行細說這裡還是一個建構函式,只是對相關資料進行初始化。這裡面有很多,就有對路徑註冊,濾波器初始化,引數的初始化等等。這裡開始進入到驅動的資料讀取端了。這裡的初始化是過載了器件的init函式,也就是

這個函式就需要仔細去閱讀了,這裡主要是去MPUID 

,然後裝置初始化開闢資料空間

進行復位相關配置等等,這裡需要配合MPU6000的暫存器手冊去看,這裡不詳細說明,如果有需要大家提出來,本人也是可以出一個文件進行說明,來教大家如何檢視資料手冊和編寫底層驅動的。

這裡的重頭函式,這裡面就有了資料的讀取了。進入該函式,首先進行定義資料,真正的讀取是函式

這個函式是read,至於為什麼是read函式就需要有一點linux的常識了,這裡的read是一個虛擬函式。這裡後面到時候在做解釋。

這裡就開始組合資料幀了,得到原始的加速度,溫度和陀螺儀資料。

得到資料後對這些資料的處理也比價多,有資料非0判斷、資料交換、旋轉、資料偏移糾正濾波。這些裡面就涉及到了演算法哦,比如原始資料的濾波器就用到了二階濾波。演算法這塊我們暫時不去細講,目前的文件比較適合應用,到時候也會出一些文件適合真正的高手,就是演算法這塊了。

資料相關處理完了之後就是nuttx 機制出馬了需要釋出資料。就是通過

這裡也說一下,sensor_accelsensor_gyro這兩個就是主題的名字,至於這個主題就是

這個資料夾下的.msg檔案的名字了。開啟這些檔案你可以看到


這裡面就有對資料的說明了,這裡說一下.msg檔案只是一個過渡檔案,最終會通過系統工具轉換為.h檔案。如果自己要寫新的主題資料也是一樣的編寫一個.msg檔案然後再目錄下的Cmakelists檔案加入新的.msg檔案就Ok了。在使用的時候加入標頭檔案(對應的檔案.h>就行了。這個生成的h檔案是在目錄下。釋出資料後就差不多完事了。然後就是啟動自動收集資料了。


。這樣MPU6000的資料和驅動就打通了哦。

這裡對nuttx的相關函式進行說明一下,自己去理解哦,這個並不難,也沒必要知道函式怎麼來的,只需要知道函式功能和使用就行了。

int poll(struct pollfd fds[], nfds_t nfds, int timeout)

功能:監控檔案描述符(多個);

說明:timemout=0,poll()函式立即返回而不阻塞;timeout=INFTIM(-1),poll()會一直阻塞下去,直到檢測到return > 0

引數:

    fds:struct pollfd結構型別的陣列;

    nfds:用於標記陣列fds中的結構體元素的總數量;

    timeout:poll函式呼叫阻塞的時間,單位:毫秒;

返回值:

    >0:陣列fds中準備好讀、寫或出錯狀態的那些socket描述符的總數量;

    ==0:poll()函式會阻塞timeout所指定的毫秒時間長度之後返回;

    -1:poll函式呼叫失敗;同時會自動設定全域性變數errno

int orb_subscribe(const struct orb_metadata *meta)

功能:訂閱主題(topic;

說明:即使訂閱的主題沒有被公告,但是也能訂閱成功;但是在這種情況下,卻得不到資料,直到主題被公告;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

返回值:

 錯誤則返回ERROR;成功則返回一個可以讀取資料、更新話題的控制代碼;如果待訂閱的主題沒有定義或宣告則會返回-1,然後會將errno賦值為ENOENT;

eg:

    int fd = orb_subscribe(ORB_ID(topicName));

int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)

功能:從訂閱的主題中獲取資料並將資料儲存到buffer中;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

    handle:訂閱主題返回的控制代碼;

    buffer:從主題中獲取的資料;

返回值:

 返回OK表示獲取資料成功,錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    struct sensor_combined_s raw;

    orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);

orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)

功能:公告發布者的主題;

說明:在釋出主題之前是必須的;否則訂閱者雖然能訂閱,但是得不到資料;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

    data:指向一個已被初始化,釋出者要釋出的資料儲存變數的指標;

返回值:錯誤則返回ERROR;成功則返回一個可以釋出主題的控制代碼;如果待發布的主題沒有定義或宣告則會返回-1,然後會將errno賦值為ENOENT;

eg:

    struct vehicle_attitude_s att;

    memset(&att, 0, sizeof(att));

    int att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);

int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)

功能:釋出新資料到主題;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

    handle:orb_advertise函式返回的控制代碼;

    data:指向待發布資料的指標;

返回值:OK表示成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);

int orb_set_interval(int handle, unsigned interval)

功能:設定訂閱的最小時間間隔;

說明:如果設定了,則在這間隔內釋出的資料將訂閱不到;需要注意的是,設定後,第一次的資料訂閱還是由起初設定的頻率來獲取,

引數:

    handle:orb_subscribe函式返回的控制代碼;

    interval:間隔時間,單位ms;

返回值:OK表示成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    orb_set_interval(sensor_sub_fd, 1000);

orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)

功能:裝置/驅動器的多個例項實現公告,利用此函式可以註冊多個類似的驅動程式;

說明:例如在飛行器中有多個相同的感測器,那他們的資料型別則類似,不必要註冊幾個不同的話題;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

    data:指向一個已被初始化,釋出者要釋出的資料儲存變數的指標;

    instance:整型指標,指向例項的ID(從0開始);

    priority:例項的優先順序。如果使用者訂閱多個例項,優先順序的設定可以使使用者使用優先順序高的最優資料來源;

返回值:

 錯誤則返回ERROR;成功則返回一個可以釋出主題的控制代碼;如果待發布的主題沒有定義或宣告則會返回-1,然後會將errno賦值為ENOENT;

eg:

    struct orb_test t;

    t.val = 0;

    int instance0;

    orb_advert_t pfd0 = orb_advertise_multi(ORB_ID(orb_multitest), &t, &instance0, ORB_PRIO_MAX);

int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)

功能:訂閱主題(topic;

說明:通過例項的ID索引來確定是主題的哪個例項;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

    instance:主題例項ID;例項ID=0orb_subscribe()實現相同;

返回值:

 錯誤則返回ERROR;成功則返回一個可以讀取資料、更新話題的控制代碼;如果待訂閱的主題沒有定義或宣告則會返回-1,然後會將errno賦值為ENOENT;

eg:

    int sfd1 = orb_subscribe_multi(ORB_ID(orb_multitest), 1);

int orb_unsubscribe(int handle)

功能:取消訂閱主題;

引數:

    handle:主題控制代碼;

返回值:

    OK表示成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    ret = orb_unsubscribe(handle);

int orb_check(int handle, bool *updated)

功能:訂閱者可以用來檢查一個主題在釋出者上一次更新資料後,有沒有訂閱者呼叫過ob_copy來接收、處理過;

說明:如果主題在在被公告前就有人訂閱,那麼這個API將返回“not-updated”直到主題被公告。可以不用poll,只用這個函式實現資料的獲取。

引數:

    handle:主題控制代碼;

    updated:如果當最後一次更新的資料被獲取了,檢測到並設定updatedture;

返回值:

    OK表示檢測成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    if (PX4_OK != orb_check(sfd, &updated)) {

        return printf("check(1) failed");

    }

    if (updated) {

        return printf("spurious updated flag");

    }

    //or

    bool updated;

    struct random_integer_data rd;

    orb_check(topic_handle, &updated);

    if (updated) {

        orb_copy(ORB_ID(random_integer), topic_handle, &rd);

        printf("Random integer is now %d\n", rd.r);

    }

int orb_stat(int handle, uint64_t *time)

功能:訂閱者可以用來檢查一個主題最後的釋出時間;

引數:

    handle:主題控制代碼;

    time:存放主題最後釋出的時間;0表示該主題沒有釋出或公告;

返回值:

    OK表示檢測成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    ret = orb_stat(handle,time);

int orb_exists(const struct orb_metadata *meta, int instance)

功能:檢測一個主題是否存在;

引數:

    meta:uORB元物件,可以認為是主題id,一般是通過ORB_ID(主題名)來賦值;

    instance:ORB 例項ID;

返回值:

    OK表示檢測成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    ret = orb_exists(ORB_ID(vehicle_attitude),0);

int orb_priority(int handle, int *priority)

功能:獲取主題優先級別;

引數:

    handle:主題控制代碼;

    priority:存放獲取的優先級別;

返回值:

    OK表示檢測成功;錯誤返回ERROR;否則則有根據的去設定errno;

eg:

    ret = orb_priority(handle,&priority);

資料流程使用如下圖:


相關推薦

PX4-Pixhawk-MPU6000感測器驅動解析

第四章MPU6000感測器驅動解析          Mpu6000是一個3軸加速度和3軸陀螺儀感測器,這一章節我們將對MPU6000這個感測器進行解析,依照這個解析步驟同樣可以對L3GD20(3軸陀螺儀)、HMC5883(3軸磁力計)、MS5611(氣壓高度計)程式進行

PX4-Pixhawk-GPS解析

第五章 PX4-GPS解析在上一章節我們對感測器MPU6000做了一個解析,MPU6000所支援的協議是SPI。這一章節我們來解析GPS,GPS使用的是串列埠通訊。這裡我們著重講解UBLOX的解析過程,並且會附帶串列埠的解析說明。這一章節完了之後大家有興趣可以嘗試RTK的資料

Spring.Net 如何管理您的類___對象的手動裝配

div 委托 其它 .net else 基礎 只需要 構造器 事件觸發 前面我們知道了什麽是對象,什麽是對象工廠,什麽是應用程序上下文。這一次我們來看一下對象的裝配。   Spring.Net 中有多種裝配對象的方式,裝配這個詞可能比較學術化,我們可以理解為對象的創建。

visual 計算機 機器碼 規範 number erp 單詞 設計 lower ①代碼規範 每個人對於什麽是“好”的代碼規範未必認同,這時我們很有必要給出一個基準線—什麽是好的代碼規範和設計規範 計算機只關心編譯生成的機器碼,你的程序采用哪種縮進風格,變量名有無統一的

Netty In Action中文版 - :Transports(傳輸)

duplicate pipeline 客戶 下列表 bytes 線程安全 get 工具 jsb 本章內容 Transports(傳輸)NIO(non-blocking IO,New IO), OIO(Old IO,blocking IO), Local(本地),

《構建之法》讀書筆記

解決 更多 發現 開發 空白 知識點 相互 文字 人的 本章理論和知識點有:代碼規範、極限編程、結對編程、兩人合作的不同階段、影響他人的技巧 一、代碼規範 1、代碼風格規範。主要是文字上的規定,看似表面文章,實際上非常重要。 代碼風格的原則是:簡明,易讀,無二義性 。包括了

讀完《兩人合作》的內容後的總結

learn 處理 總結 str 放棄 價值 內容 驗證 我認 兩人合作是團隊合作的基礎;這裏介紹的這個基礎型“團隊”中通用的一些方法以及最重要的——交流——的細節 1.代碼規範 代碼風格規範。主要是文字上的規定; 縮進:4個空格,而不是tab; 關於斷行與空白的{}

讀構建之法 :兩人合作

應用 結對編程 使用 一對一 測試 一個 比較 以及 領域 程序員寫的代碼最終是人在看,所以代碼規範很重要,原則是:簡明,易讀,無二義性。 不光是程序書寫的格式問題,還牽涉到程序設計、模塊之間的關系、設計模式等方方面面。 代碼復審的正確定義看代碼是否在代碼規範的框架內正確的

Linux學習

linux5-1-1查看系統負載命令命令 w或命令uptimeload average :a(1分鐘內系統的平均負載 ),b(5分鐘內),c(15分鐘內)a:一分鐘內有多少個進程使用cpucat /proc/cpuinfo 顯示的processor的值就是cpu核數a>核數 負載偏高5-1-2vmsta

構建之法讀書心得

算法 邏輯錯誤 規範 審核 領域 之間 心得 使用 部分 代碼風格規範——主要是文字上的規定,看似表面文章,實際上非常重要 代碼風格的原則是:簡明,易讀,無二義性 代碼設計規範——牽涉到程序設計、模塊之間的關系、設計模式等方方面面的通用原則 代碼設計規範不光是程序書寫的格

隨筆

說明 設計規範 使用 規格 處理 維護 之間 代碼規範 應用 代碼風格規範——主要是文字上的規定,看似表面文章,實際上非常重要 代碼風格的原則是:簡明,易讀,無二義性 代碼設計規範——牽涉到程序設計、模塊之間的關系、設計模式等方方面面的通用原則 代碼設計規範不光是程序書寫

總結

程序 交換 幫助 格式 由於 編程 代碼 機器 更多 一、代碼規範 需要我們在編程中特別註意這一點,要保持代碼工整可修改,無二義性,每一行一句代碼盡量加以註釋。不僅是要讓機器編譯讀懂,還要程序員能讀懂 二、代碼風格、設計規範 在代碼設計規範中,要考慮程序設計、模塊之

-面向對象編程

com ges 執行函數 proto cto str 原型 fin 創建對象 1 面向對象   一般地, 類是對象的類型模板, 實例是根據類創建的對象   但是在JavaScript中不區分類和實例, 而是通過原型(prototype)來實現面向對象編程   使用原型

Java(

簡潔 重復 清晰 快速 結束 編寫 int() input 出現 第四章 一、 switch結構(開關語句)的語法 switch(表達式[dream1] ){ case 常量1[dream2] : //語句塊1

java面向對象

cat code per ext 修飾符 health 不能 基礎知識 類名 一、 接口的基礎知識 1、為什麽需要接口 為解決實際應用中,單一繼承無法解決的問題 2、什麽是接口 a) 基本概念? 接口是一種特殊的抽象類 接口是一種規範和標準,可以約束類的行為,是一些

C++對象模型——Inline Functions()

優化 tor tracking 改善 pan c++ col ria 表達式 4.5 Inline Functions 以下是Point class 的一個加法運算符的可能實現內容: class Point { friend Point operato

2017.06.29數據挖掘基礎概念

構建 企業 操作 允許 包含 元數據 體系結構 當前 然而 第四章39、為什麽在進行聯機分析處理(OLAP)時,我們需要一個獨立的數據倉庫,而不是直接在日常操作的數據庫上進行 1、提高兩個系統的性能 2、操作數據庫支持多事務的並發處理,需要並發控制和恢復機制,確保一

2017.07.06 IT項目管理筆記整理

區分 進度 一個 最長 需要 有效 依據 世紀 分解 進度是對執行的活動和裏程碑所制定的工作計劃日期表。 進度問題是項目生命周期內造成項目沖突的主要原因。 時間管理原則: 1、區分重要與緊急的關系 2、適當運用Pareto原則 3、合理預算 4、有限反應 5、果斷決策 6

JavaScript語言精粹_

前綴 原型對象 高度 單例 write on() 整體 方法調用 通過 4.1 函數對象   在JavaScript中,函數就是對象。對象是“名/值”對的集合並擁有一個連到原型對象的隱藏鏈接。對象字面量產生的對象連接到Object.prototype。函數對象連接到Func

.流程控制與數組

lean mage .cn nal ati alt 什麽 lan int 流程控制結構: 分支結構   根據分支條件來選擇性的執行某段代碼。   if:   switch:     case語句後面只能是byte、short、char、int四種整型類型,枚舉類型和Java