APM 學習 9 --- 存儲和 EEPROM 管理

英文原文地址:  https://ardupilot.org/dev/docs/learning-ardupilot-storage-and-eeprom-management.html

存儲和 EEPROM 管理

        ArduPilot 支持的每個板都有某種形式的持久性存儲。它用於保存用戶參數,航路點,集會點,地形數據和許多其他有用的信息。爲了提供對此存儲的訪問,ArduPilot 具有4種基本機制 :

  • the AP_HAL::Storage object, accessed as hal.storage (存儲對象,作爲 hal.storage 訪問)
  • the StorageManager library to give a higher level abstraction layer on hal.storage(StorageManager 庫以在 hal.storage 上提供更高級別的抽象層)
  • DataFlash for storing to an on-board logging area(DataFlash,用於存儲到板載日誌記錄區域)
  • Posix IO functions to traditional filesystems (for example VFAT on a microSD card), on boards that support it(Posix IO 針對傳統文件系統的功能(例如microSD卡上的VFAT),適用於支持它的硬件。)

        需要持久存儲的其他庫和功能都建立在這些基本系統上,例如,AP_Param 庫(處理用戶可設置的參數)建立在 StorageManager 的頂部,而 StorageManager 又建立在 AP_HAL :: Storage 的頂部。 AP_Terrain 庫(處理地形數據)建立在 Posix IO 功能的基礎上,用於保存地形數據庫。

1,AP_HAL :: Storage 庫

        AP_HAL :: Storage 對象適用於所有平臺。 ArduPilot 支持的板上通過此接口可用的最小存儲大小爲 4096 字節。一些板卡提供了更多的空間-例如PX4v1具有8k的EEPROM,而Pixhawk具有16k的FRAM。所有這些都隱藏在 AP_HAL :: Storage API 之中。

       hal.storage API 非常簡單,它只有3個功能:

  • init() to start up the storage subsystem (init()啓動存儲子系統)
  • read_block() to read a block of bytes (read_block()讀取一個字節塊)
  • write_block() to write a block of bytes (write_block()寫入一個字節塊)

     使用這種非常簡單的API的原因是,鼓勵開發人員使用 StorageManager API 而不是hal.storage,僅在啓動新板或進行調試時才研究hal.storage。

        可用存儲空間的大小在宏HAL_STORAGE_SIZE的AP_HAL / AP_HAL_Boards.h中設置。這意味着我們尚不支持動態確定此接口可用的存儲空間。如果要動態調整大小的存儲,則需要使用Posix IO。

        目前系統沒有用於AP_HAL :: Storage API的示例,因此您可以編寫一個。如果您已經深入到ArduPilot教程中,那麼您應該已經看到了足夠的示例,以瞭解如何從頭開始編寫示例。因此,編寫一個library / AP_HAL / examples / Storage示例,該示例計算 hal.storage 數據的全部內容的8位 XOR,並將其打印到控制檯。然後將示例作爲補丁提交至 ArduPilot github,請務必遵循補丁提交指南。

我會很感興趣地看到將這個練習添加到教程中多長時間後才能提交…。

