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 72 24°C PM2.5 13
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 04

訊息與 QoS

為什麼訂閱了卻收不到:訊息型別與服務品質
Interaction 30 minute(s)

Learning Objectives

  • 讀懂 Twist、LaserScan、Odometry 這些常用訊息的欄位
  • 說出發布者與訂閱者型別不合、QoS 不相容時會發生什麼
  • 依官方相容規則判斷一組 QoS 能不能連上
  • 說明晚加入的訂閱者為什麼收不到舊訊息,以及 TRANSIENT_LOCAL 的用途
  • 說明感測器資料為什麼寧可丟掉也不要舊的

節點都起來了,topic 名稱也對,還是收不到

第 3 課看過名稱打錯會收不到。這一課是另外兩個更難發現的原因:訊息型別不合,以及 QoS 不相容。兩者的共同點是程式不會當掉,機器人只是安靜地不動。

先看 ROS 2 的訊息長什麼樣子。訊息的型別寫在定義檔裡,欄位可以再包別的訊息。官方的 common_interfaces 定義了最常用的幾個:

訊息 重要欄位 用途
geometry_msgs/msg/Twist linear、angular(各是 x、y、z) 速度指令。差速機器人只用 linear.x 和 angular.z
sensor_msgs/msg/LaserScan header、angle_min、angle_increment、range_min、range_max、ranges、intensities 光達一圈的距離
nav_msgs/msg/Odometry header、child_frame_id、pose、twist 里程計:位置、朝向與速度

header 裡有時間戳記(stamp)和座標系名稱(frame_id)。感測器資料都帶著它,這樣才知道資料是什麼時候、相對於哪個座標系量到的。

真實環境可以用 ros2 interface show geometry_msgs/msg/Twist 看定義。

訊息是有型別的物件

看怎麼建立訊息、填巢狀欄位,以及填錯時會怎樣。注意:這裡的錯誤訊息來自模擬環境。真實的 ROS 2 也會拒絕型別不對的訊息,但錯誤出現的時機與文字以實際執行為準。

互動練習:為什麼光達讀不到

這支程式應該要往前走、看到牆就停。但只要沒收到光達資料,它就不會動(看不見就不動,這是對的設計)。一步一步找出問題。

面板的輸出是模擬環境的輸出。 警告的文字依 rclpy 原始碼的寫法,沒有和真實環境對照過。

QoS:對傳輸品質的要求

QoS(Quality of Service)是每個發布者與訂閱者各自設定的傳輸規則。最常用的三個:

政策 選項 意思
Reliability(可靠性) RELIABLE 保證送達,可能重送
BEST_EFFORT 盡量送,掉了就算了
Durability(持久性) VOLATILE 不保留舊訊息
TRANSIENT_LOCAL 發布者保留訊息,給晚加入的訂閱者
History(歷史) KEEP_LAST 加 depth 只留最新的 depth 筆
KEEP_ALL 全部留著(受資源限制)

create_publisher(String, 'topic', 10) 裡的 10 就是 KEEP_LAST、depth=10,其他維持預設:RELIABLE、VOLATILE。

相容規則:發布者「提供」、訂閱者「要求」,要求的品質不能比提供的高,否則不連線。

發布者 訂閱者 結果
BEST_EFFORT BEST_EFFORT 可以
BEST_EFFORT RELIABLE 不連線
RELIABLE BEST_EFFORT 可以
RELIABLE RELIABLE 可以
發布者 訂閱者 結果
VOLATILE VOLATILE 可以,只收新訊息
VOLATILE TRANSIENT_LOCAL 不連線
TRANSIENT_LOCAL VOLATILE 可以,只收新訊息
TRANSIENT_LOCAL TRANSIENT_LOCAL 可以,新舊訊息都收得到

(兩張表依 ROS 2 官方文件 About Quality of Service settings,CC BY 4.0,翻譯並有修改。)

真實環境可以用 ros2 topic info /scan --verbose 看每個發布者與訂閱者的 QoS。不確定對方怎麼發布時,訂閱者用 BEST_EFFORT 幾乎都連得上,所以訂閱感測器資料常用 qos_profile_sensor_data。

互動練習:晚加入的訂閱者

map_server 啟動時把地圖發布一次。planner 晚 1 秒才開始訂閱。地圖不會再發第二次,它收得到嗎?

檔案開頭的 QOS 是這支程式用的 QoS。要改成 TRANSIENT_LOCAL 可以這樣寫:

QOS = QoSProfile(depth=1, durability=DurabilityPolicy.TRANSIENT_LOCAL)

感測器資料寧可丟掉也不要舊的

官方的感測器資料 QoS(qos_profile_sensor_data)用 BEST_EFFORT 加較小的佇列,理由是:感測器資料要的是及時,比每一筆都送到重要。

想想機器人一邊走一邊避障:0.2 秒前的距離還有用,3 秒前的距離是危險的,因為程式會以為牆還很遠。如果每一筆都要保留、都要處理,一旦處理速度跟不上,佇列就越積越長,手上的資料也越來越舊。

depth 決定佇列滿了之前能積多少。大佇列不會讓你漏資料,但可能讓你越來越落後;小佇列會丟資料,但手上的永遠是比較新的。沒有哪一個永遠對:

資料 比較在意什麼 常見設定
光達、相機、IMU 要新 BEST_EFFORT、小 depth
速度指令 要新,而且不能掉太多 RELIABLE、小 depth
地圖、感測器安裝位置 晚到也要拿得到 RELIABLE、TRANSIENT_LOCAL
記錄研究或除錯資料 每筆都要 RELIABLE、大 depth,並確認存得夠快

下面用訊息上的時間戳記,實際量資料有多舊。

互動練習:量資料有多舊

節點每筆光達要處理 0.3 秒,光達每 0.2 秒來一筆,所以一定跟不上。程式把「這筆資料已經過了多久」發布到 /age,「數值曲線」畫的就是它。

機器人在這個練習不會動,所以沒有畫世界。

確認一下

1.

發布者 RELIABLE+VOLATILE,訂閱者 BEST_EFFORT+TRANSIENT_LOCAL。連得上嗎?

2.

你的節點訂閱 /scan 時直接寫數字 10,光達用 BEST_EFFORT 發布。會發生什麼?

3.

節點 A 發布 Float64 到 /speed,節點 B 用 Float32 訂閱 /speed。下面哪個最接近實際情況?

4.

避障節點處理得比光達慢。把訂閱的 depth 從 5 改成 500,機器人會變得比較安全嗎?

第 1 次作答

重點整理

  • 訊息有固定的欄位與型別;header 帶著時間戳記與座標系。
  • 訂閱了收不到,除了名稱,還要查型別與 QoS。這兩種情況程式都不會當掉。
  • QoS 相容規則:訂閱者要求的不能高於發布者提供的。RELIABLE 訂閱 BEST_EFFORT、TRANSIENT_LOCAL 訂閱 VOLATILE 都連不上。
  • 晚加入的訂閱者收不到舊訊息,除非兩邊都用 TRANSIENT_LOCAL;/tf_static 就是這樣。
  • 處理跟不上時,大佇列讓資料越來越舊,小佇列讓資料被丟掉。感測器資料通常選新,紀錄資料通常選完整。

下一課看另一種溝通方式:問一句答一句的 service,以及不改程式就能調整的參數。

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