dbus通信與接口介紹 2019-07-26

DBUS是一種高級(jí)的進(jìn)程間通信機(jī)制。DBUS支持進(jìn)程間一對(duì)一和多對(duì)多的對(duì)等通信,在多對(duì)多的通訊時(shí),需要后臺(tái)進(jìn)程的角色去分轉(zhuǎn)消息,當(dāng)一個(gè)進(jìn)程發(fā)消息給另外一個(gè)進(jìn)程時(shí),先發(fā)消息到后臺(tái)進(jìn)程,再通過(guò)后臺(tái)進(jìn)程將信息轉(zhuǎn)發(fā)到目的進(jìn)程。DBUS后臺(tái)進(jìn)程充當(dāng)著一個(gè)路由器的角色。

? ? DBUS中主要概念為總線,連接到總線的進(jìn)程可通過(guò)總線接收或傳遞消息,總線收到消息時(shí),根據(jù)不同的消息類(lèi)型進(jìn)行不同的處理。DBUS中消息分為四類(lèi):

? ? 1.? Methodcall消息:將觸發(fā)一個(gè)函數(shù)調(diào)用 ;

? ? 2.? Methodreturn消息:觸發(fā)函數(shù)調(diào)用返回的結(jié)果;

? ? 3.? Error消息:觸發(fā)的函數(shù)調(diào)用返回一個(gè)異常 ;

? ? 4.? Signal消息:通知,可以看作為事件消息。

1.2? DBUS應(yīng)用場(chǎng)景

? ? 根據(jù)DBUS消息類(lèi)型可知,DBUS提供一種高效的進(jìn)程間通信機(jī)制,主要用于進(jìn)程間函數(shù)調(diào)用以及進(jìn)程間信號(hào)廣播。

1 . 函數(shù)調(diào)用

? ? DBUS可以實(shí)現(xiàn)進(jìn)程間函數(shù)調(diào)用,進(jìn)程A發(fā)送函數(shù)調(diào)用的請(qǐng)求(Methodcall消息),經(jīng)過(guò)總線轉(zhuǎn)發(fā)至進(jìn)程B。進(jìn)程B將應(yīng)答函數(shù)返回值(Method return消息)或者錯(cuò)誤消息(Error消息)。

2 . 消息廣播

? ? 進(jìn)程間消息廣播(Signal消息)不需要響應(yīng),接收方需要向總線注冊(cè)感興趣的消息類(lèi)型,當(dāng)總線接收到“Signal消息”類(lèi)型的消息時(shí),會(huì)將消息轉(zhuǎn)發(fā)至希望接收的進(jìn)程。

1.3? DBUS通信特點(diǎn)

? ? DBUS是一種低延遲、低開(kāi)銷(xiāo)、高可用性的進(jìn)程間通信機(jī)制。其協(xié)議是二進(jìn)制的,避免序列化的過(guò)程,通信效率較高。DUBUS可以提供一些更高層的功能:

? ? 1.? 結(jié)構(gòu)化的名字空間;

? ? 2.? 獨(dú)立于架構(gòu)的數(shù)據(jù)格式;

? ? 3.? 支持消息中的大部分通用數(shù)據(jù)元素;

? ? 4.? 帶有異常處理的通用遠(yuǎn)程調(diào)用接口;

? ? 5.? 支持廣播類(lèi)型的通信。

2. 技術(shù)實(shí)現(xiàn)

2.1 實(shí)現(xiàn)原理

? ? DBUS是一種高級(jí)的IPC通信機(jī)制,通信流程如圖 2?1所示。在DBUS通信過(guò)程中,存在一個(gè)后臺(tái)進(jìn)程(BUS Daemon Process)。后臺(tái)進(jìn)程和普通進(jìn)程間信息交互是通過(guò)域套接字進(jìn)行通信。

圖 2-1 DBUS通信原理

? ? 如圖 2?1所示,進(jìn)程1(Process1)需先連接到總線(dbus_bus_get),其次構(gòu)造消息(dbus_message_new_signal),然后發(fā)送消息(dbus_connection_send)到后臺(tái)進(jìn)程。后臺(tái)進(jìn)程接收消息,然后根據(jù)消息類(lèi)型對(duì)消息進(jìn)行不同處理(bus_dispatch_matches)。

