ROS通信机制(二) —— 服务(service)与srv文件

2023-05-16

文章目录

  • 简述
  • 特点
  • 相关常用命令
  • 通信模型
  • 核心元素
  • 通信过程
  • 代码示例(服务端和客户端)
    • 服务端(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 [服务名称] [参数]用输入的参数请求服务

通信模型

在这里插入图片描述

核心元素

  1. ROS Master(管理者)
    必须首先被运行,并使用XMLRPC服务器,负责管理节点之间的消息通信中的连接信息。
  2. Server (服务端)
    服务端以请求作为输入,以响应作为输出,请求和响应都是消息,服务端收到服务请求后,执行指定的服务,并将结果下发给客户端,服务端是用于执行指定命令的节点。
  3. Client (客户端)
    客户端以请求作为输出,以响应作为输入,请求和响应都是消息,并发送服务请求到服务端后接收其结果,客户端是用于传达给定命令并接收结果值的节点。

通信过程

  1. 运行主节点
  2. 运行服务端
    服务端向主节点注册自身信息,包括节点名称、服务名称、消息类型、URI地址和端口。
  3. 运行客户端
    客户端端向主节点注册自身信息,包括节点名称、服务名称、消息类型、URI地址和端口。
  4. 主节点向客户端发送服务端信息
    主节点向客户端发送此客户端希望访问的服务端节点的名称、服务名称、消息类型、URI地址和端口等信息。
  5. 客户端发送请求
    客户端根据主节点响应的信息,使用 TCPROS 与 服务端建立网络连接,并发送请求数据。
  6. 服务端发送响应
    服务端接收、处理请求的数据,并将响应结果返回给客户端。

代码示例(服务端和客户端)

需求描述:编写服务端和客户端文件,模拟打开、关闭开关的操作,服务端收到请求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 COMPONENTS
  roscpp
  rospy
  std_msgs
  message_generation
)

# 配置srv源文件,FILES将引用当前功能包目录的srv目录中的*.srv文件,自动生成一个头文件(*.h)
add_service_files(
  FILES
  AddTwoInts.srv
)

# 生成消息时依赖于std_msgs
generate_messages(
  DEPENDENCIES
  std_msgs
)

