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 18

路徑規劃

從這裡到那裡怎麼走:A*、Dijkstra 與膨脹地圖
Interaction實作 35 minute(s)

Learning Objectives

  • 把柵格地圖看成圖,用 Dijkstra 與 A* 找最短路徑
  • 說明啟發函數為什麼能減少展開的格子,什麼條件下結果仍然最短
  • 解釋膨脹與代價地圖:機器人有大小,路徑不能貼著牆
  • 把規劃出來的路徑交給控制器實際走完

地圖怎麼變成可以搜尋的東西

機器人現在有地圖,也知道自己在教室門口。它要去走廊另一端的飲水機,中間有柱子和幾張椅子。路徑規劃要回答的問題是:走哪些格子?

做法是把地圖看成圖(graph):每個空的格子是一個節點,相鄰的格子之間有邊,邊的權重是移動距離。上下左右是 1,斜著走是 √2(約 1.414)。這樣就變成圖論的最短路徑問題,機器人領域沒有發明新東西。

Dijkstra 演算法(1959)的想法是由近到遠一圈一圈往外走:每次都從「目前已知距離起點最近、還沒處理的格子」往外展開。第一次走到目標時,那條路就是最短的。

它的問題是完全不知道目標在哪裡,往目標的反方向也同樣認真地搜尋。

A*(Hart、Nilsson、Raphael,1968)多加一項估計:

Dijkstra 的排序依據:f(n) = g(n)
A*       的排序依據:f(n) = g(n) + h(n)

g(n):從起點走到 n 實際花了多少
h(n):從 n 到終點「估計」還要多少(啟發函數)

h 讓搜尋優先往目標的方向走。只要 h 不會高估真實距離,A* 找到的仍然是最短路徑。常用的 h:

移動方式 啟發函數 為什麼不會高估
上下左右 曼哈頓距離:abs(dx) + abs(dy) 沒有牆時也至少要走這麼多步
八方向 對角距離:max(abs(dx), abs(dy)) + (√2 - 1) × min(abs(dx), abs(dy)) 同上,只是斜著走比較省

如果 h 永遠是 0,A* 就變成 Dijkstra。

一步一步看 A* 怎麼挑下一格

一張 4 × 3 的小地圖,起點和終點都在第一列,中間被牆隔開。注意 heapq 每次拿出 f 最小的格子:一開始 h 把搜尋往右引,碰到牆之後 f 變大,才改走下面繞過去。

互動練習:比較 Dijkstra 與 A*

綠色淡底是展開過的格子,藍線是路徑。「展開」的格子數大致代表花了多少計算時間。可以點地圖切換牆(滑鼠拖曳可以連續畫),也可以用欄、列輸入。

動手寫:A*

四方向移動,每步代價 1,所以啟發函數用曼哈頓距離。補上 h 和放進佇列的 f。程式會印出路徑和展開的格子數。

你的輸出
預期輸出

機器人不是一個點

上面的路徑常常貼著牆角走。把機器人當成一個點時這沒問題,但真實機器人有半徑,中心走在牆邊的格子上,車身就撞到牆了。

常見的作法是膨脹(inflation):與其在搜尋時檢查「車身會不會撞」,不如先把牆加厚一個機器人半徑,再把機器人當成一個點來規劃。這樣規劃器不用知道機器人的形狀(以圓形機器人來說)。

膨脹有一個馬上會碰到的副作用:太窄的門會被封起來。這不是錯誤,而是地圖在告訴你「這台機器人過不去」。

但只把牆加厚還不夠。貼著膨脹區邊緣走理論上不會撞,實際上定位和控制都有誤差,稍微偏一點就撞了。所以除了「不能走」的區域,再加一層代價:越靠近牆,走起來越貴。規劃器會自己權衡繞遠路還是走靠近牆的地方。這種每格記一個代價的地圖叫代價地圖(costmap)。

ROS 2 的 Nav2 把代價地圖分成很多層(靜態地圖、感測器看到的障礙物、膨脹)再疊在一起,全域規劃器與局部控制器各有一張。它的膨脹是依離障礙物的距離呈指數衰減;下面的小工具為了好讀,用線性衰減。

互動練習:機器人有大小

這張地圖中間有一道牆,有一扇只有一格寬的小門,下面有一扇比較寬的門。橘色是膨脹後不能走的地方,淡橘色是靠近牆、代價較高的地方。

規劃好了,還要走得到

規劃器只產出一串格子,沒有下任何速度指令。把路徑變成 /cmd_vel 是控制器的工作,第 9 課已經寫過:依序朝著下一個路點轉向、前進,到了就換下一個。

分工要記清楚:

  • 規劃器:知道地圖,不管馬達,通常幾秒才重算一次
  • 控制器:不管全局,讀最新的感測器與位置,每秒下很多次指令

下面的節點把兩者接起來:開機時用 A* 算一次路徑,之後用 P 控制沿著路點走。藍色虛線看不到,但左邊世界的藍線就是實際走過的路。

互動練習:走完規劃的路徑

世界裡的機器人半徑 0.18 公尺,格子 0.3 公尺。INFLATE 是把牆往外加厚幾格。

確認一下

1.

八方向移動的地圖,啟發函數用曼哈頓距離 abs(dx) + abs(dy),會發生什麼事?

2.

A* 的 h 永遠回傳 0,和 Dijkstra 比起來如何?

3.

膨脹半徑設定成機器人真實半徑,一點都沒有多留。真實世界會有什麼問題?

4.

機器人開機時規劃一次路徑,之後走廊上有人放了一台推車。只有規劃器和路徑跟隨的系統會怎樣?

5.

一張 1000 × 1000 格的地圖,用 A* 規劃一條穿越整張圖的路。怎樣最可能減少計算量?

第 1 次作答

重點整理

  • 柵格地圖可以看成圖,每個空格是節點。規劃就是最短路徑問題。
  • Dijkstra 由近到遠全方向搜尋;A* 用 f = g + h 優先往目標走。h 不高估就保證最短。
  • h 看不見牆,遇到死路 A* 省得比較少;權重大於 1 換到速度,放棄最短保證。
  • 機器人有大小:先膨脹牆,再把機器人當成點;代價地圖讓路徑自己離牆遠一點。
  • 找不到路徑時要停下來回報,不要放寬安全邊界硬走。

下一課處理規劃器看不到的東西:路上突然出現的障礙物。

這一課完成了!
Next lesson:局部避障與導航
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。