National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 16

佔用柵格建圖

邊走邊畫地圖:光達怎麼變成地圖
Interaction實作 35 minute(s)

Learning Objectives

  • 說明佔用柵格怎麼表示地圖,以及「沒看過」和「看過是空的」的差別
  • 用 log-odds 更新一個格子,說明它為什麼能把雜訊平均掉
  • 用 Bresenham 把一條光達射線變成要更新的格子
  • 用 /scan 與 /odom 建出一張地圖,說明里程計有誤差時地圖為什麼會糊掉

機器人需要的地圖長什麼樣子

把機器人放進一間它沒去過的教室。光達每一圈給它幾十個距離,下一圈又是另外幾十個。如果只看當下這一圈,它不會知道背後走過的走廊長什麼樣子,也沒辦法規劃怎麼繞過去。它需要把每一圈的資料累積成一張地圖。

最常見的表示法是佔用柵格(occupancy grid):把地面切成方格,每一格記一個「這裡有東西的機率」。這個想法來自 Moravec 與 Elfes 在 1985 年用聲納建圖的研究。

每個格子有三種狀態,第三種最容易被忽略:

狀態 意思 規劃時怎麼對待
大概有東西 機率高 不能走
大概是空的 機率低 可以走
還沒看過 機率 0.5,完全不知道 不能當成空的

「沒看過」不等於「空的」。如果把沒看過的地方當成可以走,機器人就會往從來沒確認過的方向全速前進。

這一課假設機器人知道自己在哪裡,先專心處理「看到的東西怎麼累積」。這個假設什麼時候不成立,課程最後會回來談。

log-odds:把機率的乘法換成加法

感測器會錯,所以一次觀測不能直接把格子定成有或沒有。比較合理的作法是累積證據:看到一次有東西,機率往上調一點;再看到一次,再往上調。

直接更新機率要做乘除,而且數值會擠在 0 和 1 附近。實務上常改記 log-odds:

l = ln(p / (1 - p))
p = 1 - 1 / (1 + e^l)

幾個值記下來就夠用:

機率 p log-odds l
0.5(不知道) 0
0.7 約 0.85
0.4 約 -0.4
0.93 約 2.55

這樣一來,更新只剩加法:射線停在這一格就加 0.85,射線穿過這一格就減 0.4。沒看過的格子是 0,不需要特別處理。

為什麼加和減的大小不一樣?射線穿過只告訴你「這條線上沒擋到」,射線停住的那一格比較可能真的有東西。這兩個數字是假設值,要依感測器調整,下面的小工具可以改。

代價也要知道:這個算法把每個格子當成互相獨立,也假設每次觀測獨立。實際上同一面牆相鄰的格子並不獨立,同一個位置連掃十次的誤差也可能是同一個原因造成的,所以機率的數字不要照字面解讀,當作「累積了多少證據」比較準確。

一步一步看一個格子的 log-odds

這個格子真的有東西。光達看到它三次,有一次量到比較遠(射線穿過它)。注意錯的那一次沒有把結果毀掉,只是讓證據少一點。

一條射線會經過哪些格子

光達給的是距離,要更新地圖得先知道這條線穿過哪些格子。在方格上畫直線的經典作法是 Bresenham 演算法:從起點一格一格走,每一步用整數累積的誤差決定要往 x 走、往 y 走,還是兩個都走。

起點 (2, 1),終點 (6, 3):(2,1) → (3,1) → (4,2) → (5,2) → (6,3)

只用整數加減,不需要浮點運算,每條射線只碰到它真正經過的格子。一條射線的更新規則是:

  • 除了最後一格,全部標成空的(減)
  • 最後一格標成佔用(加)
  • 如果光達在射程內沒有打到東西(inf),這一路都是空的,但沒有任何一格可以標佔用

下面的小工具把這些步驟攤開來。深灰是還不知道,白色是認為空的,黑色是認為有東西。

互動練習:看光達怎麼畫出地圖

藍色圓點是機器人。這裡的雜訊是「量到的距離差幾格」,是教學用的簡化,不是真實光達的感測模型。亂數的種子是固定的,同樣的操作結果相同。

動手寫:用一條射線更新地圖