? ? 進(jìn)程2(Process2)接收消息前需要連接到總線,并告知總線自己希望得到的消息類(lèi)型(dbus_bus_add_match),然后等待接收消息(dbus_connection_pop_message)。進(jìn)程2(Process2)收到總線轉(zhuǎn)發(fā)的消息時(shí)會(huì)根據(jù)消息類(lèi)型,做不同的處理(若是信號(hào)類(lèi)型則不需要發(fā)送返回值給總線)。

2.2 連接到總線

? ? 進(jìn)程間通信前,需要連接到總線。調(diào)用dbus_bus_get函數(shù)連接進(jìn)程到總線,建立進(jìn)程和總線之間的連接(DBusConnection)。建立連接后,需要為這個(gè)連接注冊(cè)名稱,方便后面對(duì)這個(gè)連接進(jìn)行操作,調(diào)用dbus_bus_request_name函數(shù)對(duì)連接進(jìn)行注冊(cè)名稱。

? ? 建立連接和注冊(cè)名稱是在程序開(kāi)始時(shí)執(zhí)行,程序結(jié)束時(shí),調(diào)用dbus_connection_close函數(shù)關(guān)閉一個(gè)連接。函數(shù)接口聲明如程序清單 2?1所示。

程序清單 2-1 建立、注冊(cè)名稱和關(guān)閉連接

[plain] view plain copy

DBusConnection? *dbus_bus_get? (DBusBusType? type,? DBusError? *error)? ? ? ? ? ? /*? 建立和總線的連接? */?


int? dbus_bus_request_name? (DBusConnection? *connection,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? ? ? *name,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned int? ? ? ? flags,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusError? ? ? ? *error)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 注冊(cè)連接名稱? ? ? */?


void? dbus_connection_close? (DBusConnection? *connection)? ? ? ? ? ? ? ? ? ? ? ? ? /*? 關(guān)閉連接? ? ? ? ? */?

2.3 信號(hào)發(fā)送與接收

2.3.1 信號(hào)發(fā)送

? ? DBUS中信號(hào)是一種廣播的消息,當(dāng)發(fā)出一個(gè)信號(hào),所有連接到 DBUS 總線上并注冊(cè)了接受對(duì)應(yīng)信號(hào)的進(jìn)程,都會(huì)收到該信號(hào)。

? ? 進(jìn)程發(fā)出一個(gè)信號(hào)前,需要?jiǎng)?chuàng)建一個(gè) DBusMessage 對(duì)象來(lái)代表信號(hào),然后追加上一些需要發(fā)出的參數(shù),就可以發(fā)向總線了。發(fā)完之后需要釋放消息對(duì)象。信號(hào)發(fā)送的函數(shù)聲明如程序清單 2?2所示。

程序清單2-2? 信號(hào)發(fā)送接口

[cpp] view plain copy

DBusMessage? *dbus_message_new_signal? (const? char? *path,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const? char? *iface,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const? char? *name)? ? ? ? ? ? ? ? ? ? ? /*? 創(chuàng)建信號(hào)類(lèi)型消息? ? ? */?


void? dbus_message_iter_init_append? ( DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessageIter? *iter)? ? ? ? ? ? ? ? /*? 加入?yún)?shù)到信號(hào)? ? ? ? */?


dbus_bool_t? dbus_connection_send? ( DBusConnection? *connection,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dbus_uint32_t? ? *serial)? ? ? ? ? ? ? ? ? ? ? /*? 發(fā)送信號(hào)到總線? ? ? ? */?


void? dbus_message_unref? (DBusMessage *message)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 釋放消息? ? ? ? ? ? ? */?

2.3.2 信號(hào)接收

? ? 進(jìn)程接收信號(hào)時(shí),需先告知總線進(jìn)程感興趣的消息,然后等待接收消息。信號(hào)接收函數(shù)聲明如程序清單 2?3所示。

