cartographer為Google提供的激光SLAM開源庫,通常通過其提供的ROS平臺封裝進行使用,該庫結構清晰,模塊完整,值得深入研究。 項目官網:https://google-cartographer.readthedocs.io/en/latest/ 項目Github:https://gi ...
cartographer為Google提供的激光SLAM開源庫,通常通過其提供的ROS平臺封裝進行使用,該庫結構清晰,模塊完整,值得深入研究。
項目官網:https://google-cartographer.readthedocs.io/en/latest/
項目Github:https://github.com/cartographer-project/cartographer
環境安裝與配置具體參考:https://www.cnblogs.com/lvchaoshun/p/9824528.html
安裝過程中可能會碰到一些版本衝突之類的問題,耐心上網尋求解決方法。
溫馨提示:本系列主要介紹源碼內容,不介紹環境搭建,僅作為自己學習過程記錄,可能會比較亂,有疑問歡迎留言討論。
下麵進入正題,下圖是cartographer官網提供的軟體架構圖,本系列將通過cartographer_ros封裝庫中調用順序,對程式主線進行介紹,暫未使用到的或次要的信息以後有空再分析。
首先我們找到cartographer_ros中程式入口,即cartographer_ros/cartographer_ros/cartographer_ros/node_main.cc,其中的main函數為cartographer_ros節點啟動的程式入口。
其他都是ros平臺初始化相關的函數,只用看98行Run方法。
可以看到該函數內主要是些初始化工作,創建map_builder傳給node進行初始化、讀取pbstream地圖文件,並調用StartTrajectoryWithDefaultTopics函數,該函數定義在node.cc中。
我們會發現AddTrajectory是核心功能入口。××該函數需重點關註,之後我們還會回來一個個分析其中調用的關鍵函數。
該函數功能比較多,我們一步步看。首先363行創建一個set保存感測器話題的編號,用於之後訂閱器訂閱。366行調用map_builder_bridge_實例的AddTrajectory函數,在cartographer_ros中類名包含“bridge”的類基本上都是作為“橋梁”調用cartographer源碼的類。我們可以看到map_builder_bridge_為map_builder_bridge.cc中定義的MapBuilderBridge的實例,此時關註map_builder_bridge.cc中定義的AddTrajectory函數內容。
根據cartographer全局配置參數和最初Run方法中定義的map_builder實例類型,我們瞭解到map_builder_為cartographer/mapping/map_builder.cc中定義的MapBuilder類的實例。上圖函數內容分為兩塊,一塊調用map_builder_的AddTrajectoryBuilder函數,創建trajectory_builder並設置結果回調,返回一個路徑id作為當前軌跡的編號,詳情下篇再介紹;另一塊主要初始化一個SensorBridge實例,並放入sensor_birdges_這個map中,以及保存該路徑id對應的配置參數。
接下來我們回到node.cc中核心功能入口函數。368與369行分別創建與當前路徑編號對應的位姿預測器(PoseExtrapolator)與感測器採樣器(TrajectorySensorSamplers),根據配置參數創建實例沒啥好說的。371行啟動ros話題訂閱器,並設置回調函數。這之後的創建定時器和記錄話題編號也很簡單。我們主要關註話題訂閱的回調函數。
上圖截取了LaunchSubsribers函數的部分代碼,通過其回調函數,我們發現最終會調用sensor_bridge.cc中定義的HandleLaserScan函數。此處僅僅舉個例子,該函數僅處理激光雷達數據(普通LaserScan類型消息、多回波、點雲等),其他感測器數據(如IMU、里程計等)會調用不同的回調函數。
我們觀察HandleLaserScan函數實現。
首先對點雲細分,預設num_subdivisions_per_laser_scan_=10。points對象的類型為cartographer_ros自定義類型,其中保存了每個點的光強、位置與時間增量。time_to_subdivision_end保存了最後一個點的時間增量,即一塊細分點雲間時間間隔(第一個點之前的時刻到最後一個點之後的時刻之間的時間間隔)。之後做一些時間戳的運算,或許是諸如(..., -0.06, -0.04, -0.02, 0)的一組時間戳。最後調用HandleRangefinder將數據添加到全局路徑構造器,如下圖所示。
此處trajectory_builder_會是GlobalTrajectoryBuilder類的實例,是由於map_builder_的AddTrajectoryBuilder函數中調用了對應的構造函數,此處已涉及cartographer源碼。
本節主要介紹了cartographer_ros封裝是如何跳轉到cartographer源碼中的,主要包括ros節點、map_builder與trajectory_builder的創建,pose_extrapolator與trajectory_sensor_samplers的初始化以及感測器話題訂閱與處理。從下一節開始,將根據調用順序介紹cartographer源碼。