ROS2 通信三大件之动作 -- Action

news2024/11/24 15:50:33

通信最后一个,也是不太容易理解的方式action,复杂且重要

1、创建action数据结构

创建工作空间和模块就不多说了

在模块  src/action_moudle/action/Counter.action  下创建文件 Counter.action

int32 target  # Goal: 目标 
---
int32 current_value  # Result: 结果
---
int32[] sequence  # Feedback: 中间状态反馈

需要注意的是 这几个值不要搞混,结果和中间状态容易搞错

添加依赖:src/action_moudle/package.xml

  <depend>rclcpp_action</depend> 

  <depend>rosidl_default_generators</depend>
  <depend>rosidl_default_runtime</depend>

  <member_of_group>rosidl_interface_packages</member_of_group>

src/action_moudle/CMakeLists.txt

find_package(rosidl_default_generators REQUIRED)
find_package(rclcpp_action REQUIRED)


# 设置消息和服务文件路径
set(action_FILES
  "action/Counter.action"
)

# 添加消息和服务生成目标
rosidl_generate_interfaces(${PROJECT_NAME}
  ${action_FILES}
  DEPENDENCIES std_msgs
)

# 安装 Action 文件
install(DIRECTORY action/
  DESTINATION share/${PROJECT_NAME}/action
)

编译后生成install/action_moudle/include/action_moudle/action_moudle/action/counter.hpp

至此action文件生成

2、编写Count计时的Action服务端和客户端代码

AI生成的代码靠不住,改了很多才编译过

src/action_moudle/src/action_server.cpp

#include "rclcpp/rclcpp.hpp"
#include "action_moudle/action/counter.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include <memory>
#include <vector>

using Counter = action_moudle::action::Counter;
using namespace std::placeholders;

class CounterActionServer : public rclcpp::Node
{
public:
    CounterActionServer() : Node("counter_action_server")
    {
        action_server_ =
            rclcpp_action::create_server<Counter>(this, "counter", std::bind(&CounterActionServer::handle_goal, this, _1, _2),
                                                  std::bind(&CounterActionServer::handle_cancel, this, _1), std::bind(&CounterActionServer::handle_accepted, this, _1));
    }

private:
    rclcpp_action::Server<Counter>::SharedPtr action_server_;

    rclcpp_action::GoalResponse handle_goal(const rclcpp_action::GoalUUID& uuid, std::shared_ptr<const Counter::Goal> goal)
    {
        (void)uuid;
        RCLCPP_INFO(this->get_logger(), "Received goal request with target: %ld", goal->target);
        return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
    }

    rclcpp_action::CancelResponse handle_cancel(const std::shared_ptr<rclcpp_action::ServerGoalHandle<Counter>> goal_handle)
    {
        RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
        return rclcpp_action::CancelResponse::ACCEPT;
    }

    void handle_accepted(const std::shared_ptr<rclcpp_action::ServerGoalHandle<Counter>> goal_handle)
    {
        using namespace std::placeholders;
        std::thread{std::bind(&CounterActionServer::execute, this, _1), goal_handle}.detach();
    }

    void execute(const std::shared_ptr<rclcpp_action::ServerGoalHandle<Counter>> goal_handle)
    {
        RCLCPP_INFO(this->get_logger(), "Executing goal");
        rclcpp::Rate loop_rate(1);
        const auto   goal     = goal_handle->get_goal();
        auto         feedback = std::make_shared<Counter::Feedback>();
        auto         result   = std::make_shared<Counter::Result>();

        result->current_value = 0;
        feedback->sequence.push_back(0);

        if (goal_handle->is_canceling())
        {
            goal_handle->canceled(result);
            RCLCPP_INFO(this->get_logger(), "Goal canceled");
            return;
        }
        goal_handle->publish_feedback(feedback);

        for (int i = 1; i <= goal->target; ++i)
        {
            result->current_value = i;
            feedback->sequence.push_back(i);
            if (goal_handle->is_canceling())
            {
                goal_handle->canceled(result);
                RCLCPP_INFO(this->get_logger(), "Goal canceled");
                return;
            }
            goal_handle->publish_feedback(feedback);
            loop_rate.sleep();
        }

        goal_handle->succeed(result);
        RCLCPP_INFO(this->get_logger(), "Returning result");
    }
};

