ROS 2基础概念#6:服务(Service)| ROS 2学习笔记

news2024/12/22 2:34:40

服务(Service)是 ROS 2 计算图中节点通信的另一种方法。 服务基于调用和响应模型,而不是主题的发布者-订阅者模型。 虽然主题允许节点订阅数据流并获取持续更新,但服务仅在客户端专门调用时才提供数据。

ROS 2服务的基本概念

ROS 2服务定义了一种一对一的通信模式。在这种模式下,一个节点可以作为服务服务器(Service Server),另一个节点可以作为服务客户端(Service Client)。服务客户端向服务服务器发起请求,并同步等待服务器的响应。

服务通信基于预先定义的服务类型进行,服务类型定义了请求和响应的结构。这些类型在ROS 2中通过.srv文件定义,类似于消息类型是通过.msg文件定义的。.srv文件的每一部分分别定义了请求和响应的数据结构。

服务的类型

ROS 2服务包含如下两种类型

  • 服务服务器(Service Server)
  • 服务客户端(Service Client)

在ROS 2中,服务指的是远程过程调用。 换句话说,一个节点可以对另一个节点进行远程过程调用,该节点将进行计算并返回结果。

此结构反映在服务消息定义的外观中:

uint32 request
---
uint32 response

在 ROS 2 中,服务预计会快速返回,因为客户端通常正在等待结果。 服务永远不应该用于运行时间较长的进程,特别是在特殊情况下可能需要抢占的进程。 如果您的服务将进行长时间运行的计算,请考虑改用动作(action)。

服务由服务名称标识,该名称看起来很像主题名称(但位于不同的命名空间中)。

一个服务由两部分组成:服务服务器和服务客户端。

服务服务器

服务服务器是接受远程过程请求并对其执行某些计算的实体。 例如,假设 ROS 2 消息包含以下内容:

uint32 a
uint32 b
---
uint32 sum

服务服务器将是接收此消息、将 a 和 b 加在一起并返回总和的实体。

注意:

每个服务名称只能有一个服务服务器。 当多个服务服务器具有相同的服务名称时,未定义哪个服务服务器将接收客户端请求。

服务客户端

服务客户端是请求远程服务服务器代表其执行计算的实体。 从上面的示例来看,服务客户端是创建包含 a 和 b 的初始消息的实体,并等待服务服务器计算总和并返回结果。

与服务服务器不同,可以有任意数量的服务客户端使用相同的服务名称。

服务(Service)描述规范

服务在 ROS 包的 srv/ 目录中的 .srv 文件中进行描述和定义。服务描述文件由请求和响应消息类型组成,以—分隔。 任何两个以 — 连接的 .msg 文件都是合法的服务说明。

下面一个非常简单的服务示例,它接收一个字符串并返回一个字符串:

string str
---
string str

当然,也可能变得更复杂(如果您想引用同一包中的消息,则不得提及包名称):

#request constants
int8 FOO=1
int8 BAR=2
#request fields
int8 foobar
another_pkg/AnotherMessage msg
---
#response constants
uint32 SECRET=123456
#response fields
another_pkg/YetAnotherMessage val
CustomMessageDefinedInThisPackage value
uint32 an_integer

你也可以把一个服务嵌套进另外一个服务中。

服务实例分析

假设我们正在开发一个机器人应用,在这个应用中,机器人需要从一个传感器服务中获取温度读数。我们可以定义一个GetTemperature.srv服务,其请求部分为空(不需要输入参数),响应部分包含一个浮点数表示的温度值。

定义.srv文件

# GetTemperature.srv
float64 temperature

服务服务器

服务服务器的回调函数接收到请求后,会从传感器获取温度读数,并将这个值作为响应返回给客户端。

include "rclcpp/rclcpp.hpp"
include "example_interfaces/srv/get_temperature.hpp"

void handle_temperature_request(
const std::shared_ptr request,
std::shared_ptr response)
{
response->temperature = read_sensor_temperature(); // 假设这个函数从传感器读取温度
RCLCPP_INFO(rclcpp::get_logger("server"), "Sending back response: [%f]", response->temperature);
}

