robot-notes — 機器人知識筆記 GitHub ↗
本章與本頁目次

調度

robot-notes /調度/跨車隊協調/OpenRMF:跨車隊調度

OpenRMF:跨車隊調度

VDA5050 解決了「一套主控怎麼跟不同廠的車講話」。但還有一層更上面的問題沒解決:很多家車隊同時在一個場域跑,彼此共用門、電梯、窄道,誰來協調? 這就是 OpenRMF 要補的那塊。

延伸閱讀:VDA5050SLAM定位


1. 根本問題:各車隊只看得到自己的車

每家 AMR 自帶 fleet manager(車隊管理系統),但它只看得到、也只管得了自己的車。多家車隊共用同一個物理空間時,衝突無可避免——RMF 官方直接說「多廠商、多機器人系統仍是未解問題」:

2. 第一性原理:在車隊「之上」加一層,而不是取代它們

OpenRMF(Open Robotics Middleware Framework)由 Open Robotics(ROS 維護者)主導、建在 ROS 2 上。關鍵定位:它不取代各家 fleet manager,而是疊在所有車隊「之上」做協調

為什麼是「疊上面」而不是「換掉」?第一性原理:各廠的導航與避障是他們的核心 IP、而且運作良好,不需要、也換不掉。真正缺的東西只有一個——全局意圖的可見性(誰打算走哪、何時走)。OpenRMF 補的就是這塊,讓各廠保留自己的車隊系統,只透過一個轉接層接進來:

OpenRMF 疊在各家車隊之上,每家透過一個 fleet adapter 接入

核心元件

3. 交通協商:從「事後撞到」變「事前預測」

這是 OpenRMF 跟「各車隊各自為政」最根本的差別:

各自為政→現場才卡死;共用時空排程→在時空圖上事前偵測衝突並協商

第一性原理在「共用一張時空排程」:

  1. 共用時空排程:所有接入的車隊,都必須把自家車「打算走的行程」上報到中央排程庫。排程庫因此擁有各自為政時缺的全局視野
  2. 衝突偵測(預防):車的軌跡以分段三次樣條表示,兩兩比對在時空上是否交疊;交疊就發 conflict notice。
  3. 協商化解:被通知的車隊各自提交「能容納對方」的替代行程(降速、暫停、繞行),RMF 的協商機制收斂到一組彼此相容、整體延遲較小的方案。(traffic 協商層相對平等對待各車,優先序主要在 rmf_task 派工端;細節以官方實作為準。)
  4. 避障分工不變:RMF 用「帶時間維度的 A*」處理車隊級的時空避讓;單車對突發障礙的即時避障,仍由各車自己負責——對 VDA5050 車隊就是協定規定的車端職責。

對比很清楚:沒有共用排程時,衝突只能在現場「卡住了」才被動處理;有了排程庫,衝突在「還沒走進去之前」就被預測並協商掉。這也接回 VDA5050 的 released/horizon:RMF 協商定案後,才讓主控釋放下一段路。

4. OpenRMF 與 VDA5050 怎麼搭

層次很清楚:OpenRMF(跨車隊協調)→ fleet adapter →(對 VDA5050 車隊)VDA5050 over MQTT → 各廠 AMR

換句話說,adapter 跨在兩條不同的匯流排上:RMF 這側走 DDS(ROS 2 內部),車隊那側走 MQTT。兩邊都是 pub/sub,但不是同一張網——adapter 是唯一的接點,這也是為什麼「寫 adapter」聽起來像翻譯工作,實際上還要處理兩套傳輸語意的差異。

理想上,對「支援 VDA5050」的車隊用一個 VDA5050 fleet adapter,讓 RMF 扮演 VDA5050 的 master control。

兩者的職責邊界,與 adapter 真正要做的事

5. 串接流程:從下任務到車執行

把前面組起來,一筆任務從下達到車執行、再回報協商的完整資料流:

OpenRMF↔VDA5050 串接 sequence:下任務→競標派工→fleet adapter→VDA5050 order→車→state 回報→交通協商

逐步看:

  1. 下任務:上層系統發 SubmitTask 給 RMF Dispatcher(rmf_task_ros2rmf_dispatcher_node)。
  2. 競標派工(RMF 內部,ROS 2):Dispatcher 發 BidNotice 廣播 → 各 fleet adapter 用 rmf_task::TaskPlanner 算成本回 BidProposal → Dispatcher 比價(fastest-to-finish / lowest-cost)發 DispatchRequest 指定得標車隊。
  3. 規劃:得標車隊的 adapter,RMF 用 nav graph 規劃整段路線,逐 waypoint 下 NavigationRequest
  4. 翻成 VDA5050(走 MQTT):adapter 把目的地翻成 VDA5050 order(node/edge 的 JSON)發給車。
  5. 車回報:車週期發 VDA5050 state(位置、電量、模式)。
  6. 更新回 RMF:adapter 把 state 轉成 RobotUpdateHandle.update(...) 餵回 rmf_traffic 的時空排程。
  7. 協商:排程偵測到衝突 → 重規劃 → 追加 order 更新;這裡 RMF「已協商釋出的路段」對映到 VDA5050 order 的 released 旗標(逐段放行),未協商完的後續段標 released:false(horizon)。

