[ROS2] --- service

news2024/11/23 15:15:45

1 service介绍

1.1 service概念

话题通信是基于订阅/发布机制的,无论有没有订阅者,发布者都会周期发布数据,这种模式适合持续数据的收发,比如传感器数据。机器人系统中还有另外一些配置性质的数据,并不需要周期处理,此时就要用到另外一种ROS通信方式——服务(Service)。服务是基于客户端/服务器模型的通信机制,服务器端只在接收到客户端请求时才会提供反馈数据。

1.2 service特点

  • 同一个服务(名称相同)有且只能有一个节点来提供
    在这里插入图片描述

  • 同一个服务可以被多个客户端调用(可以一对一也可一对多)
    在这里插入图片描述

  • 同步通信
    这个过程一般要求越快越好,假设服务器半天没有反应,你的浏览器一直转圈圈,那有可能是服务器宕机了,或者是网络不好,所以相比话题通信,在服务通信中,客户端可以通过接收到的应答信息,判断服务器端的状态,我们也称之为同步通信。

2 自定义通信接口

和话题通信类似,服务通信的核心还是要传递数据,数据变成了两个部分,一个请求的数据,比如请求苹果位置的命令,还有一个反馈的数据,比如反馈苹果坐标位置的数据,这些数据和话题消息一样,在ROS中也是要标准定义的,话题使用.msg文件定义,服务使用的是.srv文件定义。

2.1 新建工作空间

mkdir -p dev_ws/src
cd dev_ws/src
ros2 pkg create custom_interface --build-type ament_cmake

2.2 编写srv接口文件

# 创建srv目录
cd  dev_ws/src/custom_interface
mkdir srv
touch CapitalFullName.srv

CapitalFullName.srv

string name
string surname
---
string capitalfullname

2.3 编译

colcon build

3 service代码实现

上面第二步已经实现了自定义接口,并在install目录生成了对应的头文件,我们下面的代码中可以直接引用这个自定义接口了。

3.1 新建工作空间

前面已经讲解过,这里不再赘述
这里创建工作空间名为learning03_service

3.2 server_node_class.cpp

/**
 * @file service_node_class.cpp
 *
 * @brief A basic ROS2 service server node with class implementation that gets two 
 *        strings as request and answer with a capitalized full string as response.
 *        It's necessary to use the custom message defined in the external
 *        package "Custom msg and srv"
 *        To call the service from a terminal use on a single line:
 *        ros2 service call /create_cap_full_name 
 *        custom_interface/srv/CapitalFullName "{name: x, surname: y}"
 *
 * @author Antonio Mauro Galiano
 * Contact: https://www.linkedin.com/in/antoniomaurogaliano/
 *
 */


#include "rclcpp/rclcpp.hpp"
#include "custom_interface/srv/capital_full_name.hpp"
#include <boost/algorithm/string.hpp>


class MyServiceNode : public rclcpp::Node
{
private:
  rclcpp::Service<custom_interface::srv::CapitalFullName>::SharedPtr service_;
  void ComposeFullName(const std::shared_ptr<custom_interface::srv::CapitalFullName::Request> request,
        std::shared_ptr<custom_interface::srv::CapitalFullName::Response> response);

public:
  MyServiceNode(std::string passedNodeName="VOID")
    : Node(passedNodeName)
  {
    RCLCPP_INFO(this->get_logger(), "I am ready to capitalize your full name");
    // like the subscriber class node it's needed the boost::bind to acces the member method 
    // with 2 placeholders to pass request and response to the callback
    service_ = this->create_service<custom_interface::srv::CapitalFullName>("create_cap_full_name", 
      std::bind(&MyServiceNode::ComposeFullName, this, std::placeholders::_1, std::placeholders::_2 ));
  }
  
};

// method to handle the client request and give back a response
// the service gets the name and surname and responses with a capitalized full name
void MyServiceNode::ComposeFullName(const std::shared_ptr<custom_interface::srv::CapitalFullName::Request> request,
        std::shared_ptr<custom_interface::srv::CapitalFullName::Response> response)
{
  std::string fullName = request->name + " " + request->surname;
  std::string capitalFullName = boost::to_upper_copy<std::string>(fullName);
  response->capitalfullname = capitalFullName;    
  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming name: %s" "\tIncoming surname: %s",
              request->name.c_str(), request->surname.c_str());
  RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sending back the capitalize full name: [%s]", response->capitalfullname.c_str());
}