# 运行时依赖,描述了库、catkin构建依赖项和系统依赖的功能包
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES topic_test
 CATKIN_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,B
    if (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机器人开发笔记汇总》总目录 — ★★★ ☝

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS通信机制(二) —— 服务(service)与srv文件 的相关文章

  • Spring框架中的DAO和Service层到底是什么?

    Spring框架中的DAO和Service层到底是什么 我正在寻找理论答案 就 Spring 而言 没有区别 按照惯例 您可以使用以下方式标记 DAO 类 Repository和服务 Service 前者还进行一些持久层异常转换 既然您在理
  • AngularJS 服务 http 成功函数使用错误的“this”范围

    a 的成功函数 http put无权访问this内部调用的服务的范围 我需要在 PUT 请求的回调中更新服务的属性 这是我在服务中尝试做的事情的简化示例 var myApp angular module myApp function rou
  • 棒棒糖中的 takePicture 失败

    以下代码正在使用 可在后台拍照 它对于棒棒糖以下的所有版本都工作正常 但在以下版本中给出运行时异常takePicture null null mcall 有任何想法吗 public void takePictures final int d
  • 使用 powershell 从远程服务器获取服务状态

    如何获取需要用户名和密码登录的远程计算机的服务状态 我正在尝试使用以下代码找到解决方案 serviceStatus get service ComputerName machineName Name service 默认语法为get ser
  • 启动时启动服务但不进行任何活动

    我想创建一个仅包含服务 无活动 的应用程序 该服务必须在启动时启动 我的问题是 如果没有活动 启动接收器似乎不会调用 我用下面的例子进行了测试 我有不同的文件 MyReceiver java package com test teststa
  • Android - 为服务实现startForeground?

    所以我不确定在哪里 如何实现此方法以使我的服务在前台运行 目前我在另一项活动中通过以下方式开始我的服务 Intent i new Intent context myService class context startService i 然
  • android widget 和 localservice 绑定

    我编写播放器 它的主要活动是运行本地服务 我找不到如何将本地服务绑定到小部件 当我尝试像在活动中一样绑定它时 它失败了 请帮助我 添加 1 何时可以联系后台服务 http www developer com ws data article
  • Silverlight WCF服务跨域问题

    我有一个 silverlight 应用程序 托管在 Intranet mydomain net 和一个 WCF 服务 webservices mydomain net 我需要跨站点策略文件吗 如果是这样 只允许从 Intranet mydo
  • Google Play 商店中基于服务的 Android 应用程序

    我正在开发一个应用程序 该应用程序仅包含一些服务 没有任何活动 即没有 UI 基本上 当用户在他 她的设备上安装应用程序时 我希望有 2 到 3 个服务在后台运行 对此我有几个疑问 应用程序安装后我的服务将如何启动 我的BroadcastR
  • 更改 TFS 构建代理的身份

    我们有一个运行集成测试的 TFS 构建代理 其中一些测试会调用 Internet 上的 Web 服务 我们的网络使用代理与互联网通信 由于构建代理在网络服务上的身份下运行 并且网络服务的设置未配置为使用代理 因此测试失败 我该如何执行以下操
  • onTaskRemoved() 在华为和小米设备中没有被调用

    我一直在使用onTaskRemoved 服务中的方法 用于检测应用程序何时通过滑动从设备最近列表中删除 我执行一些日志记录和发生这种情况时需要执行的一些其他操作 它工作完美 然后我在运行Android 6 0的华为设备上检查了这个方法 该方
  • Mongod 服务启动退出,代码为 100

    Problem 我的 mongo 服务不再启动 root machine service mongod start root machine service mongod status mongod service High perform
  • 如何将dll作为服务运行?

    我知道如何编写 dll 如何编写服务以及如何运行 dllrundll32 但现在我想编写一个在Windows中作为服务安装的dll 我不知道这是否可能或应该导出 dll 中的哪个函数 如何将 dll 作为服务安装并运行 有几种不同的方法可以
  • 在 Android Studio 中调试服务的正确方法?

    在 Android Studio 中调试服务有正确的方法吗 或者 Android Studio 无法做到这一点 当我尝试调试时 它只会断开套接字 与目标虚拟机断开连接 地址 localhost 8600 传输 socket 希望你能在这里帮
  • 在 Google Colaboratory 上运行gym-gazebo

    我正在尝试在 Google Colaboratory 上运行gym gazebo 在Colab上运行gazebo服务器 没有gui的gazebo 有问题 显示警告 Unable to create X window Rendering wi
  • Android 中的计时器任务在无限期时间后停止运行

    我是安卓新手 我正在开发一个应用程序 其中一段特定的代码在后台每 5 秒后执行一次 为了实现这一目标 我使用带有定时器的服务 其中包含定时器任务 有时它工作正常 但经过一段时间后 我的服务正在运行 但计时器任务在 android 中自动停止
  • 从前台服务的活动中释放内存

    我有一个带有前台服务和一项活动的应用程序 该服务可以在启动时自行启动 也可以从 Activity 中启动 我注意到当服务在启动时自行启动时 内存使用量约为 3MB 一旦我打开该 Activity 内存使用量就会跃升至约 9mB 一旦 Act
  • 如何打开定位服务

    当有人第一次拒绝时 如何从实际应用程序重新打开定位服务 我可以选择关闭或打开它 您只能提示他们在屏幕上打开定位服务 如下所示 UIApplication sharedApplication openURL NSURL URLWithStri
  • Android 后台服务示例,具有交互式调用方法

    我不是 Android 方面的专家 我正在寻找一个 Android 应用程序的示例 该应用程序使用一个服务 其中有真正的功能方法 或者换句话说 一个服务可以用来做什么 我们什么时候需要它 超越简单的东西服务举例 我确信您渴望获得一些工作代码
  • asp.net web 服务和 Ihttphandler 的区别

    像发出 AJAX 请求 传递一个参数并返回结果这样简单的任务 都可以使用 Web Service 和 IHttpHandler 来完成 那么有什么区别呢 ASP NET Web 服务实际上是一种 HttpHandler 它提供基于 W3C

随机推荐

  • python socket小结

    Python socket 简单编程小结 首先创建服务器端的socket socket server import socket 定义变量 HOST 61 34 localhost 34 PORT 61 是数字类型 xff0c 不是字符串类
  • STM32 IO口模拟I2C+驱动MPU6050

    一年前写的博客 xff0c 没有把驱动代码分享出来是我疏忽了 xff0c 可以到网盘下载驱动代码 链接 xff1a https pan baidu com s 1SDVQfyoOoycCY 6eSXamlQ 密码 xff1a ipj7 之后
  • git常用操作(branch tag)

    git日常总结 1 初次在本地下载分支代码操作2 初次下载远程代码3 创建分支3 1 创建本地分支3 2创建远程分支 4 删除分支4 1 删除本地分支4 2删除远程分支 5 删除文件5 1 删除本地文件5 2 删除远程文件 6 删除提交6
  • openwrt出现md5sum mismatch错误

    原文地址 xff1a http catinmay com openwrt E5 87 BA E7 8E B0md5sum mismatch E9 94 99 E8 AF AF 刚刚帮人搞路由器一运行安装命令就会出现此错误 xff0c 错误提
  • python——系统交互subprocess

    目录 一 os与commands模块 1 os system 函数实例 2 os popen 函数实例 3 commands getstatusoutput 函数实例 二 subprocess模块 1 subprocess模块中的常用函数
  • strcat 你真的懂吗?

    http blog chinaunix net uid 26914516 id 4215338 html 声明 xff1a 使用GCC编译 strcat xff08 连接两字符串 xff09 函数定义 xff1a char strcat c
  • HTTP超全详解

    HTTP协议简介 超文本传输协议 xff08 英文 xff1a HyperText Transfer Protocol xff0c 缩写 xff1a HTTP xff09 是一种用于分布式 协作式和超媒体信息系统的应用层协议 HTTP是一个
  • 【Linux】三次握手和四次挥手详解

    三次握手和四次挥手 TCP 协议提供的是 xff1a 面向连接 可靠的 字节流服务 使用 TCP 协议通信的双发必须先建立连接 xff0c 然后才能开始数据的读写 双方都必须为该连接分配必要的内核资源 xff0c 以管理连接的状态和连接上数
  • Sion 450行的c++ HttpClient

    Sion Sion是一个轻量级的c 43 43 http客户端 xff0c 仅单头文件450行 xff0c 自带std string的扩展Sion is a lightweight C 43 43 HTTP Client with only
  • bluerov软件调试教程(一 )

    bluerov是目前最流行的一款消费级ROV xff0c 其架构简单 xff0c 可操作性强 xff0c 比同类型的ROV体验感要高很多 xff0c 本系列教程将从bluerov的软件调试 xff0c 硬件调试 xff0c 装舱等三个方面去
  • 安装完成Ubuntu20.04之后要做的事:基础配置、界面美化、异常处理与常用软件的安装

    文章目录 一 换源1 1 通过软件更新1 2 通过修改源文件 二 安裝显卡驱动2 1 解决显卡驱动安装的错误 三 设置新建文件模板四 卸载系统软件五 安裝中文输入法5 1 安装5 2 解决键盘短暂失灵和延迟的问题 六 双系统时间同步七 修改
  • 【C++】Windows客户端与Ubuntu服务器基于socket的简易网络编程

    C 43 43 Windows客户端与Ubuntu服务器基于socket的简易网络编程 服务器端 本人使用的clion远程连接的ubuntu服务器来运行以下代码 xff0c 理论上也可以直接放在服务器上 创建项目后 xff0c 先运行以下代
  • Python中pyusb的开发及使用

    Python中pyusb的开发及使用 因为项目的需求 xff0c 需要将FPGA端的图像像素数据经过USB2 0协议传输到PC端 xff0c 因此需要使用python的pyusb库来进行数据的发送和接收 以下纪录在使用pyusb库的方法和所
  • NVIDIA Jetson Xavier NX 实现官方Jeston-inference深度学习样例

    一 jetson inference相关项目组件的下载 首先附上官方提供的jetson inference项目文件的Github仓库地址 xff0c 大家可以自行前往下载 jetson inference下载地址 xff1a https g
  • CMake 混编c和c++代码

    准备工作 wsl 或者 有linux 系统 购买阿里云或者其他云服务器 xff09 cmake gcc git 等一些必要的软件安装 环境 windows 下 的 wsl wsl 安装下载 例子 拿 Unix网络编程 举例 作者对原生接口进
  • Ros中使用find_object_2d快速实现物体的检测识别

    运行环境 xff1a Ubuntu16 04 ros kinetic版本 准备工作 xff1a 需要r提前安装的webcam的驱动 xff0c 这里推荐使用两种usb cam和uvc camera xff08 1 xff09 usb cam
  • ubuntu16.04多版本Python任意切换(亲测有效)

    UBUNTU16 04的系统安装ROS之后 xff0c 自带的是Python2 7 12的版本 然后实际使用中 xff0c 可能用到其他工具需要装Python3 5以上的版本 安装完之后 xff0c 可能经常在编译某些工程的时候出现一些代码
  • ROS中级教程学习笔记1-手动创建ROS package

    之前在基础教程中 xff0c 我们使用的是catkin create pkg自动创建ros包 xff0c 实际上就是一个package xml文件和CMakeLists txt文件加文件夹 xff0c 所以手动创建看看能不能呢和自动创建有一
  • 串口分类

    串口一般来说就是UART xff0c 它实际只定义了数据链路层的规范 xff0c 也就是起始位 数据位 停止位 但是在不同的物理层又分为 xff1a TTL串口 RS232串口 RS485串口等 TTL串口 xff1a 它是MCU芯片之间进
  • ROS通信机制(二) —— 服务(service)与srv文件

    文章目录 简述特点相关常用命令通信模型核心元素通信过程代码示例 xff08 服务端和客户端 xff09 服务端 xff08 server cpp xff09 客户端 xff08 client cpp xff09 配置 CMakeLists