ray 是一條射線依序經過的格子,最後一格是光達打到東西的地方。補上更新規則,再印出每一格的機率。grid 是字典,沒看過的格子不在裡面,.get(cell, 0.0) 會當成 0。

你的輸出
預期輸出

互動練習:用 ROS 2 節點建一張地圖

這支節點訂閱 /scan 和 /odom,一邊繞房間一邊累積 log-odds,21 秒時把地圖印到「輸出」面板:# 有東西、. 空的、? 沒看過,最後一行拿真實地圖來對答案。

有一行少了東西:LaserScan 的角度是相對光達本身的,不是相對地圖。模擬世界的 angle_min 是 -π,也就是從正後方開始;真實的光達起始角由驅動決定,所以程式一律用 angle_min 與 angle_increment 計算。

如果機器人也不知道自己在哪裡

上面的程式有一個很大的前提:/odom 給的位置是準的。模擬世界的里程計沒有雜訊,所以成立。真實機器人的輪子會打滑,里程計會累積誤差(第 8 課),只要位置偏掉,後面每一圈都會畫在錯的位置,同一面牆就變成好幾面。

這是機器人領域有名的雞生蛋問題:

  • 要建地圖,得先知道自己在哪裡
  • 要知道自己在哪裡,得先有地圖

同時解這兩件事叫 SLAM(Simultaneous Localization and Mapping)。一個常見的想法是比對這一圈光達和已經建好的地圖,用比對結果修正里程計的累積誤差;走回去過的地方時,還能發現「這裡我來過」,把整張地圖的誤差一次修掉(loop closure)。

ROS 2 常用的現成套件是 slam_toolbox,這門課不實作 SLAM,只要知道這個問題的結構。下一課會處理比較簡單的一半:地圖已經有了,機器人不知道自己在哪裡。

建好的地圖在 ROS 2 用 nav_msgs/msg/OccupancyGrid 傳遞:

header          frame_id 通常是 map
info.resolution 每格幾公尺
info.width      有幾欄
info.height     有幾列
info.origin     格子 (0, 0) 在 map 座標系的位姿
data            一維陣列,從 (0, 0) 開始逐列排列;-1 是不知道,0 是空的,ROS 工具常用 1 到 100 表示佔用程度

注意 data 的 -1:訊息定義本身就把「不知道」和「空的」分開了,和這一課開頭的三種狀態一致。訊息定義也說明數值的意義依應用而定,所以要看接收端怎麼解讀。另外它的第 0 個元素是地圖左下角(origin 的位置),上面的小工具和字串地圖則是第 0 列在最上面,自己轉換時很容易差一個上下顛倒。

互動練習:里程計有誤差時的地圖

同一支程式(TODO 已補好),這次世界的里程計與光達都有雜訊。紅色虛線是里程計估計的路徑,藍線是真實路徑,兩條會慢慢分開。程式不用改,看結果就好。

確認一下

1.

走廊盡頭有一面玻璃門,光達的雷射穿過去,量到門外很遠的牆。掃很多次之後,地圖上的玻璃門會是什麼樣子?

2.

光達在射程內沒有打到東西,回傳 inf。下面哪個作法最合理?

3.

某格的 log-odds 是 0.85。接下來射線穿過它兩次(L_FREE 是 0.4),它現在是多少?代表什麼?

4.

為什麼 log-odds 通常要設上下限?如果不設,一面牆被連續看到一萬次之後,有人把牆拆了,會發生什麼事?

5.

規劃路徑時,把「未知」的格子當成可以走。這個設定有什麼風險?

第 1 次作答

重點整理

  • 佔用柵格把地面切成格子,每格記佔用機率。未知和空的是兩回事。
  • log-odds 把更新變成加法:射線停住的格子加、穿過的格子減。
  • 累積證據可以平均掉隨機雜訊,平均不掉每次都一樣的錯(玻璃、黑色物體)。
  • 光達的角度是相對光達的,建圖前要轉到地圖座標,並且用 angle_min、angle_increment 算。
  • 位置不準,地圖就會糊掉;同時估計位置和地圖叫 SLAM。OccupancyGrid 的 data 用 -1 表示未知,從地圖左下角開始排列。

下一課反過來:地圖有了,機器人被放在某個地方,它要怎麼知道自己在哪裡。

這一課完成了!
Next lesson:粒子濾波定位
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。