int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<MyServiceNode>("service_node");
  rclcpp::spin(node);   // the service starts to wait and manage requests
  rclcpp::shutdown();
}

3.3 client_node_class.cpp

/**
 * @file client_node_class.cpp
 *
 * @brief A basic ROS2 service client node with class implementation that asks the user 
 *        to input twostrings and gets back a capitalized full string from the server service.
 *        It's necessary to use the custom message defined in the external 
 *        package "custom_interface"
 *
 * @author Antonio Mauro Galiano
 * Contact: https://www.linkedin.com/in/antoniomaurogaliano/
 *
 */


#include "custom_interface/srv/capital_full_name.hpp"
#include "rclcpp/rclcpp.hpp"


using namespace std::chrono_literals;


class MyClientNode : public rclcpp::Node
{
private:
  const std::string name_;
  const std::string surname_;
  rclcpp::Client<custom_interface::srv::CapitalFullName>::SharedPtr client_;
  void ServerResponse();

public:
  MyClientNode(std::string passedNodeName="VOID", std::string passedName="VOID", std::string passedSurname="VOID")
    : Node(passedNodeName), name_(passedName), surname_(passedSurname)
  {
    client_ = this->create_client<custom_interface::srv::CapitalFullName>("create_cap_full_name");
    this->ServerResponse();
  }
  
};


void MyClientNode::ServerResponse()
{
  auto request =
    std::make_shared<custom_interface::srv::CapitalFullName::Request>();

  request->name = name_;
  request->surname = surname_;
  std::chrono::seconds myPause = 1s;

  while (!client_->wait_for_service(1s)) 
  {
    if (!rclcpp::ok()) 
    {
      RCLCPP_ERROR(rclcpp::get_logger("rclcpp"),
                   "Interrupted while waiting for the service. Exiting.");
    }
    RCLCPP_INFO(rclcpp::get_logger("rclcpp"),
                "SERVICE NOT AVAILABLE, waiting again...");
  }

  auto result = client_->async_send_request(request);

  // note that for the MyClientNode object it's used the get_node_base_interface
  // to allow the client spinning for a server response
  // it returns the needed rclcpp::node_interfaces::NodeBaseInterface::SharedPtr 
  if (rclcpp::spin_until_future_complete(this->get_node_base_interface(), result) ==
      rclcpp::FutureReturnCode::SUCCESS)
  {
    RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Capitalized full name: %s",
                result.get()->capitalfullname.c_str());
  } else
  {
    RCLCPP_ERROR(rclcpp::get_logger("rclcpp"),
                 "Failed to call service create_cap_full_name");
  }
}


int main(int argc, char **argv)
{
  rclcpp::init(argc, argv);
  std::string name = "";
  std::string surname = "";
  std::cout << "Insert the name -> ";
  std::cin >> name;
  std::cout << "Insert the surname -> ";
  std::cin >> surname;
  auto node = std::make_shared<MyClientNode>("client_node", name, surname);
  rclcpp::shutdown();
}

3.4 CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(learning03_service)

# Default to C99
if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(custom_interface REQUIRED)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # uncomment the line when a copyright and license is not present in all source files
  #set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # uncomment the line when this package is not in a git repo
  #set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

# add_executable(service_node src/service_node.cpp)
# ament_target_dependencies(service_node rclcpp custom_interface)

# add_executable(client_node src/client_node.cpp)
# ament_target_dependencies(client_node rclcpp custom_interface)

add_executable(client_node_class src/client_node_class.cpp)
ament_target_dependencies(client_node_class rclcpp custom_interface)

add_executable(service_node_class src/service_node_class.cpp)
ament_target_dependencies(service_node_class rclcpp custom_interface)

install(TARGETS
	#  service_node
	#  client_node
	 client_node_class
	 service_node_class
   DESTINATION lib/${PROJECT_NAME}
 )

