Cartographer参数调优
参考Cartographer_ros官方教程
不幸的是,调整 Cartographer 真的很困难。 该系统有许多参数,其中许多参数会相互影响。 本调优指南试图使用具体的示例来解释一些原则性方法。
内置工具
Cartographer 提供了用于 SLAM 评估的内置工具,这些工具对于测量局部 SLAM 质量特别有用。 它们是独立的可执行文件,随 cartographer
核心库一起提供,因此是独立的,但与 cartographer_ros
兼容。 因此,请前往 Cartographer Read the Docs Evaluation 以获取概念概述和如何在实践中使用这些工具的指南。
这些工具假设您已将 SLAM 状态序列化为 .pbstream
文件。 使用 cartographer_ros
,您可以调用 assets_writer
来序列化状态。
例子:局部SLAM调优
对于这个例子,我们将从 cartographer
commit aba4575 和 cartographer_ros commit 99c23b6 开始,然后查看我们测试数据集中的 bag 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
配置。 看看这个例子的各个子图,它们已经很好地适应了两个约束,所以我们假设这个参数已经很好地调整了。
调整 CeresScanMatcher
在我们的例子中,扫描匹配器可以在不影响分数的情况下自由地前后移动匹配。 我们希望通过让扫描匹配器为偏离它得到的先验而付出更多代价来惩罚这种情况。 控制它的两个参数是 TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight
和 rotation_weight
。 越高,将结果偏离先验的代价就越大,或者换句话说:扫描匹配必须在另一个位置产生更高的分数才能被接受。
出于教学目的,让我们偏离先验的代价变得高昂:
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1e3
这允许优化器非常自由地覆盖扫描匹配器的结果。 这导致位姿接近于先验,但与深度传感器不一致并且明显损坏。实验表明此处使用2e2
可以获得更好的结果 。
在这里,扫描匹配器使用旋转仍然稍微弄乱了结果。 将 rotation_weight
设置为 4e2
会给我们一个合理的结果。
验证
为了确保我们没有针对这个特定问题过度调整,我们需要针对其他收集的数据运行配置。 在这种情况下,新参数确实显示了滑动,例如在 b2-2016-04-05-14-44-52.bag
的开头,因此我们不得不将 translation_weight
降低到 1e2
。 对于我们想要修复的情况,此设置更糟,但不再滑动。 在检查它们之前,我们将所有权重归一化,因为它们只有相对意义。 这次调整的结果是 PR 428。一般来说,总是尝试针对平台而不是特定的数据包进行调整。
特殊情况
默认配置和上述调整步骤侧重于质量。 只有在我们取得了良好的质量后,我们才能进一步考虑特殊情况。
低延迟
低延迟是指在接收到传感器输入后不久就可以使用优化的局部姿态,通常在一秒钟内,并且全局优化没有积压。 在线算法需要低延迟,例如机器人定位。 在前台运行的局部 SLAM 直接影响延迟。 全局 SLAM 建立了一个后台任务队列。 当全局 SLAM 无法跟上队列时,漂移会无限累积,因此应调整全局 SLAM 以使其实时工作。
有许多选项可以调整不同的组件以提高速度,我们将它们从推荐的、直接的组件到更具影响性的组件排序。 建议一次只探索一个选项,从第一个开始。
为了调整全局 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
- 降低
search windows sizes
,.linear_xy_search_window
,.linear_z_search_window
,.angular_search_window
- 增加
global_constraint_search_after_n_seconds
- 降低
decrease 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 或里程计的信任程度来设置这些权重。 默认情况下,里程计类似于局部slam(扫描匹配)位姿被加权到全局优化中。 然而,来自车轮编码器的里程计通常在旋转中具有很高的不确定性。 在这种情况下,旋转权重可以减少,甚至降到零。