ROS2动作通信的实现

文章目录

  • 1.动作通信的概念及应用场景
    • 1.1 概念
    • 1.2 应用场景
  • 2.准备工作
  • 3.动作通信的实现
    • 3.1 动作通信接口消息
    • 3.2 服务端实现
    • 3.3 客户端实现
    • 3.4 编译及运行


1.动作通信的概念及应用场景

1.1 概念

动作通信适用于长时间运行的任务。就结构而言动作通信由目标、反馈和结果三部分组成;就功能而言动作通信类似于服务通信,动作客户端可以发送请求到动作服务端,并接收动作服务端响应的最终结果,不过动作通信可以在请求响应过程中获取连续反馈,并且也可以向动作服务端发送任务取消请求;就底层实现而言动作通信是建立在话题通信和服务通信之上的,目标发送实现是对服务通信的封装,结果的获取也是对服务通信的封装,而连续反馈则是对话题通信的封装。

在这里插入图片描述

1.2 应用场景

机器人导航到某个目标点,此过程需要一个节点A发布目标信息,然后一个节点B接收到请求并控制移动,最终响应目标达成状态信息。

其感觉很像是服务通信的过程
因为需求中要A发送目标,B执行并返回结果,这是一个典型的基于请求响应的应答模式,不过,如果只是使用基本的服务通信实现,存在一个问题:
导航是一个过程,是耗时操作,如果使用服务通信,那么只有在导航结束时,才会产生响应结果,而在导航过程中,节点A是不会获取到任何反馈的,从而可能出现程序"假死"的现象,过程的不可控意味着不良的用户体验,以及逻辑处理的缺陷(比如:导航中止的需求无法实现)。
更合理的方案应该是:导航过程中,可以连续反馈当前机器人状态信息,当导航终止时,再返回最终的执行结果。

一般适用于耗时的请求响应场景,用以获取连续的状态反馈。
提示:这里对文章进行总结:

2.准备工作

老样子:
在这里插入图片描述

3.动作通信的实现

3.1 动作通信接口消息

在这里插入图片描述

3.2 服务端实现

需求:编写动作通信,动作客户端提交一个整型数据N,动作服务端接收请求数据并累加1-N之间的所有整数,将最终结果返回给动作客户端,且每累加一次都需要计算当前运算进度并反馈给动作客户端。

// 1.包含头文件;
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "base_interfaces_demo/action/progress.hpp"
using namespace std::placeholders;
using base_interfaces_demo::action::Progress;
using GoalHandleProgress = rclcpp_action::ServerGoalHandle<Progress>;// 3.定义节点类;
class MinimalActionServer : public rclcpp::Node
{
public:
explicit MinimalActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())  
: Node("minimal_action_server", options)
{    
// 3-1.创建动作服务端;  
this->action_server_ = rclcpp_action::create_server<Progress>(      this,      "get_sum",      std::bind(&MinimalActionServer::handle_goal, this, _1, _2),      std::bind(&MinimalActionServer::handle_cancel, this, _1),      std::bind(&MinimalActionServer::handle_accepted, this, _1));    
RCLCPP_INFO(this->get_logger(),"动作服务端创建,等待请求...");  
}private:  
rclcpp_action::Server<Progress>::SharedPtr action_server_;  
// 3-2.处理请求数据;  
rclcpp_action::GoalResponse handle_goal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Progress::Goal> goal)  
{    
(void)uuid;    
RCLCPP_INFO(this->get_logger(), "接收到动作客户端请求,请求数字为 %ld", goal->num);    
if (goal->num < 1) {      return rclcpp_action::GoalResponse::REJECT;    
}   
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;  
}  // 3-3.处理取消任务请求;  
rclcpp_action::CancelResponse handle_cancel(    const std::shared_ptr<GoalHandleProgress> goal_handle)  
{    (void)goal_handle;    RCLCPP_INFO(this->get_logger(), "接收到任务取消请求");    return rclcpp_action::CancelResponse::ACCEPT;  
}  void execute(const std::shared_ptr<GoalHandleProgress> goal_handle)  
{    
RCLCPP_INFO(this->get_logger(), "开始执行任务");    
rclcpp::Rate loop_rate(10.0);    
const auto goal = goal_handle->get_goal();    
auto feedback = std::make_shared<Progress::Feedback>();    
auto result = std::make_shared<Progress::Result>();    
int64_t sum= 0;    for (int i = 1; (i <= goal->num) && rclcpp::ok(); i++) {      sum += i;      // Check if there is a cancel request      if (goal_handle->is_canceling()) {        result->sum = sum;        goal_handle->canceled(result);        RCLCPP_INFO(this->get_logger(), "任务取消");        return;      }      feedback->progress = (double_t)i / goal->num;      goal_handle->publish_feedback(feedback);      RCLCPP_INFO(this->get_logger(), "连续反馈中,进度:%.2f", feedback->progress);      loop_rate.sleep();    } if (rclcpp::ok()) { 
result->sum = sum; 
goal_handle->succeed(result);
RCLCPP_INFO(this->get_logger(), "任务完成!");
}
}// 3-4.生成连续反馈。  void handle_accepted(const std::shared_ptr<GoalHandleProgress> goal_handle)
{
std::thread{std::bind(&MinimalActionServer::execute, this, _1), goal_handle}.detach();
}
};int main(int argc, char ** argv)
{
// 2.初始化 ROS2 客户端;  
rclcpp::init(argc, argv);
// 4.调用spin函数,并传入节点对象指针;  
auto action_server = std::make_shared<MinimalActionServer>();
rclcpp::spin(action_server);
// 5.释放资源。  
rclcpp::shutdown();
return 0;
} 

