在ros中打开下载的功能包头文件具体信息_ROS学习笔记——服务通信

ROS的结构是一个分布式的框架,为用户提供很多节点或者进程之间的通信服务,ROS的通信机制是ROS最底层也是最重要的技术。ROS大致上有三种通信机制,话题通信机制、服务通信机制以及参数管理机制。本文就浅谈一下自己对其中服务通信的学习。

服务通信它是一种自己带有应答的通信机制,它的原理如下图1所示。

0688d4c5cb99abd08a7d5e8edf56d3d8.png

图1、基于服务器/客户端的服务通信机制

1、Talker注册:Talker启动,通过123端口向Master注册发布者的信息。

2、Listener注册:Listener启动,向 Master注册订阅者的信息。

3、ROS Master进行信息的匹配:通过Listener订信息找到匹配的服务提供者信息,并向Listener发布Talker的TCP地址信息。

4、Listener与Talker建立网络链接。

5、Talker向Listener发布服务应答数据。

在常用的乌龟历程中提供了很多设置功能,这些设置功能都是以服务的形式提供。可以使用如下命令查看系统中的服务列表。

rosservice list

本文以简单的加法运算为例子,学习了解ROS中的服务应用。其中Client发布两个需要相加的数,Server节点接收后完成相加并反馈结果。在学习前需要创建相应的工作空间以及相应的功能包,因为此步骤与话题通信一致,此处不再赘述。

1、自定义服务数据

在自己的功能包下创建一个定义服务数据类型的srv文件/<功能包名称>/srv/AddTwoInts.srv:

int64 a
Int64 b
---
int64 sum

其中上部分为服务请求数据,用来储存两个需要相加的数据。下部分为服务应答数据,用来储存相加的结果。

2、配置依赖和编译规则

此处与话题通信一致,需要在package.xml和CMakeList.txt中进行一些添加。

打开package.xml文件,添加以下依赖:

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

打开CMakeList.txt文件,添加以下配置:

find_package( ...... message_generation) #找到相应的位置进行添加
add_service_files(FILES Person.srv)
generate_messages(DEPENDENCIES std_msgs)
catkin_package(...... message_runtime)   #找到相应位置,取消其注释并添加

添加完成后就可以进行编译,若编译成功就可以在工作空间下的devel/include/<功能包名称> 文件中可以找到编译出来的头文件。

3、创建Server和Client代码

首先创建Server节点,提供加法运算的功能,并且返回求和结果。在功能包下的src/server.cpp里面编写相应代码:

#include "ros/ros.h"
#include "learning_communication/AddTwoInts.h"

//service 回调函数,输入参数req 输出参数res
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节点初始化
ros::init(argc,argv,"add_two_ints_server");
//创建节点句柄
ros::NodeHandle n;
//创建一个名为add_two_ints的server,注册回调函数add()
ros::ServiceServer service = n.advertiseService("add_two_ints",add);
//循环等待回调函数
ROS_INFO("Ready to add ints.");
ros::spin();
return 0;
}

然后进行Client节点的创建,通过终端输入两个加数,等待应答结果。在功能包下的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;
//创建一个client,请求add_two_int service
//service消息类型是learning_communication::AddTwoInts的类型
ros::ServiceClient client = n.serviceClient<learning_communication::AddTwoInts>("add_two_ints");
learning_communication::AddTwoInts srv;
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_INFO("Failed to call service add_two_ints");
}
return 0;
}

4、编译功能包

此时需要在CMakelist.txt中添加相应的编译规则。

add_executable(server src/server.cpp) #生成相应的执行文件
target_link_libraries(server ${catkin_LIBRARIES}) #server与client相连接
add_dependencies(server ${PROJECT_NAME}_gencpp) #与动态生成的头文件相依赖
add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)

添加了以上内容后就可以编译功能包。

5、运行Server与Client

首先启动roscore,在终端中输入以下命令:

roscore

运行Server节点:

rosrun learning_communication server

此处的learning_communication为本文所使用的功能包名称。运行成功后就会出现如图2所示结果。

fcb9c9294739328b1a653d1a609e77d0.png

图2、 Server节点启动结果

运行Client节点,并输入两个加数:

rosrun learning_communication client 2 3

Client发布服务请求,Server完成服务之后并反馈给Client。在两者终端就可以看见如图3和如图4所示的结果。

3c092977b51bcc7124d7b892fa202eba.png

图3、Server接收到服务后完成加法,并反馈给Client

3f09cfb2077ad4ae6421600a2f41dfd3.png

图4、Client发布请求并接收到反馈

总结

通过以上学习及其练习可以大致的掌握ROS通信机制中的服务通信,但是作为初学者在练习过程中会遇到很多问题,大多在于相关编译过则及其依赖或者代码编写的错误,所以自己手敲代码非常重要,多加练习才能熟能生巧。这里分享一个自己所遇到的错误,自己在最后运过程中当输入运行Client节点的命令之后,Server端就会得到如下反馈:

Reason given for shutdown:[new node registered with same name]

因为它不是以Error形式出现,所以没有告诉错误的位置,首先我的第一反应就是查看相应的Client和Server代码并检查节点名称,发现两者并没有错。然后就考虑是否是编译规则及其相关依赖出现错误(因为整个过程就只在这些里面进行过修改),发现CMakeList.txt中的:

add_executable(client src/client.cpp)

我误将client.cpp写成了server.cpp,导致出现了错误。因为这句的意思是生产相对应的可执行文件,如果误写为server.cpp,就意味着服务端与客户端两者可执行文件相同,所以就出现了节点名称重复。


参考
古月·ROS入门21讲
创客智造
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值