研究ROS通信機制
研究ROS通信機制
- 0.前言
- 1.話題通信
- 1.1 理論模型
- 1.2 話題通訊的基本操作
- 1.2.1 C++
- 1.2.2 Python中使用自己的虛擬環境包
- 1.2.2.1 參考1
- 1.2.2.2 參考2
- 1.2.2.3 /usr/bin/env:“python”:沒有那個文件或目錄
- 1.2.3 Python
- 1.2.2.1 發布方
- 1.2.2.2 訂閱方
- 1.2.2.3 添加可執行權限
- 1.2.2.4 配置CMakeLists.txt
- 1.2.2.5 執行
- 1.2.2.6 訂閱者少數據
- 1.3 話題通信自定義msg
- 1.3.1 創建自定義信息
- 1.3.2 自定義msg,C++調用
- 1.3.2.1 vscode配置
- 1.3.2.2 發布方
- 1.3.2.3 訂閱方
- 1.3.2.4 配置cmakeList.txt
- 1.3.2.5 執行
- 1.3.3 自定義msg,Python調用
- 1.3.3.1 vscode配置
- 1.3.3.2 發布方
- 1.3.3.3 訂閱方
- 1.3.3.4 權限設置
- 1.3.3.5 配置 CMakeLists.txt
- 1.3.3.6 執行
0.前言
機器人是一種高度復雜的系統性實現,在機器人上可能集成各種傳感器(雷達、攝像頭、GPS…)以及運動控制實現,為了解耦合,在ROS中每一個功能點都是一個單獨的進程,每一個進程都是獨立運行的。更確切的講,ROS是進程(也稱為Nodes)的分布式框架。 因為這些進程甚至還可分布于不同主機,不同主機協同工作,從而分散計算壓力。不過隨之也有一個問題: 不同的進程是如何通信的?也即不同進程間如何實現數據交換的?在此我們就需要介紹一下ROS中的通信機制了。
ROS 中的基本通信機制主要有如下三種實現策略:
話題通信(發布訂閱模式)
服務通信(請求響應模式)
參數服務器(參數共享模式)—相當于共享內存?共享數據池?
1.話題通信
話題通信是ROS中使用頻率最高的一種通信模式,話題通信是基于發布訂閱模式的,也即:一個節點發布消息,另一個節點訂閱該消息。話題通信的應用場景也極其廣泛,比如下面一個常見場景:
機器人在執行導航功能,使用的傳感器是激光雷達,機器人會采集激光雷達感知到的信息并計算,然后生成運動控制信息驅動機器人底盤運動。
在上述場景中,就不止一次使用到了話題通信。
以激光雷達信息的采集處理為例,在 ROS 中有一個節點需要時時的發布當前雷達采集到的數據,導航模塊中也有節點會訂閱并解析雷達數據。
再以運動消息的發布為例,導航模塊會根據傳感器采集的數據時時的計算出運動控制信息并發布給底盤,底盤也可以有一個節點訂閱運動信息并最終轉換成控制電機的脈沖信號。
以此類推,像雷達、攝像頭、GPS… 等等一些傳感器數據的采集,也都是使用了話題通信,換言之,話題通信適用于不斷更新的數據傳輸相關的應用場景。
概念:以發布訂閱的方式實現不同節點之間數據交互的通信模式。
作用:用于不斷更新的、少邏輯處理的數據傳輸場景。
另可參考:
http://wiki.ros.org/ROS/Tutorials/CreatingMsgAndSrv
http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29
http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29
疑惑:話題通信,有實時性問題嗎?實時性如何保證的?
1.1 理論模型
話題通信實現模型是比較復雜的,該模型如下圖所示,該模型中涉及到三個角色:ROS Master (管理者)、Talker (發布者)、Listener (訂閱者)
ROS Master 負責保管 Talker 和 Listener 注冊的信息,并匹配話題相同的 Talker 與 Listener,幫助 Talker 與 Listener 建立連接,連接建立后,Talker 可以發布消息,且發布的消息會被 Listener 訂閱。
需要說明的是:
使用的協議由RPC和TCP
talker和listener都可以存在多個
talker和listener建立連接后,master就可以關閉了
整個流程由以下步驟實現:
0.Talker注冊
Talker啟動后,會通過RPC在 ROS Master 中注冊自身信息,其中包含所發布消息的話題名稱。ROS Master 會將節點的注冊信息加入到注冊表中。
1.Listener注冊
Listener啟動后,也會通過RPC在 ROS Master 中注冊自身信息,包含需要訂閱消息的話題名。ROS Master 會將節點的注冊信息加入到注冊表中。
2.ROS Master實現信息匹配
ROS Master 會根據注冊表中的信息匹配Talker 和 Listener,并通過 RPC 向 Listener 發送 Talker 的 RPC 地址信息。
3.Listener向Talker發送請求
Listener 根據接收到的 RPC 地址,通過 RPC 向 Talker 發送連接請求,傳輸訂閱的話題名稱、消息類型以及通信協議(TCP/UDP)。
4.Talker確認請求
Talker 接收到 Listener 的請求后,也是通過 RPC 向 Listener 確認連接信息,并發送自身的 TCP 地址信息。
5.Listener與Talker件里連接
Listener 根據步驟4 返回的消息使用 TCP 與 Talker 建立網絡連接。
6.Talker向Listener發送消息
連接建立后,Talker 開始向 Listener 發布消息。
注意1:上述實現流程中,前五步使用的 RPC協議,最后兩步使用的是 TCP 協議
注意2: Talker 與 Listener 的啟動無先后順序要求
注意3: Talker 與 Listener 都可以有多個
注意4: Talker 與 Listener 連接建立后,不再需要 ROS Master。也即,即便關閉ROS Master,Talker 與 Listern 照常通信。
1.2 話題通訊的基本操作
編寫發布訂閱實現,要求發布方以10HZ(每秒10次)的頻率發布文本消息,訂閱方訂閱消息并將消息內容打印輸出。
在模型實現中,ROS master 不需要實現,而連接的建立也已經被封裝了,需要關注的關鍵點有三個:發布方、接收方、數據(此處為普通文本)
流程:
編寫發布方實現;
編寫訂閱方實現;
編輯配置文件;
編譯并執行。
1.2.1 C++
- 發布方
/*需求: 實現基本的話題通信,一方發布數據,一方接收數據,實現的關鍵點:1.發送方2.接收方3.數據(此處為普通文本)PS: 二者需要設置相同的話題消息發布方:循環發布信息:HelloWorld 后綴數字編號實現流程:1.包含頭文件 2.初始化 ROS 節點:命名(唯一)3.實例化 ROS 句柄4.實例化 發布者 對象5.組織被發布的數據,并編寫邏輯發布數據
*/
// 1.包含頭文件
#include "ros/ros.h"
#include "std_msgs/String.h" //普通文本類型的消息
#include <sstream>int main(int argc, char *argv[])
{ //設置編碼setlocale(LC_ALL,"");//2.初始化 ROS 節點:命名(唯一)// 參數1和參數2 后期為節點傳值會使用// 參數3 是節點名稱,是一個標識符,需要保證運行后,在 ROS 網絡拓撲中唯一ros::init(argc,argv,"talker");//3.實例化 ROS 句柄ros::NodeHandle nh;//該類封裝了 ROS 中的一些常用功能//4.實例化 發布者 對象//泛型: 發布的消息類型//參數1: 要發布到的話題//參數2: 隊列中最大保存的消息數,超出此閥值時,先進的先銷毀(時間早的先銷毀)ros::Publisher pub = nh.advertise<std_msgs::String>("chatter",10);//5.組織被發布的數據,并編寫邏輯發布數據//數據(動態組織)std_msgs::String msg;// msg.data = "你好啊!!!";std::string msg_front = "Hello 你好!"; //消息前綴int count = 0; //消息計數器//邏輯(一秒10次)ros::Rate r(1);//節點不死while (ros::ok()){//使用 stringstream 拼接字符串與編號std::stringstream ss;ss << msg_front << count;msg.data = ss.str();//發布消息pub.publish(msg);//加入調試,打印發送的消息ROS_INFO("發送的消息:%s",msg.data.c_str());//根據前面制定的發送貧頻率自動休眠 休眠時間 = 1/頻率;r.sleep();count++;//循環結束前,讓 count 自增//暫無應用ros