1. 程式人生 > >拿ROS navigation 玩自主導航攻略(1)——by 西工大一小學生

拿ROS navigation 玩自主導航攻略(1)——by 西工大一小學生

http://blog.exbot.net/archives/1129

這個攻略是為一些有自己的硬體平臺,想快速上手ROS navigaion的同學(老師 etc。。)準備的,並且假設大家已經對ROS的基本概念(程序間通訊topic service 資料型別 msg)有了基本的瞭解,有基本的C++/python程式設計技術,有基本的移動機器人技術概念。我的攻略與yuanbo she前輩的exbot_xi平臺介紹有些不同,我將著眼與更深一層的講解,期望大家能針對不同的硬體平臺都能得心應手。

  1. 首先是你需要的硬體平臺:

一個可以與你上位機(執行ROS linux)通過某種硬體匯流排通訊的移動平臺。(移動平臺需要能接受上位機的速度 

指令,並且向上位機返回里程計資料,一般是編碼器的累計值)

一個RGBD-camera (kinect xition etc。。。)或者一個鐳射雷達(hokuyo rplidar etc。。。)(這兩個對以後的很多部分都有影響,會在後面仔細講解)

以上是基本要求,一般移動平臺類似與turtlebot或者exbot_xi都已經有非常成熟的ROS介面,大家問得比較多的也是ROS介面這部分的問題,我一直用的都是我們嵌入式同學做的底盤,我就著重講一下這個介面怎麼寫。

首先是速度介面:

一般來說,導航規劃層(不管是用什麼自主移動的package),直接輸出都是一個topic “cmd_vel”, 裡面的資料型別為 geometry_msgs/Twist 這個資料型別表示的是3d空間中的速度,2d的移動機器人只會用到三個值 linear.x linear.y 與 angular.z 分別表示水平分速度,垂直分速度,與角速度。而對於移動平臺來說,下位機大多接受到的是幾個輪子分別的角速度(如果是封裝完全的移動平臺,可以跳過這一部分),我們需要將一個描述一個平面剛體的三個分速度對映成驅動部分的速度,這裡涉及到一個底盤運動學解算的問題,一般來說分為差動底盤(turtlebot那種通過兩個輪子轉速不同來實現轉彎)和全向底盤這兩種,不同的底盤對應的解算公式也是不同的,詳見自主移動機器人導論(Introduction to Autonomous Mobile Robots

)第二章的講解,具體公式可以搜尋網上論文。

做完解算後一般情況就可以傳送給下位機了,與下位機通訊的手段多種多樣,則使用的程式設計介面也相應的不同。我用過串列埠與CAN匯流排,推薦使用c++ boost 串列埠與 python-can。

但是很多情況下針對不同的移動平臺的下位機,有些細節需要注意:

1. 傳送的頻率:這個要看嵌入式部分的要求。

