【無人駕駛系列四】 基於Spark與ROS分散式無人駕駛模擬平臺
本文是無人駕駛技術系列的第四篇,著重介紹基於Spark與ROS的分散式無人駕駛模擬平臺。無人駕駛的安全性和可靠性是通過海量的功能和效能測試來保證的。無人駕駛系統是一個複雜的系統工程,在它的整個研發流程中,測試工作至關重要同時也繁重複雜。顯然將全部測試工作都集中在真車上進行是一種成本異常高昂且安全係數非常低的方案。通過綜合考慮測試中各種可能發生的正常或異常狀況,軟體模擬成為了面向無人駕駛系統的更安全且更經濟有效的替代測試手段。
無人駕駛模擬技術
無人車駕駛系統由感知、預測、決策、控制等眾多功能模組組成,每個模組都各自擁有複雜的結構和演算法。絕大部分情況下,系統開發人員在測試過程中很難對海量的輸出引數作評價。同時,開發人員不僅需要單獨測試一個功能模組,也需要集合聯調多個模組。因此,系統開發人員所需要的模擬器必須能夠直觀正確地反映出輸出引數的意義,同時還要既能對各個模組進行單一的測試,又能將各個模組按照不同需求組合後進行整合測試。
模擬器技術主要有兩種:第一種是基於合成數據對環境、感知以及車輛進行模擬,這種模擬器主要用於控制與規劃演算法的初步開發上;第二種是基於真實資料的回放以測試無人駕駛不同部件的功能及效能。在本文中,我們主要討論基於資料回放的模擬器。
出於需儘量真實地模擬真車環境的需求,我們的模擬器採用了和真車相同的機器人作業系統ROS。ROS是一種基於訊息傳遞通訊的分散式計算框架。這種框架方便開發人員進行模組化程式設計,這一特性對於模擬器來說至關重要。在無人駕駛系統中,每一個功能模組在ROS中都部署在一個節點上,節點間的通訊依靠事先定義好格式的message完成。在模擬器中開發人員只需要使用相同的通訊格式,針對每個功能模組製作模擬模組,然後根據測試需求搭配真實功能模組和模擬模組。例如,如果想進行決策模組和控制模組的功能聯調,我們需要將決策模組、控制模組搭配其他的模擬模組,安裝到模擬器中進行測試。如果決策模組需要單獨測試新的決策演算法,我們可以只將新的決策模組搭配其他的模擬模組安裝到模擬器上,這樣的測試結果就是隻針對決策模組的。
模擬器的組成元素
首先,無人駕駛汽車模擬器中包含了車的動態模型,用來載入測試無人車駕駛系統,並模擬無人駕駛汽車自身的行為。其次,需要模擬的是外部環境,包括靜態和動態的場景。靜態場景中包括各種靜態的交通標誌,例如停止線、交通指示牌等;動態場景主要指車周圍的動態交通流模型,例如車輛、行人、交通燈等。所有這些元素構建了與現實環境相對應的模擬世界。
模擬器的應用
無人駕駛汽車真實上路後所要面臨的外部環境是複雜多變的。模擬器在模擬測試中需要做的就是將複雜的外部環境拆解成最簡單的元素,然後重新排列組合,生成各種測試用例。
圖1 模擬器應用
圖1 模擬器應用
拿一組簡單的測試用例舉例。圖1是一個簡單的直線行駛的車道,需要測試的是無人駕駛汽車對於一輛障礙車的反應。按照障礙車可能出現的起始位置劃分,它可能出現於無人駕駛汽車的左前、左中、左後、前、後、右前、右中、右後總計八個位置。按照障礙車和無人駕駛汽車的相對速度,可分為比無人駕駛汽車快、和無人駕駛汽車速度相等以及比無人駕駛汽車慢三類。按照障礙車的行為劃分則分為直行、向左變道和向右變道三種。將這些變數相乘,再去掉其中不需要的個例,就得到了一組我們需要的測試用例。
模擬器面臨的問題
模擬器的核心問題在於“真”上,人工模擬的場景和真實場景多少會有差異,真實場景中仍然會存在許多令人想象不到的突發事件。因此,如果能採用真實的行車資料復現真實場景,就會得到比人工模擬的場景更好的測試效果。但採用真實資料復現的方案帶來的問題就是海量資料的處理。如果我們想在模擬器上覆現真實世界中每一段道路的場景,就需要讓無人駕駛汽車去採集每一段道路的資訊,這些海量的資訊是單機無法處理的,而且在每個場景下拆解元素重新排列組合生成測試用例的做法會使計算量翻倍。因此,將模擬器搭載到分散式系統上就成為了無人駕駛模擬測試的最佳選擇。
基於ROS的無人駕駛模擬器
ROS是一種基於訊息傳遞通訊的分散式計算框架。它的通訊模式可以抽象為一種message pool架構,訊息傳送節點呼叫advertise方法向指定Topic傳送ROS message,訊息接收節點呼叫subscribe方法從指定Topic接收ROS message。
ROSBAG
Rosbag是利用這一架構從Topic中錄製並且向Topic中重新播放ROS message的工具,無人駕駛汽車在資料採集過程中使用的正是Rosbag。它的功能主要分為Record和Play兩類。Record功能是在ROS中建立一個record節點,呼叫subscribe方法向所有或指定Topic接收ROS message,然後將message寫入Bag檔案。Play功能則是在ROS中建立一個play節點,呼叫advertise方法將bag中message按照時間節點發送至指定Topic。圖2展示了一個LiDAR資料在ROS中回放的例項,在這個場景中,LiDAR資料是以10Hz幀率記錄的。
圖2 ROS BAG LiDAR資料回放
圖2 ROS BAG LiDAR資料回放
Rosbag生成的資料格式是Bag,這是一個擁有兩層邏輯結構的檔案格式。如圖3所示,上層的Bag類對上抽象提供了使用者操作檔案的方法,對下封裝了對ChunkedFile的操作方法;ChunkedFile類主要對資料進行了分隔儲存,而儲存的資料為一條條ROS message,不僅包含文字資訊,也包含大量的二進位制資料,後者主要是無人駕駛汽車感測器傳送的圖片或3D點雲檔案資料。這就給傳統的主要用來處理文字日誌的分散式計算系統應用帶來了新挑戰。
圖3 ROS BAG 結構圖
圖3 ROS BAG 結構圖
模擬測試資料集
如前所述,我們主要關注基於真實資料回放的模擬器,資料量有多大呢?以來自真實世界的KITTI資料集為例(由KIT和TTIC在2012年啟動的一個合作專案,網站為http://www.cvlibs.net/datasets/kitti/,更詳細的介紹請參見《程式設計師》2016年7月刊《基於計算機視覺的無人駕駛感知系統》),KITTI的研究人員錄製了6個小時的真實資料,資料量為720GB。但是6小時的資料僅夠完成一些演算法的簡單驗證,無人駕駛產品所需求的資料量遠大於此。比如谷歌的無人車在過去幾年中收集了超過40000小時的真實資料,總資料量估計超過了5PB。如此大量的資料,基於單機的模擬遠不能支撐其處理,所以我們必須為基於真實資料回放的模擬器設計一個高效的分散式計算平臺。
計算量的挑戰
巨大的資料處理量對計算平臺造成很大的壓力。例如,KITTI資料整集6小時的原資料包括了超過1000000張140萬畫素的彩圖,如果使用單機的基於深度學習的影象識別平臺,每張彩圖分析時間大概是0.3秒。這樣,僅是分析KITTI資料集的圖片,就需要超過100小時,而如果分析谷歌無人車級別的整體圖片資料,在單機處理上就需要超過60萬個小時。
基於Spark的分散式模擬平臺
Spark是UC Berkeley AMPLab開源的通用平行計算框架。Spark基於記憶體實現的分散式計算,擁有Hadoop所具有的優點;但不同於Hadoop,Spark Job的中間輸出和結果可以儲存在記憶體中,從而不再需要讀寫HDFS,因此Spark能更好地應用於需要迭代的Map-Reduce演算法。
圖4 分散式模擬平臺總體架構
圖4 分散式模擬平臺總體架構
如圖4所示,為了高效地進行無人駕駛回放模擬,我們設計了基於Spark的分散式模擬平臺框架。我們使用Spark進行資源的分配管理、資料的讀寫以及ROS的節點管理。在Spark Driver上,我們可以觸發不同的模擬應用,比如基於LiDAR的定位、基於圖片的物體識別、車輛決策與控制等。Spark Driver會根據資料量與計算量等需求請求Spark worker資源。每個Spark worker首先會把Rosbag資料讀入記憶體,然後通過pipe啟動ROS Node程序進行計算。我們也可以使用JNI方式連線Spark worker以及ROS Node,但這將涉及對ROS的修改,使得整個系統難以維護與迭代。經過權衡之後,我們最終選擇了pipe的設計方案。
在pipe的設計方案中,有兩個問題需要解決:第一,Spark本身支援讀取文字資料,但並不支援多媒體資料讀取,我們需要設計一個高效的二進位制檔案讀取方法。第二,Rosbag的play功能如何從記憶體中讀取快取的資料,record功能如何將資料快取至記憶體中。以下我們將討論這些設計。
二進位制檔案流式管道處理
Spark操作資料的核心是彈性分散式資料集(RDD),它允許程式設計師以一種容錯的方式在一個大型叢集上執行記憶體計算。百度美國研發中心之前的一個工作就是在這一資料結構的基礎上引入了新的RDD來實現二進位制檔案流式管道處理。其結構如圖5所示(關於這個設計的細節請參考《程式設計師》2016年1月刊《基於Spark的百度圖搜變現系統架構》)。
圖5 BinPiped RDD的總體設計和主要功能
圖5 BinPiped RDD的總體設計和主要功能
在每一個Spark的worker上,worker根據Binpiped RDD的資訊通過標準輸入流在記憶體中將資料傳送給使用者程式,使用者程式處理完資料後通過標準輸出流在記憶體中將資料傳回給Spark的worker。worker將資料彙集儲存到HDFS上。
Rosbag快取資料讀取
在當前使用場景下(如圖6),我們的輸入是一定量的Bag二進位制檔案,以某種形式儲存在分散式檔案系統上面,而使用者想要的輸出是所有這些Bag檔案在每一個worker上回放資訊進入模擬器後經過處理得到的資料,顯然這一過程通過Rosbag的play和record功能最易實現。
圖6 模擬器在分散式平臺的運作流程
圖6 模擬器在分散式平臺的運作流程
圖7 MemoryChunkedFile設計
圖7 MemoryChunkedFile設計
不過這一過程中還存在缺失的環節,即Rosbag的play功能如何從記憶體中讀取快取的資料,以及record功能如何將資料快取至記憶體中。為了實現這一功能,我們為原來的Bag和ChunkedFile的兩層邏輯結構增加了一個分支邏輯層。如圖7所示,MemoryChunkedFile類繼承於ChunkedFile類並且重寫了ChunkedFile所有的方法。MemoryChunkedFile在向下層讀寫檔案時是向記憶體讀寫資料,而不是像ChunkedFile類一樣向硬碟讀寫資料。這樣做的一個好處就是worker通過標準輸入流傳給模擬器的資料不用經過磁碟I/O讀寫就可以被直接讀入,經過模擬器處理的資料也不用經過磁碟I/O讀寫就可以由記憶體直接傳回worker。這樣的讀寫模式極大地縮短了模擬器處理資料的時間。
通過這一邏輯層的新增,我們可以將模擬器部署到Spark叢集內的每一臺worker機器上。通過載入不同的配置檔案使每臺機器執行不同的模組;也可以通過部署相同模組不同模型的條件下執行相同資料,以比較模型的不同;還可以在相同模組相同模型的條件下執行不同資料,比對不同資料的差異。由此可見,分散式系統的使用為模擬器添加了無數擴充套件的可能。
效能評估
在設計實現的同時,我們對系統進行了效能評估。隨著計算資源的增加,計算時間也線上性地降低,系統表現出很強的可擴充套件性,可以承受很大的資料量與計算量。在一個影象識別測試集中,使用單機處理影象資料耗時為3個小時,而使用8個Spark worker後,耗時僅25分鐘。假設我們使用10000個Spark worker對谷歌無人車級別的資料進行大規模的影象識別模擬測試,整個實驗也可以在100小時內完成。
結論
使用分散式系統能夠極大提升模擬器的工作能力,使無人駕駛系統的測試工作得以大規模有序地擴充套件開來。這一結果是建立在模擬器架構模組化,以及測試用例組合模組化的基礎之上的。採用分散式系統搭建模擬平臺,使得在真車上路之前測試無人駕駛汽車將要行駛的每一條道路成為現實。當然無人駕駛汽車在真實道路上的測試依然必不可少,但是模擬器已經為無人駕駛系統測試了海量的基礎情景,使我們可以以最低的成本最大限度地保障真車測試時的安全。
無人駕駛技術系列:
光學雷達(LiDAR)在無人駕駛技術中的應用
基於ROS的無人駕駛系統
基於計算機視覺的無人駕駛感知系統