ROS通信机制(二) —— 服务(service)与srv文件
文章目录
- 简述
- 特点
- 相关常用命令
- 通信模型
- 核心元素
- 通信过程
- 代码示例(服务端和客户端)
- 服务端(server.cpp)
- 客户端(client.cpp)
- 配置 CMakeLists.txt
- 编译和运行
- 问题扩展
- 自定义消息
- 自定义srv文件
- 编辑配置文件
- 执行编译
- 修改服务端和客户端代码
- 编译和运行
简述
服务消息通信是指请求服务的服务客户端与负责服务响应的服务服务器之间的同步双向服务消息通信,一个服务被分成服务服务器和服务客户端,其中服务服务器只在有请(request)的时候才响应(response),而服务客户端会在发送请求后接收响应。
特点
与话题不同,服务是一次性消息通信。因此,当服务的请求和响应完成时,两个连接的节点将被断开。该服务通常被用作请求机器人执行特定操作时使用的命令,或者用于根据特定条件需要产生事件的节点。由于它是一次性的通信方式,又因为它在网络上的负载很小,所以它也被用作代替话题的手段,因此是一种非常有用的通信手段。
相关常用命令
命令 | 详细说明 |
---|---|
rosservice list | 显示活动的服务信息 |
rosservice info [服务名称] | 显示指定服务的信息 |
rosservice type [服务名称] | 显示服务类型 |
rosservice find [服务类型] | 查找指定服务类型的服务 |
rosservice uri [服务名称] | 显示ROSRPC URI服务 |
rosservice args [服务名称] | 显示服务参数 |
rosservice call [服务名称] [参数] | 用输入的参数请求服务 |
通信模型
核心元素
ROS Master(管理者)
必须首先被运行,并使用XMLRPC服务器,负责管理节点之间的消息通信中的连接信息。Server (服务端)
服务端以请求作为输入,以响应作为输出,请求和响应都是消息,服务端收到服务请求后,执行指定的服务,并将结果下发给客户端,服务端是用于执行指定命令的节点。Client (客户端)
客户端以请求作为输出,以响应作为输入,请求和响应都是消息,并发送服务请求到服务端后接收其结果,客户端是用于传达给定命令并接收结果值的节点。
通信过程
运行主节点
运行服务端
服务端向主节点注册自身信息,包括节点名称、服务名称、消息类型、URI地址和端口。运行客户端
客户端端向主节点注册自身信息,包括节点名称、服务名称、消息类型、URI地址和端口。主节点向客户端发送服务端信息
主节点向客户端发送此客户端希望访问的服务端节点的名称、服务名称、消息类型、URI地址和端口等信息。客户端发送请求
客户端根据主节点响应的信息,使用 TCPROS 与 服务端建立网络连接,并发送请求数据。服务端发送响应
服务端接收、处理请求的数据,并将响应结果返回给客户端。
代码示例(服务端和客户端)
需求描述:编写服务端和客户端文件,模拟打开、关闭开关的操作,服务端收到请求true(1)时打印 “开关打开” 的信息,收到请求false(0)时打印 “开关关闭” 的信息。
首先,这里创建了一个service_test的包,然后分别创建server.cpp(服务端)和client.cpp(客户端)两个文件。
服务端(server.cpp)
#include "ros/ros.h"
#include "std_srvs/SetBool.h"bool processRequest(std_srvs::SetBool::Request &req,std_srvs::SetBool::Response &res)
{res.success = req.data;if(req.data){res.message = "开关已打开";}else{res.message = "开关已关闭";}ROS_INFO("状态切换为:%d --- %s", res.success, res.message.c_str());return true;
}int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点ros::init(argc, argv, "server");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化服务端对象// 参数1为服务名称,参数2为处理请求的回调函数ros::ServiceServer server = nh.advertiseService("service_chatter", processRequest);ros::spin();return 0;
}
客户端(client.cpp)
#include "ros/ros.h"
#include "std_srvs/SetBool.h"
#include <cstdlib>int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点// 参数3为节点名称,全局唯一ros::init(argc, argv, "client");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化客户端对象// 参数1为服务名称ros::ServiceClient client = nh.serviceClient<std_srvs::SetBool>("service_chatter");// 4.定义请求数据std_srvs::SetBool srv;srv.request.data = atoll(argv[1]);// 6.发送请求开关已打开bool success = client.call(srv);// 7.处理响应if (success){ROS_INFO("请求成功,收到反馈数据:%d --- %s", srv.response.success, srv.response.message.c_str());}else{ROS_ERROR("请求失败");return 1;}return 0;
}
配置 CMakeLists.txt
# 节点构建选项,配置可执行文件
add_executable(server src/server.cpp)
add_executable(client src/client.cpp)# 节点构建选项,配置目标链接库
target_link_libraries(server${catkin_LIBRARIES}
)
target_link_libraries(client${catkin_LIBRARIES}
)
编译和运行
使用Ctrl+Shift+B进行编译,然后先使用roscore命令启动主节点。source下环境变量,然后运行服务端。在新终端source下环境变量,然后运行客户端,并附带请求参数。
问题扩展
话题的发布者和订阅者是没有启动顺序的要求的,因为消息是在循环发送,所以谁先启动谁后启动都能发送、接收消息。服务通信有所区别,需要先启动服务端,再启动客户端,否则会提示 “请求失败”。
我们可以使用消息阻塞函数来优化此问题,如果客户端先启动则一直阻塞,直到服务端启动后再继续执行。
在客户端发送请求之前添加下面的代码:
ros::service::waitForService("service_chatter");
自定义消息
ROS的服务类型可以在这里查看。
需求描述:客户端提交两个整数至服务端,服务端进行求和计算并响应结果给客户端。
自定义srv文件
srv 文件内的可用数据类型与 msg 文件一致,不同的是,srv文件中的数据分成两部分,使用 “- - -” 隔开,上面是请求数据,下面是响应数据。
首先,在service_test包中创建srv文件夹,然后,在文件夹中创建消息文件(AddTwoInts.srv)。
int64 A
int64 B
---
int64 Sum
编辑配置文件
- 在package.xml中添加编译依赖与执行依赖
<!-- 编译时依赖 -->
<build_depend>message_generation</build_depend>
<!-- 运行时依赖 -->
<exec_depend>message_runtime</exec_depend>
- 在CMakeLists.txt编辑 srv相关配置
# catkin构建时依赖的组件包,前3个创建ROS包时已经自动生成了,这里添加了message_generation
find_package(catkin REQUIRED COMPONENTSroscpprospystd_msgsmessage_generation
)# 配置srv源文件,FILES将引用当前功能包目录的srv目录中的*.srv文件,自动生成一个头文件(*.h)
add_service_files(FILESAddTwoInts.srv
)# 生成消息时依赖于std_msgs
generate_messages(DEPENDENCIESstd_msgs
)# 运行时依赖,描述了库、catkin构建依赖项和系统依赖的功能包
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES topic_testCATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
执行编译
使用Ctrl+Shift+B进行编译,然后可以在/devel/service_test目录下看到自动生成的头文件AddTwoInts.h,此时便可以代后面的代码中进行引用了。
PS: 在修改代码之前,先在c_cpp_properties.json文件中添加下头文件路径,否则在代码中引用头文件时会出现找不到的情况。之前已经添加过的话,这里就不需要再重复添加了。
修改服务端和客户端代码
也可参考ROS WIKI中的代码示例。
下面我们在代码中使用自定义的srv来进行通信。
- 服务端(server.cpp)
#include "ros/ros.h"
#include "service_test/AddTwoInts.h"bool processRequest(service_test::AddTwoInts::Request &req,service_test::AddTwoInts::Response &res)
{res.Sum = req.A + req.B;ROS_INFO("收到请求数据: x=%ld, y=%ld", (long int)req.A, (long int)req.B);ROS_INFO("响应的计算结果为: [%ld]", (long int)res.Sum);return true;
}int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点ros::init(argc, argv, "server");// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化服务端对象// 参数1为服务名称,参数2为处理请求的回调函数ros::ServiceServer server = nh.advertiseService("service_chatter", processRequest);ros::spin();return 0;
}
- 客户端(client.cpp)
#include "ros/ros.h"
#include "service_test/AddTwoInts.h"
#include <cstdlib>int main(int argc, char **argv)
{// 设置编码setlocale(LC_ALL, "");// 1.初始化ROS节点// 参数3为节点名称,全局唯一ros::init(argc, argv, "client");// 这里的形参argc表示第二个形参数组argv中字符串的个数,即命令行传递的参数个数// argv[0]:文件路径,/home/zbw/robot_test_ws/devel/lib/service_test/client// argv[1]:传入的参数1,A// argv[2]:传入的参数2,Bif (argc != 3){ROS_ERROR("请提交两个整数");return 1;}// 2.实例化ROS句柄ros::NodeHandle nh;// 3.实例化客户端对象// 参数1为服务名称ros::ServiceClient client = nh.serviceClient<service_test::AddTwoInts>("service_chatter");// 等待服务端启动ros::service::waitForService("service_chatter");// 4.定义请求数据service_test::AddTwoInts srv;srv.request.A = atoll(argv[1]);srv.request.B = atoll(argv[2]);// 6.发送请求开关已打开bool success = client.call(srv);// 7.处理响应if (success){ROS_INFO("请求成功,收到反馈数据:%ld", (long int)srv.response.Sum);}else{ROS_ERROR("请求失败");return 1;}return 0;
}
编译和运行
使用Ctrl+Shift+B进行编译,然后使用roscore命令启动主节点,source下环境变量,分别运行服务端和客户端即可看到通信数据的打印输出。
☝ ★★★ — 返回 《ROS机器人开发笔记汇总》总目录 — ★★★ ☝
ROS通信机制(二) —— 服务(service)与srv文件相关推荐
- ROS通信机制(一) —— 话题(topic)与msg文件
文章目录 简述 特点 相关常用命令 通信模型 核心元素 通信过程 代码示例(发布者和订阅者) 发布者(talker.cpp) 订阅者(listener.cpp) 配置 CMakeLists.txt 编 ...
- ROS入门跟着我就够了(二)上 ROS通信机制
由于这一章东西比较多,我分了上下两篇,下部分可以在< ROS 入门跟着我就够了>专辑中查看 ROS 中的基本通信机制主要有如下三种实现策略: 话题通信(发布订阅模式)服务通信(请求响应模式 ...
- ROS 通信机制(已整理)
文章目录 节点与节点管理器 ROS通信机制 1. 话题通信 1.1 基本话题通信 1.1.1 C++实现 发布方 demo01_pub.cpp 订阅方 demo01_sub.cpp 1.1.2 Pyt ...
- 【ROS理论与实践-赵虚左老师】Chap2 ROS通信机制
第二章 ROS通信机制 通信是ROS中的核心 Core 机器人是一种高度复杂的系统性实现,在机器人上可能集成各种传感器(雷达.摄像头.GPS-)以及运动控制实现,为了解耦合,在ROS中每一个功能点都是 ...
- Chapter2 ROS通信机制----基础篇(Ⅰ)vs配置及通信基础
目录 一.复习及launch 1.1 深入理解配置信息(非常重要) 1.2 launch文件演示 二.ROS通信机制-----基础 2.1 本节导论 2.2 话题通信 2.2.1 话题通信概述 2.2 ...
- ROS自主导航学习———ROS通信机制
前言 前面ROS很多都忘记了 ,现在来重新回顾一下内容 ROS 中的基本通信机制主要有如下三种实现策略: 话题通信(发布订阅模式) 服务通信(请求响应模式) 参数服务器(参数共享模式) Action通 ...
- ROS通信机制——发布/订阅者模型
目录 发布/订阅者模型 (一)发布者 (二)订阅者 (三)综合 参考资料 ROS (Robot Operating System),即机器人操作系统,是为了加快机器人的开发效率,提高机器人软件代码的复 ...
- ROS通信机制:话题、服务、参数
目录 话题通信 理论模型 流程 通信样例 自定义消息的通信 服务通信 理论模型 服务通信自定义srv 参数服务器 理论模型 参数操作 话题通信 话题通信是ROS中使用频率最高的一种通信模式,话题通信是 ...
- 6th ROS通信机制概述
ROS通信是ROS的核心之一. 一.基本概念 节点(Node) 一个节点就表示一个进程 多节点.端到端.分布式通信机制 消息(Message) 节点之间通过订阅和发布传递的数据 可以使用ROS提供的消 ...
最新文章
- 基于opencv的cfar算法实现海岸线检测
- matlab图像的腐蚀和膨胀_OpenCV图像处理系列八 --- 腐蚀与膨胀
- 腾讯商业数据分析师培养计划
- 修改java启动参数_如何修改jvm启动参数
- java每日小算法(10)
- 信息学奥赛一本通 1083:计算星期几 | OpenJudge NOI 小学奥数 7831
- 【训练过程】2) Train the VAEs of domain A and domain B respectively(分别训练域A和域B的VAE)
- golang 还是php web,golang适合做web开发吗?
- python编程可以做什么菜_Python 编程! 我是菜菜菜鸟 大家帮帮忙
- [SSH] 传输文件
- 你真的了解“真的了解”的含义吗
- python - zipfile模块
- 淘宝类目运营方法 怎么快速获取流量和销量
- 搜狗主动提交url并反馈快照更新软件(含源码)
- APM —全链路追踪
- 包中校中辉盛业集团荣获“中国优秀诚信品牌”奖项
- 适合在家种植的中药材
- 测试架构师需要具备哪些能力?
- 第四十七章 SQL命令 GRANT(一)
- BASLER Pylon 抓取策略