程序清單 2-3 信號(hào)接收接口

[cpp] view plain copy

void? dbus_bus_add_match? ( DBusConnection? *connection,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? ? ? *rule,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusError? ? ? *error)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 告知總線感興趣的消息? */?


DBusMessage? *dbus_connection_pop_message? ( DBusConnection? *connection)? ? ? ? /*? 接收消息? ? ? ? ? ? ? */?


dbus_bool_t? dbus_message_is_signal? (DBusMessage? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? ? *iface,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? *signal_name)? ? ? ? ? ? ? ? ? ? /*? 判斷消息是否為信號(hào)? ? */?

2.4 函數(shù)調(diào)用和提供函數(shù)調(diào)用

2.4.1 函數(shù)調(diào)用

? ? 調(diào)用一個(gè)遠(yuǎn)程函數(shù)與發(fā)送一個(gè)信號(hào)原理類(lèi)似,需要先創(chuàng)建一個(gè)消息(DBusMessage),然后通過(guò)注冊(cè)在 DBUS上的名稱指定發(fā)送的對(duì)象。然后追加相應(yīng)的參數(shù),調(diào)用方法分為兩種,一種是阻塞式的,另一種為異步調(diào)用。異步調(diào)用的時(shí)候會(huì)得到一個(gè)“DBusMessage *” 類(lèi)型的返回消息,從這個(gè)返回消息中可以獲取一些返回的參數(shù)。

? ? 函數(shù)調(diào)用的函數(shù)聲明如程序清單 2?4所示。

程序清單 2-4 函數(shù)調(diào)用接口

[cpp] view plain copy

DBusMessage? *dbus_message_new_method_call? (const char? *destination,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? *path,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? *iface,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? *method)? ? ? ? ? ? ? ? ? ? /*? 創(chuàng)建一個(gè)函數(shù)調(diào)用消息? ? */?


void? dbus_message_iter_init_append? (DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessageIter? *iter)? ? ? ? ? ? ? ? ? ? /*? 為消息添加參數(shù)? ? ? ? ? */?


dbus_bool_t? dbus_connection_send_with_reply? (DBusConnection? *connection,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessage? ? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusPendingCall? **pending_return,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int? ? ? ? ? ? timeout_milliseconds)? ? ? /*? 發(fā)送消息? ? ? ? ? ? ? ? */?


void? dbus_pending_call_block? (DBusPendingCall? *pending)? ? ? ? ? ? ? ? ? ? ? ? ? /*? 阻塞等待返回值? ? ? ? ? */?


DBusMessage? *dbus_pending_call_steal_reply? (DBusPendingCall? *pending)? ? ? ? ? ? /*? 獲得返回消息? ? ? ? ? ? */?


dbus_bool_t? dbus_message_iter_init? (DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessageIter? *iter)? ? ? ? ? ? ? ? ? ? /*? 獲取參數(shù)? ? ? ? ? ? ? ? */?

2.4.2 接收函數(shù)調(diào)用

? ? 提供遠(yuǎn)程函數(shù)調(diào)用,首先需告知總線進(jìn)程感興趣的消息,其次從總線獲取消息并判定消息是方法調(diào)用。然后從消息中獲取參數(shù)進(jìn)行函數(shù)執(zhí)行,最后創(chuàng)建返回消息,并發(fā)送消息至總線,由總線轉(zhuǎn)發(fā)至調(diào)用的進(jìn)程。函數(shù)聲明如程序清單 2?5所示。

程序清單 2-5 接收函數(shù)調(diào)用接口

[cpp] view plain copy

void? dbus_bus_add_match? ( DBusConnection? *connection,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? ? ? *rule,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusError? ? ? *error)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*? 請(qǐng)求獲取調(diào)用消息? ? ? */?


DBusMessage? *dbus_connection_pop_message? ( DBusConnection? *connection)? ? ? ? ? /*? 從總線獲取消息? ? ? ? */?


dbus_bool_t? dbus_message_is_method_call (DBusMessage? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? *iface,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? const char? ? *method)? ? ? ? ? ? ? ? ? ? ? /*? 判定消息是方法調(diào)用? ? */?


