ROS 创建及使用msg和srv(一)介绍了如何创建和编译msg及srv文件,接下来将介绍如何使用。
1. 使用新建的msg
上一章work/src/myros/msg目录下建立了num.msg文件,现在要使用num.msg创建两个节点,在myros/src目录下新建exa1.cpp和exa2.cpp,同时调用num.msg。
1.1 exa1.cpp:
#include "ros/ros.h"
#include "myros/num.h"//包含进之前编写的num.msg 功能包/.msg文件名称
// 由编译系统自动根据我们先前创建的msg文件生成的对应该msg文件的头文件。
#include <sstream>
int main(int argc, char **argv)
{
ros::init(argc, argv, "exa1_node"); //节点名称
ros::NodeHandle n;
ros::Publisher pub = n.advertise<myros::num>("message", 1000);
ros::Rate loop_rate(10);
while (ros::ok())
{
//使用自定义消息类型int32 A,int32 B,int32 C
myros::num msg;
msg.A = 1;
msg.B = 2;
msg.C = 3;
pub.publish(msg);//发布消息
ros::spinOnce();
loop_rate.sleep(); //休眠时间
}
return 0;
}
1.2 exa2.cpp:
#include "ros/ros.h"
#include "myros/num.h" //包含进之前编写的num.msg 功能包/.msg文件名称
void Callback(const myros::num::ConstPtr& msg)//回调函数
{
//这里使用了自定义消息类型int32 A,int32 B,int32 C
ROS_INFO("I heard: [%d] [%d] [%d]", msg->A, msg->B, msg->C);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "exa2_node");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("message", 1000, Callback);
ros::spin();
return 0;
}
1.3 编辑CMakeList.txt文件
为了编译节点,在CMakeList.txt文件末尾或文中相对应位置添加:
add_executable(exa1_node src/exa1.cpp)
add_executable(exa2_node src/exa2.cpp)
add_dependencies(exa1_node myros_generate_messages_cpp)
add_dependencies(exa2_node myros_generate_messages_cpp)
target_link_libraries(exa1_node ${catkin_LIBRARIES})
target_link_libraries(exa2_node ${catkin_LIBRARIES})
1.4 运行
在终端:
$ cd work/ //切换到工作空间
$ catkin_make
$ roscore
新建终端:
source devel/setup.bash
rosrun myros exa1_node //rosrun 功能包名 节点名
新建终端:
source devel/setup.bash
rosrun myros exa2_node //rosrun 功能包名 节点名
2. 使用新建的srv
在开始本节之前,对节点之间的通信方式进行回顾。
节点之间常用两种通信方式:topic(话题)、service(服务)。
“话题”通信:不同的 node 可以向同一个 topic 上发送、接收数据,每个 node 都是相对独立的,只需要负责自己的功能实现以及外部接口,不需要关心其他 node 的行为。这是一种开放式的收、发数据的方式,也是 node 之间通讯的主要形式,有利于构造分布式大系统。
“服务”通信:是一种请求+反馈的通信机制。消息的传输只涉及两个 node:发送请求的一方称为 client,提供服务的一方叫做 server。在通过 service 形式进行通讯时,client 首先向 server 请求服务, 收到消息之后 server 运行事先设置好的服务功能,并返回消息给 client。 service 通讯一般用在事件触发情景中,例如满足某个条件就令 node 开启某项功能,并希望确认功能确实顺利开启。
————————————————
版权声明:本段转自CSDN博主「su扬帆启航」的原创文章
原文链接:https://blog.csdn.net/orange_littlegirl/article/details/96474090
Topic话题 | Service服务 |
---|---|
节点A——>话题T (节点A发布话题T) 话题T<——节点B (节点B订阅话题T) | 节点A——>服务节点S (节点A请求服务S) 服务节点S<——节点A (服务S响应节点A) |
异步通信 | 同步通信 |
话题内容的数据格式——msg | 服务的通信数据格式——srv |
用于连续高频的数据发布和接收:雷达测障碍物、里程计等 | 用于偶尔调用的功能或执行某一项功能:拍照、语言识别等 |
————————————————
版权声明:本表格为CSDN博主「墨水兰亭」的原创
原文链接:https://blog.csdn.net/moshuilangting/article/details/86484042
之前介绍的都是通过话题进行通信,接下来就是使用新建的srv文件采用服务通信,服务允许发送请求和获得响应。
上一章work/src/myros/srv目录下建立了ber.srv文件,现在用ber.srv创建两个节点(service、client),在myros/src目录下新建exa3.cpp和exa4.cpp,同时调用ber.srv。
2.1 exa3.cpp(service):
#include "ros/ros.h"
#include "myros/ber.h"
//由编译系统自动根据我们先前创建的srv文件生成的对应该srv文件的头文件。
bool add(myros::ber::Request &req,myros::ber::Response &res)
{
res.sum = req.A + req.B + req.C;//A、B、C是先前在.srv文件中定义的名称
ROS_INFO("request: A=%d, B=%d C=%d", (int)req.A, (int)req.B, (int)req.C);
ROS_INFO("sending back response: [%d]", (int)res.sum);
return true;
}
//服务的处理操作在add()函数中实现(求和),他的输入参数是.srv中的request和response两部分。通常在处理函数中,我们对 Request 部分的数据进行相应的服务操作,然后将结果写入到 Response 中。处理函数返回值是 bool 类型,表示服务是否成功执行。
// A B C sum 的数据类型(int float 等)要确定好。
//相加后,关于request和response的信息被记录下来。最后,service完成计算后返回true值。
int main(int argc, char **argv)
{
ros::init(argc, argv, "exa3_node");
ros::NodeHandle n;
//创建服务并在ROS中发布广播
ros::ServiceServer service = n.advertiseService("add_3_ints", add);
//建立完成service,并且发布消息 值得注意的是 add_3_ints 并不是“话题”,因为这个是“服务”
ROS_INFO("Ready to add 3 ints."); //在命令行窗口输出信息
ros::spin();
return 0;
}
2.2 exa4.cpp(client):
#include "ros/ros.h"
#include "myros/ber.h" //包含先前所创建的srv文件
#include <cstdlib>
int main(int argc, char **argv)
{
ros::init(argc, argv, "exa4_node");
if (argc != 4)
{
ROS_INFO("usage: add_3_ints_client A B C ");
return 1;
}
ros::NodeHandle n;
ros::ServiceClient client = n.serviceClient<myros::ber>("add_3_ints");
//下面创建srv文件的一个实例,并且加入需要发生的数据值 add_3_ints不是“话题”
myros::ber srv;
srv.request.A = atoi(argv[1]);
srv.request.B = atoi(argv[2]);
srv.request.C = atoi(argv[3]);
//这里实例化一个由ROS编译系统自动生成的service类,并给其request成员赋值。
//一个service类包含两个成员request和response。
//同时也包括两个类定义Request和Response。
if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum);
}
else
{
ROS_ERROR("Failed to call service add_3_ints");
return 1;
}
//这段代码是在调用service。
//由于service的调用是模态过程(调用的时候占用进程阻止其他代码的执行),一旦调用完成,将返回调用结果。
//如果service调用成功,call()函数将返回true,srv.response里面的值将是合法的值。
//如果调用失败,call()函数将返回false,srv.response里面的值将是非法的。
return 0;
}
2.3 编辑CMakeList.txt文件
为了编译节点,在CMakeList.txt文件末尾或文中相对应位置添加:
add_executable(exa3_node src/exa3.cpp)
add_executable(exa4_node src/exa4.cpp)
add_dependencies(exa3_node myros_generate_messages_cpp)
add_dependencies(exa4_node myros_generate_messages_cpp)
target_link_libraries(exa3_node ${catkin_LIBRARIES})
target_link_libraries(exa4_node ${catkin_LIBRARIES})
2.4 运行
在终端:
$ cd work/ //切换到工作空间
$ catkin_make
$ roscore
新建终端:
source devel/setup.bash
rosrun myros exa3_node //rosrun 功能包名 节点名
新建终端:
source devel/setup.bash
rosrun myros exa4_node 1 2 4 //rosrun 功能包名 节点名
最近发现一片博客写的也蛮好,附上链接供以后查看。
ROS自定义msg类型及使用