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
     \        /
      *--*--*
迴環閉合約束會把修正向後分攤到每一個位姿,而不只是終點。