3.3 客户端实现

需求:编写动作客户端实现,可以提交一个整型数据到服务端,并处理服务端的连续反馈以及最终返回结果。

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "base_interfaces_demo/action/progress.hpp"
using base_interfaces_demo::action::Progress;
using GoalHandleProgress = rclcpp_action::ClientGoalHandle<Progress>;
using namespace std::placeholders;// 3.定义节点类;
class MinimalActionClient : public rclcpp::Node
{
public:  
explicit MinimalActionClient(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())  
: Node("minimal_action_client", node_options)  
{    // 3-1.创建动作客户端;    this->client_ptr_ = rclcpp_action::create_client<Progress>(this,"get_sum");    }  // 3-2.发送请求;  void send_goal(int64_t num)  {      if (!this->client_ptr_) {    RCLCPP_ERROR(this->get_logger(), "动作客户端未被初始化。");    }    if (!this->client_ptr_->wait_for_action_server(std::chrono::seconds(10))) {      RCLCPP_ERROR(this->get_logger(), "服务连接失败!");      return;    }    auto goal_msg = Progress::Goal();    goal_msg.num = num;    RCLCPP_INFO(this->get_logger(), "发送请求数据!");    auto send_goal_options = rclcpp_action::Client<Progress>::SendGoalOptions();        send_goal_options.goal_response_callback =std::bind(&MinimalActionClient::goal_response_callback, this, _1);    send_goal_options.feedback_callback =std::bind(&MinimalActionClient::feedback_callback, this, _1, _2);    send_goal_options.result_callback =std::bind(&MinimalActionClient::result_callback, this, _1);    auto goal_handle_future = this->client_ptr_->async_send_goal(goal_msg, send_goal_options);  
}private:
rclcpp_action::Client<Progress>::SharedPtr client_ptr_;// 3-3.处理目标发送后的反馈;  
void goal_response_callback(GoalHandleProgress::SharedPtr goal_handle)  
{    
if (!goal_handle) 
{    RCLCPP_ERROR(this->get_logger(), "目标请求被服务器拒绝!");    } else {     RCLCPP_INFO(this->get_logger(), "目标被接收,等待结果中");    }  
}  // 3-4.处理连续反馈;  
void feedback_callback(GoalHandleProgress::SharedPtr,const std::shared_ptr<const Progress::Feedback> feedback)  
{    int32_t progress = (int32_t)(feedback->progress * 100);      RCLCPP_INFO(this->get_logger(), "当前进度: %d%%", progress);  }// 3-5.处理最终响应。  
void result_callback(const GoalHandleProgress::WrappedResult & result)  
{    switch (result.code) {  case rclcpp_action::ResultCode::SUCCEEDED:        break;      case rclcpp_action::ResultCode::ABORTED:      RCLCPP_ERROR(this->get_logger(), "任务被中止");        return;      case rclcpp_action::ResultCode::CANCELED:        RCLCPP_ERROR(this->get_logger(), "任务被取消");        return;      default:        RCLCPP_ERROR(this->get_logger(), "未知异常");        return;  }    RCLCPP_INFO(this->get_logger(), "任务执行完毕,最终结果: %d", result.result->sum);  }
};int main(int argc, char ** argv)
{  
// 2.初始化 ROS2 客户端;  
rclcpp::init(argc, argv);  
// 4.调用spin函数,并传入节点对象指针;  
auto action_client = std::make_shared<MinimalActionClient>();  
action_client->send_goal(10);  
rclcpp::spin(action_client);
// 5.释放资源。  
rclcpp::shutdown();
return 0;
} 

