1. 簡介
你是否曾有過這樣的疑問:我按照文檔安裝了ROS,依照要求寫了一些示例節點(node)、消息(msg)和話題(topic),但覺得過程既麻煩又繁瑣。也許你開始懷疑:為什么需要ROS?它到底幫我解決了什么問題?
本文將通過一個簡單的例子,介紹ROS的架構,闡明它解決了哪些問題,以及它如何幫助我們簡化開發流程。
2. 移動案例
假設我們要編寫一個能夠控制機器人移動的程序。
- 隨著程序的增多,我們需要進行模塊化,方便分工合作和代碼復用;
- 還需要開放移動接口,使得其他模塊能夠調用移動控制功能;
- 對應,需要選型一個通信機制來傳遞移動指令;
- 移動指令的格式,返回消息的格式需要規范化管理;
- 指令可能需要同時傳給多個模塊,如果下游模塊沒有及時收到可能需要緩存;
- 此外,我們還需要確保各個模塊服務的持續運行,能夠有效管理;
- 模塊多了后,多對多的消息傳遞,日志,可能需要一種有效的監控和調試手段。
你會發現,一個簡單的移動控制功能,背后可能涉及了大量的框架設計、標準化工作和大量代碼量,如果全部手工實現,不同的人實現方案可能五花八門,也使得開發者很難專注于機器人的核心功能(如更好地移動、剎車、轉彎等)。
在這種情況下,ROS的出現就解決了這些問題。下面是ROS中的一些關鍵概念:
- 節點(node):每個節點對應一個功能模塊,ROS會幫助你管理節點的生命周期,確保它們穩定運行并完成各自的任務,免去你手動管理進程或線程的麻煩。
- 消息(message):消息定義了節點之間傳遞的數據結構,如運動指令、雷達數據、坐標數據等。ROS提供了許多常用的消息類型,你可以直接使用這些標準的消息類型,無需重復設計數據格式。如果你的團隊其他成員或外部開源項目遵循相同的消息標準,那么這些模塊可以無縫對接。
- 話題(topic):話題是消息傳遞的方式之一。比如,假設你和其他模塊約定使用
cmd_vel
話題來傳遞運動指令。所有需要發送或接收運動指令的節點都可以訂閱或發布到cmd_vel
話題。當遙控器節點發布指令時,移動控制節點只需訂閱cmd_vel
話題,接收到指令后即可控制機器人移動。和消息隊列的概念很相似,這個機制有效的解決了分層解耦和模塊化的問題。
3. ROS框架
3.1 整體架構
根據上述案例,ROS的架構可以簡要概括為:編寫節點(node),節點程序中通過話題(topic)或服務(service)與其他節點進行通信,完成機器人相關的邏輯控制。整體架構圖如下,左側是ROS1,右側是ROS2,兩者的架構類似。
ROS的框架大致分為三層:
- 應用層:即我們編寫的各個節點。
- 中間層:ROS提供API以及內部通信機制,幫助開發者與ROS系統交互。
- 操作系統層:ROS并不是獨立的操作系統,而是依賴于現有操作系統運行。ROS1僅支持Linux,ROS2支持更多操作系統。
圖中其他名詞解釋:
- Master(主節點):負責管理系統中的節點,提供節點注冊、發現和信息轉發等服務。
- Client Library(客戶端庫):提供開發者API,供節點編程、消息傳遞等操作。
- TCPROS/UDPROS(TCP/UDP協議):ROS1中的通信協議,負責節點間數據傳輸。
- Nodelet API(節點內API):允許多個節點在同一進程內運行,避免進程間通信的開銷。
- Abstract DDS Layer(抽象DDS層):ROS2的核心通信機制,基于DDS標準提供分布式通信能力。
- Intra-process API(進程內通信API):用于高效的內部通信,避免跨進程通信的開銷。
- DDS(數據分發服務):ROS2的底層通信協議,負責實現節點間高效可靠的數據交換。
ROS1和2主要區別:
- ROS1依賴Master節點來協調節點間的通信,而ROS2使用DDS協議實現去中心化的分布式通信。
- ROS2引入了進程內通信(Intra-process API),減少了進程間通信的開銷,提高了效率。
- ROS2的DDS通信層使得它更加靈活,可以支持不同的操作系統和硬件平臺。
3.2 通信機制
通信機制是ROS的核心,開發節點的主要目的是數據的流轉和處理。充分利用ROS的通信框架是標準化、簡化以及提升開發靈活性和健壯性的關鍵。
3.2.1 話題
話題通信是ROS中最常用的通信方式,類似于常見的消息隊列。
如下圖,假設有兩個節點,node2訂閱了/topic
話題,它會監聽這個話題是否有新消息。當node1發布消息到/topic
話題時,node2會立即觸發回調函數進行處理。
需要注意:
- 消息的格式由
.msg
文件定義,消息可以是簡單或嵌套的復合結構。 - 發布和訂閱節點是多對多的,多個節點可以同時發布到同一話題,也可以有多個節點同時訂閱一個話題的數據。
例如,在機器人移動的場景中,node1負責發送移動指令(例如通過遙控器接收指令),而node2負責根據指令控制機器人的硬件(如電機)。
這種基于話題的開發方式將功能分層解耦,靈活且可靠,ROS會確保每個節點穩定運行,消息可靠傳遞。
3.2.2 服務
雖然話題的發布/訂閱模型非常靈活,但在需要雙向同步傳輸的場景下,服務(Service)更加合適。服務采用客戶端/服務器模型,包含兩個數據類型:一個用于請求,另一個用于應答,類似于HTTP請求。
如下圖,node2作為服務方提供一個服務,調用地址為/service
。當node1作為客戶端調用該服務時,會向/service
發送請求數據,node2收到請求后進行處理,并將結果返回給node1,完成一次服務調用。
總結:
- 話題適用于異步通信,解耦信息的生產者和消費者,常用于實時更新的數據交換。
- 服務適用于同步通信,采用客戶端/服務器模式,常用于需要強邏輯處理的數據交換。
4. 開發文件結構
在ROS框架下,可以看到我們的主要任務是編寫節點代碼,并通過ROS命令啟動節點,形成完整的系統。ROS支持多種編程語言(C、Python、Java),但代碼必須遵循ROS的組織結構。
ROS文件結構:
- 工作空間(Workspace):頂級目錄(圖中的catkin workspace)為一個工作空間。
- 構建文件:二級目目錄中的
build
、devel
、install
為構建過程生成的文件。 - 功能包(Package):在
工作空間
.src
目錄下,是一系列的功能包,每個功能包可包含多個節點,具體取決于項目需求。
功能包是我們主要面向開發的內容,功能包內部目錄結構:
- config:存放配置文件。
- include:存放頭文件。
- scripts:存放可直接運行的Python腳本。
- src:存放C++源代碼。
- launch:存放啟動文件。
- msg:存放自定義消息類型。
- srv:存放自定義服務類型。
- CMakeLists.txt:編譯規則。
- package.xml:功能包清單。
5. 小結
ROS為機器人開發提供了一個強大的框架,簡化了功能模塊化設計、數據交換和服務通信。通過標準化的消息、話題和服務,ROS幫助開發者高效構建分布式、可擴展的機器人系統,減少了低層次的通信和管理工作,使開發者能夠專注于機器人本身的核心功能。