int main(int argc, char* argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<CounterActionServer>());
    rclcpp::shutdown();
    return 0;
}

src/action_moudle/src/action_client.cpp

#include "rclcpp/rclcpp.hpp"
#include "action_moudle/action/counter.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include <memory>

using Counter = action_moudle::action::Counter;
using namespace std::placeholders;

class CounterActionClient : public rclcpp::Node
{
public:
    CounterActionClient() : Node("counter_action_client")
    {
        action_client_ = rclcpp_action::create_client<Counter>(this, "counter");

        while (!action_client_->wait_for_action_server())
        {
            if (!rclcpp::ok())
            {
                RCLCPP_ERROR(this->get_logger(), "Interrupted while waiting for the action server. Exiting.");
                return;
            }
            RCLCPP_INFO(this->get_logger(), "Action server not available, waiting again...");
        }

        auto goal   = Counter::Goal();
        goal.target = 10;

        auto send_goal_options                   = rclcpp_action::Client<Counter>::SendGoalOptions();
        send_goal_options.goal_response_callback = std::bind(&CounterActionClient::goal_response_callback, this, std::placeholders::_1);
        send_goal_options.feedback_callback      = std::bind(&CounterActionClient::feedback_callback, this, std::placeholders::_1, std::placeholders::_2);
        send_goal_options.result_callback        = std::bind(&CounterActionClient::result_callback, this, std::placeholders::_1);

        action_client_->async_send_goal(goal, send_goal_options);
    }

private:
    rclcpp_action::Client<Counter>::SharedPtr action_client_;

    void goal_response_callback(rclcpp_action::ClientGoalHandle<Counter>::SharedPtr goal_handle)
    {
        if (!goal_handle)
        {
            RCLCPP_INFO(this->get_logger(), "Goal rejected");
        }
        else
        {
            RCLCPP_INFO(this->get_logger(), "Goal accepted");
        }
    }
    // void goal_response_callback(std::shared_future<std::shared_ptr<rclcpp_action::ClientGoalHandle<Counter>>> future)
    // {
    //     auto goal_handle = future.get();
    //     if (!goal_handle)
    //     {
    //         RCLCPP_INFO(this->get_logger(), "Goal rejected");
    //     }
    //     else
    //     {
    //         RCLCPP_INFO(this->get_logger(), "Goal accepted");
    //     }
    // }

    void feedback_callback(std::shared_ptr<rclcpp_action::ClientGoalHandle<Counter>>, const std::shared_ptr<const Counter::Feedback> feedback)
    {
        // RCLCPP_INFO(this->get_logger(), "Current value: %ld", feedback->current_value);
        RCLCPP_INFO(this->get_logger(), "Sequence value: %s", print_sequence(feedback->sequence).c_str());
    }

    void result_callback(const rclcpp_action::ClientGoalHandle<Counter>::WrappedResult& result)
    {
        switch (result.code)
        {
            case rclcpp_action::ResultCode::SUCCEEDED:
                RCLCPP_INFO(this->get_logger(), "Result: %d", result.result->current_value);
                break;
            case rclcpp_action::ResultCode::ABORTED:
                RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
                break;
            case rclcpp_action::ResultCode::CANCELED:
                RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
                break;
            default:
                RCLCPP_ERROR(this->get_logger(), "Unknown result code");
                break;
        }
        rclcpp::shutdown();
    }

    std::string print_sequence(const std::vector<int32_t>& sequence)
    {
        std::stringstream ss;
        ss << "[";
        for (size_t i = 0; i < sequence.size(); ++i)
        {
            if (i > 0)
            {
                ss << ", ";
            }
            ss << sequence[i];
        }
        ss << "]";
        return ss.str();
    }
};

int main(int argc, char* argv[])
{
    rclcpp::init(argc, argv);
    rclcpp::spin(std::make_shared<CounterActionClient>());
    rclcpp::shutdown();
    return 0;
}

src/action_moudle/CMakeLists.txt  添加

find_package(action_moudle REQUIRED)
find_package(rclcpp_action REQUIRED)

