第252篇 Cartographer深度解析——Google出品的激光SLAM方案
前两篇聊了LOAM和LeGO-LOAM,都是基于特征点的方法。这篇换个思路,聊一个完全不同的方案——Cartographer。Cartographer是Google在2016年发表在ICRA上的,后来开源了,是Google内部用了多年的SLAM系统。它最初是为Google Tango和Project Ara设计的,后来被广泛应用在机器人和自动驾驶领域。
它和LOAM系列最大的区别是什么?不用特征点,直接用栅格地图做匹配。这个思路来自概率机器人学,把SLAM问题转化为概率估计问题。Cartographer在Google内部经过了很多年的打磨,工程实现非常成熟。面试中Cartographer和LOAM经常被拿来对比,你得清楚两者的架构差异和适用场景。
Cartographer的整体架构
Cartographer也是前后端分离的,但架构和LOAM很不一样。
前端:局部子图构建 + 分支定界匹配。把连续的激光帧构建成局部子图(submap),每个子图是一个小的栅格地图。新帧和当前子图做匹配,用的是分支定界算法(Branch and Bound),不需要特征提取。前端输出的是高频的位姿估计和局部子图。
后端:全局优化。检测到回环后,用SPA(Sparse Pose Adjustment)做全局位姿图优化。Cartographer的后端是纯图优化,不像LOAM那样分前后端建图。后端的优化结果会反馈给前端,更新子图的位姿。
这个架构有个特点:前端和后端是异步的。前端持续构建子图、做匹配,后端在后台做全局优化。两者通过消息队列通信,互不阻塞。这个设计让Cartographer的实时性很好,不会因为后端优化而卡住前端。
# Cartographer的核心流程
class Cartographer:
def process(self, scan, pose):
# 前端:构建子图 + 匹配
submap.insert(scan, pose)
match_result = branch_and_bound_match(scan, submap)
# 回环检测
if detect_loop_closure(scan, all_submaps):
pose_graph.add_constraint(loop_constraint)
# 后端:全局优化
pose_graph.optimize()
return match_result.pose
子图构建与匹配
Cartographer的前端核心是子图(submap)的概念。
子图是什么?把连续N帧激光数据融合成一个栅格地图,就是一个子图。每个子图覆盖一小块区域,比如10米x10米。当传感器移动超过一定距离,就创建新的子图。子图之间是独立的,各自维护自己的坐标系。全局优化负责把不同子图的坐标系对齐。
子图的大小是个重要的参数。太小了,子图数量多,全局优化的计算量大。太大了,子图内的累积误差大,匹配效果差。一般根据场景大小来调,室内场景10米左右比较合适。
匹配怎么做?新来的激光帧和当前子图做匹配,用的是概率栅格匹配。每个栅格有一个占据概率值,激光帧的每个点落在栅格上,算似然概率。最大化所有点的似然概率之和,就是最优位姿。
概率栅格用的是对数几率(log-odds)表示法,而不是直接存概率值。为什么?因为概率值在0和1之间,连乘容易数值下溢。对数几率把乘法变成加法,数值稳定性更好。更新公式是:l_new = l_old + log(p/(1-p)),其中p是观测的占据概率。
分支定界算法是Cartographer匹配的核心。它把搜索空间分成多个层级,从粗到细搜索。粗层级快速排除不可能的区域,细层级精确定位。这个算法的好处是不需要好的初始位姿,全局搜索能力强。但代价是计算量大,比特征匹配慢不少。
# 分支定界匹配的核心思想
def branch_and_bound_match(scan, submap):
# 粗搜索:低分辨率栅格
candidates = coarse_search(scan, submap.low_res)
# 细搜索:高分辨率栅格
for candidate in candidates:
refined = fine_search(scan, submap.high_res, candidate)
return best_pose(refined)
回环检测与全局优化
Cartographer的回环检测也是基于子图的。当新子图和旧子图的重叠区域足够大时,就尝试做匹配。如果匹配成功,就认为检测到了回环。
回环检测的关键是怎么判断两个子图有重叠。Cartographer用的是位置距离+姿态距离的阈值判断。如果两个子图的位姿距离小于阈值,就认为它们可能重叠,尝试做分支定界匹配。这个策略简单高效,但可能会漏检一些远距离的回环。
全局优化用的是SPA(Sparse Pose Adjustment),本质上是位姿图优化。Cartographer用Ceres Solver做非线性优化,支持多种约束类型:匹配约束、IMU约束、里程计约束。Ceres Solver是Google开源的非线性优化库,性能很好,Cartographer的全局优化就靠它。
Cartographer的全局优化是实时的,每次加入新约束就增量更新。这个设计让Cartographer在大规模场景下也能保持很好的实时性。但增量更新也有缺点:如果早期有位姿估计错误,后面很难纠正,只能靠回环检测来修正。
面试追问环节
面试官:Cartographer和LOAM的主要区别是什么?
最大的区别是匹配方式。LOAM用特征点(边缘点+平面点)做点到线、点到面匹配。Cartographer不用特征,直接用栅格地图做概率匹配。LOAM的特征提取快但建图质量一般,Cartographer的栅格地图建图质量好但计算量大。另外,Cartographer有子图的概念,LOAM没有。
面试官:Cartographer适合什么场景?
Cartographer特别适合室内场景,比如办公楼、仓库、商场。它的栅格地图很适合导航和路径规划,建出来的地图干净漂亮。Google最初就是在Google Tango和Project Ara上用的Cartographer,都是室内场景。室外场景也能用,但效果不如室内好,因为室外环境特征少,栅格匹配容易退化。
面试官:Cartographer有什么局限?
计算量大,对硬件要求高。分支定界匹配虽然全局搜索能力强,但计算量比特征匹配大很多。另外,Cartographer的栅格地图是2.5D的,对三维场景的表达能力有限。还有,Cartographer对参数比较敏感,子图大小、匹配参数都要根据场景调。在嵌入式平台上跑Cartographer比较吃力,通常需要性能较好的处理器。
面试官:Cartographer的分支定界和ICP有什么区别?
ICP是迭代最近点,需要好的初始位姿,容易陷入局部最优。分支定界是全局搜索,从粗到细,不需要好的初始位姿。但分支定界的计算量大,ICP在初始位姿好的情况下收敛很快。实际使用中,Cartographer先用分支定界做粗匹配,再用ICP做精匹配,两者结合效果最好。
面试官:实际项目中用Cartographer要注意什么?
子图大小要调,太小了回环检测效果差,太大了计算量大。分支定界的搜索范围也要调,太大会很慢,太小可能漏匹配。还有,Cartographer的IMU融合和LOAM系列不一样,它用的是紧耦合方式,IMU的标定要好。栅格分辨率也是个重要参数,太高分辨率计算量大,太低分辨率匹配精度差。室内场景一般用0.05米的分辨率。
Cartographer和LOAM代表了激光SLAM的两种不同思路:特征匹配 vs 栅格匹配。两种方案各有优劣,面试中经常被拿来对比。实际项目中选哪个,要看具体场景和硬件条件。
Cartographer后来也支持了3D激光SLAM,用3D概率栅格做匹配。但3D版本的计算量更大,对硬件要求更高。Google开源的Cartographer代码质量很高,文档也很完善,是学习SLAM的好材料。建议跑一下官方的2D demo,感受一下栅格匹配的效果。
上一篇:第251篇 LeGO-LOAM深度解析——轻量级地面优化激光SLAM
下一篇我们聊HDL-Graph-SLAM,另一个重要的激光SLAM方案。
如果这篇文章对你有帮助,欢迎点赞支持一下,你的鼓励是我持续更新的动力!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)