參數介紹
之所以要首先介紹參數而不是實操,是因為大部分建圖失敗、漂移基本上都是參數設置錯誤引起的,或者說大部分都是TF存在問題,主要是坐標系Frame之間有沖突或者對不上等原因導致的,因此把參數放在前面介紹,了解了參數和對應作用,在對比各類教程設置時才不會碰運氣解決報錯。
Cartographer的Launch與Lua文件在兩個地方存在,注意區分:
//Launch文件位置1:
carto_ws/src/cartographer_ros/cartographer_ros/launch//Lua文件位置1:
carto_ws/src/cartographer_ros/cartographer_ros/configuration_files
carto_ws/src/cartographer/configuration_files//Launch文件位置2:
carto_ws/install_isolated/share/cartographer_ros/launch//Lua文件位置2:
carto_ws/install_isolated/share/cartographer_ros/configuration_files
carto_ws/install_isolated/share/cartographer/configuration_files
如何使用看每個人的習慣,我個人的習慣是調用install_isolated下面的Launch與Lua,使用的時候基于源文件復制一個自己重命名后的Launch與Lua文件來用,且不將source的代碼添加到主目錄下面的bashrc內,每次使用手動source setup.bash文件。
使用Gazebo來進行建圖時,基于demo_backpack_2d.launch文件來實現,打開文件內容如下:
<launch><param name="/use_sim_time" value="true" /><include file="$(find cartographer_ros)/launch/backpack_2d.launch" /><node name="rviz" pkg="rviz" type="rviz" required="true"args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" /><node name="playbag" pkg="rosbag" type="play"args="--clock $(arg bag_filename)" />
</launch>
可以看到文件內主要實現了這樣幾個功能:
將use_sim_time設置為true,啟動了仿真時間
啟動了backpack_2d.launch
開啟rviz
播放rosbag
繼續打開同目錄下的backpack_2d.launch,內容如下:
<launch><param name="robot_description"textfile="$(find cartographer_ros)/urdf/backpack_2d.urdf" /><node name="robot_state_publisher" pkg="robot_state_publisher"type="robot_state_publisher" /><node name="cartographer_node" pkg="cartographer_ros"type="cartographer_node" args="-configuration_directory $(find cartographer_ros)/configuration_files-configuration_basename backpack_2d.lua"output="screen"><remap from="echoes" to="horizontal_laser_2d" /></node><node name="cartographer_occupancy_grid_node" pkg="cartographer_ros"type="cartographer_occupancy_grid_node" args="-resolution 0.05" />
</launch>
加載啟動了機器人相關的參數和功能
啟動了cartographer
remap重映射了激光雷達話題名
啟動了cartographer的地圖服務
這里因為打算新建一個Launch,所以沒必要兩個Launch來搞調用,直接將兩個內容合成一個Launch就好了,當然需要刪掉一些不需要的功能,比如啟動了backpack_2d.launch代碼不需要了、播放rosbag也不需要、加載啟動了機器人相關的參數和功能也刪掉(不愛看模型,看坐標系更直觀),remap的話題按需修改。
最后合成一個map.launch文件:
<launch><param name="/use_sim_time" value="true" /><node name="cartographer_node" pkg="cartographer_ros"type="cartographer_node" args="-configuration_directory $(find cartographer_ros)/configuration_files-configuration_basename map.lua"output="screen"><remap from="scan" to="scan" /></node><node name="cartographer_occupancy_grid_node" pkg="cartographer_ros"type="cartographer_occupancy_grid_node" args="-resolution 0.05" /><node name="rviz" pkg="rviz" type="rviz" required="true"args="-d $(find cartographer_ros)/configuration_files/demo_2d.rviz" />
</launch>
Launch文件準備好之后,繼續調整建圖的Lua文件,也就是參數部分,在launch文件內加載cartographer的部分可以注意到加載了backpack2d.lua文件。
找到對應文件,Lua文件也和Launch文件一樣存在調用其他文件的情況,為了方便起見我新建了一個Lua,把所有調用涉及到的Lua文件全部轉移到著一個文件中了,便于調參和管理。
但是需要注意兩點:
1、轉移Lua文件參數至一個文件中時注意組合的順序:一般調用關系下越深層的文件在整合時越要靠上,因為它們之間有調用關系。合成一個文件后如果調用段內容在聲明段內容的上面是會報錯的,如果搞不清楚就按原來的結構改不要整合了。
2、原來的調用關系下,可能有一些參數是重復的:一般是最外層的參數覆蓋深層的的參數,這樣安排有利于在建圖和定位不同功能下都可以調用同樣的Lua文件,只需要在最外層把某些值覆寫就可以了,整合為一個文件時注意下這個特性。
接下來進入Lua內開始研究參數,這里為了避免歧義依舊按照源代碼的Lua文件結構介紹,backpack_2d.lua文件如下:
include "map_builder.lua"
include "trajectory_builder.lua"options = {map_builder = MAP_BUILDER,trajectory_builder = TRAJECTORY_BUILDER, map_frame = "map",tracking_frame = "base_link", --追蹤坐標系published_frame = "base_link", --發布至odom_frame = "odom",provide_odom_frame = true, --是否需要提供odompublish_frame_projected_to_2d = false, use_pose_extrapolator = true,use_odometry = false, --是否使用odomuse_nav_sat = false,use_landmarks = false,num_laser_scans = 0, --單線激光雷達數num_multi_echo_laser_scans = 1, --多回波雷達數num_subdivisions_per_laser_scan = 10,num_point_clouds = 0,lookup_transform_timeout_sec = 0.2,submap_publish_period_sec = 0.3,pose_publish_period_sec = 5e-3,trajectory_publish_period_sec = 30e-3,rangefinder_sampling_ratio = 1.,odometry_sampling_ratio = 1.,fixed_frame_pose_sampling_ratio = 1.,imu_sampling_ratio = 1.,landmarks_sampling_ratio = 1.,
}MAP_BUILDER.use_trajectory_builder_2d = true
TRAJECTORY_BUILDER_2D.num_accumulated_range_data = 10return options
其中大部分參數保持默認都不會導致建圖失敗,最多輕微影響建圖效果和速度,但是有幾個參數需要重點關注,基本是每個機器都需要根據實際情況調整。
首先是:
num_laser_scans = 0,
num_multi_echo_laser_scans = 1,
兩個參數,Cartographer默認使用的雷達不是常見的發出Laserscan的雷達,這一點在第一篇文章跑Demo的時候提到過,因此需要將num_multi_echo_laser_scans改為0,num_laser_scans改為1.(如果只使用一個單線激光雷達的話)
如果沒有改這個參數,在運行時會出現大概如下的報錯:
隊列:等待什么(echo,0)
(記不住原始報錯信息了,報錯的重點是echo、等待數據、queue之類的字眼)
這個參數設置好后就是坐標系三兄弟:
? tracking_frame = "base_link",???
published_frame = "base_link",?
provide_odom_frame = true,?
大部分初學者踩坑都掉在這里了,因為這三個參數如何調整不僅取決于實際仿真環境或者實車環境下發布的TF,而且他們的調整是聯動的,先介紹參數具體功能:
tracking_frame要求給出一個坐標系,Cartographer會把機器人其他坐標系轉換到這個追蹤坐標系,比如雷達坐標系、IMU坐標系等等,這也就要求這個坐標系可以代表整個機器人的運動,通常追蹤坐標系可以選擇基坐標系或者IMU坐標系,這里將其設置為base_link,因為一般機器人都會有這個坐標系。
published_frame也要求給出一個坐標系,Cartographer會將發布的TF連接在該坐標系上,通常情況是將Map連接到該坐標系上。
provide_odom_frame詢問是否需要Cartographer給出odom,如果自己的仿真環境、實車環境帶著那當然是false。
注意!以下提到的odom等都為TF中的坐標系,而不是odom話題!
注意點一:如果啟動仿真環境或者實車環境后,打印TF樹,沒有發現tracking_frame賦的值,那么程序是要報錯的,可能原因是某些機器人基坐標系是base_footprint或者其他名字,壓根沒有base_link坐標系,導致其他坐標系沒法轉移到給定坐標系;或者環境給出了tracking_frame,但是沒有發布雷達或者IMU等傳感器到該坐標系的TF變換,程序不知道怎么將傳感器變換到這個tracking_frame,導致報錯。
解決方法也簡單,基坐標系問題可以修改tracking_frame的值或者修改機器人urdf的基座標系命名(推薦),缺TF問題,直接手動給出基座標系到雷達等傳感器坐標系的靜態TF變換,大部分場景下激光雷達應該都是和機器人之間是固連關系吧?
靜態TF發布可以寫在仿真環境啟動的Launch文件里面,具體內容在第二篇文章有提到。
注意點二:published_frame是Cartographer發布的TF所連接的坐標系,一般Cartographer只提供map的坐標系,因此此處也就是給出map->published_frame.但是需要Cartographer提供odom下,此處就變成了odom->published_frame。通常情況下選擇odom都沒錯,但是這些情況下就需要調整了:
provide_odom_frame為false,也就是不需要提供odom坐標系,同時仿真環境也沒有提供odom坐標系,這種情況下需要調整為仿真環境中TF樹最高的一個坐標系,以本文第二篇提到的TF樹為例,如果沒有odom的話,就需要填寫base_link,這樣最終TF樹結構為map->base_link。
provide_odom_frame為true,那么此處需要填寫TF樹最高的一個坐標系,即Cartographer提供map->odom.我們提供odom->published_frame的信息。
開始建圖
調整完參數開始建圖,通常話題是/scan、/imu、/odom的都不需要額外修改。
啟動仿真環境后,啟動Cartographer的Launch,如果出現下面類似的ERROR也不要慌:
[rospack] Error: package 'turtlebot3_sim_test' not found
[librospack]: error while executing command
[ERROR] [1753412286.262920514, 142.830000000]: Could not load resource [package://turtlebot3_sim_test/meshes/bases/waffle_pi_base.stl]: Unable to open file "package://turtlebot3_sim_test/meshes/bases/waffle_pi_base.stl".
[rospack] Error: package 'turtlebot3_sim_test' not found
[librospack]: error while executing command
[ERROR] [1753412286.282568001, 142.850000000]: Could not load resource [package://turtlebot3_sim_test/meshes/sensors/lds.stl]: Unable to open file "package://turtlebot3_sim_test/meshes/sensors/lds.stl".
[rospack] Error: package 'turtlebot3_sim_test' not found
[librospack]: error while executing command
[ERROR] [1753412286.300414295, 142.868000000]: Could not load resource [package://turtlebot3_sim_test/meshes/wheels/left_tire.stl]: Unable to open file "package://turtlebot3_sim_test/meshes/wheels/left_tire.stl".
[rospack] Error: package 'turtlebot3_sim_test' not found
[librospack]: error while executing command
[ERROR] [1753412286.317263047, 142.885000000]: Could not load resource [package://turtlebot3_sim_test/meshes/wheels/right_tire.stl]: Unable to open file "package://turtlebot3_sim_test/meshes/wheels/right_tire.stl".
這是因為仿真環境的功能包放在了Cartographer外面,工作空間不同,也沒有在bashrc里面寫source,因此模型的加載出現錯誤,會導致rviz看不見模型,完全不影響功能,反而有利于看TF,好事。
啟動后可以看到TF:
接下來就可以操作虛擬環境的小車開始運動來進行建圖了。
建圖完畢后時用下面的代碼保存地圖:
1、軌跡停止更新(建圖產生的submap都在軌跡0上),這個代碼有時執行時會和卡住一樣,不要著急,他只有軌跡徹底完成才會輸出信息,有的時候建圖太慢導致堆積了很多幀沒有處理完讓他處理就好了
rosservice call /finish_trajectory 0
2、保存地圖至指定位置(有不少教程花括號漏了后半截)
rosservice call /write_state "{filename: '<絕對路徑>/***.pbstream'}"
3、將Cartographer產生的pbstream地圖轉化為ROS常用地圖格式文件:.yaml和.pgm文件(需要就執行,也可以當作可視化地圖用)
rosrun cartographer_ros cartographer_pbstream_to_ros_map -map_filestem=絕對路徑/地圖名字 -pbstream_filename=絕對路徑/地圖名字.pbstream -resolution=0.05
至此建圖流程就結束了,下面匯總下可能會出現的問題,以下也有可能在定位階段出現問題:
問題一:TF類報錯,各類TF不存在、父子坐標系沖突、小車建圖漂移等等
首先檢查Launch中是否啟用了虛擬時間,接下來按照上文提到的Lua文件中的坐標三兄弟,檢查自己的設置是否正確,檢查建議采用關閉Cartographer,先看仿真環境的TF樹正不正確,再啟動兩者結合報錯信息查看。
下面給出常用的TF排查命令:
//打印當前TF樹結構
rosrun rqt_tf_tree rqt_tf_tree//查看指定兩個坐標之間的坐標變換
rosrun tf tf_echo frame1 frame2
問題二:靜止狀態正常,小車一開始運動rviz中激光幀就開始亂飛或者扭曲變形,具體表現為激光幀亂動、等比例縮小、變為一條線或者一個點。
檢查在基坐標系與傳感器坐標系的變換,如果使用了靜態坐標發布,是否設置在了變化?建議設置為0 0 0 0 0 0也就是重合。如我之前設置了z軸偏移:
<node pkg="tf2_ros" type="static_transform_publisher" name="base_link_to_base_scan" args="0.0 0.0 0.5 0.0 0.0 0.0 base_link base_scan" />
?以上變化導致我的小車在運動時激光幀出現了旋轉,變成了垂直于地面,在rvzi中表現為變成一條線。
問題三:建圖時空地出現無法去除的灰色或者障礙內部變成白色
障礙內部入侵:
出現灰色區域:
以上主要是參數的問題,可以在Lua文件里面調整擊中和未命中的概率,同時也有可能與機器人的速度有關,尤其是機器人轉彎速度過快,電腦性能不夠(很多使用虛擬機)也有可能影響。
其中障礙內部入侵主要是因為機器人轉彎過快且傳感器頻率、性能不夠導致的,一般降低機器人移動速度能有效緩解。
出現灰色區域這一現象主要影響視覺觀感,對定位等功能完全不受影響,但如果非常在意,可以找到TRAJECTORY_BUILDER_2D對應Lua文件,調整:
submaps = {
...
...hit_probability = 0.55,miss_probability = 0.46, --0.49
...
}
其中hit可以讓黑色障礙物更快變黑,miss可以讓未知區域更快變白,適當降低miss值可以有效降低灰色區域,但是不要降的過低,將會導致障礙也更容易變白,適當降低加上灰色區域多走一步就能有效解決問題。
最后建圖如下(80*80M):