2. 關於速度的平滑: 對於規劃層而言,即使有加速度等一些引數的限制,它輸出的速度值可能還是對於下位機過於不友好(比如過大的加速減速,不定的傳送頻率等等),那麼就在速度介面這邊就要執行一個平滑的過程,turtlebot中給出了一個非常好的速度插值的包(

http://wiki.ros.org/yocs_velocity_smoother)大家看情況使用。

總體來說,流程就是訂閱 “cmd_vel”topic 然後將速度做處理,傳送給下位機執行。

再者是里程計介面:

一般導航都會要求一個里程計資料的輸入,這個可以解釋為“通過編碼器的轉動推測輪子在時間片中的位移,進一步算出機器人整體的位移與速度”。和速度介面類似,一般移動平臺返回的是輪子轉角,需要做逆運動學解算,結果為機器人中心相對與計算開始的“原點”。

這個部分需要注意的地方主要就是釋出頻率了。這個頻率涉及到之後的costmap更新與座標系的訪問超時問題,之後會仔細講解。

都準備好了之後,那就要對這幾個部分進行除錯,就我的經驗而言,問題最多的部分是里程計部分,介紹大家一個小技巧,在rviz中顯示 odometry ,然後移動機器人,觀察其是否能回到原點。

硬體部分非常重要,我認為一定要在結合ROS的視覺化工具進行充分的除錯,要不然在之後的開發中會非常麻煩,硬體的問題比軟體的問題隱蔽得多,而且難以定位。

還有就是感測器介面:

一般rgbd-camera與鐳射雷達都有相應的sensor driver 提供,roslaunch相應檔案就可以了。

感測器一般在訊息的 header中都需要相應的感測器採集座標系,對於固定的感測器使用 http://wiki.ros.org/tf#static_transform_publisher tf中的static_transform_publisher 給定感測器與機器人中心相對位姿就可以了。

  1. SLAM 與 navigaion ROS 工具綜述:

很多應用ROS做 自主導航的新手都不清楚ROS提供的這些工具和工具之間的關係,接下來我將總體闡述下這些。

ROS 中的重要相關部分部分:

tf : 座標轉換庫,提供實時的座標轉換查詢與更改服務。 它將座標轉換表示為樹形結構,而座標轉換資料的更新速度直接影響 其他節點的實時性,進而導致整個系統的執行出錯,出問題大部分也是在這部分。

actionlib:提供動作(action ROS中表示一些長時間,連續性的行為)的程式設計介面,提供動作執行時的檢視狀態,終止, 搶佔等一系列功能。ROS中的自主移動規劃層向上的程式設計介面一般都是通過這個庫。

(可選瞭解)

pluginlib : 提供可配置的元件(配置檔案就可以規定元件的新增與更換,提供了執行時改變元件的可能性)navigaion 中提供了對於多種planner的支援。

dynamic_reconfigure : 提供執行時改變演算法(節點)引數的功能。

SLAM:

提到SLAM, 在社群中應用最多的應該是 Gmapping 與 hector_slam這兩種2d slam方法了,其實,SLAM演算法的實現不得不說的就是 這個(http://openslam.org/),這上面有幾乎所有主流slam方法的C++/C實現,ROS的 gmapping就是呼叫的這個上面的程式碼。不管是視覺還是鐳射雷達演算法都非常豐富。

機器人的導航規劃部分:

我瞭解最深的是ROS navigation metapackage , 一般它輸入為鐳射雷達(使用rgbd-camera 效果不佳)與里程計資料,輸出為cmd_vel 機器人在2d平面上的速度。與之類似的是hector_navigation。這一部分主要解決安全路徑的規劃問題。

  1. ROS navigation 軟體框架介紹

如果要讓 navigation 跑起來,有些知識我們是必須知道的。

(1) navigaion總體介紹:

navigaion總體介紹

這個圖絕對是最好的。

我們可以清楚得看見之前說的navigation的輸入:里程計odometry, 鐳射雷達或者rgbd-camera的資訊sensor_topics,還有已知的先驗地圖(可選),座標系變換資訊,輸出就是cmd_vel速度。

從軟體架構角度來講move_base類 作為navigation的邏輯核心存在。

從移動機器人體系結構來說,move_base規定了整個規劃層的行為流程。

而如果要配置ROS navigation,重點就是move_base 與它元件的配置。

定位與navigation meta package的關係:

這一部分是論壇裡面問得最多的。也是最不好搞清楚的部分。

首先我想先補充一些ROS tf tree的知識。

ROS 中對於多座標系的處理是使用樹型表示,在機器人自主導航中,ROS會構建這幾個很重要的座標系:

base_link: 一般位於tf tree的最根部,物理語義原點一般為表示機器人中心,為相對機器人的本體的座標系。

odom:一般直接與base_link 相連結,語義為一個對於機器人全域性位姿的粗略估計。取名來源於odometry(里程計),一般這個座標系的資料也是來源於里程計。對於全域性位姿的估計方法很多,比如在hector SLAM與導航體系中,就採用了imu資料估計全域性位姿,還有很多視覺里程計的演算法(visual odometry)也能提供位姿估計。原點為開始計算位姿那個時刻的機器人的位置。之

odom_combined 這個tf一般為好幾種位姿估計方法的資訊融合後的資料。在navigation metapackage中有 robot_pose_ekf 這個包是用擴充套件卡爾曼濾波演算法(EKF)融合不同感測器的資料。

map: 一般與odom(或者odom_combined)相連,語義為一個經過先驗(或者SLAM)地圖資料矯正過的,在地圖中的位姿資訊。與odom同為全域性座標系。原點為地圖原點(地圖原點在地圖相應的yaml檔案中有規定)。

一個完整的ROS navigation 執行時的tf tree 如下:

navigation 執行時的tf tree

(base_footprint 座標系不是必須的)

而通過在tf, 你就可以在程式裡詢問機器人在全域性座標系中的資訊了。這對於路徑規劃是非常重要的。

在機器人定位與導航體系中,定位模組作為規劃層的輸入與參考資料所存在。而對於ROS navigation 體系而言,因為它先天的模組間通訊方式實現了模組間的完全解耦,所以對於導航規劃層而言(具體就是move_base 這個node),什麼定位方法,靜態還是動態的地圖,對於導航層內部幾乎沒有區別。在這種思想指導下,navigation metapackage 中 就有了為模擬器環境下的定位工具包fake_localization: 用於把模擬器中的位姿(就是直接吧odom 變換成map)估計直接變換成關於全域性地圖的定位,簡化定位部分;對於動態建立的地圖slam, gmapping 在ROS中提供從 odom -》map的座標轉換,也可以作為navigation 中 move_base 的輸入。

從定位這部分擴充套件開來, 對於導航規劃層來說,模擬器還是實物傳回來的資料這些都無所謂。只要有相應的資料就可以執行相應功能。所以我們配置navigation的時候思路就是先把資料流接對,然後再根據自己機器人硬體與執行任務的不同修改相應的引數。

(2)navigation 各個部分的解析:

具體每個部分的引數列表在wiki上都有,我把一些比較重要的概念挑出來了。

move_base: 在之前說過了, move_base 部分作為navigation的邏輯核心。它實現了一個供上層節點呼叫的action 介面(通過actionlib 實現),即給定座標資訊與相應座標位置,執行相應的安全導航動作。對於下層控制器,之前說過了輸出為cmd_vel 2d速度。 它規定了這個navigation的行為

ROS navigation 導航規劃層提供一個在良好的定位條件下,安全導航到指定目標座標的功能。

總體可以視為一個 慎思-反應 混合正規化。

行為層: move_base 綜合機器人狀態與上層指令,給出機器人當前行為:正常導航,執行恢復動作,給上層節點返回失敗,終止導航。其中恢復動作可以自己定義。

全域性規劃層:global_planner

區域性規劃層: local_planner

控制器層(一般就是之前自己寫的速度傳送部分)

costmap_2d : 這一部分可看作為navigation的輸入處理器。不同的感測器輸入的資料差異很大(鐳射雷達 & RGBD-camera)通過costmap_2d , 不同的資料被處理成統一的格式:柵格地圖,權值用經過概率方法處理過的,表示空間中障礙物,未知與安全區域。生成出來的costmap則是planner的輸入。

global_planner : 為navigation的全域性規劃器,接受costmap生成的 global costmap 規劃出從起始點到目標點的路徑,為local_planner 作出參考。

local_planner : 為navigation 的區域性規劃器,接受costmap 生成的local costmap 規劃出速度。

recovery_behavior : 規定move_base 行為集合中處理異常情況的行為

這是主體部分。 要理解ROS navigation 最重要的部分是nav_core: 這個包裡面就包含了global_planner , local_planner 與 recovery_behavior的基類的標頭檔案。但是極其重要。

我之前提到過的pluginlib , 而最重要的就是: 在ROS navigation中, move_base 提供的是框架,在move_base 中是通過nav_core 中規定的planner 與 recovery_behavior 的基類的介面進行呼叫。與具體的實現方法隔離開來。而具體採用的方法由pluginlib 根據不同引數匯入。這樣的實現方法使得navigation的可定製性大大增加。像base_local_planner 中就實現了兩種區域性路徑規劃方法,global_planner 實現了A* 與Dijkstra 兩種方法,在navigation_experimental 中還有更多這樣的實現。這賦予了這個框架很大的靈活性。通過不同的配置方法可以讓navigation適應很多不同的任務。

(3)navigation 的配置

完成與嵌入式層的互動後,就可以著手配置navigation了。基本就是按照官網上這個教程把launch檔案和相應的yaml檔案配起來就好了(http://wiki.ros.org/navigation/Tutorials/RobotSetup)。我這裡就不贅述了,我就講一下最容易出問題的幾個地方。

對於導航規劃層來說,整個系統的表現與實時性息息相關,就我個人對於ROS navigation的實踐來說,制約表現好壞的最重要一部分就是costmap的生成。costmap會分別生成兩份,local_costmap 與 global_costmap 。這兩份的引數是完全不同的。先是local_costmap ,local_planner 要求的實時性還是挺高的(特別是你把速度調高的時候),而local_costmap 所依賴的全域性座標系一般是odom,繪製costmap的時候會反覆詢問odom-》base_link 座標系的資訊,tf資料延遲要是大了會影響costmap,進而導致機器人planner實時性降低,機器人移動遲緩或者撞上障礙物。所以有個引數transform_tolerance一定要慎重。如果是使用靜態先驗地圖做導航,那麼全域性的costmap可以選擇使用static_map選項,這樣的話在move_base 建立之初就會根據先驗地圖生成一次,以後不會再更新了。這樣會節省一些計算量。

而如果採用動態地圖(實時slam出來的)或者根本不使用先驗地圖,那可以將全域性的costmap所依賴的全域性座標系也改為odom, rolling_window選項代替static選項,這樣costmap就會實時更新,要注意的是這樣的話你上層程式給出的目標點就不能超過rolling_window的範圍。

基本除錯好這些navigation就可以初步的執行起來了,而之後就是針對不同環境與不同任務對規劃器進行選擇與除錯。

附錄: 一些ROS中的視覺里程計演算法:

http://wiki.ros.org/libviso2

amcl 包中的定位演算法(adaptive monte carlo localization)與 gmapping中的基本概率方法:

《Probabilistic Robotics》