当前位置: 首页 > news >正文

编写一个简单的服务和客户端(C++)

 

背景

当节点使用服务进行通信时,发送数据请求的节点称为客户端节点,响应请求的节点称为服务节点。请求和响应的结构由.srv文件确定。

这里使用的例子是一个简单的整数加法系统;一个节点请求两个整数之和,另一个节点响应结果。

任务

1 创建包

导航到上一教程ros2_ws中创建的目录。

回想一下,包应该在src目录中创建,而不是在工作区的根目录中。导航到ros2_ws/src并创建一个新包:

ros2 pkg create --build-type ament_cmake cpp_srvcli --dependencies rclcpp example_interfaces

cpp_srvcli您的终端将返回一条消息,验证您的包及其所有必需文件和文件夹的创建。

--dependencies参数将自动将必要的依赖行添加到package.xmlCMakeLists.txt。 是包含.srv 文件的example_interfaces包,您需要构建请求和响应:

int64 a
int64 b
---
int64 sum

前两行是请求的参数,破折号下面是响应。

1.1 更新package.xml

由于您--dependencies在包创建期间使用了该选项,因此无需手动将依赖项添加到package.xmlCMakeLists.txt

不过,与往常一样,请确保将描述、维护者电子邮件和姓名以及许可证信息添加到package.xml.

<description>C++ client server tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>

2 编写服务节点

ros2_ws/src/cpp_srvcli/src目录中,创建一个名为的新文件add_two_ints_server.cpp,并将以下代码粘贴到其中:

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"#include <memory>void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,std::shared_ptr<example_interfaces::srv::AddTwoInts::Response>      response)
{response->sum = request->a + request->b;RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld",request->a, request->b);RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum);
}int main(int argc, char **argv)
{rclcpp::init(argc, argv);std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_server");rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service =node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", &add);RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add two ints.");rclcpp::spin(node);rclcpp::shutdown();
}
2.1 检查代码

前两条#include语句是您的包依赖项。

add函数将请求中的两个整数相加,并将总和提供给响应,同时使用日志通知控制台其状态。

void add(const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,std::shared_ptr<example_interfaces::srv::AddTwoInts::Response>      response)
{response->sum = request->a + request->b;RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Incoming request\na: %ld" " b: %ld",request->a, request->b);RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "sending back response: [%ld]", (long int)response->sum);
}

main函数逐行完成以下任务:

  • 初始化 ROS 2 C++ 客户端库:

    rclcpp::init(argc, argv);
    
  • 创建一个名为 的节点add_two_ints_server

    std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_server");
    
  • 创建一个以add_two_ints该节点命名的服务,并使用以下方法自动在网络上通告它&add

    rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service =
    node->create_service<example_interfaces::srv::AddTwoInts>("add_two_ints", &add);
    
  • 准备好后打印一条日志消息:

    RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Ready to add two ints.");
    
  • 旋转节点,使服务可用。

    rclcpp::spin(node);
    
2.2 添加可执行文件

add_executable宏生成一个可执行文件,您可以使用 运行。添加以下代码块以创建名为 的可执行文件:ros2 runCMakeLists.txtserver

add_executable(server src/add_two_ints_server.cpp)
ament_target_dependencies(server
rclcpp example_interfaces)

因此可以找到可执行文件,将以下行添加到文件末尾之前:ros2 runament_package()

install(TARGETS
  server
  DESTINATION lib/${PROJECT_NAME})

您现在可以构建包,获取本地安装文件并运行它,但我们首先创建客户端节点,以便您可以看到完整的系统在工作。

3 编写客户端节点

ros2_ws/src/cpp_srvcli/src目录中,创建一个名为的新文件add_two_ints_client.cpp,并将以下代码粘贴到其中:

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"#include <chrono>
#include <cstdlib>
#include <memory>using namespace std::chrono_literals;int main(int argc, char **argv)
{rclcpp::init(argc, argv);if (argc != 3) {RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "usage: add_two_ints_client X Y");return 1;}std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_client");rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client =node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();request->a = atoll(argv[1]);request->b = atoll(argv[2]);while (!client->wait_for_service(1s)) {if (!rclcpp::ok()) {RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting.");return 0;}RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again...");}auto result = client->async_send_request(request);// Wait for the result.if (rclcpp::spin_until_future_complete(node, result) ==rclcpp::FutureReturnCode::SUCCESS){RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sum: %ld", result.get()->sum);} else {RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service add_two_ints");}rclcpp::shutdown();return 0;
}
3.1 检查代码

与服务节点类似,以下代码行创建节点,然后为该节点创建客户端:

std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_client");
rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client =node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");

接下来,创建请求。它的结构是由.srv前面提到的文件定义的。

auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
request->a = atoll(argv[1]);
request->b = atoll(argv[2]);

while循环给客户端 1 秒的时间来搜索网络中的服务节点。如果找不到,它将继续等待。

RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "service not available, waiting again...");

如果客户端被取消(例如,通过您进入Ctrl+C终端),它将返回一条错误日志消息,表明它被中断。

RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Interrupted while waiting for the service. Exiting.");return 0;