dbus_bool_t? dbus_message_iter_init? (DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessageIter? *iter)? ? ? ? ? ? ? ? ? ? /*? 獲取參數(shù)? ? ? ? ? ? ? */?


DBusMessage? *dbus_message_new_method_return? (DBusMessage *method_call)? ? ? ? ? ? /*? 創(chuàng)建返回消息? ? ? ? ? */?


void? dbus_message_iter_init_append? ( DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessageIter? *iter)? ? ? ? ? ? ? ? ? /*? 在消息中填入?yún)?shù)? ? ? */?


dbus_bool_t? dbus_connection_send? ( DBusConnection? *connection,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DBusMessage? ? *message,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dbus_uint32_t? ? *serial)? ? ? ? ? ? ? ? ? ? ? ? /*? 發(fā)送返回消息? ? ? ? ? */?

3. 小結(jié)

? ? DBUS是一種高效、易用的進(jìn)程間通信方式。本文檔介紹了DBUS的通信原理,以信號(hào)收發(fā)和方法調(diào)用為框架,介紹了DBUS中常用的函數(shù)接口。

DBus分為兩種類(lèi)型:system bus(系統(tǒng)總線),用于系統(tǒng)(Linux)和用戶程序之間進(jìn)行通信和消息的傳遞;session bus(回話總線),用于桌面(GNOME, KDE等)用戶程序之間進(jìn)行通信。?

上節(jié)補(bǔ)存:

Name: 圖模型中的Name 在ROS的封裝體系中非常重要,所有的resource(從node到topic到service和 parameter等)都是在某個(gè)namespace中用特定的Name進(jìn)行了定義。 一般來(lái)說(shuō),resource 可以在自己的namespace中創(chuàng) 建新的resource,訪問(wèn)和使用已有的resource。鏈接可以建立在不同的資源之間,namespace保證了不同resource間的Name 不會(huì)沖突,也封裝了resource內(nèi)部。

(可以參考C++中namespace的概念。因?yàn)镽OS分布式系統(tǒng)的設(shè)計(jì)思路,對(duì)與不同主機(jī)上,不同功能區(qū)塊,都可以用namespace對(duì)其中 的resource name 包括 topic name 等 進(jìn)行保護(hù),使得name管理更加結(jié)構(gòu)化,更多體現(xiàn)在對(duì)于代碼重用性的提高)

Computation graph: Computation graph是一個(gè)p2p的網(wǎng)絡(luò)結(jié)構(gòu)。Node之間的鏈接關(guān)系的拓?fù)浣Y(jié)構(gòu)為 mesh(網(wǎng)狀)

Node:node是一個(gè)處理計(jì)算的進(jìn)程。(操作系統(tǒng)中的一個(gè)進(jìn)程,因?yàn)橐加枚丝谔?hào)進(jìn)行通訊,多機(jī)分布式系統(tǒng)中還要標(biāo)明ip,詳見(jiàn)后面的 uri)Node在graph中使用topic service和parameter相互通訊,協(xié)調(diào)工作。在不同的系統(tǒng)設(shè)計(jì)中,node承載的功能粒度也 不一樣。比如大部分的設(shè)備驅(qū)動(dòng)都是單獨(dú)占用一個(gè)node,為了提高代碼復(fù)用率經(jīng)常會(huì)有細(xì)粒度的劃分,而在很多視覺(jué)處理的系統(tǒng)避免使用多節(jié)點(diǎn)結(jié)構(gòu),傳遞圖像 數(shù)據(jù)會(huì)造成系統(tǒng)資源浪費(fèi)(nodelet的應(yīng)用)。Node的使用極大的增加了系統(tǒng)模塊化和代碼封裝的程度,也給系統(tǒng)帶來(lái)了一些錯(cuò)誤容忍的能力。

