Cartographer 调优方法论
引言
调优 Cartographer 可能非常复杂。系统参数众多,且多参数间存在相互影响。本调优指南通过具体示例,解释一种有原则的调优思路,帮助您系统性地优化 Cartographer。
内置工具
Cartographer 提供了多种用于 SLAM 评估的内置工具,特别适合衡量局部 SLAM 的精度。它们作为独立的可执行文件,与核心 cartographer 库配套,同时兼容 cartographer_ros。
建议查看 Cartographer 评估文档,了解评估工具的背景知识及实用指南。
这些工具基于将 SLAM 状态序列化到 .pbstream 文件。您可以利用 cartographer_ros 中的 assets_writer 功能生成此文件。详见利用 Cartographer ROS 生成的地图。
示例:调优局部 SLAM
本示例基于 cartographer 提交 aba4575 和 cartographer_ros 提交 99c23b6,选用测试数据集中的 b2-2016-04-27-12-31-41.bag 进行实验。
问题识别
初始配置的轨迹在录制文件早期出现了一些滑动。录制轨迹经过德意志博物馆一处坡道的时候,违背了 2D SLAM 的平坦地板假设。激光扫描数据表明 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_weightTRAJECTORY_BUILDER_2D.ceres_scan_matcher.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 需要进行调整以使其能够实时运行。
有许多选项可以调优不同组件的速度,我们按推荐的顺序列出它们,从直接的到更具侵入性的。建议一次只尝试一个选项,从第一个开始。配置参数请参阅 Cartographer 文档中。
降低全局 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 - 减少搜索窗口大小:
.linear_xy_search_window、.linear_z_search_window、.angular_search_window - 增加
global_constraint_search_after_n_seconds - 减少
max_num_iterations
降低局部 SLAM 延迟的措施
要降低局部 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(扫描匹配)位姿。
然而,来自轮式编码器的里程计通常在旋转方面具有较高的不确定性。在这种情况下,可以减少旋转权重,甚至可以降低到零。
仍然有问题?
如果您无法让 Cartographer 在您的数据上可靠地工作,可以开一个 GitHub issue 寻求帮助。开发人员很乐意提供帮助,但只有在您遵循问题模板时才能提供帮助,该模板包含:
rosbag_validate的结果- 指向包含您配置的
cartographer_ros分支的链接 - 指向重现问题的
.bag文件的链接
NOTE
提示:许多问题已被提交并解决。查看 cartographer_ros 的已关闭 Issues 和 cartographer 的已关闭 Issues 可能帮助您快速定位解决方案。
Cody Gu