ament_export_dependencies(rosidl_default_runtime)
ament_package()

3.5 package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>learning03_service</name>
  <version>0.0.0</version>
  <description>Example nodes to create service server and service client</description>
  <maintainer email="foo@foo.foo">Antonio Mauro Galiano</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>

  <exec_depend>rclcpp</exec_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <depend>custom_interface</depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

4 编译运行

# 编译
colcon build

# source环境变量
source install/setup.sh

# 运行publisher
ros2 run learning03_service client_node_class

# 运行subsriber
ros2 run learning03_service server_node_class

5 service常用指令

# 查看service列表
ros2 service list

# 查看所有service类型
ros2 service list -t

# 查看service类型
ros2 service type <service_name>

# 查看同一类型所有在运行的service
ros2 service find <service_type>

# 查看service内容
ros2 interface show <service_interface>
ros2 interface show <service_name>

# 调用service
ros2 service call <service_name> <service_type>

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

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

相关文章

迅为3588开发板 sudo: 无法解析主机:/DNS配置

环境申明 RK3588 ubuntu 22.04 jammy 迅为开发板 hostname 看是否有Host .&#xff0c;如果没有&#xff0c; sudo vim /etc/hostname在里面加一行&#xff0c;我这就这一个 iTOP-RK3588hosts 修改本地hosts sudo vim /etc/hosts127.0.0.1 localhost localhost iTOP-RK3…

ai人工智能洗稿软件免费有哪些好用?【最新AI洗稿软件盘点】

在当今信息时代&#xff0c;内容创作已成为人们工作和生活中不可或缺的一部分。为了提高创作效率&#xff0c;越来越多的人转向人工智能洗稿软件。本文将专心分享一些优质的免费AI洗稿软件。 免费AI洗稿软件的崛起 免费AI洗稿软件的崛起为许多创作者带来了便利&#xff0c;使他…

贪心算法背包问题c

在背包问题中&#xff0c;贪心算法通常用来解决0-1背包问题&#xff0c;也就是每种物品都有固定数量&#xff0c;你可以选择拿或者不拿&#xff0c;但不可以拿走部分。以下是一个用C语言实现的贪心算法的例子&#xff1a; #include <stdio.h>#define MAX_N 1000#define …

卷王开启验证码后无法登陆问题解决

问题描述 使用 docker 部署&#xff0c;后台设置开启验证&#xff0c;重启服务器之后&#xff0c;docker重启&#xff0c;再次访问系统&#xff0c;验证码获取失败&#xff0c;导致无法进行验证&#xff0c;也就无法登陆系统。 如果不了解卷王的&#xff0c;可以去官网看下。…

从零开始搭建企业管理系统(三):集成 Spring Data Jpa

集成 Spring Data Jpa 什么是 Jpa什么是 Spring Data Jpa什么是 HibernateJPA、Spring Data Jpa、Hibernate 之间的关系集成 Spring Data JpaPOM 依赖配置文件UserEntity启动程序Jpa 配置Jpa 注解UserRepositoryUserServiceUserServiceImplUserControllerBaseEntity 什么是 Jpa…

.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection

文章目录 前言什么是依赖注入C# 使用依赖注入框架介绍 Microsoft.Extensions.DependencyInjectionNuget安装简单单例使用打印结果 自动装配举例自动装配测试用例打印结果自动装配执行顺序测试用例有歧义构造函数渐进式构造函数循环依赖 自动装配结论 手动装配手动注入别名注入 …

ShardingSphere数据分片之分表操作

1、概述 Apache ShardingSphere 是一款分布式的数据库生态系统&#xff0c; 可以将任意数据库转换为分布式数据库&#xff0c;并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 Apache ShardingSphere 设计哲学为 Database Plus&#xff0c;旨在构建异构数据库上…

L1-030:一帮一

题目描述 “一帮一学习小组”是中小学中常见的学习组织方式&#xff0c;老师把学习成绩靠前的学生跟学习成绩靠后的学生排在一组。本题就请你编写程序帮助老师自动完成这个分配工作&#xff0c;即在得到全班学生的排名后&#xff0c;在当前尚未分组的学生中&#xff0c;将名次最…