3.4 编译及运行

CMakeLists怎么该就不说了,前面两个已经说得很清楚了!

colcon build --packages-select cpp03_action  编译

在这里插入图片描述

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

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

相关文章

吴恩达机器学习-可选实验室:可选实验:使用逻辑回归进行分类(Classification using Logistic Regression)

在本实验中&#xff0c;您将对比回归和分类。 import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_common import dlc, plot_data from plt_one_addpt_onclick import plt_one_addpt_onclick plt.style.use(./deeplearning.mplstyle)jupy…

第三百九十二回

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何混合选择多个图片和视频文件"相关的内容&#xff0c;本章回中将介绍如何通过相机获取图片文件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. …

JavaWeb--Maven

一&#xff1a;概述 1.简介 Maven 是专门用于管理和构建 Java 项目的工具&#xff0c;它的主要功能有&#xff1a; 提供了一套标准化的项目结构 提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布 …… &#xff09; 提供了一套…

Minio搭建文件服务器

目录 一、Minio使用&#x1f355;1.1 Minio介绍1.2 Minio安装1.3 Minio入门 二、创建后端服务&#x1f953;2.1创建一个SpringBoot项目2.2 代码实现2.2.1 FileUploadController2.3.2 FileUploadService2.3.3 MinioProperties2.3.4 MinioServerApplication2.2.4 配置文件内容 三…

如何使用固定公网地址SFTP远程传输文件至安卓Termux本地目录?

文章目录 1. 安装openSSH2. 安装cpolar3. 远程SFTP连接配置4. 远程SFTP访问4. 配置固定远程连接地址 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一种基于SSH&#xff08;Secure Shell&#xff09;安全协议的文件传输协议。与FTP协议相比&#xff0c;SFTP使用了…

misc40

下载附件&#xff0c;发现只有第三个wav文件需要密码&#xff0c;其他都可以看 打开 conversion.txt 二进制转十进制得到202013 开 一张普通的二维码.png&#xff0c;直接扫不出结果。 010查看图片尾部发现 Brainfuck 编码 解码得到&#xff1a; 和谐民主和谐文明和谐和谐和谐…

数据分析-Pandas数据分组箱线图

数据分析-Pandas数据分组箱线图 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&#x…

在垃圾回收时哪些可以作为垃圾回收的根对象?

1.System.class 由启动类加载器加载的类&#xff0c;一些核心的类&#xff0c;不如说 2.Native Stack java虚拟机在执行方法调用时必须执行操作系统方法&#xff0c;操作系统方法执行时所引用的一些java对象。 3.Thread 活动线程所引用的一些对象。 4.Busy monitor 被同…

深度学习-Softmax 回归 + 损失函数 + 图片分类数据集

Softmax 回归 损失函数 图片分类数据集 1 softmax2 损失函数1均方L1LossHuber Loss 3 图像分类数据集4 softmax回归的从零开始实现 1 softmax Softmax是一个常用于机器学习和深度学习中的激活函数。它通常用于多分类问题&#xff0c;将一个实数向量转换为概率分布。Softmax函…

Spring Boot 自动装配的原理!!!

SpringBootApplication SpringBootConfiguration&#xff1a;标识启动类是一个IOC容器的配置类 EnableAutoConfiguration&#xff1a; AutoConfigurationPackage&#xff1a;扫描启动类所在包及子包中所有的组件&#xff0c;生…

