Cartographer是基于图优化的SLAM,采用误差累计少,计算成本低的Scan to Map
匹配方式,而不是造成误差快速累积和计算成本高的scan to scan匹配。整个算法分为局部SLAM和全局SLAM,两部分都对雷达观测的位姿进行了优化。
虽然cartographer适用于2D和3D两种情况,但3D情况下,cartographer用的不如LOAM多
订阅的话题
节点cartographer_node
订阅的话题是:scan
, tf
, tf_static
。 cartographer_node
的launch需要增加remap,因为它接受的话题名称和我们现有的话题可能不一致:1
2
3<remap from="scan" to="/scan" />
<remap from="odom" to="/xqserial_server/Odom" />
<remap from="imu" to="/xqserial_server/IMU" />
所有相关的话题名称都定义在node_constants.h
cartographer_node 发布的话题
scan_matched_points2, 类型
sensor_msgs/PointCloud2
,scan-to-submap
匹配的2D点云数据,这个云可以根据配置进行滤波和投影。是scan
话题的大部分,不会包括行走的人的轮廓submap_list, 类型
cartographer_ros_msgs/SubmapList
,所有轨迹的所有submaps的列表,成员:1
2
3
4
5
6
7
8std_msgs/Header header
cartographer_ros_msgs/SubmapEntry[] submap
# 其中submap的类型如下
int32 trajectory_id
int32 submap_index
int32 submap_version
geometry_msgs/Pose pose话题包括一个子图的ID list(包括轨迹ID和子图index),以及子图的全局位姿。
发布话题的源码流程是 Node::PublishSubmapList
—— MapBuilderBridge::GetSubmapList()
—— PoseGraph2D::GetAllSubmapPoses()
—— PoseGraph2D::GetSubmapDataUnderLock
—— PoseGraph2D::ComputeLocalToGlobalTransform
trajectory_node_list
,类型为visualization_msgs/MarkerArray
,即轨迹路径node列表,代码是
1 | void Node::PublishTrajectoryNodeList( |
constraint_list: 类型为
visualization_msgs/MarkerArray
,约束列表landmark_poses_list: 类型为
visualization_msgs/MarkerArray
,路标点位姿列表
节点 cartographer_occupancy_grid_node
发布话题 map
(栅格地图), 订阅submap_list [cartographer_ros_msgs/SubmapList]
。 cartographer_occupancy_grid_node
节点将子图转换为ROS的地图格式
服务
- submap_query (cartographer_ros_msgs/SubmapQuery): 查询submap的服务,输入的是
trajectory_id
和submap_index
start_trajectory
类型cartographer_ros_msgs/StartTrajectory
,通过将其传感器主题和轨迹选项指定为二进制编码的原型来启动另一个轨迹。返回指定的轨迹ID。
StartTrajectory.srv
:1
2
3
4
5
6
7
8string configuration_directory
string configuration_basename
bool use_initial_pose
geometry_msgs/Pose initial_pose
int32 relative_to_trajectory_id
---
cartographer_ros_msgs/StatusResponse status
int32 trajectory_id
命令稍微长了点:1
2
3
4
5
6
7rosservice call /start_trajectory "configuration_directory: '/home/user/carto_ws/src/cartographer_ros/cartographer_ros/configuration_files'
configuration_basename: 'localization.lua'
use_initial_pose: true
initial_pose:
position: {x: 5.211, y: 5.617, z: 0.0}
orientation: {x: 0.0, y: 0.0, z: 0.689, w: 0.725}
relative_to_trajectory_id: 0"
出错的地方可能会在relative_to_trajectory_id
:1
2
3
4
5
6
7status:
code: 5
message: "Trajectory 6 doesn't exist."
status:
code: 3
message: "Trajectory 5 is in 'DELETED' state."
加载 frozen state 意味着不插入no pose graph constraints. 一条frozen trajectory和它的子图不受 optimization影响
finish_trajectory
类型cartographer_ros_msgs/FinishTrajectory
: Finish 一个给定ID的轨迹,方式是运行最终的图优化。
1 | int32 trajectory_id |
命令rosservice call finish_trajectory "trajectory_id: 5"
,得到这样的结果:1
2
3
4status:
code: 3
message: "Topics are already used by another trajectory."
trajectory_id: 0
trajectory_query
- get_trajectory_states (cartographer_ros_msgs/GetTrajectoryStates): 返回所有轨迹的ID和状态, 可以用于从单独的节点观察Cartographer的状态。
1
2
3
4
---
cartographer_ros_msgs/StatusResponse status
cartographer_ros_msgs/TrajectoryStates trajectory_states
命令rosservice call /get_trajectory_states "{}"
,比如得到这样的结果:1
2
3
4
5
6
7
8
9
10
11
12status:
code: 0
message: ''
trajectory_states:
header:
seq: 0
stamp:
secs: 1612232712
nsecs: 41338148
frame_id: ''
trajectory_id: [0, 1, 2, 3, 4, 5]
trajectory_state: [2, 2, 2, 2, 2, 0]
trajectory_state
的枚举值也就是 轨迹的四种状态对应: ACTIVE, FINISHED, FROZEN, DELETED
- write_state (cartographer_ros_msgs/WriteState): 将当前内部状态写入磁盘到文件名。用于保存pbstream文件,此文件可用作
assets_writer_main
的输入,以生成概率网格,X-Rays或PLY文件等资源
read_metrics
类型(cartographer_ros_msgs/ReadMetrics)
, 返回Cartographer的所有内部指标的最新值。运行时度量标准的集合(collection of runtime metrics)是可选的,必须使用节点中的-collect_metrics
命令行标志激活:1
2
3
4
5
6
7
8
9<node name="cartographer_node" pkg="cartographer_ros"
type="cartographer_node" args="
-configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basename map.lua
-collect_metrics true"
output="screen">
<remap from="scan" to="/scan_rectified" />
<remap from="odom" to="/odom" />
</node>
如果没有加-collect_metrics
标志,rosservice call /read_metrics "{}"
的结果:1
2
3
4
5
6
7status:
code: 14
message: "Collection of runtime metrics is not activated."
metric_families: []
timestamp:
secs: 1612333336
nsecs: 359502516
需要的tf变换
必须提供从所有传入传感器数据帧到配置的tracking_frame
和published_frame
的转换。通常,这些是由robot_state_publisher或static_transform_publisher定期发布的。
发布的tf变换
提供map_frame
和 published_frame
之间的转换。如果在Lua中启用了provide_odom_frame
,则将提供配置的odom_frame
和published_frame
之间的连续(不受循环闭包影响)转换。
其他节点
- cartographer_rosbag_validate
可以检测bag中的错误,使用:1
rosrun cartographer_ros cartographer_rosbag_validate -bag_filename <bag filename>
比如会有这样的结果:1
2
3
4
5
6
7
8
9
10
11
12
13E0722 22:11:01.138546 3442 rosbag_validate_main.cc:389] IMU data (frame_id: "imu") has a large gap, largest is 0.064731 s, recommended is [0.0005, 0.005]s with no jitter.
I0722 22:11:01.139314 3442 rosbag_validate_main.cc:398] Time delta histogram for consecutive messages on topic "/IMU_data" (frame_id: "imu"):
Count: 27679 Min: 0.000144 Max: 0.064731 Mean: 0.005027
[0.000144, 0.006602) Count: 27445 (99.154594%) Total: 27445 (99.154594%)
[0.006602, 0.013061) Count: 181 (0.653925%) Total: 27626 (99.808517%)
[0.013061, 0.019520) Count: 42 (0.151740%) Total: 27668 (99.960258%)
[0.019520, 0.025979) Count: 7 (0.025290%) Total: 27675 (99.985550%)
[0.025979, 0.032437) Count: 3 (0.010839%) Total: 27678 (99.996384%)
[0.032437, 0.038896) Count: 0 (0.000000%) Total: 27678 (99.996384%)
[0.038896, 0.045355) Count: 0 (0.000000%) Total: 27678 (99.996384%)
[0.045355, 0.051814) Count: 0 (0.000000%) Total: 27678 (99.996384%)
[0.051814, 0.058272) Count: 0 (0.000000%) Total: 27678 (99.996384%)
[0.058272, 0.064731] Count: 1 (0.003613%) Total: 27679 (100.000000%)
需要的时间范围是[0.0005, 0.005],但是看给出的范围列表,只有第一个还算在这个范围里,剩下约1%不合要求。
- cartographer_pbstream_map_publisher
一个简单的节点,它从序列化的Cartographer状态(pbstream格式)创建静态占用网格。如果实时更新不重要,它是占用网格节点的有效替代方案。 发布话题:map (nav_msgs/OccupancyGrid),只发布一次