Master node: master node 給ros系統(tǒng)中其他節(jié)點(diǎn)提供命名與注冊(cè)的服務(wù)。它跟蹤節(jié)點(diǎn)中的publisher與 subscriber,service 的server與client,記錄其他節(jié)點(diǎn)的位置(uri標(biāo)明,host與port),并將這些信息通知給需要 建立鏈接的節(jié)點(diǎn)。(從分布式系統(tǒng)的角度分析,ros這樣p2p網(wǎng)絡(luò)中集中式管理peer信息,也為仿真環(huán)境提供虛擬時(shí)鐘 /clock 重要:ROS多機(jī)系統(tǒng)中,ros的全局時(shí)鐘僅是本機(jī)的系統(tǒng)時(shí)鐘,多機(jī)需要同步系統(tǒng)時(shí)間的工具來(lái)實(shí)現(xiàn)ros內(nèi)時(shí)鐘同步,一般是ntp,pr2應(yīng)用 linux中的chrony進(jìn)行基于ntp的系統(tǒng)時(shí)間同步)

Message: node之間通訊規(guī)定的統(tǒng)一數(shù)據(jù)格式,ros內(nèi)部有數(shù)據(jù)格式規(guī)定語(yǔ)言來(lái)定義,然后由相應(yīng)語(yǔ)言的client library中的message_generation 組件生成目標(biāo)代碼。提供統(tǒng)一的串行化/解串行化 方法。

Topic:ros中廣為使用的是異步的 publish-subscribe 通訊模式。這種方式將信息的產(chǎn)生和使用雙方解耦。一般來(lái)說(shuō),節(jié)點(diǎn)沒(méi) 有通訊對(duì)方那邊的信息。Node從需要的topic那取得消息,topic 可以有多個(gè) subscriber 與publisher。Topic 一般 用于單向,消息流通訊。Node 需要同步通訊交換信息時(shí)一般使用service。Topic 一般擁有很強(qiáng)的類(lèi)型定義:一種類(lèi)型的topic只能接受/ 發(fā)送特定數(shù)據(jù)類(lèi)型(message type)的message。Publisher 沒(méi)有被要求類(lèi)型一致性,但是接受時(shí)subscriber會(huì)檢查類(lèi)型 的md5,進(jìn)而報(bào)錯(cuò)。

Service: service 用于處理ros通訊中的同步通訊,采用server/client 語(yǔ)義。每個(gè)service type擁 有 request 與 response兩部分,對(duì)于service中的 server,ros不會(huì)檢查重名(name conflict),只有最后 注冊(cè)的server會(huì)生效,與client建立連接。

Parameter: parameter 可以看作為ros系統(tǒng)運(yùn)行時(shí)中定義的全局變量,而master node 中有 parameter server 來(lái)維護(hù)這些變量。而namespace的存在使得parameter 擁有了非常清晰的層次劃分,避免了重名,而且使 得parameter訪問(wèn)可以單獨(dú)訪問(wèn)也可以樹(shù)狀訪問(wèn)(層層解析namespace)

URI:定位node在分布式系統(tǒng)中的位置,格式為: protocol://host:port,protocol一般為http或者 rosrpc, host為 hostname 或者 ip 地址,port則為端口號(hào)。

TCPROS:基于tcp協(xié)議的ros應(yīng)用層數(shù)據(jù)協(xié)議,用于解析topic 與 service的二進(jìn)制數(shù)據(jù)流。

遠(yuǎn)程過(guò)程調(diào)用(RPC)

ROS 通訊中,節(jié)點(diǎn)通過(guò)遠(yuǎn)程過(guò)程調(diào)用來(lái)實(shí)現(xiàn)建立連接,傳輸數(shù)據(jù)。ROS 中遠(yuǎn)程過(guò)程調(diào)用采用XML-RPC 實(shí)現(xiàn)。遠(yuǎn)程調(diào)用負(fù)責(zé)管理節(jié)點(diǎn)對(duì)計(jì)算圖 中信息的獲取與更改,還有一些全局的設(shè)置。RPC不直接支持?jǐn)?shù)據(jù)的流傳輸(通過(guò)TCPROS與 UDPROS支持)。XML-RPC 優(yōu)勢(shì)在于支持它的語(yǔ) 言類(lèi)型很多,而XML本身的文本屬性導(dǎo)致方便人調(diào)試。XML-RPC被封裝在http協(xié)議中傳輸,XML-RPC 調(diào)用時(shí)無(wú)狀態(tài)的 (stateless),沒(méi)有狀態(tài)信息需要追蹤,簡(jiǎn)化了控制邏輯。