然后客户端发送请求,节点旋转直到收到响应或失败。

3.2 添加可执行文件

返回CMakeLists.txt为新节点添加可执行文件和目标。从自动生成的文件中删除一些不必要的样板后,您的文件CMakeLists.txt应该如下所示:

cmake_minimum_required(VERSION 3.5)
project(cpp_srvcli)find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(example_interfaces REQUIRED)add_executable(server src/add_two_ints_server.cpp)
ament_target_dependencies(server
  rclcpp example_interfaces)add_executable(client src/add_two_ints_client.cpp)
ament_target_dependencies(client
  rclcpp example_interfaces)install(TARGETS
  server
  client
  DESTINATION lib/${PROJECT_NAME})ament_package()

4 构建并运行

在构建之前,最好rosdep在工作区的根目录 ( ros2_ws) 中运行以检查是否缺少依赖项:

Linux苹果系统视窗
rosdep install -i --from-path src --rosdistro galactic -y

导航回工作区的根目录,ros2_ws并构建新包:

Linux苹果系统视窗
colcon build --packages-select cpp_srvcli

打开一个新终端,导航到ros2_ws并获取安装文件:

Linux苹果系统视窗
. install/setup.bash

现在运行服务节点:

ros2 run cpp_srvcli server

终端应返回以下消息,然后等待:

[INFO] [rclcpp]: Ready to add two ints.

打开另一个终端,再次从内部获取安装文件ros2_ws。启动客户端节点,后跟任意两个以空格分隔的整数:

ros2 run cpp_srvcli client 2 3

例如,如果您选择23,客户端将收到如下响应:

[INFO] [rclcpp]: Sum: 5

返回到运行服务节点的终端。您将看到它在收到请求和收到的数据以及发回的响应时发布了日志消息:

[INFO] [rclcpp]: Incoming request
a: 2 b: 3
[INFO] [rclcpp]: sending back response: [5]

在服务器终端中输入Ctrl+C以停止节点旋转。

相关文章:

编写一个简单的服务和客户端(C++)

背景 当节点使用服务进行通信时&#xff0c;发送数据请求的节点称为客户端节点&#xff0c;响应请求的节点称为服务节点。请求和响应的结构由.srv文件确定。 这里使用的例子是一个简单的整数加法系统&#xff1b;一个节点请求两个整数之和&#xff0c;另一个节点响应结果。 …...

InseRF: 文字驱动的神经3D场景中的生成对象插入

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

类厂,变长参数,序列化