# 创建可执行文件
add_executable(action_server src/action_server.cpp)
ament_target_dependencies(action_server rclcpp std_msgs action_moudle rclcpp_action)

add_executable(action_client src/action_client.cpp)
ament_target_dependencies(action_client rclcpp std_msgs action_moudle rclcpp_action)

# 安装目标
install(TARGETS
  action_server action_client
  DESTINATION lib/${PROJECT_NAME}
)

3、编译后测试

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

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

相关文章

[Python学习日记-45] Python 中模块的介绍与导入

[Python学习日记-45] Python 中模块的介绍与导入 简介 模块的概念与好处 模块的分类 模块导入和调用 自定义模块 模块的查找路径 简介 在前面的学习当中偶尔我们会看到 import ... 一个什么东西的&#xff0c;或者 from ... import ...&#xff0c;那时候并没有进行介绍&…

react+ts+vite 别名一直爆红问题

已经配置如下代码安装了types/node import path from "path"; // https://vitejs.dev/config/ export default defineConfig({plugins: [react()],server: {proxy: {"/api": {target: "http://localhost:3000",changeOrigin: true,rewrite: (pa…

如何选择安全的谷歌浏览器插件

在数字时代&#xff0c;浏览器插件为我们提供了极大的便利&#xff0c;增强了我们的浏览体验。然而&#xff0c;随着便利性的增加&#xff0c;安全性问题也日益凸显。选择安全的谷歌浏览器插件是保障个人信息安全的重要步骤。以下是详细的教程&#xff0c;帮助你选择和使用安全…

81 NAT-静态NAT

一 NAT 出口方向实验 1 配置接口的IP地址 2 配置nat 静态映射 3 测试 无法ping 通 202.38.1.100 4 接口上开启静态Nat映射规则 [FW-Router-BJ-GigabitEthernet0/1]nat static enable 6 5 查看配置 [FW-Router-BJ]display nat static 6 测试 7 查看NAT 会话状态 8 静态…

Qt自定义一个圆角对话框

如何得到一个圆角对话框&#xff1f; 步骤&#xff1a; 1、继承自QDiaglog 2、去掉系统自带的边框 3、设置背景透明,不设置4个角会有多余的部分出现颜色 4、对话框内部添加1个QWidget&#xff0c;给这个widget设置圆角&#xff0c;并添加到布局中让他充满对话框 5、后续对…

Redis协议详解及其异步应用

目录 一、Redis Pipeline&#xff08;管道&#xff09;概述优点使用场景工作原理Pipeline 的基本操作步骤C 示例&#xff08;使用 [hiredis](https://github.com/redis/hiredis) 库&#xff09; 二、Redis 事务概述事务的前提事务特征&#xff08;ACID 分析&#xff09;WATCH 命…

【HarmonyOS】HMRouter使用详解(二)路由跳转

路由跳转 HMRouter中使用HMRouterMgr的静态方法push()和replace()来实现路由跳转。使用pop()方法来实现页面返回 push &#xff1a;目标页面不会替换当前页&#xff0c;而是插入页面栈。可以使用pop实现页面的返回操作。replace&#xff1a;目标页面会替换当前页&#xff0c;并…

西门子828d的plc一些信息记录

1、虽然是200的plc但是引入了DB的形式替代原来的V存储区。 2、用户自定义DB块范围&#xff0c;DB9000-DB9063,共64个DB块。 可用地址范围如上图 机床MCP483面板地址表&#xff0c;其它类型的面板地址自己在828d简明调试手册里查看。 如何上载828d的plc程序&#xff1a; 1.通…

web-105linux权限提升

rsync未授权本地覆盖 Rsync 是 linux 下一款数据备份工具&#xff0c;默认开启 873 端口 https://vulhub.org/#/environments/rsync/common/ 借助 Linux 默认计划任务调用/etc/cron.hourly&#xff0c;利用 rsync 连接覆盖 前提条件就是需要知道rsync的密码或者存在未授权 -提…

【成品设计】基于Arduino平台的物联网智能灯