使用Postman进行自动化集成测试

1 前言 笔者在使用Node开发HTTP接口的过程中&#xff0c;发现当接口数量越来越多&#xff0c;且接口之间互相依赖时&#xff0c;接口测试流程就会变得十分繁琐&#xff0c;且容易出错。那如何才能高效且全面地对接口进行测试呢&#xff1f; 通过实践&#xff0c;笔者发现可以…

程序员的职业连续性就那么重要吗?

大家好&#xff0c;我是风筝&#xff0c;微信搜「古时的风筝」&#xff0c;更多干货 年初的时候时候一个同学跟我聊天说起最近面试的经历。说投了不少简历&#xff0c;但是面试的机会不多&#xff0c;而且有的负责照片的 HR 直接跟他说&#xff1a;“你的工作连续性不达标&…

AI专题报告:AI多模态提升商业化价值,应用多点开花验证景气度

今天分享的AI系列深度研究报告&#xff1a;《AI专题报告&#xff1a;AI多模态提升商业化价值&#xff0c;应用多点开花验证景气度》。 &#xff08;报告出品方&#xff1a;太平洋证券&#xff09; 报告共计&#xff1a;21页 1 一周行情回顾 上周上证综指、深证成指、创业板指…

两个月软考-高项上岸

文章目录 前言结缘软考功亏一篑有始有终2个月计划资料部分计划截图 总结 前言 我们看小说或者电视剧电影都会看到这样的情节&#xff0c;主角一开始锦衣玉食&#xff0c;突然家道中落&#xff0c;啥都没了&#xff0c;主角再一路奋起重新找回了属于自己的一切&#xff1b;还有…

视频汇聚/音视频流媒体视频平台/视频监控EasyCVR分享页面无法播放,该如何解决?

国标GB28181安防视频监控/视频集中存储/云存储EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统…

数据库系统概论期末经典大题讲解(范式提升、求闭包、求主码)

上一次我们介绍了数据库中关系代数查询&#xff0c;从选择、投影到连接等操作符&#xff0c;探索了数据库查询 大家可以移步我的文章&#xff1a;数据库系统概论期末经典大题讲解&#xff08;用关系代数进行查询&#xff09;-CSDN博客 今天&#xff0c;我们将继续沿着数据库系统…

111.am40刷机折腾记4-firefly镜像-dp正常显示

1. 平台&#xff1a; rk3399 am40 4g32g 2. 内核&#xff1a;firefly的内核&#xff08;整体镜像&#xff09; 版本&#xff1a; linux4.4.194 3. 交叉编译工具 &#xff1a;暂时不编译 4. 宿主机&#xff1a;ubuntu18.04 5. 需要的素材和资料&#xff1a;boot-am40-202…

14、SQL注入——HTTP文件头注入

文章目录 一、HTTP Header概述1.1 HTTP工作原理1.2 HTTP报文类型1.3 较重要的HTTP Header内容 二、HTTP Header注入2.1 HTTP Header注入的前提条件2.2 常见的HTTP Header注入类型 一、HTTP Header概述 1.1 HTTP工作原理 1.2 HTTP报文类型 &#xff08;1&#xff09;请求报文 …

CrystalDiskInfo中文版(硬盘检测工具) v9.1.1.0 绿色汉化版-供大家学习研究参考

更新内容 重新支持三星SATA SSD寿命报告 增加对ZHITAI SC001的支持 新增SK hynix Gold S31支持 增加了KLEVV NEO N610的支持。 改进的Micron/Crucial SATA SSD支持 已更改 卸载程序将显示一个确认对话框&#xff0c;用于删除设置。 强大功能 1.拥有多国语言&#xff0c;…

element中el-select多选v-model是对象数组

文章目录 一、问题二、解决三、最后 一、问题 element中的el-select的v-model一般都是字符串或者字符串数组&#xff0c;但是有些时候后端接口要求该字段要传对象或者对象数组&#xff0c;如果再转换一次数据&#xff0c;对于保存配置和回显都是吃力不讨好的事情。如下所示&am…