目的 在记录nav2中的各类信息,保存到文件中,以便后面回放来分析算法的编程中发现。 各种信息记录的数据不同,可能还会有变化,所以决定采用类厂模式,参见C++设计模式入门 记录的基类 有个信息记录的基类,不同的记录对应不同的子类。 enum rcdType{RT_NA,RT_nav2Info,R…...

LLK的2023年度总结

文章目录 一月二月三月四月五月六月七月八月九月十月十一月十二月 一月 此时的俺还在沉浸在蓝桥杯的练习和女朋友的甜蜜期&#xff0c;感觉没啥大长进。然后荣幸地知道了自己C语言实验因为某种非技术原因而挂科了。此时自己地目标由保研自然地转换到考研比赛就业的方向了。接着…...

Redis-浅谈redis.conf配置文件

Redis.conf Redis.conf是Redis的配置文件&#xff0c;它包含了一系列用于配置Redis服务器行为和功能的选项。 以下是Redis.conf中常见的一些选项配置&#xff1a; bind: 指定Redis服务器监听的IP地址&#xff0c;默认为127.0.0.1&#xff0c;表示只能本地访问&#xff0c;可以…...

【liunx】线程池+单例模式+STL,智能指针和线程安全+其他常见的各种锁+读者写者问题

线程池单例模式STL,智能指针和线程安全其他常见的各种锁读者写者问题 1.线程池2.线程安全的单例模式3.STL,智能指针和线程安全4.其他常见的各种锁4.读者写者问题 喜欢的点赞&#xff0c;收藏&#xff0c;关注一下把&#xff01; 1.线程池 目前我们学了挂起等待锁、条件变量、信…...

Golang的API项目快速开始

开启一个简单的API服务。 golang的教程网上一大堆&#xff0c;官网也有非常详细的教程&#xff0c;这里不在赘述这些基础语法教程&#xff0c;我们意在快速进入项目开发阶段。 golang好用语法教程传送门&#xff1a; m.runoob.com/go/ 编写第一个API 前提&#xff1a;按照上一…...

机器学习_实战框架

文章目录 介绍机器学习的实战框架1.定义问题2.收集数据和预处理(1).收集数据(2).数据可视化(3).数据清洗(4).特征工程(5).构建特征集和标签集(6).拆分训练集、验证集和测试集。 3.选择算法并建立模型4.训练模型5.模型的评估和优化 介绍机器学习的实战框架 一个机器学习项目从开…...

Java8常用新特性

目录 简介 1.默认方法 2..Lambda表达式 3.Stream API 4.方法引用 5.Optional类 简介 Java 8是Java编程语言的一个重要版本&#xff0c;引入了许多令人兴奋和强大的新特性。这些特性使得Java程序更加现代化、灵活和高效。让我们一起来探索一些Java 8的常用新特性吧&#…...

Go语言中的Channel

1. 简介 Channel是Go语言中一种重要的并发原语&#xff0c;它允许goroutine之间安全地交换数据。Channel是一个类型化的队列&#xff0c;它可以存储一个特定类型的值。goroutine可以通过发送和接收操作来向channel中写入和读取数据。 2. Channel的类型 Channel的类型由其元素…...

Unity中URP下实现深度贴花

文章目录 前言一、场景设置二、实现思路1、通过深度图求出像素所在视图空间的Z值2、通过模型面片的求出像素在观察空间下的坐标值3、结合两者求出 深度图中像素的 XYZ值4、再将此坐标转换到模型的本地空间&#xff0c;把XY作为UV来进行纹理采样 三、URP下实现1、通过深度图求出…...

openssl3.2 - 官方demo学习 - cipher - aesccm.c

文章目录 openssl3.2 - 官方demo学习 - cipher - aesccm.c概述笔记END openssl3.2 - 官方demo学习 - cipher - aesccm.c 概述 aesccm.c 是 AES-192-CCM 的加解密应用例子, 用的EVP接口. 看到不仅仅要用到key, iv, data, 在此之前还要设置 nonce, tag, 认证数据. 为啥需要设置…...

点云从入门到精通技术详解100篇-基于多传感器融合的智能汽车 环境感知(下)

目录 基于激光雷达点云的目标检测 4.1 点云神经网络检测模型 4.2 点云预处理...

蓝桥杯单片机组备赛——蜂鸣器和继电器的基本控制

文章目录 一、蜂鸣器和继电器电路介绍二、题目与答案2.1 题目2.2 答案2.3 重点函数解析 一、蜂鸣器和继电器电路介绍 可以发现两个电路一端都接着VCC&#xff0c;所以我们只要给另一端接上低电平就可以让蜂鸣器和继电器进行工作。与操作LED类似&#xff0c;只不过换了一个74HC5…...

嵌入式linux 编译qt5(以v851s为例)

本文参考Blev大神的博客&#xff1a;Yuzuki Lizard V851S开发板 --移植 QT5.12.9教程&#xff08;群友Blev提供&#xff09; - Allwinner / 柚木PI-V851S - 嵌入式开发问答社区 (100ask.net) 一. 环境准备 1.下载qt5源码&#xff1a;Open Source Development | Open Source …...

uniapp 实战 -- app 的自动升级更新(含生成 app 发布页)

uniapp 提供了 App升级中心 uni-upgrade-center &#xff0c;可以便捷实现app 的自动升级更新&#xff0c;具体编码和配置如下&#xff1a; 1. 用户端 – 引入升级中心插件 下载安装插件 uni-upgrade-center - App https://ext.dcloud.net.cn/plugin?id4542 pages.json 中添加…...

微服务http调用其他服务的方法

在对应需要调的服务配置文件加上路径 #审批方案微服务配置 server.port: 9004 upload.path: /alldev/u01/ schedule.cron.countDown: 0 0 8-18 * * ? statistics.syskey: ywsp schedule.countDown.isExecute: true post.url.updateStatus: http://10.3.2.222:8888/ecological…...

vagrant 用户名密码登录

正常登录后 sudo -i 切换到root权限 vim /etc/ssh/vim sshd_config 将PasswordAuthentication no设置 为yes 重启sshd.service服务 systemctl restart sshd.service...

强化学习应用(三):基于Q-learning的无人机物流路径规划研究(提供Python代码)

一、Q-learning简介 Q-learning是一种强化学习算法&#xff0c;用于解决基于马尔可夫决策过程&#xff08;MDP&#xff09;的问题。它通过学习一个价值函数来指导智能体在环境中做出决策&#xff0c;以最大化累积奖励。 Q-learning算法的核心思想是通过不断更新一个称为Q值的…...

探索SQL性能优化之道:实用技巧与最佳实践

SQL性能优化可能是每个数据库管理员和开发者在日常工作中必不可少的一个环节。在大数据时代&#xff0c;为确保数据库系统的响应速度和稳定性&#xff0c;掌握一些实用的SQL优化技巧至关重要。 本文将带着开发人员走进SQL性能优化的世界&#xff0c;深入剖析实用技巧和最佳实践…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4&#xff0c;后7...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

在Zenodo下载文件 用到googlecolab googledrive

方法&#xff1a;Figshare/Zenodo上的数据/文件下载不下来&#xff1f;尝试利用Google Colab &#xff1a;https://zhuanlan.zhihu.com/p/1898503078782674027 参考&#xff1a; 通过Colab&谷歌云下载Figshare数据&#xff0c;超级实用&#xff01;&#xff01;&#xff0…...

标注工具核心架构分析——主窗口的图像显示

&#x1f3d7;️ 标注工具核心架构分析 &#x1f4cb; 系统概述 主要有两个核心类&#xff0c;采用经典的 Scene-View 架构模式&#xff1a; &#x1f3af; 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 &#x1f527; 关键函数&…...