⚠️ 誠實標註:第 7 步「RMF released ↔ VDA5050 released horizon」的對映是依兩邊協定語意推得的整合設計建議,官方沒有逐欄定義的權威文件(因為官方 RMF-as-VDA5050-master adapter 尚未成熟,見 §7)。實務多走 adapter 內自行轉換,或經 InOrbit vda5050_connector(MQTT_bridge + Controller + Adapter 三件)這類中介。

6. 怎麼寫一個 fleet adapter

把一個車隊接進 RMF,就是寫一支 fleet adapter。先選整合層級(對 RMF 的控制力由高到低):

層級 RMF 的控制力 何時用
Full Control 最高:RMF 規劃完整路徑、可即時打斷重派 車的 API 接受「導到某點」且可被打斷
Easy Full Control 同上,但只填 callback、不碰內部邏輯 官方建議起點,多數整合用這個
Traffic Light 最低:RMF 只能 pause/resume,車自己規劃路徑 車自有完整導航,只想要 RMF 當「路口紅綠燈」防撞

這就是「RMF 規劃整條路下發」(Full Control)vs「車自己導航」(Traffic Light)的差別——大多數導入用 Easy Full Control:RMF 用 nav graph 逐 waypoint 下目的地,車負責實際開過去。

Fleet Adapter 居中:向下對車隊下指令(navigate/stop/execute_action)、向上讀狀態(position/map/battery_soc)回報 RMF

fleet_adapter_template(Python)開始,要實作的就兩組函式:

往車隊下指令(RMF → 車):              從車隊讀狀態(車 → RMF):
  navigate(目的地 x,y,θ, 地圖名, 速限)   position()    → 車在自己座標的 [x,y,θ]
  start_activity(...)  dock/開門/電梯     map()         → 目前地圖名
  stop()               叫車停            battery_soc() → 電量
                                         is_command_completed() → 命令完成了沒

對應 Easy Full Control 的 C++ API:加車用 add_robot(name, initial_state, configuration, callbacks);callbacks 裡是 NavigationRequest(去某目的地、完成時呼叫 execution.finished())、StopRequestActionExecutor;狀態用 EasyRobotUpdateHandle::update(RobotState{map, position, battery_soc}, ...) 回報。add_robot 回傳的 RobotUpdateHandle 一定要存起來,之後持續用它更新車況。

config.yaml 要填的(車隊契約):車隊名、limits(線/角速度與加速度上限)、profile(footprint 半徑、vicinity 防護半徑)、reversible(可否倒退)、battery_system(電壓/容量/充電電流)、mechanical_system(質量/慣量/摩擦)、recharge_threshold/recharge_soc(何時回充、充多滿)、task_capabilities(loop/delivery/clean)、以及 reference_coordinates(RMF 座標 ↔ 車座標的對應,建議至少 4 組 waypoint 求轉換——呼應 §4 的「座標要先對齊」)。

最小寫法的 pseudo-code(VDA5050 fleet adapter 骨架 + 用 REST API 叫 RMF 派任務)整理在 實作小抄:adapter + 派任務怎麼把它部署起來(adapter 一容器、core 一容器、DDS 跨容器)見 RMF 多容器部署

7. 現況:哪些是現成的、哪些還在路上

前面講的是架構上該怎麼搭。實際要導入時,得知道這條路上哪一段已經鋪好、哪一段還沒。

一句話:VDA5050 與 OpenRMF 在架構上是天作之合(一個管車隊內共同語言、一個管跨車隊協調),但「RMF 直連 VDA5050 車隊」的成熟 adapter 還在路上,規劃導入時要把這點算進去。

8. 落地場景與開源位置

用途 repo
總入口 github.com/open-rmf
交通管理 open-rmf/rmf_traffic
ROS2 整合 + fleet adapter open-rmf/rmf_ros2
任務 open-rmf/rmf_task
demo open-rmf/rmf_demos
adapter 範本 open-rmf/fleet_adapter_template
社群 adapter 清單 open-rmf/awesome_adapters

9. 來源

附錄:系統需求、語言與安裝

這節是要動手裝的時候才需要,概念部分讀完前面就夠了。

跑在 ROS 2 上,跟著 ROS 2 的 Tier-1 平台走:

ROS 2 distro Ubuntu 備註
Humble 22.04 LTS,最常用
Jazzy 24.04 LTS,較新
Kilted / Rolling 24.04 / 滾動 較新 / 開發用

三個接下來一直會用到的詞先釘住:waypoint 是路網上的一個停靠點(帶座標與朝向);lane 是連接兩個 waypoint 的有向路段;兩者合起來就是 nav graphRMF 規劃時只在這張圖上走,不碰自由空間——怎麼從一個 waypoint 開到下一個,是車自己的事。。

  • 核心 repo:rmf_traffic(協商引擎)、rmf_task(競標派工)、rmf_ros2(ROS2 節點層,含 rmf_fleet_adapter)、rmf_battery(電量/回充模型)、rmf_traffic_editorrmf_demos