1》數(shù)據(jù)類(lèi)型:

在XML-RPC中,方法參數(shù)和其返回值被封裝在value 的實(shí)體中,value有以下幾種固定的類(lèi)型可以選擇。(xml中體現(xiàn)為value的子標(biāo)簽)

string 為ascii 碼的字符串,為value的默認(rèn)格式。不合法的字符只有& 和 <,s & <;表示。

int 或者 i4 是32位的有符號(hào)整型,十進(jìn)制表示中,前綴-號(hào)則為負(fù)數(shù)。

boolean 只有兩種取值,0和1,用于表示布爾類(lèi)型。

double? 實(shí)數(shù)類(lèi)型,前綴-號(hào)表示負(fù)數(shù)。

dataTime.iso8601 日期時(shí)間,用iso-8601格式表示。

base64 用 base64算法編碼的二進(jìn)制字符串。

array values組成的表,在data實(shí)體下一層

Struct 又稱為map 表示關(guān)系的集合,每一個(gè)struct實(shí)體是由一個(gè) name 與 value的鍵值對(duì)組成。

2》 請(qǐng)求與應(yīng)答:

遠(yuǎn)程過(guò)程調(diào)用由兩個(gè)階段組成:請(qǐng)求(request) 與 應(yīng)答(response)。 一個(gè)調(diào)用者將方法調(diào)用請(qǐng)求發(fā)給 被調(diào)用者,然后被調(diào)用者返回調(diào)用是否成功與相應(yīng)返回值。

連接模式:

下面將簡(jiǎn)述節(jié)點(diǎn)與其他節(jié)點(diǎn)如何進(jìn)行連接,最后初始化一個(gè)topic data的流傳輸,service 的實(shí)現(xiàn)有些許不同。

在之前對(duì)于節(jié)點(diǎn)與計(jì)算圖的介紹中,節(jié)點(diǎn)在master node處注冊(cè) 自己在publish /subscribe topic。通過(guò) registerPublisher()和 registerSubscriber() 。節(jié)點(diǎn)在master處注冊(cè)完自己的 subscribe/publish topic后,master都會(huì)返回一個(gè)成功的應(yīng)答,其中包含所有publisher節(jié)點(diǎn)的URI,然 后 subscriber去與相應(yīng)的publisher建立連接傳輸 topic 相關(guān)信息(topic name,樹(shù)蕨類(lèi)型,傳輸類(lèi)型等)。有任何新的 節(jié)點(diǎn)去publisher 一個(gè)topic并且在master處已經(jīng)完成自己的注冊(cè)時(shí),master會(huì)給所有subscribe 這個(gè)topic的節(jié)點(diǎn)發(fā) 出一個(gè)publisherUpdate() 請(qǐng)求,里面包含所有可用的 publisher的URI,topic 消息的數(shù)據(jù)由TCPROS協(xié)議傳輸。

簡(jiǎn)單來(lái)說(shuō)就是各個(gè)節(jié)點(diǎn)在 master處注冊(cè)信息,master發(fā)現(xiàn)有節(jié)點(diǎn)subscribe/publish相同的topic時(shí),將 publisher的 信息通過(guò) RPC 分發(fā)給各個(gè)subscriber,subscriber與publisher建立第一次連接,傳輸topic信 息,然后再根據(jù)publisher返回的topic 信息,建立第二次連接,publisher開(kāi)始 傳輸具體的數(shù)據(jù)。

service

而對(duì)稱的過(guò)程是 注銷(xiāo)(unregisteration), publisher 通過(guò)遠(yuǎn)程調(diào)用unregisterPublisher(), 然 后subscriber通過(guò)unregisterSubscriber()注銷(xiāo),然而,是否關(guān)閉publisher與 subscriber間的數(shù)據(jù)流傳 輸取決于節(jié)點(diǎn)本身。