int main(int argc, char **argv)
{
rclcpp::init(argc, argv);
auto node = rclcpp::Node::make_shared("temperature_sensor_server");
auto server = node->create_service("get_temperature", handle_temperature_request);
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

服务客户端

客户端发起请求时不需要提供任何数据,它只需要等待温度读数的响应。

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/get_temperature.hpp"

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    auto node = rclcpp::Node::make_shared("temperature_sensor_client");
    auto client = node->create_client<example_interfaces::srv::GetTemperature>("get_temperature");
    
    auto request = std::make_shared<example_interfaces::srv::GetTemperature::Request>();
    auto future = client->async_send_request(request);
    
    // 等待响应
    if (rclcpp::spin_until_future_complete(node, future)

ROS 2服务命令行工具

在使用如下的命令行工具前,先启动两个 turtlesim 节点: /turtlesim 和 /teleop_turtle

打开一个 Terminal 并运行:

ros2 run turtlesim turtlesim_node 

打开另外一个 Terminal 并运行:

ros2 run turtlesim turtle_teleop_key

列举所有的ROS 2服务

在新终端中运行如下命令将返回系统中当前活动的所有服务的列表:

ros2 service list

将得到类似如下的结果:

/clear
/kill
/reset
/spawn
/teleop_turtle/describe_parameters
/teleop_turtle/get_parameter_types
/teleop_turtle/get_parameters
/teleop_turtle/list_parameters
/teleop_turtle/set_parameters
/teleop_turtle/set_parameters_atomically
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
/turtlesim/describe_parameters
/turtlesim/get_parameter_types
/turtlesim/get_parameters
/turtlesim/list_parameters
/turtlesim/set_parameters
/turtlesim/set_parameters_atomically

您将看到两个节点都有相同的六个服务,其名称中包含参数。 ROS 2 中的几乎每个节点都有这些参数构建的基础设施服务。现在,让我们关注turtlesim特定的服务:/clear, /kill, /reset, /spawn, /turtle1/set_pen, /turtle1/teleport_absolute和/turtle1/teleport_relative。

查看服务类型

服务具有描述服务的请求和响应数据的结构的类型。 服务类型的定义与主题类型类似,不同之处在于服务类型有两部分:一个用于请求的消息,另一个用于响应。

要找出服务的类型,请使用以下命令:

ros2 service type <service_name>

我们来看看turtlesim的/clear服务。 在新终端中输入命令:

ros2 service type /clear

将看到如下的结果:

std_srvs/srv/Empty

Empty 类型表示服务调用在发出请求时不发送任何数据,在接收响应时不接收任何数据。

查看所有服务类型

要同时查看所有活动服务的类型,您可以将 –show-types 选项(缩写为 -t)附加到 list 命令:

ros2 service list -t

将看到如下的结果:

/clear [std_srvs/srv/Empty]
/kill [turtlesim/srv/Kill]
/reset [std_srvs/srv/Empty]
/spawn [turtlesim/srv/Spawn]
...
/turtle1/set_pen [turtlesim/srv/SetPen]
/turtle1/teleport_absolute [turtlesim/srv/TeleportAbsolute]
/turtle1/teleport_relative [turtlesim/srv/TeleportRelative]
...

寻找服务

如果要查找特定类型的所有服务,可以使用以下命令:

ros2 service find <type_name>

例如,您可以像这样找到所有 Empty 类型服务:

ros2 service find std_srvs/srv/Empty

将看到如下的结果:

/clear
/reset

查看服务接口参数

您可以从命令行调用服务,但首先您需要了解输入参数的结构。

ros2 interface show <type_name>.srv

在 /clear 服务的 Empty 类型上尝试此操作:

ros2 interface show std_srvs/srv/Empty.srv

将看到如下的结果:

---

— 将请求结构与响应结构分开。 但是空类型不会发送或接收任何数据。 所以它的结构是空白的。

让我们检查一下具有发送和接收数据类型的服务,例如 /spawn。 从 ros2 service list -t 的结果我们知道/spawn的类型是turtlesim/srv/Spawn。

要查看 /spawn 服务的请求和响应参数,请运行以下命令:

ros2 interface show turtlesim/srv/Spawn

将得到如下返回结果:

float32 x
float32 y
float32 theta
string name # Optional.  A unique name will be created and returned if this is empty
---
string name

— 行上方的信息告诉我们调用 /spawn 所需的参数。 x、y 和 theta 确定生成的Turtle的 2D 姿势,并且名称显然是可选的。

在这种情况下,您不需要了解该行下方的信息,但它可以帮助您了解从调用中获得的响应的数据类型。

调用ROS 2服务

现在您已经知道什么是服务类型、如何查找服务类型以及如何查找该类型参数的结构,您可以使用以下方式调用服务:

ros2 service call <service_name> <service_type> <arguments>

部分是可选的。 例如,空类型服务没有任何参数:

ros2 service call /clear std_srvs/srv/Empty

此命令将清除turtlesim 窗口中海龟绘制的任何线条。

现在我们通过调用 /spawn 并设置参数来生成新的 turtle。 从命令行进行的服务调用中的输入需要采用 YAML 语法。

ros2 service call /spawn turtlesim/srv/Spawn "{x: 2, y: 2, theta: 0.2, name: ''}"

您将获得正在发生的情况的方法风格视图,然后是服务响应:

requester: making request: turtlesim.srv.Spawn_Request(x=2.0, y=2.0, theta=0.2, name='')

response:
turtlesim.srv.Spawn_Response(name='turtle2')

你的turtlesim窗口将立即更新为新生成的 turtle:

总结

节点可以使用 ROS 2 中的服务进行通信。与主题(一种单向通信模式,其中节点发布可供一个或多个订阅者使用的信息)不同,服务是一种请求/响应模式,其中客户端向节点发出请求 提供服务,服务处理请求并生成响应。

一般不要在服务中使用连续通话的服务;这种情况下使用主题(topic)或者动作(action)会更合适。

作者ROS 2学习笔记系列文章:ROS 2学习笔记 归档 - HY's Blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1501438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5个实用的PyCharm插件

大家好&#xff0c;本文向大家推荐五个顶级插件&#xff0c;帮助开发人员提升PyCharm工作流程&#xff0c;将生产力飞升到新高度。 1.CodiumAI 安装链接&#xff1a;https://plugins.jetbrains.com/plugin/21206-codiumate--code-test-and-review-with-confidence--by-codium…

RabbitMQ架构详解

文章目录 概述架构详解核心组件虚拟主机&#xff08;Virtual Host&#xff09;RabbitMQ 有几种广播类型 概述 RabbitMQ是⼀个高可用的消息中间件&#xff0c;支持多种协议和集群扩展。并且支持消息持久化和镜像队列&#xff0c;适用于对消息可靠性较高的场合 官网https://www.…

Thingsboard学习杂记

知识杂记 1.遵循磁盘绑定的内存数据库和遵循磁盘支持的内存数据库 遵循磁盘绑定的内存数据库和遵循磁盘支持的内存数据库有不同的工作方式&#xff0c;它们的优点和缺点也不同。 遵循磁盘绑定的内存数据库的优点&#xff1a; 数据库可以支持更大的数据集合&#xff0c;因为数…

2024 批量下载公众号文章内容/阅读数/在看数/点赞数/留言数/粉丝数导出pdf文章备份(带留言):公众号记忆承载近1500篇历史文章在线查看,找文章方便了

关于公众号文章批量下载&#xff0c;我之前写过很多文章&#xff1a; 视频更新版&#xff1a;批量下载公众号文章内容/话题/图片/封面/音频/视频&#xff0c;导出html&#xff0c;pdf&#xff0c;excel包含阅读数/点赞数/留言数 2021陶博士2006/caoz的梦呓/刘备我祖/六神读金…

Threejs着色器(GPU)编程——感温管网

管网,作为支撑现代城市运转的重要基础设施,是隐藏在地面之下的庞大工程网络。这些管网如同城市的血脉,负责输送各种必要的资源,如水源、热力、燃气等,同时排除废水和其他废弃物。然而,由于其位于地下,人们往往难以直接感知其存在和运行状态。为了保障这些地下管网的安全…

王道机试C++第 4 章 字符串:字符串内容详解及三个小程序 Day29

第 4 章 字符串 本章介绍一种基础数据类型——字符串&#xff0c;并且介绍一些字符串处理的方法及字符串匹配的方法。虽然字符串的内容非常基础&#xff0c;但是十分重要。希望读者能够好好学习本章的内容&#xff0c;为此后的学习打下良好的基础。 4.1 字符串内容详解 由于 …

3月求职黄金期!如何打造自己的岗位优势?这6大分析维度很重要!

三月份&#xff0c;又到了一年的求职黄金期。在今年这场求职大队中&#xff0c;想要找到一份满意的工作&#xff0c;你不仅要学会打造一份高质量简历&#xff0c;还要懂得完美应对HR的各项提问。 一、岗位能力的6大分析维度 虽说是求职黄金期&#xff0c;但找工作也不是随便找…

一键查看:大厂网站都用了啥技术栈,有图有真相。

本次我们采用Wappalyzer插件来看下国内大厂的网站都采用了什么技术架构&#xff0c;文章最后由Wappalyzer的安装方法。 今日头条网站 淘宝网站 哔哩哔哩 京东商城 花瓣网 CSDN 国务院 网易 58同城 腾讯网 如何安装Wappalyzer 用Edge浏览器即可

c++的STL(2)-- vector容器

目录 1. 默认构造 代码: 相关知识点: 2. 有参构造函数 以及 使用{}初始化对象 代码: 相关知识点: 3. vector容器在尾部添加和删除元素 代码: 使用push_back()和pop_back()进行尾部元素的添加和删除 相关知识点: 代码: 使用emplace_back在尾部添…

Spring Boot中SQL语句报错

报错原因&#xff1a; You have an error in your SQL syntax 你的SQL语句出现错误 报错位置&#xff1a; check the manual that corresponds to your MySQL server version for the right syntax to use near :/sql/schema.sql.t_film at line 1 在:/sql/schema.sql附近使用…

Linux系统——Haproxy高性能负载均衡软件

目录 一、Haproxy介绍 1.Haproxy定义 2.Haproxy主要特性 二、安装Haproxy 1.yum安装 2.第三方rpm包安装 3.编译安装 3.1解决Lua环境 3.2编译安装Haproxy 三、配置文件详解 1.状态页 2.日志管理 2.1定义日志到其他主机站点 3.指定进程线程个数 4.cpu亲缘性 5.多进…

md5绕过

文章目录 \\和\\\md5数组绕过科学计数法绕过双md加密md5碰撞Hash长度攻击 下面会以同一道题给大家演示&#xff1a; (题目来源与nssctf) 和 在php代码中我们会看到和&#xff0c;虽然两个都是表示相等&#xff0c;但是在细节上会有所部区别 &#xff1a;是弱比较&#xff0c;只…

Java基础面试题(day 01)

&#x1f4d1;前言 本文主要是【Java】——Java基础面试题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

httprunner参数化

1. 示例 引入对应的Parameters 1.1. CSV参数 from httprunner import HttpRunner, Config, Step, RunRequest, Parameters pytest.mark.parametrize("param", Parameters({"mobile_phone-pwd": "${P(csv_data/mobile_phone-pwd.csv)}"}))def …

C#中实现接口的一些小知识(C#用abstract或virtual来实现接口成员)

文章目录 不可用的修饰可用的修饰非抽象类实现接口抽象类实现接口抽象类与接口方法同名时一同实现 不可用的修饰 在C#中实现接口时&#xff0c;我们不能直接使用static或const来实现接口成员&#xff0c;因为接口中的成员默认都是实例成员&#xff0c;并且它们表示一种契约&am…

【SpringMVC】快速体验 SpringMVC接收数据 第一期

文章目录 一、SpringMVC 介绍1.1 主要作用1.2 核心组件和调用流程理解 二、快速体验三、SpringMVC接收数据3.1 访问路径设置3.1.1 精准路径匹配3.1.2 模糊路径匹配3.1.3 类和方法级别区别3.1.4 附带请求方式限制3.1.5 进阶注解 与 常见配置问题 3.2 接收参数&#xff08;重点&a…

C++ 智能指针深度剖析

文章目录 1. 前言2. 为什么需要智能指针&#xff1f;3. 内存泄漏3.1 内存泄漏的概念及危害3.2 内存泄漏的分类3.3 如何检测内存泄漏3.4 如何避免内存泄漏 4. 智能指针的使用及原理4.1 RAII思想4.2 智能指针的原理4.3 C智能指针发展历史4.4 std::auto_ptr4.5 std::unique_ptr4.6…

计算机组成原理之机器:存储器之辅助存储器

计算机组成原理之机器&#xff1a;存储器之辅助存储器 笔记来源&#xff1a;哈尔滨工业大学计算机组成原理&#xff08;哈工大刘宏伟&#xff09; Chapter3&#xff1a;存储器之辅助存储器 3.1 概述 3.2 磁记录原理 通不同方向电流时磁化方向不同&#xff0c;由此区分写入…

vue 使用谷歌地图 @googlemaps/js-api-loader 进行模糊搜索

<template><div class"map"><div class"mapLeftStyle"><el-inputv-model"input"placeholder"请输入内容"class"controls"input"chnageinput"><i slot"prefix" class"e…

2007-2022年上市公司迪博内部控制评价缺陷数量数据

2007-2022年上市公司迪博内部控制评价缺陷数量数据 1、时间&#xff1a;2007-2022年 2、范围&#xff1a;上市公司 3、指标&#xff1a;证券代码、证券简称、辖区、证监会行业、申万行业、是否存在财报内控重大缺陷、财报内控重大缺陷数量、是否存在财报内控重要缺陷、财报内…