C++特殊类设计【特殊类 || 单例对象 || 饿汉模式 || 懒汉模式】

目录 一&#xff0c;特殊类设计 1. 只在堆上创建的类 2. 只允许在栈上创建的类 3. 不能被继承的类 4. 不能被拷贝的类 5. 设计一个类&#xff0c;只能创建一个对象&#xff08;单例对象&#xff09; 饿汉模式 懒汉模式 C11静态成员初始化多线程安全问题 二&#xff…

linux安装ngnix完整步骤(支持centos/银河麒麟操作系统)

linux安装ngnix&#xff08;支持centos/银河麒麟操作系统&#xff09; 本次操作系统安装ngnix采用离线或在线安装方式&#xff0c;离线就是不联网环境&#xff0c;在线则是联网环境&#xff1b;支持centos7或centos8或国产操作系统&#xff08;银河麒麟高级服务器操作系统&…

element-ui radio 组件源码分享

今日简单分享 radio 组件的实现原理&#xff0c;主要从以下三个方面来分享&#xff1a; 1、radio 页面结构 2、radio 组件属性 3、radio 组件方法 一、radio 页面结构 1.1 页面结构如下&#xff1a; 二、radio 属性 2.1 value / v-model 属性&#xff0c;类型为 string / …

鲜为人知的闰年判定大坑

【题目描述】 输入年份&#xff0c;判断是否为闰年。如果是&#xff0c;则输出yes&#xff0c;否则输出no。 提示&#xff1a;简单地判断除以4的余数是不够的。 【题目来源】 刘汝佳《算法竞赛入门经典 第2版》习题1-7 年份&#xff08;year&#xff09; 【解析】 一、闰…

Decontam去污染:一个尝试

为了程序运行的便利性&#xff0c;不想将Decontam放到windows的Rstudio里面运行&#xff0c;需要直接在Ubuntu中运行&#xff0c;并且为了在Decontam时进行其他操作&#xff0c;使用python去运行R 首先你需要有一个conda环境&#xff0c;安装了R&#xff0c;Decontam&#xff0…

云计算的部署方式(公有云、私有云、混合云、社区云)

云计算的部署方式(公有云、私有云、混合云、社区云) 目录 零、00时光宝盒 一、云计算的部署方式 1.1、公有云&#xff08;Public Cloud&#xff09; 1.2、私有云&#xff08;Private Cloud&#xff09;  1.3、混合云&#xff08;Hybrid Cloud&#xff09; 1.4、社区云&am…

【C++】list模拟实现list迭代器失效问题

list模拟实现&list迭代器失效问题 一&#xff0c;list模拟实现1. list的主要框架接口模拟2. list构造&拷贝构造&析构3. list迭代器3.1 普通迭代器3.2 const迭代器 4. 增删查改 二&#xff0c;迭代器失效问题1. list的迭代器失效原因2. 解决办法 一&#xff0c;list…

Java 汇编源码查看环境搭建

目录 一、简介 二、在IDEA开发环境中搭建汇编环境 2.1 在IDEA中搭建字节码查看环境 2.1.1 搭建步骤 2.1.1.1 第一步 2.1.1.2 第二步 2.1.1.3 第三步 2.1.1.4 第四步 2.1.2 验证 2.2 在IDEA开发环境中搭建汇编代码查看环境 2.2.2 配置HSDIS插件 2.2.3 验证HSDIS插件是…

[虚拟机保护逆向] [HGAME 2023 week4]vm

[虚拟机保护逆向] [HGAME 2023 week4]vm 虚拟机逆向的注意点&#xff1a;具体每个函数的功能&#xff0c;和其对应的硬件编码的*长度* 和 *含义*&#xff0c;都分析出来后就可以编写脚本将题目的opcode转化位vm实际执行的指令 &#xff1a;分析完成函数功能后就可以编写脚本输出…

深度学习在硬件和计算平台上的优化:实现更快、更高效的突破

引言 深度学习&#xff0c;作为机器学习领域的一个子集&#xff0c;通过模拟人脑神经元的连接方式&#xff0c;构建复杂的网络结构来处理和分析数据。然而&#xff0c;随着深度学习模型规模的不断扩大和复杂度的提高&#xff0c;其对计算资源的需求也呈指数级增长。因此&#…