[待使用] cartographer自带的一些工具包可以帮助你来测量局部SLAM的质量,这部分可以参考下面的文档
Cartographer Read the Docs Evaluation site
使用这些工具前假设你已经知道如何将SLAM保存到.pbstream中,你可以调用assets_writer来保存SLAM结果到.pbstream格式。
我们测试的数据包是b2-2016-04-27-12-31-41.bag,可以点击评论aba4575和评论99c23b6查看一些细节。
在经过德意志博物馆的一个斜坡时(这违背了激光2D平整地面的假设),我们发现SLAM运行时的定位有一些滑动(位移),这明显SLAM前端遇到了问题,究其原因是我们太过于相信激光匹配的结果而忽略了其他传感器的作用。我们的目的就是改善这个问题。
我们只看这个发生问题的子图,因为这个错误包含在这个子图中,我们也看到随着时间的运行,全局SLAM发现了一些异常也尝试修正它,但是一但这个子图包含了错误则永远包含在子图中,全局SLAM无法纠正。
因为这个问题发生在子图中,所以这是一个局部SLAM问题,所以我们关掉全局SLAM,防止它干扰我们的调试,关闭方法如下:
POSE_GRAPH.optimize_every_n_nodes = 0
通过这个参数,之前提到过,查看每个独立的子图内部没有太大的累计误差时,则可确定,不宜过大或过小。
TRAJECTORY_BUILDER_2D.submaps.num_range_data
在我们的例子中,激光匹配可以任意的前后左右进行匹配不会影响得分,我们想增加这样一种策略,就是当匹配偏离初始值时,要付出更多的代价,离初始值越远,代价越大,就是如果要接受更远距离的匹配结果就需要更高匹配得分。可以通过这两个参数调试
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight
为了明显的看到这种惩罚效果可以设置的权重大一些,如下:
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1e3
实验结果显示1e3高昂代价使得与深度传感器探测的及其不符,明显发生断裂,当translation_weight为2e2时才能显示出较好的效果,
这里扫描匹配使用旋转仍然带来了一些干扰,我们这里设置rotation_weight为4e2,可以看出一个合理的结果。
为了验证我们没有过度调整这个特定的问题,我们把调试的结果用其他数据集验证一下,在这个例子(translation_weight = 2e2、rotation_weight = 4e2)中,验证的数据包发生了滑动(位移),所以我们再降低translation_weight为1e2,这样设置可能会糟糕但是没有发生滑动(位移),权重是个无单位的量,在使用之前会进行归一化,因为它只有相对的概念。
[为什么?] 那如何解决长廊问题?可以通过调节这里的translation_weight、rotation_weight来解决吗?答案是不能的,为什么不能?因为translation_weight、rotation_weight只能降低误匹配的概率,对于长廊这种毫无特征的环境,纯激光通过匹配是解决不了的,需要加入其他信息,如在地上或墙上添加二维码。
上面的默认配置和调试步骤是为了得到高质量的地图,下面我们的案例是在我们已经得到高质量地图后,需要进一步考虑的其他案例。
低延迟意味着我们在接收到传感器输入后不久(通常在一秒钟内)获得优化的姿态,并且全局优化线程里没有任务积压。比如机器人实时定位就需要低延时,作为前端局部SLAM直接影响延迟。全局SLAM建立了一系列后台任务, 当全局SLAM无法跟上队列时,漂移(错误位姿)可能会无限期累积,因此应将全局SLAM调整为实时工作。
有很多参数可以调节不同组件的速度,我们从建议的、简单的、到更深层的参数来分别介绍,我们建议一次只更改一种参数,更多参数的介绍在Cartographer documentation。
为了调试全局SLAM来实现低延时,我们降低计算量直到实现输出能保持一致地跟上输入,在这之后我们我们不再降低,因为我们尽可能的保持输出地图质量,为了降低全局SLAM延时,我们可以:
对于降低局部SLAM的延时,我们可以:
注意:大的网格的副作用是会稍微增加匹配的得分,所以匹配阈值也要相应的增加。
纯定位不同于建图,第一点,我们希望全局SLAM和局部SLAM都能保持低延时,第二点,全局SLAM通常要计算已知地图和新建地图之间大量的内部约束。
为了调试纯定位,我们首先会打开TRAJECTORY_BUILDER.pure_localization = true同时大幅度降低POSE_GRAPH.optimize_every_n_nodes数量以接收实频数据。当这样设置后,全局SLAM通常会变得很慢,所以下一步我们大幅度降低global_sampling_ratio和constraint_builder.sampling_ratio来降低要计算的约束量。然后,如上所述,为降低延迟,我们调整直到系统能够可靠地实时运行。
运行纯定位时,submaps.resolution的分辨率要和加载地图的分辨率一致,我们没有对分辨率未对应的情况进行验证,可能不能很好的工作。
如果一个独立的里程计数据源被作为输入传入局部SLAM(use_odometry = true),我们同样可以用这个数据源来调试全局SALM。
总的来说我们有4个独立的权重可以用来调试局部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相似。但是,齿轮编码器通常在旋转方面具有很高的不确定性。 在这种情况下,旋转权重甚至可以减小到零。
可以在Github上面提问,但是请按照正确的请求格式进行,务必把你用的配置文件、数据离线包发给我们。
当然也可以在这篇CSDN下面提问,很高兴解答您的问题。
[待解决问题] 是我自己本身还有些不太清楚的地方,待明白后再来更新。不影响您的阅读。