緒論
SLAM(同步定位和地圖繪制)在自動駕駛、AGV 和無人機等各種應(yīng)用中引起了人們的廣泛關(guān)注。盡管目前有很多優(yōu)秀的 SLAM 項目可以參考,但是他們的復(fù)雜性(高性能)及依賴性(依賴于許多外部庫),使得它們無法移植到簡單的平臺(例如嵌入式系統(tǒng))。
該項目更加重視簡潔的算法和更少的依賴性。很多不開源的庫也將被刪除。另一方面,利用FPGA加速來達到實時的處理速度。
功能
10 FPS實時運行
閉環(huán)檢測
3D占用網(wǎng)格地圖生成
通過 USB 3.0 連接進行實時監(jiān)控
軟件和硬件的所有設(shè)計文件均開源
GitHub
項目很復(fù)雜,感興趣的不會太多,提前放出代碼
bin --- 預(yù)構(gòu)建的二進制文件
doc---相關(guān)文件
src --- 源文件
vivado --- Vivado 工程目錄
系統(tǒng)概覽
系統(tǒng)級框圖如下所示。
傳感器板
傳感器板連接到FPGA開發(fā)板( Ultra96-V2 )以捕獲立體圖像。該板硬件是開源的,開源鏈接如下:
該板包含雙 CMOS 圖像傳感器和兩個 mikroBUS 。
在兩個mikroBUS站點中的一個站點上安裝了一個帶有內(nèi)置LED(按鈕G點擊)的單按鈕開關(guān)的模塊,用于在獨立模式下控制系統(tǒng)。IMU模塊也已安裝,但未在本項目中使用。
圖像格式為 640x480 ,30 FPS。然后將幀速率降低到 FPGA 內(nèi)的所需速率。
遷移到其他傳感器板
該傳感器板的設(shè)計符合 Ultra96-V2 規(guī)范。如果其他傳感器板也符合這些規(guī)范,則應(yīng)該可以遷移到其他傳感器板。圖像傳感器配置為 640x480 分辨率和 30 FPS。一個按鈕開關(guān)和一個 LED 連接到 FPGA。
FPGA
圖像傳感器連接到 FPGA(或可編程邏輯,PL端)。用于立體視覺的圖像處理,如立體校正和塊匹配(stereo rectification 和 block matching)。FPGA也被用作一些功能的硬件加速。
遠程申請
裸機應(yīng)用程序在兩個 R5 處理器之一上運行,用來控制 FPGA。此應(yīng)用程序在本文中也稱為“遠程應(yīng)用程序”。此應(yīng)用程序與 Linux 應(yīng)用程序協(xié)同工作。此應(yīng)用程序還控制 USB 3.0 連接,因此如果板卡連接到 Windows PC,此系統(tǒng)就像是具有某些立體視覺功能的 USB 網(wǎng)絡(luò)攝像頭一樣工作。
Linux應(yīng)用
Petalinux 系統(tǒng)建立在四個 A53 處理器上。在該系統(tǒng)上運行處理 SLAM 相關(guān)操作的應(yīng)用程序。該應(yīng)用程序在本文中稱為“Linux 應(yīng)用程序”。
Petalinux 系統(tǒng)以 SMP(Symmetric Multiprocessing)模式運行。這意味著工作負載由 Linux 系統(tǒng)分配給每個處理器。
處理器間通信 (IPC)
這兩個應(yīng)用程序通過在 FPGA 中實現(xiàn)的內(nèi)存映射寄存器相互通信。這些寄存器由“消息”寄存器和“參數(shù)”寄存器組成。處理器在“消息”寄存器中寫入特定的消息 ID 以通知對方。另一個 CPU 輪詢“消息”寄存器并做出適當?shù)捻憫?yīng)。如有必要,可以發(fā)送四個 32 位參數(shù)。
調(diào)試電腦
調(diào)試電腦用于監(jiān)控板子的狀態(tài)。除了通過 UART 進行的調(diào)試功能外,還可以通過 USB 3.0 連接實時查看視頻處理中的立體圖像。當連接到 Windows PC 時,此系統(tǒng)被視為 UVC(USB Video Class)設(shè)備,因此不需要特殊的設(shè)備驅(qū)動程序。
內(nèi)存映射
FPGA開發(fā)板上有 2GB 的物理內(nèi)存。該區(qū)域的前 3 / 4 被 Linux 系統(tǒng)使用。另一個保留給遠程應(yīng)用程序。
開發(fā)環(huán)境
主要開發(fā)在 Windows 上執(zhí)行,但 Petalinux 開發(fā)需要 Linux 環(huán)境。所以使用VirtualBox在Windows 10上虛擬搭建一個Linux環(huán)境。
此項目需要安裝兩個 Vitis 。Windows 上的一個用于遠程應(yīng)用程序開發(fā),另一個用于 Linux 應(yīng)用程序。
開發(fā)階段
嵌入式系統(tǒng)的開發(fā)比較麻煩,所以需要劃分為三個階段。
第 1 階段是在 Windows上進行純軟件解決方案開發(fā)。這個階段對于軟件開發(fā)是最有效的。算法的性能也在這個階段得到了驗證。
在第 2 階段,軟件被移植到運行在開發(fā)板板上的 Petalinux 系統(tǒng)。在這個過渡階段,注意軟件源代碼是相同的。板載 SD 卡用于存儲數(shù)據(jù)。
在最后階段,一些功能被FPGA電路和控制FPGA的裸機應(yīng)用所取代。一些功能還應(yīng)用了硬件加速,以進一步減少處理時間。
算法(傳感器數(shù)據(jù)采集)
立體校正
立體校正過程將左右圖像在同一平面上進行變換,并使它們水平對齊。立體校正在 FPGA 內(nèi)部實時執(zhí)行,然后在存儲到 DDR 內(nèi)存之前進行雙線性插值。
為了使 FPGA 電路更簡單,支持信息由軟件預(yù)先生成。此信息包括要處理的數(shù)據(jù)的位置和長度,并按到達時間的順序排序。
立體校正參數(shù)通過 OpenCV 函數(shù)獲得,該函數(shù)使用 7x5 棋盤圖案實現(xiàn) Bouguet 算法。這些參數(shù)保存在 XML 文件中并存儲在 SD 卡上。
當前的實現(xiàn)忽略了鏡頭畸變,因為使用的圖像傳感器幾乎沒有畸變,而試圖消除它們的畸變會導(dǎo)致圖像產(chǎn)生更多畸變。
X-Sobel 濾波器
X-Sobel 濾波器用作塊匹配的預(yù)處理,結(jié)果存儲在 DDR 內(nèi)存中。
塊匹配
塊匹配搜索立體圖像對之間的視覺對應(yīng)關(guān)系。立體校正后,左圖中的一個位置出現(xiàn)在右圖中同一行的左側(cè)。源圖像中每個像素的這些差異形成了密集的深度圖。
塊匹配是通過移植OpenCV的StereoBM功能在FPGA中實現(xiàn)的。塊匹配所需的計算量非常大,但可以通過 OpenCV 中實現(xiàn)的“滑動窗口”技術(shù)來減少。為了進一步減少處理時間,F(xiàn)PGA 并行計算 32 個視差。
GFTT探測器
GFTT(Good Features To Track)用于檢測關(guān)鍵點。關(guān)鍵點是圖像中通常包含角的獨特部分。
該算法與OpenCV的goodFeaturesToTrack函數(shù)相同,但部分函數(shù)移植到FPGA中實現(xiàn),以減少軟件處理時間。
該功能由以下步驟組成。
應(yīng)用XY-Sobel濾波器提取邊緣
計算特征值量化角點的尖銳度
對特征值應(yīng)用閾值并選擇好的關(guān)鍵點
步驟1和步驟2需要對圖像中的每個像素都進行計算,計算量較大,因此采用FPGA實現(xiàn)。
ORB 描述符生成器
ORB(Oriented FAST and Rotated BRIEF)特征描述符用于量化檢測到的關(guān)鍵點的視覺唯一性。同一物體的關(guān)鍵點具有相似的描述符,因此即使比例和角度略有不同,我們也可以從不同的圖像幀中搜索同一物體的關(guān)鍵點。
實際計算由 OpenCV 函數(shù)執(zhí)行。每個 ORB 描述符都是一個 256 位的二進制字符串。
算法(SLAM)
SLAM 算法是根據(jù)RTAB-Map中實現(xiàn)的 F2F 算法構(gòu)建的。
坐標
該項目涉及兩個坐標系。它們是圖像坐標和world (或者 robot)坐標。
這兩個都是右手坐標系,所以一個簡單的旋轉(zhuǎn)矩陣R就可以在它們之間進行轉(zhuǎn)換。源圖像在圖像坐標中捕獲。然后將計算出的相機位姿轉(zhuǎn)換為world 坐標。
視覺里程計Visual Odometry
視覺里程計計算連續(xù)圖像幀期間相機姿勢的轉(zhuǎn)換。
該算法由以下階段組成。
1.關(guān)鍵幀選擇
實際視覺里程計是在關(guān)鍵幀和新圖像幀之間計算的。使用關(guān)鍵幀的原因是為了減少累積每一幀的測距誤差,尤其是當相機靠近固定位置時。當匹配的關(guān)鍵點數(shù)量低于閾值時,關(guān)鍵幀將被更新。
2. 關(guān)鍵點匹配
關(guān)鍵點在兩個圖像幀之間匹配。通過比較關(guān)鍵點的 ORB 描述符來計算相似度。以前的相機姿勢(如果可用)用于縮小搜索范圍。此階段的輸出是匹配關(guān)鍵點的 ID 及其 2D/3D 位置。
3.運動估計
解決 PnP 問題以計算相機的旋轉(zhuǎn)和平移,從而最大限度地減少兩者之間的誤差
投影到當前圖像平面上的參考幀中關(guān)鍵點的 3D 位置,以及當前幀中關(guān)鍵點的二維位置。
輸出是相機的相對運動。它在圖像坐標中計算,然后轉(zhuǎn)換為world坐標。
在這個項目中,相機姿勢是使用圖表來描述的。估計的相機姿勢和運動分別作為節(jié)點和鏈接添加到圖中。
視覺關(guān)鍵詞Visual Word Dictionary
視覺關(guān)鍵詞包含視覺詞,它們實際上是分配有唯一 ID 的 ORB 描述符。每次新的圖像幀到達時,該幀中包含的 ORB 描述符都會與現(xiàn)有的視覺詞相匹配。如果它與現(xiàn)有單詞匹配,則增加該單詞的引用計數(shù)器。如果不是,則描述符被分配一個新的 ID 并成為一個新的視覺詞。
視覺詞的數(shù)量隨時間增加。與所有現(xiàn)有的視覺詞匹配實際上是這個應(yīng)用程序中最耗時的過程。為了讓軟件實時運行,這個計算在一個單獨的線程中處理。因為閉環(huán)檢測不一定在每一幀中運行,所以這一操作很有效,。
閉環(huán)檢測
閉環(huán)檢測是識別先前訪問過的場景并向該節(jié)點添加另一個鏈接。
向圖形添加閉環(huán)鏈接可以通過兩種方式減少圖形錯誤。
添加閉環(huán)鏈接時會重建圖。在這個過程中,連接了從起始節(jié)點到結(jié)束節(jié)點的最短路徑。這將消除循環(huán)期間累積的里程計誤差。
閉環(huán)鏈接將為圖形添加額外的約束。通過最小化由此類約束引起的誤差,將提高估計姿勢的準確性。
默認情況下,閉環(huán)檢測每 5 幀運行一次。最新的 30 幀也將被忽略。這些抽取是為了消除相鄰節(jié)點被接受為閉環(huán),因為它們對圖優(yōu)化幾乎沒有貢獻。
每當一個新的圖像幀到達時,TF-IDF(詞頻-逆文檔頻率)分數(shù)就會通過查閱視覺詞典來計算其他圖像幀的分數(shù)。當更多的單詞包含在共同點時,這個分數(shù)會更高,并且單詞越稀有。
選擇具有最高 TF-IDF 分數(shù)的圖像幀作為閉環(huán)的候選者。然后,在兩個圖像幀之間執(zhí)行類似于視覺里程計中的運動估計。當重投影誤差低于閾值時,該鏈接被接受為閉環(huán)鏈接并添加到圖中。
圖形優(yōu)化
當閉環(huán)鏈接向圖形添加額外約束時,會出現(xiàn)差異,從而導(dǎo)致圖形中出現(xiàn)錯誤。通過最小化此類錯誤,可以提高圖表的準確性。
在這個項目中,只估計相機位姿。這稱為“姿態(tài)調(diào)整”,與“束調(diào)整”相對,后者估計相機姿態(tài)和觀察點的 3D 坐標。
這類問題可以通過最小化這種形式的成本函數(shù) F(x) 來解決。
這里 eij 被定義為位姿 xi 和 xj 之間的誤差向量,而 zij 是它們之間的約束。Ω為信息矩陣,由重投影誤差的協(xié)方差的倒數(shù)得到。
F(x) 的一階近似值通過圍繞 x 初始值的泰勒級數(shù)展開如下給出。
Jij 是關(guān)于 xi 和 xj 的雅可比矩陣。
F(x) 由 x 最小化,x 是通過求解以下等式獲得的,其中 λ 是傾銷因子。
將 Δx 添加到初始值以更接近最優(yōu)解。
雅可比計算遵循g2o的實現(xiàn)(https://github.com/RainerKuemmerle/g2o)。原始相機姿態(tài)包括旋轉(zhuǎn)矩陣,它們不能直接放入方程中,因為它們是一種過度參數(shù)化的表示。在這個項目中,歸一化四元數(shù)的軸用作最小表示。這也遵循 g2o 的實現(xiàn),因此我們可以對雅可比矩陣使用相同的計算。因此相機姿勢將是 6 個元素的向量。
假設(shè)我們有 N 個節(jié)點,那么 H 的大小是 6N x 6N,向量 b 是 6N。矩陣 H 可以非常大,但其元素大部分為零,因為 H 僅在對應(yīng)節(jié)點之間存在約束的情況下才為非零。因此,將 H 視為稀疏矩陣是有利的。構(gòu)建稀疏矩陣和求解方程由Eigen執(zhí)行,SimplicialLDLT 作為稀疏線性求解器。
占用網(wǎng)格圖
3D 占用網(wǎng)格圖是從優(yōu)化的位姿圖和密集的深度圖生成的。地圖的實際生成由Octomap執(zhí)行。結(jié)果以“二叉樹(.bt)”格式存儲在 SD 卡上。
表現(xiàn)
KITTI 數(shù)據(jù)集在驗證算法時用作參考。
準確性
下圖是用KITTI數(shù)據(jù)集序列00模擬時的軌跡鳥瞰圖。
在此仿真中,主要在 5 個區(qū)域檢測到閉環(huán),平移和旋轉(zhuǎn)誤差分別為 0.91% 和 0.0038 度/米。
請注意,此結(jié)果僅顯示算法的性能,因為此仿真中使用的圖像是由不同的圖像傳感器捕獲的。
3D 占用網(wǎng)格地圖
下圖是在上述模擬中生成并由octovis顯示的 3D 占用網(wǎng)格圖。密集深度圖的分辨率在兩個方向上都降低了 1 / 4,然后在通過 Octomap 構(gòu)建體素圖之前通過估計的相機姿勢進行投影。
處理時間
下圖顯示了處理圖像傳感器輸入時應(yīng)用程序和 FPGA 主線程的處理時間。
視覺關(guān)鍵詞更新和閉環(huán)檢測在應(yīng)用程序的子線程中運行。處理時間隨著視覺詞的數(shù)量增加,如下所示。
時隙為 500 毫秒,因為它們每 5 幀運行一次。當處理時間超過這個時隙時,下一次執(zhí)行將推遲到上一個線程完成,這樣就不會干擾視覺里程計的實時運行。
內(nèi)存消耗
下圖顯示了在 Windows 上處理 KITTI 數(shù)據(jù)集序列 00 時的內(nèi)存消耗(僅顯示前 1700 幀)。內(nèi)存消耗隨著時間的推移而增加,其中大部分是密集的深度圖和視覺詞。當應(yīng)用程序運行在FPGA上時,這塊內(nèi)存占用了Linux控制的內(nèi)存空間,限制了連續(xù)運行的時間。
FPGA利用率
下表顯示了 FPGA 資源利用率。FPGA設(shè)備是 XCZU3EG-SBVA484-1-I。
如何復(fù)現(xiàn)
先決條件
Xilinx Tools 2020.2 必須安裝在兩個平臺(Ubuntu和Windows)上。
Petalinux 2020.2 必須安裝在 Ubuntu 上。
假定 Xilinx Tools 安裝到 Ubuntu 上的 [XILINX_DIR]。
假定 git 中的必要文件已復(fù)制到兩個平臺。
下載 Eigen 3.4.0 并將其放置在“slam/include”目錄下,目錄結(jié)構(gòu)如下:
?
slam ?└─include ???????└─Eigen
?
硬件
傳感器板的擴展接口是開漏電路,不能直接控制開關(guān)和LED。因此,在 Button G click board 上需要進行以下修改。
構(gòu)建 FPGA 項目(在 Windows 上)
git文件中已經(jīng)構(gòu)建好項目。
“dvp”項目
啟動 Vivado,并在“Tcl Console”中鍵入以下命令。
?
cd?[WORK_DIR]/U96-SLAM/vivado source?create_dvp.tcl
?
? 將創(chuàng)建名為“dvp”的項目。
點擊“工具→創(chuàng)建并打包新IP...”,打開“創(chuàng)建并打包新IP”對話框。繼續(xù)進行以下設(shè)置。
?
[Create?Peripheral,?Package?IP?or?Package?a?Block?Design] ??Packaging?Options:?Package?your?current?project [Package?Your?Current?Project] ??IP?location:?[WORK_DIR]/U96-SLAM/src/ip_repo/dvp
?
出現(xiàn)提示時選擇“是”,然后單擊“完成”。
將出現(xiàn)“Package IP - dvp”。
選擇“Review and Package”,點擊“Package IP”。
? “dvp”的 IP 源將導(dǎo)出到“ip_repo/dvp”目錄。
關(guān)閉“dvp”項目。
“fpga_top”項目
啟動 Vivado,并在“Tcl Console”中鍵入以下命令。
?
cd?[WORK_DIR]/U96-SLAM/vivado source?create_fpga_top.tcl
?
? 將創(chuàng)建名為“fpga_top”的項目。
雙擊“Sources”面板中的“Design Sources→design_1_wrapper→design_1_i”,打開“design_1.bd”框圖。
如果“/dvp_0 block in this design should be upgraded.” 顯示在窗口頂部,單擊“Report IP Status”,然后單擊“Upgrade Selected”。只有當修改了“dvp”模塊時才會發(fā)生這種情況。
單擊 Flow Navigator 中的“Generate Bitstream”。
? “design_1.bit”將在“fpga_top.runs/impl_1/”目錄中創(chuàng)建。
單擊“File→Export→Export Hardware”打開“Export Hardware Platform”對話框。繼續(xù)進行以下設(shè)置。
?
[Output] ??Include?bitstream:?Selected [Files] ??XSA?file?name:?design_1_wrapper ??Export?to:?[WORK_DIR]/U96-SLAM/vivado/fpga_top
?
? “design_1_wrapper.xsa”將在指定目錄中創(chuàng)建。
構(gòu)建裸機應(yīng)用程序(在 Windows 上)
只有在修改裸機應(yīng)用程序時才需要此項目。“StereoBM.elf”已經(jīng)包含在 git 存儲庫中。
在“[WORK_DIR]/U96-SLAM”下創(chuàng)建名為“vitis”的目錄。啟動 Vitis,將此目錄設(shè)置為 Vitis Workspace,然后單擊“Launch”。
?
[WORK_DIR]/U96-SLAM/vitis
?
單擊“Create Application Project”以打開“新建應(yīng)用程序項目”對話框。繼續(xù)進行以下設(shè)置。注意選擇R5處理器。
?
[Platform] ??Create?a?new?platform?from?hardware?(XSA) ??XSA?File:?[WORK_DIR]U96-SLAMvivadofpga_topdesign_1_wrapper.xsa ??Target?processor?to?create?FSBL:?psu_cortexr5_0 [Application?Project?Details] ??Application?project?name:?StereoBM ??Target?processor:?psu_cortexr5_0 [Domain] ??Remain?as?default [Templates] ??SW?development?templates:?Empty?Application
?
單擊“完成”。
? 將創(chuàng)建“StereoBM_system”項目。
在“Application Project Settings”中,單擊“Navigate to BSP Settings”。
點擊“Board Support Package”中的“Modify BSP Settings...”。“板級支持包設(shè)置”對話框?qū)⒋蜷_。
點擊“Overview→standalone”,進行如下修改。
?
stdin:?psu_uart_1 stdout:?psu_uart_1
?
這是必要的,因為 uart_1 在 開發(fā)板中用作標準輸入/輸出。
在“Explorer”中右鍵單擊“StereoBM_system→StereoBM→src”,然后從菜單中單擊“Import Sources...”以打開“Import Sources”對話框。繼續(xù)進行以下設(shè)置。
?
From?directory:?[WORK_DIR]/U96-SLAM/src/StereoBM/src Select?All:?click
?
單擊“完成”。
在資源管理器窗格中選擇“StereoBM”,然后通過單擊 Hammer 圖標旁邊的箭頭圖標選擇“Release”構(gòu)建。
? “StereoBM.elf”將在“Release”目錄中生成。
構(gòu)建“StereoBM_system”而不是“StereoBM”也會生成 ROM 引導(dǎo)文件。
構(gòu)建 Petalinux 系統(tǒng)(在 Ubuntu 上)
配置系統(tǒng)
獲取 Petalinux 環(huán)境。
?
source?[XILINX_DIR]/petaLinux-2020.2/bin/settings.sh
?
通過鍵入以下命令創(chuàng)建“petalinux”項目。
?
cd?[WORK_DIR]/U96-SLAM petalinux-create?--type?project?--template?zynqMP?--name?petalinux cd?petalinux/
?
? “petalinux”目錄將在 [WORK_DIR]/U96-SLAM/” 下創(chuàng)建。
將“design_1_wrapper.xsa”復(fù)制到“U96-SLAM/vivado”目錄。如果沒有更改 FPGA 設(shè)計,則在 git 存儲庫的“U96-SLAM/bin”目錄中提供預(yù)構(gòu)建文件。
如下配置 Petalinux 系統(tǒng)。
以下“petalinux-xxxx”命令必須在“petalinux”目錄中發(fā)出。
?
petalinux-config?--get-hw-description?../vivado
?
“misc/config 系統(tǒng)配置”對話框?qū)⒋蜷_。進行以下設(shè)置,然后“退出”。
?
Subsystem?AUTO?Hardware?Settings?→?Serial?Settings?→ ??PMUFW?Serial?stdin/stdout?:?psu_uart_1 ??FSBL?Serial?stdin/stdout:?psu_uart_1 ??ATF?Serial?stdin/stdout:?psu_uart_1 ??DTG?Serial?stdin/stdout:?psu_uart_1 DTG?Settings?→?MACHINE_NAME:?avnet-ultra96-rev1 Image?Packaging?Configuration?→?Root?filesystem?type:?EXT4?(SD/eMMC/SATA/USB)
?
以下命令第一次運行可能需要很長時間。
?
petalinux-config?-c?kernel “Linux/arm64?5.4.0?內(nèi)核配置”對話框?qū)⒋蜷_。進行以下設(shè)置,然后“退出”。 Enable?loadable?module?support?[*]?(default) Networking?support?→?Bluetooth?subsystem?support?> Device?Drivers?→?Remoteproc?drivers?→ ??Support?for?Remote?Processor?subsystem?[*]?(default) ??ZynqMP_r5?remoteproc?support??(default) ??
?
最后,鍵入以下配置命令。
?
petalinux-config?-c?rootfs
?
“Configuration”對話框?qū)⒋蜷_。進行以下設(shè)置,然后“退出”。
?
Filesystem?Packages?→ ??libs?→?libmetal?→?libmetal?[*] ??misc?→?gdb?[*]?(for?debug?purpose) ???????→?sysfsutils?→?libsysfs?[*] Petalinux?Package?Groups?→ ??packagegroup-petalinux-openamp?→?packagegroup-petalinux-openamp?[*] ??packagegroup-petalinux-opencv?→?packagegroup-petalinux-opencv?[*] Image?Features?→?auto-login?[*]
?
在“[WORK_DIR]/U96-SLAM/petalinux/project-spec/meta-user/recipes-bsp/device-tree/files/”中打開“system-user.dtsi”并復(fù)制并粘貼以下文本。
?
/include/?"system-conf.dtsi" /?{ reserved-memory?{ ????????#address-cells?=?<2>; ????????#size-cells?=?<2>; ????????ranges; ????????rproc_0_dma:?rproc@0x6ed00000?{ ????????????no-map; ????????????compatible?=?"shared-dma-pool"; ????????????reg?=?<0x0?0x6ed00000?0x0?0x00100000>; ????????}; ????????rproc_0_reserved:?rproc@0x5ed00000?{ ????????????no-map; ????????????reg?=?<0x0?0x5ed00000?0x0?0x10000000>; ????????}; ????}; ????zynqmp-rpu?{ ????????compatible?=?"xlnx,zynqmp-r5-remoteproc-1.0"; ????????#address-cells?=?<2>; ????????#size-cells?=?<2>; ????????ranges; ????????core_conf?=?"split"; ????????r5_0:?r5@0?{ ????????????#address-cells?=?<2>; ????????????#size-cells?=?<2>; ????????????ranges; ????????????memory-region?=?<&rproc_0_reserved>,?<&rproc_0_dma>; ????????????pnode-id?=?<0x7>; ????????????mboxes?=?<&ipi_mailbox_rpu0?0>,?<&ipi_mailbox_rpu0?1>; ????????????mbox-names?=?"tx",?"rx"; ????????????tcm_0_a:?tcm_0@0?{ ????????????????reg?=?<0x0?0xFFE00000?0x0?0x10000>; ????????????????pnode-id?=?<0xf>; ????????????}; ????????????tcm_0_b:?tcm_0@1?{ ????????????????reg?=?<0x0?0xFFE20000?0x0?0x10000>; ????????????????pnode-id?=?<0x10>; ????????????}; ????????}; ????}; ????zynqmp_ipi1?{ ????????compatible?=?"xlnx,zynqmp-ipi-mailbox"; ????????interrupt-parent?=?<&gic>; ????????interrupts?=?<0?29?4>; ????????xlnx,ipi-id?=?<7>; ????????#address-cells?=?<1>; ????????#size-cells?=?<1>; ????????ranges; ????????/*?APU<->RPU0?IPI?mailbox?controller?*/ ????????ipi_mailbox_rpu0:?mailbox@ff90000?{ ????????????reg?=?<0xff990600?0x20>, ??????????????????<0xff990620?0x20>, ??????????????????<0xff9900c0?0x20>, ??????????????????<0xff9900e0?0x20>; ????????????reg-names?=?"local_request_region", ????????????????????????"local_response_region", ????????????????????????"remote_request_region", ????????????????????????"remote_response_region"; ????????????#mbox-cells?=?<1>; ????????????xlnx,ipi-id?=?<1>; ????????}; ????}; ????chosen?{ ????????bootargs?=?"console=ttyPS0,115200?root=/dev/mmcblk0p2?rw?earlyprintk?rootfstype=ext4?rootwait?uio_pdrv_genirq.of_id=generic-uio?devtmpfs.mount=1?earlycon"; ????}; }; &dvp_0?{ ??compatible?=?"generic-uio"; };
?
該文件聲明使用遠程處理器并保留其內(nèi)存空間。該文件還將FPGA內(nèi)部的“dvp”模塊設(shè)置為“generic-uio”設(shè)備,以便我們可以使用內(nèi)置的“generic-uio”設(shè)備驅(qū)動程序訪問它。
自動運行應(yīng)用程序
以下過程將使我們的應(yīng)用程序在系統(tǒng)啟動時自動運行。
?
petalinux-create?-t?apps?--template?install?-n?myinit?--enable
?
? “myinit”目錄將在“project-spec/meta-user/recipes-apps”下創(chuàng)建。
將以下文本復(fù)制并粘貼到“myinit.bb”和“files/myinit”。
【myinit.bb】
?
# #?This?file?is?the?myapp-init?recipe. # SUMMARY?=?"Simple?myinit?application" SECTION?=?"PETALINUX/apps" LICENSE?=?"MIT" LIC_FILES_CHKSUM?=?"file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" SRC_URI?=?"file://myinit? ?" S?=?"${WORKDIR}" FILESEXTRAPATHS_prepend?:=?"${THISDIR}/files:" inherit?update-rc.d INITSCRIPT_NAME?=?"myinit" INITSCRIPT_PARAMS?=?"start?99?S?." do_install()?{ ?install?-d?${D}${sysconfdir}/init.d ?install?-m?0755?${S}/myinit?${D}${sysconfdir}/init.d/myinit } FILES_${PN}?+=?"${sysconfdir}/*"
?
【文件/myinit】
?
#!/bin/sh cd?~/home/root ./run
?
這些文件使“myinit”成為一個啟動應(yīng)用程序,它將在“home/root”目錄中執(zhí)行“run”腳本。
構(gòu)建 Petalinux
現(xiàn)在我們可以通過以下命令構(gòu)建 Petalinux 系統(tǒng)。
“petalinux-build”命令可能需要很長時間。
?
petalinux-build
?
第一次會出現(xiàn)錯誤消息,說明設(shè)備樹中存在錯誤。然后,打開以下目錄中的“pl.dtsi”,刪除mipi_csi_rx_subsyst_0和mipi_csi_rx_subsyst_1條目。
?
“[WORK_DIR]/U96-SLAM/petalinux/components/plnx_workspace/device-tree/device-tree/pl.dtsi”
?
生成的文件應(yīng)如下所示。
【pl.dtsi】
?
/?{ ?amba_pl:?amba_pl@0?{ ??#address-cells?=?<2>; ??#size-cells?=?<2>; ??compatible?=?"simple-bus"; ??ranges?; ??dvp_0:?dvp@a0000000?{ ???clock-names?=?"s00_axi_aclk",?"m00_axi_aclk"; ???clocks?=?<&zynqmp_clk?71>,?<&zynqmp_clk?71>; ???compatible?=?"xlnx,dvp-1.0"; ???interrupt-names?=?"intr"; ???interrupt-parent?=?<&gic>; ???interrupts?=?<0?89?4>; ???reg?=?<0x0?0xa0000000?0x0?0x10000>; ???xlnx,m00-axi-addr-width?=?<0x20>; ???xlnx,m00-axi-aruser-width?=?<0x0>; ???xlnx,m00-axi-awuser-width?=?<0x0>; ???xlnx,m00-axi-burst-len?=?<0x10>; ???xlnx,m00-axi-buser-width?=?<0x0>; ???xlnx,m00-axi-data-width?=?<0x20>; ???xlnx,m00-axi-id-width?=?<0x1>; ???xlnx,m00-axi-ruser-width?=?<0x0>; ???xlnx,m00-axi-target-slave-base-addr?=?<0x40000000>; ???xlnx,m00-axi-wuser-width?=?<0x0>; ??}; ??misc_clk_0:?misc_clk_0?{ ???#clock-cells?=?<0>; ???clock-frequency?=?<200000000>; ???compatible?=?"fixed-clock"; ??}; ??misc_clk_1:?misc_clk_1?{ ???#clock-cells?=?<0>; ???clock-frequency?=?<1500000000>; ???compatible?=?"fixed-clock"; ??}; ?}; };
?
CSI 接口似乎會自動添加到設(shè)備樹中,但我們在這里不需要它們,因為它們由裸機應(yīng)用程序控制。
此文件是自動生成的,不應(yīng)手動編輯,但我找不到其他方式解決上面的問題。每次編輯“system-user.dtsi”時,此問題仍然存在。
然后再次構(gòu)建 Petalinux 系統(tǒng)。
?
petalinux-build
?
這次項目應(yīng)該構(gòu)建成功了。
創(chuàng)建SDK
鍵入以下命令為平臺項目創(chuàng)建 SDK。
?
petalinux-build?--sdk
?
這將在“/images/linux/”目錄中生成“sdk.sh”。
然后鍵入以下命令以在當前位置解壓“sdk.sh”。
?
cd?images/linux petalinux-package?--sysroot
?
構(gòu)建平臺項目(在 Ubuntu 上)
在“petalinux/images/linux/”目錄下創(chuàng)建“l(fā)inux.bif”文件。然后復(fù)制并粘貼以下文本。
【linux.bif】
?
/*?linux?*/ the_ROM_image: { ????[fsbl_config]?a53_x64 ????[bootloader]?????[pmufw_image]? ????[destination_device=pl]? ????[destination_cpu=a53-0,?exception_level=el-3,?trustzone]? ????[destination_cpu=a53-0,?exception_level=el-2]? }
?
啟動 Vitis,并選擇“[WORK_DIR]/U96-SLAM/vitis”作為其工作區(qū)。
點擊“File→New→Platform Project...”打開“New platform project”對話框。繼續(xù)進行以下設(shè)置。
?
[Create?new?platform?project] ??Platform?project?name:?platform [Platform] ??Choose?"Create?a?new?platform?from?hardware?(XSA)". ??XSA?File:?[WORK_DIR]/U96-SLAM/vivado/fpga_top/design_1_wrapper.xsa ??Operating?system:?linux ??Processor:?psu_cortexa53 ??Architecture:?64-bit ??Generate?boot?components:?checked ??Target?processor?to?create?FSBL:?psu_cortexa53_0
?
單擊“完成”。
在左窗格中選擇“platform→psu_cortexa53→linux on psu_cortexa53”。
在“域:linux_domain”對話框中填寫以下信息。
?
Bif?File?????????????????:?[WORK_DIR]/U96-SLAM/petalinux/images/linux/linux.bif Boot?Components?Directory:?[WORK_DIR]/U96-SLAM/petalinux/images/linux/ Linux?Image?Directory????:?[WORK_DIR]/U96-SLAM/petalinux/images/linux/ Linux?Rootfs?????????????:?[WORK_DIR]/U96-SLAM/petalinux/images/linux/rootfs.tar.gz Sysroot?Directory????????:?[WORK_DIR]/U96-SLAM/petalinux/images/linux/sdk/sysroots/aarch64-xilinx-linux
?
選擇“平臺→psu_cortexa53_0→zynqmp_fsbl→板級支持包”
單擊“修改 BSP 設(shè)置...”。
選擇“Overview → standalone”,修改如下。
?
stdin?:?psu_uart_1 stdout?:?psu_uart_1
?
單擊“確定”。
通過單擊錘子圖標構(gòu)建項目。
? 將在 Vitis 工作區(qū)中創(chuàng)建一個名為“platform”的項目。
現(xiàn)在我們準備構(gòu)建一個運行在該平臺上的 Linux 應(yīng)用程序。
構(gòu)建 SLAM 應(yīng)用程序 (Ubuntu)
啟動 Vitis,并選擇“[WORK_DIR]/U96-SLAM/vitis”作為其工作區(qū)。
點擊“File→New→Application Project...”打開“New Application Projec”對話框。
繼續(xù)進行以下設(shè)置。
?
[Platform] ??Select?a?platform?from?repository:?platform?[custom] [Application?Project?Details] ??Application?project?name:?slam [Domain] ??Remain?as?default. [Templates] ??SW?development?templates:?Empty?Application?(C++)
?
如果在 git 控制的目錄中創(chuàng)建 Vitis 工作區(qū),則可能無法識別平臺項目。如果發(fā)生這種情況,請嘗試在 git 控制的目錄之外的某個位置創(chuàng)建 Vitis 工作區(qū)。
單擊“完成”。
? 將創(chuàng)建名為“slam”的項目。
將 git 存儲庫中“vitis/slam”中的“src”和“include”目錄復(fù)制到 [WORK_DIR]/U96-SLAM/vitis/slam/”目錄。
單擊錘子圖標旁邊的箭頭圖標并選擇“Release”。
在“Explorer”中右擊“slam”,選擇“C/C++ Build Settings”。設(shè)置如下。
?
[ARM?v8?Linux?g++?compiler] ?├─Directories ?│??└─Include?Paths ?│?????[WORK_DIR]/U96-SLAM/petalinux/images/linux/sdk/sysroots/aarch64-xilinx-linux/usr/include ?│?????[WORK_DIR]/U96-SLAM/vitis/slam/include ?└─Miscellaneous ????-c?-fmessage-length=0?-MT"$@"?-ftemplate-backtrace-limit=0 [ARM?v8?Linux?g++?linker] ?└─Libraries ???└─Libraries ??????opencv_core ??????opencv_photo ??????opencv_video ??????opencv_videoio ??????opencv_optflow ??????opencv_tracking ??????opencv_features2d ??????opencv_imgcodecs ??????opencv_highgui ??????opencv_imgproc ??????opencv_calib3d ??????pthread
?
右鍵單擊“Explorer”中的“slam”,然后單擊“Clean Project”。
再次右鍵單擊“slam”并單擊“Build Project”。
? 將生成“Release/slam.elf”。
準備 SD 卡(在Ubuntu 上)
SD 卡使用 GParted 格式化,如下圖所示。
■ 引導(dǎo)文件
如果更改了 FPGA 設(shè)計,請將“design_1_wrapper.bit”從 Windows 復(fù)制到 Ubuntu。以下命令假定“.bit”文件位于“/vivado”目錄中。
鍵入以下命令以創(chuàng)建“BOOT.BIN”。
?
cd?[WORK_DIR]/U96-SLAM/petalinux petalinux-package?--boot?--force?--fsbl?images/linux/zynqmp_fsbl.elf?--fpga?../vivado/design_1_wrapper.bit?--u-boot
?
? “BOOT.BIN”將在“/petalinux/images/linux/”目錄中生成。
將以下3個文件復(fù)制到SD卡的BOOT目錄下。
?
[WORK_DIR]/U96-SLAM/petalinux/images/linux/boot.scr ???????????????????????????????????????????BOOT.BIN ???????????????????????????????????????????image.ub
?
■ 系統(tǒng)文件
通過以下命令將“rootfs.tar.gz”解壓到SD卡的“root”目錄下。
?
sudo?tar?xzvf?[WORK_DIR]/U96-SLAM/petalinux/imeges/linux/rootfs.tar.gz?-C?[SD_CARD_DIR]/root
?
在“[SD_CARD_DIR]/root/lib/”目錄下創(chuàng)建“firmware”目錄。
將“StereoBM.elf”和“slam.elf”復(fù)制到上述目錄。
運行應(yīng)用程序
根據(jù)自動運行設(shè)置,會自動執(zhí)行SD卡上“root/home/root/”目錄下的“run”腳本。
創(chuàng)建一個名為“run”的文件并賦予其執(zhí)行權(quán)限。
?
chmod?774?run
?
然后,復(fù)制粘貼以下內(nèi)容,將文件移動到SD卡的“root/home/root/”目錄下。
【home/root/run】
?
rm?*.csv rm?*.bmp rm?*.png rm?*.jpg rm?*.txt rm?-rf?work echo?StereoBM.elf?>?/sys/class/remoteproc/remoteproc0/firmware echo?start?>?/sys/class/remoteproc/remoteproc0/state #/lib/firmware/slam.elf?-app?"STEREO_CAPTURE"?-lc?"calib_left.yml"?-rc?"calib_right.yml" #/lib/firmware/slam.elf?-app?"FRAME_GRABBER" #/lib/firmware/slam.elf?-app?"SLAM_BATCH"?-dir?"kitti/sequences/00"?-l?"image_0"?-r?"image_1"?-t?"times.txt"?-gt?"../../poses/00.txt"?-lc?"calib.txt"?-n?100 /lib/firmware/slam.elf?-app?"SLAM_REALTIME"?-lc?"calib_left.yml"?-rc?"calib_right.yml" shutdown?-h?now
?
“echo”命令與將在遠程處理器上啟動“StereoBM”應(yīng)用程序的 OpenAMP 相關(guān)。“StereoBM.elf”必須位于“l(fā)ib/firmware”中。
接下來的幾行啟動帶有一些參數(shù)的 SLAM 應(yīng)用程序。此文件包含每種應(yīng)用程序類型的示例。取消注釋其中之一并適當修改它。
最后一行將關(guān)閉操作系統(tǒng)。如果操作系統(tǒng)未正確關(guān)閉,則可能不會生成輸出文件。
根據(jù)應(yīng)用類型,可能還需要此目錄中的校準文件和測試數(shù)據(jù)。
實用程序
git 上包含一些實用程序。
它們是為 Windows 上的 Visual C++ Express 2015 編寫的。除“slam”項目外,源文件位于各自的目錄中。“slam”項目的源文件與我們已經(jīng)構(gòu)建的 Petalinux 上的“slam”項目相同。創(chuàng)建 Visual C++ 項目并將源文件添加到項目中。
這里列出了成功構(gòu)建所需的其他設(shè)置。它們適用于“Release/x64”構(gòu)建。
所有這些程序都是基于OpenCV 3.x 。在本文中,假設(shè) OpenCV 3.2.0 安裝在以下目錄結(jié)構(gòu)中。
?
opencv-3.2.0 ??└─build ????├─include ????│?└─opencv2 ????└─x64 ??????└─vc14 ????????├─bin ????????│?├─opencv_world320.dll ????????│?└─opencv_world320d.dll ????????└─lib ??????????├─opencv_world320.lib ??????????└─opencv_world320d.lib
?
■ 捕獲視頻
該程序從 USB 視頻類設(shè)備捕獲圖像。
當按下“Enter”鍵時,接收到的圖像將在寫入文件之前水平分成兩半。如果與在“Frame Grabber”模式下運行的 U96-SLAM 一起使用,該程序?qū)⑦m當?shù)刈笥曳指顖D像。按“ESC”退出程序。
“main.cpp”中的“DEVICE_ID”決定了打開哪個設(shè)備。這些索引由系統(tǒng)以增量順序自動分配。可能需要根據(jù)已連接到的 PC 的 UVC 設(shè)備的數(shù)量更改該值。
?
[Configuration?Properties] ??C/C++?→?General?→?Additional?Include?Directory:? ????[OPENCV_DIR]opencv-3.2.0uildinclude ??Linker?→?General?→?Additional?Library?Directories:? ????[OPENCV_DIR]opencv-3.2.0uildx64vc14lib ???????????Input?→?Additional?Dependencies:?opencv_world320.lib [Argument?parameters] ??None
?
■ stereo_calib
該程序讀取棋盤圖案的立體圖像對,使用 OpenCV 函數(shù)計算立體校準參數(shù),然后將它們存儲到文件中。
?
[Configuration?Properties] ??C/C++?→?General?→?Additional?Include?Directory:? ????[OPENCV_DIR]opencv-3.2.0uildinclude ??Linker?→?General?→?Additional?Library?Directories:? ???[OPENCV_DIR]opencv-3.2.0uildx64vc14lib ???????????Input?→?Additional?Dependencies:?opencv_world320.lib [Argument?parameters] ??-w,?-h?:?The?number?of?the?'inner'?intersections?of?the?chessboard?pattern. ??-s?:?The?size?of?the?grid?in?meters.?The?unit?of?this?parameter?is?important?as?it?determines?all?the?subsequent?units?including?the?pose?graph?output?of?SLAM?application. [Example] ??-w=7?-h=5?-s=0.03?[FILE_PATH]/dataset.xml
?
■ SLAM
這是 SLAM 應(yīng)用程序的 Windows 版本。源文件與 Petalinux 上的 SLAM 應(yīng)用程序相同。將“src”目錄下的所有文件添加到項目中。在 Windows 上只有沒有 FPGA 加速的批處理模式可用。
?
[Configuration?Properties] ??C/C++?→?General?→?Additional?Include?Directory:? ????[OPENCV_DIR]opencv-3.2.0uildinclude ????[WORK_DIR]U96-SLAMvcslaminclude ??????????Advanced?→?Disable?Specific?Warnings:?4996;4819 ??Linker?→?General?→?Additional?Library?Directories:? ????[OPENCV_DIR]opencv-3.2.0uildx64vc14lib ???????????Input?→?Additional?Dependencies:?opencv_world320.lib [Argument?parameters] -app????:?Application?type,?only?"SLAM_BATCH"?is?available. -dir????:?Base?directory?path.?All?the?below?paths?are?relative?to?this?directory. -l/-r???:?Image?file?paths. -lc/-rc?:?Calibration?file?paths. -t??????:?Path?to?timestamp?file. -gt?????:?Path?to?ground?truth?file. -n??????:?Number?of?files?to?be?preocessed,?negative?value?means?all?files. [Example] -app?"SLAM_BATCH"?-dir?"KITTI/odometry/dataset/sequences/00"?-l?"image_0"?-r?"image_1"?-t?"times.txt"?-gt?"../../poses/00.txt"?-lc?"calib.txt"?-n?-1
?
審核編輯:劉清
評論
查看更多