前言
ROS服务通讯
定义
[1]服务通信也是ROS中一种极其常用的通信模式,服务通信是基于请求响应模式的,是一种应答机制。也即: 一个节点A向另一个节点B发送请求,B接收处理请求并产生响应结果返回给A.
[2]以请求响应的方式实现不同节点之间数据交互的通信模式。
[3]需要两个节点.一个是服务端一个是客户端.
服务端节点通过名称提供服务,当客户端节点发送请求消息时,它响应这个消息并将结果发送到客户段节点.
客户端节点往往需要一直等待服务器响应
应用场景
服务通信更适用于对时时性有要求、具有一定逻辑处理的应用场景。
一般用于需要实现交互式"请求—响应"的机器人应用中
实现
服务通信较之于话题通信更简单些,理论模型如下图所示,该模型中涉及到三个角色:
- ROS master(管理者)
- Server(服务端)
- Client(客户端)
ROS Master 负责保管 Server 和 Client 注册的信息,并匹配话题相同的 Server 与 Client ,帮助
Server 与 Client 建立连接,连接建立后,Client 发送请求信息,Server 返回响应信息。
整个流程由以下步骤实现:
0.Server注册
Server 启动后,会通过RPC在 ROS Master 中注册自身信息,其中包含提供的服务的名称。ROS Master
会将节点的注册信息加入到注册表中。
1.Client注册
Client 启动后,也会通过RPC在 ROS Master 中注册自身信息,包含需要请求的服务的名称。ROS Master
会将节点的注册信息加入到注册表中。
2.ROS Master实现信息匹配
ROS Master 会根据注册表中的信息匹配Server和 Client,并通过 RPC 向 Client 发送 Server 的 TCP
地址信息。
3.Client发送请求
Client 根据步骤2 响应的信息,使用 TCP 与 Server 建立网络连接,并发送请求数据。
4.Server发送响应
Server 接收、解析请求的数据,并产生响应结果返回给 Client。
注意
-
客户端请求被处理时,需要保证服务器已经启动
-
服务端和客户端都可以存在多个。
服务通信自定义srv
创建功能包,然后创建srv文件夹,再创建Addints.srv
catkin_create_pkg plumbing_server_client roscpp rospy std_msgs
cd ~/catkin_1/srv/plumbing_server_client/srv
mkdir Addints.srv
用Vscode编写此文件
#客户端请求时发送的内容
int32 num1
int32 num2
---
#服务器响应发送的数据
int32 sum
编写package.xml
<build_export_depend>message_generation</build_export_depend>
<exec_depend>message_runtime</exec_depend>
编写CMakeLists.txt文件
[1]引用自定义srv文件
找到这个代码,修改如下
add_service_files(
FILES
Addints.srv
)
[2]设置自定义文件的依赖文件.不然定义的消息类型找不的
找到这个代码,修改如下
generate_messages(
DEPENDENCIES
std_msgs
)
可以看到我们的自定义文件是设置的依赖于是std_msgs文件
[3]
设置功能包依赖项(roscpp 等等)的依赖文件
找到这个代码并作出如下修改
注意不要把自定义文件的有关CMakeLists放在最后一行设置,不然会报错:
报错:enerate_messages() must be called after add_message_files()
解决方法
一切编写好后,编译此功能包
编译好后会生成中间文件:
[1]C++使用的可以在工作空间目录下的devel/include/plumbing_server_client看到生成的头文件
[2]Python使用的可以在工作空间目录下的devel/lib/python3/plumbing_server_client看到生成的头文件
> 现在就实现了一个自定义srv
服务通讯案例的C++编写
需求:
编写服务通信,客户端提交两个整数至服务端,服务端求和并响应结果到客户端。
分析:
在模型实现中,ROS master 不需要实现,而连接的建立也已经被封装了,需要关注的关键点有三个:
- [1] 服务端
- [2] 客户端
- [3] 数据
流程:
- 编写服务端实现;
- 编写客户端实现;
- 编辑配置文件;
- 编译并执行。
.cpp文件编写
CMakeLists.txt编写
服务通讯案例的C++编写
#include <ros/ros.h>
#include <plumbing_server_client/Addints.h>
int main(int argc,char *argv[])
{
setlocale(LC_ALL," ");
ros::init(argc,argv,"client");
ros::NodeHandle nh;
ros::ServiceClient client=nh.serviceClient<plumbing_server_client::Addints>("addints");
plumbing_server_client::Addints ai;
//组织请求
ai.request.num1=100;
ai.request.num2=200;
//处理响应
bool flag=client.call(ai);
if(flag==true)
ROS_INFO("结果为:%d",ai.response.sum);
return 0;
CMakeLists.txt编写
add_executable(demo2_client_node src/demo2_client.cpp)
add_dependencies(demo2_client_node ${PROJECT_NAME}_gencpp)
target_link_libraries(demo2_client_node
${catkin_LIBRARIES}
)
ROS服务命令工具:RosSRV和RosService
RosService
- rosservice call /service args 使用给定的参数调用服务
- rosservice find service_type 根据给定的服务类型查找服务
- rosservice info /services 打印有关给定服务的消息
- rosservice list 列出系统运行的活动服务
- rosservice type /service 打印给定服务的服务类型
- rosservice uri /service 打印服务的RORPC URI