前一天,我整理了 TurtleBot3 前進時需要判斷的條件:目標要接近畫面中央,而且在影像中的大小還沒有達到停止門檻。接下來,就要把這些條件和前面建立的轉向控制放在一起。
如果機器人正在往前走,紅色方塊卻移到畫面旁邊,甚至直接離開視野,它就需要根據新的辨識結果調整動作。
所以今天的目標是:整合轉向、前進與停止的判斷,讓 TurtleBot3 根據每一幀影像更新移動指令。
前面使用 error_x 判斷紅色方塊相對於畫面中心的位置,再透過 P 控制計算旋轉速度。昨天則加入目標大小的判斷,用來決定是否需要繼續靠近。
這兩個控制量各自負責的事情,可以整理成:
| 控制項目 | 作用 | 判斷依據 |
|---|---|---|
angular.z |
控制左右轉向 | 目標與畫面中心的水平誤差 error_x |
linear.x |
控制前進速度 | 目標是否接近中央,以及外接框面積 box_area |
簡單來說,angular.z 負責「往哪邊看」,linear.x 負責「要不要靠近」。最後再把兩個數值放進同一個 Twist 訊息,發布到 /cmd_vel。
看到紅色方塊後,還不能直接讓機器人往前走。如果目標已經偏到畫面邊緣,這時繼續前進,就可能朝著沒有對準目標的方向移動。
因此,我先沿用 Day 10 的條件:目標超出死區時先轉向,回到中央的容許範圍後,再根據大小決定是否前進。
| 畫面中的情況 | 機器人的動作 |
|---|---|
| 找到目標,但水平誤差超出死區 | 停止前進,調整轉向 |
| 目標在死區內,面積小於停止門檻 | 不轉向,以設定速度前進 |
| 目標在死區內,面積達到停止門檻 | 停止前進與轉向 |
| 沒有找到目標 | 停止前進與轉向 |
依照這個版本的條件,機器人會在轉向與前進之間切換。先讓動作的判斷順序清楚,之後再研究小幅轉向時持續前進的方式。
linear.x 與 angular.z接著把 Day 9 的死區、P 控制與最大角速度限制,和 Day 10 的前進條件放進同一段流程。
以下是放在影像回呼函式中的控制片段,假設程式已經取得辨識結果,並建立好 Twist 所需的匯入與 /cmd_vel 的 Publisher。target_found 代表這一幀是否找到目標;找到時,才會使用對應的 error_x 和 box_area。
面積門檻沿用前一天的名稱 AREA_THRESHOLD,其餘參數也需要先設定,再依照模擬畫面調整。
twist = Twist()
if not target_found:
# 找不到目標,停止前進與轉向
twist.linear.x = 0.0
twist.angular.z = 0.0
else:
# 先根據水平誤差決定轉向速度
if abs(error_x) <= DEAD_ZONE:
angular_z = 0.0
else:
angular_z = -KP_ANGULAR * error_x
angular_z = max(
-MAX_ANGULAR_SPEED,
min(MAX_ANGULAR_SPEED, angular_z)
)
twist.angular.z = angular_z
# 方向對準,而且尚未達到面積門檻,才往前走
if abs(error_x) <= DEAD_ZONE and box_area < AREA_THRESHOLD:
twist.linear.x = FORWARD_SPEED
else:
twist.linear.x = 0.0
# 每次完成判斷後,都發布這一幀對應的速度指令
self.cmd_vel_pub.publish(twist)
這段程式先確認有沒有找到目標,再處理轉向與前進。即使目標的面積已經達到門檻,只要它還偏離中央,機器人仍然可以原地轉向,讓目標回到畫面中間。
另外,最後的 publish() 要放在整個判斷之外,讓前進、轉向和停止的結果都能送出去。否則程式雖然算出了新的速度,機器人卻不一定有收到對應的指令。
這裡的 box_area 仍然只是 Bounding Box(外接框)在影像中的面積,用來判斷是否停止靠近,還不能直接換算成實際距離。
假設前一幀紅色方塊還在中央,機器人正在前進,下一幀方塊卻離開畫面。如果這時只是跳過控制程式,沒有發布新的速度指令,機器人就可能暫時繼續執行上一個動作。
所以只要這一幀找不到目標,就把兩個速度都設成 0:
twist.linear.x = 0.0
twist.angular.z = 0.0
接著透過前面統一的 publish(),把停止指令送出去。找不到目標,也是一種需要處理的辨識結果。
這裡處理的是「收到影像,但沒有辨識到方塊」的情況。如果相機影像直接中斷,回呼函式可能不會再執行,就需要另外加入影像逾時的檢查。
至於失去目標後要不要旋轉搜尋,可以等基本流程穩定後,再繼續研究。
前一天提到,移動跟拍除了跟得上目標,也要考慮畫面是否平順。把控制整合後,接下來就能觀察轉向、前進與停止之間的切換,會不會讓機器人的動作太突然。
例如目標的水平誤差一直在死區邊界附近變動,機器人就可能反覆切換轉向與前進;目標面積在停止門檻附近變化時,也可能出現走一下、停一下的情況。
目前先確認每個條件都能對應到預期的動作,再根據實際表現調整。等到基本追蹤流程穩定後,才繼續研究怎麼讓移動更自然,讓相機拍到的畫面也比較舒服。
接下來在 Gazebo 中,我會先讓紅色方塊位於畫面中央,確認面積小於門檻時,TurtleBot3 是否會前進;再讓目標偏向兩側,觀察機器人是否會停止前進,先調整方向。
當方塊在畫面中逐漸變大、達到停止門檻時,要確認前進速度是否歸零。最後再讓目標離開視野,檢查前進與轉向是否都會停止。
除了觀察機器人的動作,也可以一起查看 error_x、box_area 和發布的速度,確認目前是哪個條件觸發了動作。這樣遇到走走停停的情況時,才比較容易判斷要調整的是死區、面積門檻,還是速度設定。
linear.x 與 angular.z 各自負責的動作。Twist 訊息。這次先把轉向、前進與停止整合成一套控制邏輯,讓 TurtleBot3 能根據每一幀的辨識結果,決定下一步該怎麼動。接下來再透過 Gazebo 測試,確認實際動作是否符合預期。
ㄣ
下一篇會進一步觀察連續追蹤時的表現,特別是目標持續移動、方向改變,以及前進與停止切換的情況。再從這些觀察中,找出目前控制方式需要調整的地方。