作為多進程管理系統(tǒng),ROS內節(jié)點node間的數(shù)據(jù)通信交互是必須的功能俗壹,本文將首先簡單介紹ROS的三種節(jié)點間通信機制沽讹,再詳細舉例介紹話題(topic)通信方式般卑。
1. 通信機制
(一)Topic通信
消息通過發(fā)布/訂閱(Publish/Subscribe)方式傳遞,發(fā)布者節(jié)點(Talker)針對一個給定的話題發(fā)布消息爽雄,訂閱者節(jié)點(Listener)訂閱某個話題及其特定數(shù)據(jù)蝠检。話題通信是異步通信,無反饋挚瘟,有緩沖叹谁,弱實時,節(jié)點關系多對多乘盖,適于數(shù)據(jù)傳輸焰檩。
(二)Service通信
基于服務器/客服端(Sercer/Client)模型,可以使用 ROS 提供的服務類型订框,也可以使用 .srv 文件自定義析苫。服務通信是同步通信,有反饋穿扳,無緩沖衩侥,強實時,節(jié)點關系一對多矛物,適于邏輯處理顿乒。
(三)ROS Master通信
統(tǒng)籌管理所有節(jié)點,進行節(jié)點間的查找泽谨、連接等璧榄,為系統(tǒng)提供參數(shù)服務器,管理全局參數(shù)吧雹。節(jié)點管理器也體現(xiàn)了ROS的弊端即ROS Master 如果 broken down骨杂,整個系統(tǒng)將崩潰。
2.?Topic通信詳解
注:案例雄卷、代碼來自胡春旭《ROS機器人開發(fā)實踐》
2.1?創(chuàng)建 Publisher
創(chuàng)建Publisher節(jié)點 talker 通過 talker.cpp文件搓蚪。
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
? ? // ROS節(jié)點初始化
? ? ros::init(argc, argv, "talker");
? ? // 創(chuàng)建節(jié)點句柄
? ? ros::NodeHandle n;
? ? // 創(chuàng)建一個Publisher,發(fā)布名為chatter的topic丁鹉,消息類型為std_msgs::String
? ? ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
? ? // 設置循環(huán)的頻率
? ? ros::Rate loop_rate(10);
? ? int count = 0;
? ? while (ros::ok())
? ? {
? ? ? ? // 初始化std_msgs::String類型的消息
? ? ? ? std_msgs::String msg;
? ? ? ? std::stringstream ss;
? ? ? ? ss << "hello world " << count;
? ? ? ? msg.data = ss.str();
? ? ? ? // 發(fā)布消息
? ? ? ? ROS_INFO("%s", msg.data.c_str());
? ? ? ? chatter_pub.publish(msg);
? ? ? ? // 循環(huán)等待回調函數(shù)
? ? ? ? ros::spinOnce();
? ? ? ? // 按照循環(huán)頻率延時
? ? ? ? loop_rate.sleep();
? ? ? ? ++count;
? ? }
? ? return 0;
}
2.2?創(chuàng)建 Subscriber
創(chuàng)建Subscriber節(jié)點?listener 通過 listener.cpp文件妒潭。
#include "ros/ros.h"
#include "std_msgs/String.h"
// 接收到訂閱的消息后,會進入消息回調函數(shù)
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
? ? // 將接收到的消息打印出來
? ? ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
? ? // 初始化ROS節(jié)點
? ? ros::init(argc, argv, "listener");
? ? // 創(chuàng)建節(jié)點句柄
? ? ros::NodeHandle n;
? ? // 創(chuàng)建一個Subscriber揣钦,訂閱名為chatter的topic雳灾,注冊回調函數(shù)chatterCallback
? ? ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
? ? // 循環(huán)等待回調函數(shù)
? ? ros::spin();
? ? return 0;
}
2.3 修改CMakeLists.txt文件
在CMakeLists.txt文件內添加:
# 參數(shù)1:可執(zhí)行文件名稱,參數(shù)2:源文件 cpp
add_executable(talker src/talker.cpp)
add_executable(listener src/listener.cpp)
# target_link_libraries 用于設置鏈接庫(第三方庫)
target_link_libraries(talker ${catkin_LIBRARIES})
target_link_libraries(listener ${catkin_LIBRARIES})
# add_dependencies 用于設置依賴
add_dependencies(talker ${PROJECT_NAME}_generate_messages_cpp) //necessary for ros message transmission
add_dependencies(listener ${PROJECT_NAME}_generate_messages_cpp)
2.4 通信結果驗證
保存后回到workspace路徑下進行編譯:
catkin_make
打開三個terminal冯凹,順次分別輸入以下命令:
roscore
rosrun <package_name> talker
rosrun <package_name> listener
便可實現(xiàn)節(jié)點talker和listener間的通信谎亩。
3. 自定義topic通信 .msg消息文件
以上示例中通信消息僅為簡單的字符串,在實際使用中我們需要自己定義發(fā)送的信息數(shù)據(jù)文件。
(1)我們需要在package包文件夾下新建msg文件夾匈庭,用來存儲我們自定義的.msg文件夫凸。
例如,<package_name>/msg/Person.msg
string name
uint8? sex
uint8? age
uint8 unknown = 0
uint8 male? ? = 1
uint8 female? = 2
(2).msg 文件編譯設置
為了編譯.msg文件阱持,我們首先需要在package.xml文件中添加包依賴:
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
然后修改CMakeLists.txt文件:
# 在 find_package 中添加 message_generation
find_package(catkin REQUIRED COMPONENTS
? roscpp
? std_msgs
? message_generation
)
# catkin 依賴設置
catkin_package(CATKIN_DEPENDS?
? message_runtime
)
# 設置需要編譯的 msg 文件
add_message_files(FILES
? Person.msg
)
generate_messages()去掉注釋
generate_messages(DEPENDENCIES
? std_msgs
)
在需要用到該消息的cpp文件中包含消息頭文件:
#include <package_name/Person.h>
最后回到workspace路徑下進行編譯即可夭拌。
參考文檔:【ROS 學習筆記】通信機制 - 知乎