Service的工作原理與topic有些許不同,同一個(gè)service能被多個(gè)節(jié)點(diǎn)注冊(cè),但是只有最后一個(gè)能被其他節(jié)點(diǎn)接受。一個(gè)節(jié)點(diǎn)調(diào)用 service時(shí),通過(guò)lookupService() 遠(yuǎn)程調(diào)用在master處查找相應(yīng)service的URI。然后它將通過(guò)一個(gè)request 消 息調(diào)用service的提供者,如果成功了,service提供者將返回一個(gè)相應(yīng)的response 消息,失敗了返回相應(yīng)錯(cuò)誤消息,(所有的消息傳輸默 認(rèn)都是通過(guò) TCPROS協(xié)議。)

subscribe_publisher

數(shù)據(jù)流

XML-RPC為我們提供了方便整潔的遠(yuǎn)程調(diào)用協(xié)議,但是它的冗長(zhǎng)與以文本為中心的編碼格式使得它不適合高帶寬,低延遲的數(shù)據(jù)傳輸任務(wù)。ROS定義 了自己的二進(jìn)制數(shù)據(jù)流傳輸協(xié)議,減少了冗余的協(xié)議增加從而增加帶寬,協(xié)議設(shè)計(jì)使得數(shù)據(jù)幾乎不需要解析(相對(duì)于rpc),從而減少延遲。詳細(xì)的TCPROS 協(xié)議內(nèi)容可以在 wiki.ros.org/ROS/TCPROS 找到。

(現(xiàn)在ROS中也有實(shí)現(xiàn)的UDPROS協(xié)議,可以通過(guò)TransportHints 數(shù)據(jù)結(jié)構(gòu)指定下層傳輸協(xié)議,甚至通過(guò)繼承Trasport 類(lèi) 自己實(shí)現(xiàn)本機(jī)的進(jìn)程間通訊方法)。

下面撿一些TCPROS中的重點(diǎn)說(shuō)一下:

Md5:TCPROS為了保證兩邊傳輸數(shù)據(jù)類(lèi)型一致,會(huì)在協(xié)議頭中給出topic name 的md5 hash算法處理過(guò)的值,而每次你生成新的msg 時(shí),md5的值都會(huì)因?yàn)槟銉?nèi)部數(shù)據(jù)類(lèi)型的變動(dòng)而改變,這樣就避免了新msg與 舊msg 傳輸類(lèi)型不一致的問(wèn)題。

Subscriber 選項(xiàng)tcp_nodelay :如果是“1” 則給socket 設(shè)置 TCP_NODELAY 選項(xiàng),降低延遲,可能會(huì)降低傳輸效率。

Service client 選項(xiàng):persistent 設(shè)置為1,則service的鏈接會(huì)一直開(kāi)放給多個(gè) service request

(下面是一些理解:

TCPROS的協(xié)議頭占的字節(jié)數(shù)比較固定,所以傳輸一幀中只傳輸有效位幾個(gè)字節(jié)是非常不劃算的,很多情況下可以附上 std_msgs/header ,seq可以檢測(cè)丟包,stamp可以檢測(cè)消息實(shí)時(shí)性,frame_id很多情況下必備。

Roscpp 對(duì) 數(shù)據(jù)流的控制api比rospy要豐富很多,比如roscpp中有對(duì)callback queue的操作,多線程回調(diào)函數(shù)的支持等,對(duì)數(shù)據(jù)傳輸要求比較高的節(jié)點(diǎn)還是老老實(shí)實(shí)用cpp吧

在一些對(duì)延遲要求比較高而又有一些無(wú)線通訊等高延遲傳輸介質(zhì)存在的應(yīng)用中,可以考慮用低延遲的方式互聯(lián),比如xbee模塊代替wifi(自己寫(xiě)一些與其他節(jié)點(diǎn)的bridge),或者udpros代替tcpros,并且避免tcpros的協(xié)議頭占用過(guò)多帶寬)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容