不幸的是,调试cartographer真的很难。该系统具有许多参数,其中许多参数相互影响。本调试指南试图解释具体示例的原则方法。
##示例:调整局部SLAM
对于这个例子,我们将从cartographer提交aba4575和cartographer_ros提交99c23b6开始,然后从我们的测试数据集中查看包b2-2016-04-27-12-31-41.bag。
在我们的初始配置中,我们看到这个包的早期就有一些滑动,这是因为这个包经过了德国博物馆的一个斜坡,这违反了平面地板的二维假设。在激光扫描数据中可以看到相矛盾的信息被传递给SLAM。但这一下滑也表明,我们对点云的匹配程度过高,而且强烈忽视其他传感器。我们的目标是通过调优来改善情况。
如果我们只查看此特定子图,则该错误完全包含在一个子图中。我们还看到,随着时间的推移,全局SLAM发现了一些奇怪的事情并且部分地纠正了它,错误的子图将永远错误了。
由于此处的问题是子图内的滑动,因此它是本地SLAM问题。因此,让我们关闭全局SLAM,以免扰乱我们的调整.
POSE_GRAPH.optimize_every_n_nodes = 0
子图的大小通过TRAJECTORY_BUILDER_2D.submaps.num_range_data配置。看一下这个例子的各个子图,他们已经很好地拟合了这两个约束,所以我们假设这个参数调整得很好。
在我们的例程中,扫描匹配器可以在不影响匹配值的情况下,自由的向前或向后移动这个匹配。我们通过让扫描匹配器为之前获得的偏离付出更高的代价来避免这种情形,控制这个的两个参数是rotation_weight和TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight。值越高,从之前的结果中移除它就需要越高的代价,换句话说:扫描匹配器在另一个位置必须生成一个更高的匹配值才能被接受。
出于教学目的,让我们为偏离先前设置一个很高的代价:
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1e3
这允许优化器非常自由地覆盖扫描匹配器结果,这导致姿势接近先前,但与深度传感器不一致并且明显破裂,尝试使用此值可在2e2处获得更好的结果。
##特别案例
默认配置和上述调整步骤侧重于质量。只有在我们取得了良好的质量后,我们才能进一步考虑特殊情况。
通过低延迟,我们的意思是在接收到传感器输入后不久,优化的局部姿势变得可用,通常在一秒钟之内,并且全局优化没有积压.在线算法需要低延迟,例如机器人定位. 在前台运行的本地SLAM直接影响延迟。全局SLAM构建后台任务队列,当全局SLAM无法跟上队列时,漂移可以无限累积,因此应该调整全局SLAM以实时工作.
调整不同组件的速度有很多选项,我们按推荐的顺序列出它们,建议一次只探索一个选项,从第一个选项开始。配置参数记录在 Cartographer documentation.
为了调整全局SLAM以降低延迟,我们减少计算负荷,直到始终保持实时输入,以下这些阈值,我们不会进一步降低它,但要尽量达到最佳质量
为了减少全球SLAM延迟,我们可以
optimize_every_n_nodes
MAP_BUILDER.num_background_threads
最多核心数global_sampling_ratio
constraint_builder.sampling_ratio
constraint_builder.min_score
.min_num_points
, .max_range
, 增加 .max_length
voxel_filter_size
,submaps.resolution
,减少submaps.num_range_data
.linear_xy_search_window
,.linear_z_search_window``.angular_search_window
global_constraint_search_after_n_seconds
max_num_iterations
为了调整本地SLAM以降低延迟,我们可以
voxel_filter_size
submaps.resolution
.min_num_points
,.max_range
,增加.max_length
max_range
(特别是如果数据有噪音)submaps.num_range_data
请注意,较大的体素会有副作用略微增加扫描匹配分数,因此应相应地增加分数阈值。
纯粹的本地化与构图不同,首先,我们期望本地和全球SLAM的延迟更低.其次,全局SLAM通常会在先验地图的冻结轨迹与当前轨迹之间找到非常大量的相互约束。
为了调试纯粹的本地化,我们应该首先启用TRAJECTORY_BUILDER.pure_localization = true
并且强烈减少POSE_GRAPH.optimize_every_n_nodes
来快速接收结果.使用这些设置,全局SLAM通常会太慢而无法跟上。所以下一步,我们强烈减少global_sampling_ratio
和constraint_builder.sampling_ratio
以补偿大量约束
然后我们调整以降低延迟,如上所述,直到系统可靠地实时工作。
如果在pure_localization
中运行,则submaps.resolution
应与您正在运行的.pbstream
中的子图的分辨率匹配。目前未使用不同的分辨率,可能无法按预期工作
如果使用单独的测距源作为本地SLAM的输入(use_odometry = true
),我们还可以调整全局SLAM以从此附加信息中受益。
总共有四个参数允许我们在优化中调整局部SLAM和里程计的各个权重:
POSE_GRAPH.optimization_problem.local_slam_pose_translation_weight
POSE_GRAPH.optimization_problem.local_slam_pose_rotation_weight
POSE_GRAPH.optimization_problem.odometry_translation_weight
POSE_GRAPH.optimization_problem.odometry_rotation_weight
我们可以根据我们对本地SLAM或odometry的信任程度来设置这些权重。默认情况下,里程计被加权到类似于本地slam(扫描匹配)姿势的全局优化中。然而,来自车轮编码器的测距法通常具有很高的旋转不确定性,这种情况下,旋转权重可以减小,甚至降低到零
mapping
构图过程中,由其他节点发布/landmark
std_msgs/Header header
uint32 seq
time stamp
string frame_id
cartographer_ros_msgs/LandmarkEntry[] landmarks
string id
geometry_msgs/Pose tracking_from_landmark_transform
geometry_msgs/Point position
float64 x
float64 y
float64 z
geometry_msgs/Quaternion orientation
float64 x
float64 y
float64 z
float64 w
float64 translation_weight
float64 rotation_weight
注意 :
frame_id: 必须与published_frame存在tf树例如’imu_link’
id: mark的唯一标识
tracking_from_landmark_transform 这里的tf变换是从车体到mark的变换
rviz订阅/landmark_poses_list会观察到有输出点,但是id会和你发布的不一样
比如你发布的是"a"“b”“c”“d”,landmark_poses_list里面会是"1""2""3""4"这样的,
不用担心,从"a"“b”“c”"d"到"1""2""3""4"的映射在保存的时候会存在pbstream中了
下次发布的时候或者定位的时候依然按照你自己的id发布
localization
定位过程中发布/landmark
cartographer高度信任landmark,local slam不参考landmark,每次loop closure之前参考一次landmark,因此localslam时观察不到landmark起作用
注意 translation_weight越大landmark约束越强
特别注意:landmark必须和odom等其他传感器差不多的频率,比如landmark真正的频率只有5赫兹,那也要提高到20hz,其他时间都发布空值即可