《基于Arduino平台的物联网智能灯》 整体功能&#xff1a; 这个任务中要求实现一个物联网智能灯。实际测试环境中要求设备能够自己创建一个热点&#xff0c;连接这个热点后能自动弹出控制界面&#xff08;强制门户&#xff09;。 功能点 基础功能 (60分) 要求作品至少有2个灯…

发布-订阅模式(Publisher-Subscriber)

实际上&#xff0c;发布-订阅模式只是观察者模式的一个别称。 但是经过时间的沉淀&#xff0c;似乎他已经强大了起来&#xff0c;已经独立于观察者模式&#xff0c;成为另外一种不同的设计模式。在现在的发布订阅模式中&#xff0c;称为发布者的消息发送者不会将消息直接发送给…

Linux下基本指令

Linux下基本指令 登录系统输入ssh root&#xff0c;在后面输入ip公用地址&#xff0c;按下enter键&#xff0c;会弹出一个密码框&#xff0c;输入密码即可登录成功。 Xshell下Altenter全屏&#xff0c;再重复操作是取消全屏。 clear清理屏幕。 01. ls 指令&#xff08;用来…

[红队apt]文件捆绑攻击流程

免责声明:本文用于了解攻击者攻击手法&#xff0c;切勿用于不法用途 前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理黑客通过文件捆绑进行攻击的流程思路 文件捆绑原理 废话只多说这一句。 1.exe和2.exe被你捆绑为3.exe。 那么你点击了3.exe就等于点…

信息安全工程师(45)入侵检测系统组成与分类

前言 入侵检测系统&#xff08;IDS&#xff09;是一种网络安全设备或软件&#xff0c;能够监控和分析网络或系统活动&#xff0c;以检测和响应潜在的入侵行为。 一、入侵检测系统的组成 根据互联网工程任务组&#xff08;IETF&#xff09;的定义&#xff0c;一个典型的入侵检测…

文科类考研答题规范与卷面整洁度提升:高效备考的秘诀

随着考研竞争的日益激烈&#xff0c;考生们为了在众多竞争者中脱颖而出&#xff0c;纷纷寻求提升自己的备考策略&#xff0c;答题规范和卷面整洁度在文科类考研中显得尤为重要&#xff0c;本文将从答题规范和卷面整洁度两个方面&#xff0c;为广大文科类考研学子提供一些建议&a…

LeetCode刷题日记之回溯算法(一)

目录 前言组合组合总和III电话号码的字母组合总结 前言 今天开始学习回溯算法啦&#xff0c;虽然直接递归学习的时候有涉及到回溯但是没有系统性的学习&#xff0c;希望博主记录的内容能够对大家有所帮助 &#xff0c;一起加油吧朋友们&#xff01;&#x1f4aa;&#x1f4aa;…

飞腾X100适配Ubuntu说明

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

实践体验密集小目标检测,以小麦麦穗颗粒为基准,基于嵌入式端超轻量级模型LeYOLO全系列【n/s/m/l】参数模型开发构建智能精准麦穗颗粒检测计数系统

对于常规的目标检测任务来说&#xff0c;诸如&#xff1a;COCO、VOC这类基础的数据场景&#xff0c;涌现出来了一些列性能初衷的检测模型&#xff0c;YOLO系列就是其中的佼佼者&#xff0c;不断地刷榜取得了越来越好的效果&#xff0c;不过这些评测指标是基于COCO、VOC这类公开…

基于Python+sqlite3实现(Web)图书管理系统

项目名称&#xff1a;LibraryManagementSystem 一、系统目标 使用了Python作为语言,以django为后台&#xff0c;sqlite3作为数据库&#xff0c;UI基于bootstrap的图书管理系统&#xff0c;模拟图书管理的真实场景&#xff0c;考虑客观需求&#xff0c;界面简洁、操作方便&…

解决Kali直接使用root用户密码ssh远程登录不上问题

一、问题描述 当我们直接使用root用户和密码ssh远程登录时&#xff08;ssh rootKali主机的IP地址&#xff09;直接提示“SSH服务器拒绝了密码&#xff0c;请再试一次”或者“Permission denied, please try again.&#xff08;权限被拒绝&#xff0c;请重试&#xff09;”信息&…