cartographer ros使用指南-调优
说明:
介绍如何调整cartographer相关参数,以达到更好的效果
两个系统:
cartographer可以被视为两个独立但相关的系统。
第一个是本地SLAM(有时也称为前端)。
它的工作是构建一组局部一致的子图并将它们组合在一起,但它会随着时间的推移而变化。
它的大多数选项可以在用于2D的trajectory_builder_2d.lua和用于3D的trajectory_builder_3d.lua
另一个系统是全局SLAM(有时称为后端)。
它在后台线程中运行,其主要工作是找到循环闭包约束。
它通过对子图的扫描匹配扫描来实现。
它还结合了其他传感器数据,以获得更高级别的视图并确定最一致的全局解决方案。
在3D中,它还试图找到重力方向。
它的大多数选项都可以在pose_graph.lua中找到
在更高的抽象上,本地SLAM的工作是生成良好的子图,而全局SLAM的工作是将它们最一致地绑定在一起。
内置工具
cartographer提供用于SLAM评估的内置工具,这对于测量本地SLAM质量特别有用。
它们是随核心cartographer库一起提供的独立可执行文件,因此是独立的,但与cartographer_ros兼容。
因此,请前往制图师阅读文档评估网站,获取概念性概述以及如何在实践中使用这些工具的指南。
这些工具假定您已将SLAM状态序列化为.pbstream文件。
使用cartographer_ros,您可以调用assets_writer来序列化状态 - 有关详细信息,请参阅Assets writer部分。
示例:调整本地SLAM
对于这个例子,我们将从cartographer提交aba4575和cartographer_ros提交99c23b6开始,然后从我们的测试数据集中查看包b2-2016-04-27-12-31-41.bag。
在我们的初始配置中,我们看到在这个包的早期就有一些滑动,这是因为这个包经过了德国博物馆的一个斜坡,这违反了平面地板的二维假设。
在激光扫描数据中可以看到相矛盾的信息被传递给SLAM。但这一下滑也表明,我们对点云的匹配程度过高,而且对其他传感器的忽视也相当强烈。
我们的目标是通过调优来改善情况。如果我们只看这个特定的submaps,那么错误就只包含在这个submaps中。
我们也看到,随着时间的推移,全局SLAN会发现发生这些奇怪的情形,并能部分的进行纠正,然而这些有问题的submaps就永远有问题了。
由于这儿的问题是在submaps中有滑动,这是局部SLAM的问题,所以我们可以先关掉全局SLAM,以免影响我们调优。
POSE_GRAPH.optimize_every_n_nodes = 0
submaps的正确尺寸
随着时间的推移,只有闭环才能解决局部SLAM的这种漂移。
子图必须足够小,以使其内部的漂移低于分辨率,以便它们在本地正确。
另一方面,它们应该足够大以使环路闭合能够正常工作。
子图的大小通过TRAJECTORY_BUILDER_2D.submaps.num_range_data配置。
看一下这个例子的各个子图,他们已经很好地拟合了这两个约束,所以我们假设这个参数调整得很好。
扫描匹配器的选择
局部SLAM背后的理念是使用除了测距仪之外的传感器数据来预测下一个扫描应该被插入到submap的位置。
然后,CeresScanMatcher将此作为先验,并找到扫描匹配到的submap的最佳位置。
它通过插入submap 和子像素来对齐扫描。
这是快速的,但是不能修复比submaps的分辨率大得多的错误。
如果你的传感器设置和时间是合理的,只使用CeresScanMatcher通常是最好的选择
如果你没有其他传感器或你不相信它们,Cartographer 还提供了一个RealTimeCorrelativeScanMatcher。
它使用的方法类似于在闭环中对submap进行匹配,而不是与当前的submap相匹配
然后最好的匹配用作CeresScanMatcher的先验
这个扫描设备非常昂贵并且基本上不顾除测距仪外其他传感器的任何信号,但它在特征丰富的环境中是很稳定的。
相关的扫描匹配器的调优
TODO
CeresScanMatcher的调优
在我们的例程中,扫描匹配器可以在不影响匹配值的情况下,自由的向前或向后移动这个匹配。
我们通过让扫描匹配器为之前获得的偏离付出更高的代价来避免这种情形。
控制这个的两个参数是rotation_weight和TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_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延迟,我们可以
减少 optimize_every_n_nodes
增加 MAP_BUILDER.num_background_threads up to the number of cores
减少 global_sampling_ratio
减少 constraint_builder.sampling_ratio
增加 constraint_builder.min_score
for the adaptive voxel filter(s), decrease .min_num_points, .max_range, increase .max_length
增加 voxel_filter_size, submaps.resolution, decrease submaps.num_range_data
减少 search windows sizes, .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
for the adaptive voxel filter(s), decrease .min_num_points, .max_range, increase .max_length
减少 max_range (especially if data is noisy)
减少 submaps.num_range_data
请注意,较大的voxels会略微增加扫描匹配分数作为副作用,因此应该相应地增加分数阈值。
给定地图纯定位
纯定位与建图不同。
首先,我们期望本地和全局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(扫描匹配)。
然而,来自车轮编码器的里程计通常具有很高的旋转不确定性。
在这种情况下,旋转权重可以减小,甚至降至零。