JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

漂移、错误匹配与回环闭合

微小误差累积会让地图扭曲变形;认出曾经到过的地方,就能把地图重新拉回正确形状。

为什么笔直的走廊会画歪

想象你闭着眼睛走过一栋楼,靠数步数和转弯的感觉来判断位置。每一步都差那么一点点,每次转弯都偏差一两度。单看每个错误都不大,但它们不会互相抵消,而是不断累加。走了一百米后,你对自己位置的估计可能就偏了好几米,更糟的是,方向还被扭歪了。机器人在陌生环境里建图时面对的正是这种情况。在 SLAM(同步定位与建图)中,机器人只靠自己的运动和传感器,一边估计自己的路径,一边把世界画出来。

这种靠数步数得到的运动估计有个名字:里程计。它在每个瞬间之间都非常平滑,却没有任何关于绝对真相的记忆,于是它的小误差就悄悄累积起来。我们把这种缓慢的累积叫作漂移。漂移不是换个更好的轮子或更干净的传感器就能修好的故障,它是逐段估计运动时无法回避的代价。

回环闭合:「等等,我来过这里」

下面这个精妙的想法能把地图救回来。当机器人回到先前到过的地点并*认出*它时,这份「认出」就是一条漂移无法反驳的硬信息:旅程中相隔遥远的这两个时刻,发生在同一个物理位置上。根据这份认出采取行动,就叫作 回环闭合

要用上它,机器人会加上一条约束——一根纽带,宣告「我现在的位姿和我当时的位姿必须对齐」。如果把整条轨迹想象成一串由弹簧连接的位姿,里程计提供的是相邻位姿之间的弹簧。回环闭合则加上一根横跨链条的长弹簧,把松脱的那一端拉回它真正该在的地方。这正是 位姿图优化的核心:把每个位姿当作一个节点,把每次测量当作一根弹簧,让所有弹簧稳定到一个与一切矛盾都尽量小的形状。

机器人怎么确认这真的是同一个地方,而不只是个长得像的地方?它会试着把当前的传感器视图和先前的对齐——用基于 ICP(迭代最近点)的扫描匹配把两帧激光雷达点云叠在一起,或者在两幅相机画面里匹配同样的视觉地标。一次良好的几何吻合,能把一个充满希望的猜测变成一条可信的约束。

自信的错误匹配有多危险

在加上回环闭合之前,机器人得先找到候选者:在它去过的所有地方里,哪个旧视图看起来像眼前这个?这种搜索就是 地点识别——把每个场景浓缩成一个紧凑的特征签名,然后问地图「我见过类似的东西吗?」。它一旦奏效,几毫秒内就能认出一条走回头的走廊。

可现实世界里到处是「撞脸」的东西。两个不同楼层的两间办公室,可能有一模一样的桌子、一模一样的门、一模一样的空白墙面。这就是感知混淆:传感器无法区分的不同地点。如果地点识别上了当,断言出一个错误的匹配,机器人就会把地图上本不属于同一处的两个部分硬焊在一起。

判断哪个观测属于哪个地点——并拒绝错误的配对——就是数据关联问题,而回环闭合正是它咬得最狠的地方。一次错误的闭合,破坏力远超漂移。漂移只是把地图轻轻弯曲;而一条错误的约束会把整栋楼的一翼猛地拽到另一翼上,优化器又偏偏信任这根坏弹簧,于是兴高采烈地毁掉一张本来几乎正确的地图。

一次正确的闭合,能治愈整条路径

现在来看回报。假设机器人绕一大圈漂移了两米,然后正确地认出了起点。回环闭合宣告这两端必须重合——但这漂移并不是在终点一下子产生的,它是在整段旅程中均匀渗进来的。所以优化器不会只把终点啪地拉回家,而是把这份修正沿着回环里的每一个位姿向后摊开,让每个位姿都挪动一点点。误差被分摊出去,螺旋就舒展成一个干净的环。

因为位姿和地图是绑在一起的,修好路径也就修好了世界。机器人沿这一圈摆下的每一面墙、每一道门、每一个地标,都会滑到更一致的位置上。原本被画成两份略有错位的走廊,会合并成一条。这一条约束的回报是它成本的许多倍——正是这种全局修正,才让大尺度建图成为可能。

Before closure (open loop, drift accumulating):

  start *--*--*--*--*--*--*  end   <- should be back at start,
         (poses drift outward)         but ends 2 m away

Add one loop-closure spring  ( end  ===  start ):

  start *--*--*--*--*--*--* end
    ^___________________________|   correction pulled across ALL poses

After optimization (error shared out, ring closes):

      *--*--*
     /        \
    *          *      one clean loop; map de-duplicated
     \        /
      *--*--*
回环闭合约束会把修正向后分摊到每一个位姿,而不只是终点。