2,StorageManager 庫

       簡單的 hal.storage API 可輕鬆輕鬆地將 ArduPilot 移植到新板上,但實際使用起來並不方便。爲此,我們設計 StorageManager。 StorageManager 庫提供了一個API,該API將存儲抽象爲具有指定用途的僞連續數據塊。我們將可用存儲劃分爲以下區域:

  • parameters (參數)
  • fence points (柵欄點)
  • waypoints (航點)
  • rally points (集結點)
  • signing key (簽名密鑰)
  • RC bind info (RC綁定信息)

       閱讀庫 /StorageManager/StorageManager.cpp,特別要看一下頂部的表格。注意,如何爲具有更大存儲量的系統定義每種類型的多個區域。將多個不連續的存儲區域合併爲一個邏輯存儲區域的能力是添加 StorageManager 的主要動機。它使我們從在所有板上使用 4k 的存儲空間發展到使用每個板上可用的完整存儲空間,而無需要求用戶重新加載所有參數或重新加載航路點。

        避免讓用戶重新配置其自動駕駛儀板這一問題在 ArduPilot 使用中非常現象,當用戶可以更新到最新固件,他們以前設置的所有內容仍然可以使用,同時獲得新功能時,這一特徵非常重要。有時,這意味着我們必須做更多的工作,開發人員才能實現這一目標-例如這是 StorageManager 中設計的初衷。

        StorageManager API 還提供了用於讀取和寫入變量(如整數)的便捷功能。這是API,類似AP_Mission)保存和還原航點。

       代碼位於庫 /StorageManager/examples/StorageTest.cpp, 這是對StoageManager層的壓力測試,同時也是對AP_HAL :: Storage對象的壓力測試。它以隨機長度的隨機偏移量執行隨機 IO,這意味着 IO 會跨越邊界,在 FRAM 或 EEPROM 中單個參數值可能不連續。該測試示例旨在對 StorageManager API 進行壓力測試,即使將 ArduPilot 移植到新板上時,它也非常有用,因爲它很好地強調了EEPROM訪問功能。

        需要注意的是,在主板上嘗試使用 StorageTest是破壞性的測試。它不會破壞您的電路板,但會擦除您的所有參數和航路點。因此,如果您要在自己喜歡的飛機上的板上進行測試,請備份您的配置。

        作爲練習,可以向 StorageTest 添加一些配置文件,以便以 kb / sec 的形式顯示總 IO 速率以及讀寫的 IO 速率,是否注意到讀寫速率之間的差異?您是否注意到有關寫入已在該地址中設置的值的速度的任何信息?查看是否可以在StorageManager中找到解釋您的觀察結果的代碼。然後提交一個補丁,將分析輸出添加到ArduPilot github。

      接下來,搜索ArduPilot庫以優化所有使用StorageManager的位置。您正在尋找的是StorageAccess句柄,如下所示:

StorageAccess AP_Param::_storage(StorageManager::StorageParam);

聲明瞭一個名爲AP_Param :: __ storage的變量,該變量可訪問此板上存儲的StorageParam區域。

3,DataFlash庫

       自動駕駛儀需要的另一種存儲方式是機載日誌,ArduPilot 提供DataFlash庫。從許多方面來說,這是一個很奇怪的庫,首先,這個名稱很奇怪,因爲它最初是爲 APM1 的 DataFlash 芯片設計的。它是一個硬件設備驅動程序庫,隨着時間的流逝逐漸演變成一個通用的日誌記錄系統。在內部,庫的結構以幾種方式顯示此歷史記錄(雖然這並不是一個好方法)。

        如今,DataFlash API 是圍繞日誌記錄基礎結構模型設計的。它允許爲單個日誌消息定義自描述數據結構,例如用於記錄來自 GPS 傳感器的數據的“ GPS”消息。它以高效的方式處理將數據記錄到持久性存儲中的問題,還爲其他庫提供 API,供用戶在飛行後希望下載其日誌文件時將其讀取。

       ArduPilot 用於存儲日誌消息的格式爲 “ * .bin” 。 格式內容非常靈活,地面站可以制定日誌文件中消息的格式,而無需某種通用方案。每個日誌文件的最前面是一組 FMT 消息,這些消息具有衆所周知的格式,並描述了隨後的消息的格式。

        參考庫/ DataFlash /示例 /DataFlash_test/DataFlash_test.cpp,會在頂部看到一個小表,該表定義了我們將要寫入的日誌消息,在這種情況下爲“ TEST”消息,其中包含4個無符號的16位整數和兩個有符號的32位整數(這就是“ HHHHii”的含義) 。它還提供了這6個變量的名稱(分別標記爲V1至V4以及L1和L2)。

        在loop()函數中,您將看到一個調用,如下所示:

