[ROS学习笔记1]ROS的通讯:订阅、服务与动作
本文基于Ubuntu18.04 + ROS1:melodic
ROS各节点间通讯主要有三个机制:订阅、服务、动作。本文将逐一介绍其特点和使用案例。
订阅【Topic】
订阅模式就类似于杂志的订阅。发布者ROS::Publisher(出版商)向节点网络内发布advertise一个话题名(期刊名)为"exp_topic"的消息(论文),订阅者ROS::Subscriber(用户)订阅subscribe该话题(期刊)即可获取该消息(论文)。
因此,订阅模式需要实现三/两个部分,即发布者ROS::Publisher、订阅者ROS::Subscriber和消息类型msg(论文格式),其中也可以使用已有的消息类型
- [msg]:
$packege_name/msg/Paper.msgstring title string author - [ROS::Publisher]:
$packege_name/src/IEEE.cpp/** *发布IEEE_Access话题,消息类型为Paper */ #include <sstream> #include "ros/ros.h" // 这个头文件在catkin编译自定义msg的时候产生,将产生同名对象 #include "learning_communication/IEEE_Access.h" int main(int argc,char **argv) { //ros节点初始化,固定格式,最后一个参数"IEEE"为节点名称 ros::init(argc,argv,"IEEE"); // 声明一个节点n ros::NodeHandle n; //构造发布者IEEE_pub,话题名为IEEE_Access ros::Publisher IEEE_pub=n.advertise<learning_communication::IEEE_Access>("IEEE_Access",1000); // 设置循环发布时间 ros::Rate loop_rate(10); int count = 0; while (ros::ok()) { learning_communication::IEEE_Access paper; std::stringstream ss; ss<<"A Reserch on ROS Commuinication"<<count; paper.title="A Reserch on ROS Commuinication"; ss<<"A Reserch on ROS Commuinication"<<count; paper.author="yexiaowo"; // 这里%s对应的参数应该为char*,显然paper.title、paper.author均不是。c_str()方法返回一个指向以空字符结尾的char* ROS_INFO("title:%s;author:%s;index:%d",paper.title.c_str(),paper.author.c_str(),count); IEEE_pub.publish(paper); // 等待回调函数 ros::spinOnce(); loop_rate.sleep(); ++count; } return 0; } - [ROS::Subscriber]:
$packege_name/src/student.cpp/** * 该例程将订阅IEEE_Access话题,消息类型paper */ #include "ros/ros.h" #include "learning_communication/IEEE_Access.h" // 接收到订阅的消息后,会进入消息回调函数 void chatterCallback(const learning_communication::IEEE_Access::ConstPtr& paper) { // 将接收到的论文打印出来 ROS_INFO("I received: [%s]", paper->title.c_str()); } int main(int argc, char **argv) { ros::init(argc, argv, "student"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("IEEE_Access", 1000, chatterCallback); ros::spin(); return 0; } - 配置功能包
$packege_name/packege.xml<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend> - 添加编译选项
$packege_name/CMakeLists.txt#编译自定义消息msg find_package( ...... message_generation) catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime) add_message_files(FILES IEEE_Access.msg) generate_messages(DEPENDENCIES std_msgs) #编译cpp add_executable(IEEE src/IEEE.cpp) target_link_libraries(IEEE ${catkin_LIBRARIES}) add_executable(student src/student.cpp) target_link_libraries(student ${catkin_LIBRARIES}) - 运行
- terminal-1
roscore - terminal-2
source devel/setup.bash rosrun learning_communication IEEE - terminal-3
source devel/setup.bash rosrun learning_communication student
- terminal-1
服务【Service】
服务模式的通讯方式为由客户端ros::ServiceClient发起请求request,服务器ros::ServiceServer收到请求后响应,再由客户端接收应答response。
因此,需要定义请求应答消息格式srv、服务器和客户端。
- [msg]:
$packege_name/srv/AddTwoInts.srvint64 a int64 b --- int64 sum - [ros::ServiceServer]:
$packege_name/src/server.cpp#include "ros/ros.h" #include"learning_communication/AddTwoInts.h" bool add(learning_communication::AddTwoInts::Request &req,learning_communication::AddTwoInts::Response &res) { res.sum=req.a+req.b; ROS_INFO("request:x=%ld,y=%ld",(long int)req.a,(long int)req.b); ROS_INFO("sending back response:[%ld]",(long int)res.sum); return true; } int main(int argc,char **argv) { ros:: init(argc,argv,"add_two_ints_server"); ros::NodeHandle n; //注册服务,绑定add方法 ros::ServiceServer service = n.advertiseService("add_two_ints",add); ROS_INFO("ready to add two ints"); ros::spin(); return 0; } - [ros::ServiceClient]:
$packege_name/src/client.cpp#include<cstdlib> #include"ros/ros.h" #include"learning_communication/AddTwoInts.h" int main(int argc,char **argv) { ros::init(argc,argv,"add_two_ints_client"); if(argc!=3) { ROS_INFO("usage:add_two_ints_client X Y"); return 1; } ros::NodeHandle n; ros::ServiceClient client = n.serviceClient<learning_communication::AddTwoInts>("add_two_ints"); learning_communication::AddTwoInts srv; //atoll即为array[] to long long,例如atoll("sgk14 679")返回(long long)14 srv.request.a=atoll(argv[1]); srv.request.b=atoll(argv[2]); if (client.call(srv)) { ROS_INFO("Sum: %ld", (long int)srv.response.sum); } else { ROS_ERROR("Failed to call service add_two_ints"); return 1; } return 0; } - 配置功能包
$packege_name/packege.xml<build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend> - 添加编译选项
$packege_name/CMakeLists.txt#编译自定义消息srv find_package( ...... message_generation) catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime) add_service_files(FILES AddTwoInts.srv) #编译cpp add_executable(server src/server.cpp) target_link_libraries(server ${catkin_LIBRARIES}) add_dependencies(server ${PROJECT_NAME}_gencpp) add_executable(client src/client.cpp) target_link_libraries(client ${catkin_LIBRARIES}) add_dependencies(client ${PROJECT_NAME}_gencpp) - 运行
- terminal-1
roscore - terminal-2
source devel/setup.bash rosrun learning_communication server - terminal-3
source devel/setup.bash rosrun learning_communication client 123 222
- terminal-1
动作【Action】
动作模式的通讯方式为动作客户端actionlib::SimpleActionClient<$action>发步任务目标goal,动作服务器actionlib::SimpleActionServer<$action>向动作客户端通知当前状态status、周期反馈任务运行监控状态feedback、并在最后发布任务结果result。其中,动作客户端还可以提前发布取消任务的请求。cancel。
因此,需要定义动作消息格式action、服务器actionlib::SimpleActionServer<$action>和客户端actionlib::SimpleActionClient<$action>。
- [msg]:
$packege_name/srv/AddTwoInts.srv#goal uint32 singer_id --- #result uint32 songs_singed --- #feedback float32 complete_percent - [actionlib::SimpleActionServer<$action>]:
$packege_name/src/DoSing_server.cpp#include <ros/ros.h> #include <actionlib/server/simple_action_server.h> #include "learning_communication/DoSingAction.h" typedef actionlib::SimpleActionServer<learning_communication::DoSingAction> Server; void execute(const learning_communication::DoSingGoalConstPtr& goal, Server* as) { // 假设唱歌的进度,并且按照1hz的频率发布进度feedback ros::Rate r(1); learning_communication::DoSingFeedback feedback; ROS_INFO("Singer %d is working.", goal->singer_id); for(int i=1; i<=10; i++) { feedback.complete_percent= i * 10; as->publishFeedback(feedback); r.sleep(); } // 当action完成后,向客户端返回结果 ROS_INFO("Singer %d finish working.", goal->singer_id); as->setSucceeded(); } int main(int argc, char** argv) { ros::init(argc, argv, "do_sing_server"); ros::NodeHandle n; // 定义一个服务器 //boost::bind(&execute, _1, &server)(x)等同于执行execute(x,&server) Server server(n, "do_sing", boost::bind(&execute, _1, &server), false); // 服务器开始运行 server.start(); ros::spin(); return 0; } - [actionlib::SimpleActionClient<$action>]:
$packege_name/src/DoSing_client.cpp#include <ros/ros.h> #include <actionlib/server/simple_action_server.h> #include "learning_communication/DoSingAction.h" typedef actionlib::SimpleActionServer<learning_communication::DoSingAction> Server; void execute(const learning_communication::DoSingGoalConstPtr& goal, Server* as) { // 假设唱歌的进度,并且按照1hz的频率发布进度feedback ros::Rate r(1); learning_communication::DoSingFeedback feedback; ROS_INFO("Singer %d is working.", goal->singer_id); for(int i=1; i<=10; i++) { feedback.complete_percent= i * 10; as->publishFeedback(feedback); r.sleep(); } // 当action完成后,向客户端返回结果 ROS_INFO("Singer %d finish working.", goal->singer_id); as->setSucceeded(); } int main(int argc, char** argv) { ros::init(argc, argv, "do_sing_server"); ros::NodeHandle n; // 定义一个服务器 //boost::bind(&execute, _1, &server)(x)等同于执行execute(x,&server) Server server(n, "do_sing", boost::bind(&execute, _1, &server), false); // 服务器开始运行 server.start(); ros::spin(); return 0; } - 配置功能包
$packege_name/packege.xml<build_depend>actionlib</build_depend> <build_depend>actionlib_msgs</build_depend> <exec_depend>actionlib</exec_depend> <exec_depend>actionlib_msgs</exec_depend> - 添加编译选项
$packege_name/CMakeLists.txt#编译自定义动作消息 find_package(catkin REQUIRED actionlib_msgs actionlib) add_action_files(DIRECTORY action FILES DoDishes.action) generate_messages(DEPENDENCIES actionlib_msgs) #编译cpp add_executable(DoSing_client src/DoSing_client.cpp) target_link_libraries(DoSing_client ${catkin_LIBRARIES}) add_dependencies(DoSing_client ${${PROJECT_NAME}_EXPORTED_TARGETS}) add_executable(DoSing_server src/DoSing_server.cpp) target_link_libraries(DoSing_server ${catkin_LIBRARIES}) add_dependencies(DoSing_server ${${PROJECT_NAME}_EXPORTED_TARGETS}) - 运行
- terminal-1
roscore - terminal-2
source devel/setup.bash rosrun learning_communication DoSing_client - terminal-3
source devel/setup.bash rosrun learning_communication DoSing_server
- terminal-1
本文来自博客园,作者:叶小蜗,转载请注明原文链接:https://www.cnblogs.com/yexiaowo/p/ROS-communication.html

浙公网安备 33010602011771号