DataFlash.get_log_boundaries(log_num, start, end);

        這是公用API,用於DataFlash庫隱藏開發板實際存儲日誌文件的方式。在具有Posix IO的系統上(例如Pixhawk或Linux),日誌文件作爲單獨的文件存儲在microSD卡上的“ LOGS”目錄中,用戶可以通過拔出microSD卡並將其放入PC來直接複製這些文件。

        在APM2之類的板上,事情並不是那麼簡單, 因爲 APM2 在 DataFlash 芯片上具有4 MB的存儲空間,可通過 SPI 接口進行訪問。接口本身是面向頁面的,因此需要填充一個512字節(或可能是528字節!)的頁面,然後告訴芯片在填充下一頁的同時將該頁面複製到持久性存儲中。 DataFlash 執行隨機IO不是特別適用,因爲它是專爲需要連續寫入的代碼而設計,例如記錄 log 文檔。對於自動駕駛儀記錄數量而言,4兆字節的大小確實不是很大,因此我們也需要在自動駕駛儀填滿時對其進行處理。

       所有這些複雜性都隱藏在一個API中,該API提出了“日誌號”的概念,該日誌號只是在自動駕駛儀的一次飛行中寫入的一堆字節。 APM1和APM2上的DataFlash實現在每個頁面的前部使用很少的標記字節來說明正在寫入哪個日誌號,這些日誌號對應於用戶要求檢索其日誌時下載的日誌號。

4,Posix IO

       ArduPilot 支持的某些自動駕駛板基於具有Posix類API的操作系統。例如,Linux端口具有非常好的Posix子系統,而用於PX4的NuttX操作系統(例如在Pixhawk上)具有相當合理的Posix層。您可以在ArduPilot的庫中利用此功能,只要您不依賴它來滿足所有電路板的要求。

       AP_Terrain庫就是一個很好的例子,該庫保存了地形數據。地形數據太大,無法容納在EEPROM中,並且是隨機訪問的,因此不適合 DataFlash。對於自動駕駛儀的基本功能而言,它也不是必需的,因此,它是使用Posix IO實現的理想選擇。

        我們使用Posix IO的方法是,首先通過檢查AP_HAL_Boards.h中的HAVE_OS_POSIX_IO宏來檢查開發板是否支持Posix IO。然後,要知道應在文件系統上的什麼位置存儲數據,請在AP_HAL_Boards.h中添加一個特定於數據的宏,該宏給出應放置此類數據的目錄路徑。例如,宏HAL_BOARD_TERRAIN_DIRECTORY用於定義地形數據應存放的目錄。

       一旦有了滿足這兩個需求,儘管有一些注意事項,您應該只使用普通的Posix IO功能(即打開,關閉,讀取,寫入等):

  • 只能從IO計時器或自己的低優先級線程調用IO功能。
  • 切勿從可用庫的API中調用任何IO函數。甚至像stat()這樣的簡單對象。
  • 嘗試減慢存儲卡的速度,以合理大小的塊進行IO,並儘可能避免尋找。

       這些規則確實很重要, Pixhawk 上的 microSD 卡上的簡單IO可能需要一秒鐘的時間,這段時間足夠的時間讓您珍貴的四軸飛行器墜毀。 Pixhawk microSD 卡上 IO 的平均時間非常短(幾毫秒),但是當 microSD 卡決定需要花費一些時間重新讀取SD卡規定格並進行計算時,偶爾會收到緩慢的信號,不要因爲大多數時候看起來很快而嘗試進行一些小小的操作。唯一的例外是初始化功能,需要知道這些初始化功能只能在車輛啓動或撤防時調用,此時稍微的延遲也可以被接受。 

      參考library / AP_Terrain / TerrainIO.cpp,看看它如何使用 Posix IO。請注意,它用於處理所有IO的小狀態機都是通過AP_Terrain :: io_timer函數調用的。看看是否可以發現任何錯誤,並報告可能的錯誤!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章