ROS2使用C++开发动作通信

1.开发接口节点

cd chapt4_ws/


ros2 pkg create robot_control_interfaces --build-type ament_cmake --destination-directory src --maintainer-name "joe" --maintainer-email "1027038527@qq.com"


mkdir -p src/robot_control_interfaces/action
touch src/robot_control_interfaces/action/MoveRobot.action

# Goal: 要移动的距离
float32 distance
---
# Result: 最终的位置
float32 pose
---
# Feedback: 中间反馈的位置和状态
float32 pose
uint32 status
uint32 STATUS_MOVEING = 3
uint32 STATUS_STOP = 4

编辑package.xml


  <depend>rosidl_default_generators</depend>
  <member_of_group>rosidl_interface_packages</member_of_group>

编辑CMakeLists.txt
find_package(ament_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)


rosidl_generate_interfaces(${PROJECT_NAME}
  "action/MoveRobot.action"
)
 

2.开发动作节点

cd chapt4_ws/


ros2 pkg create example_action_rclcpp --build-type ament_cmake --dependencies rclcpp rclcpp_action robot_control_interfaces --destination-directory src --node-name action_robot_01 --maintainer-name "joe" --maintainer-email "1027038527@qq.com"

开发控制节点
touch src/example_action_rclcpp/src/action_control_01.cpp

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "robot_control_interfaces/action/move_robot.hpp"

class ActionControl01 : public rclcpp::Node {
 public:
  using MoveRobot = robot_control_interfaces::action::MoveRobot;
  using GoalHandleMoveRobot = rclcpp_action::ClientGoalHandle<MoveRobot>;

  explicit ActionControl01(
      std::string name,
      const rclcpp::NodeOptions& node_options = rclcpp::NodeOptions())
      : Node(name, node_options) {
    RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());

    this->client_ptr_ =
        rclcpp_action::create_client<MoveRobot>(this, "move_robot");

    this->timer_ =
        this->create_wall_timer(std::chrono::milliseconds(500),
                                std::bind(&ActionControl01::send_goal, this));
  }

  void send_goal() {
    using namespace std::placeholders;

    this->timer_->cancel();

    if (!this->client_ptr_->wait_for_action_server(std::chrono::seconds(10))) {
      RCLCPP_ERROR(this->get_logger(),
                   "Action server not available after waiting");
      rclcpp::shutdown();
      return;
    }

    auto goal_msg = MoveRobot::Goal();
    goal_msg.distance = 10;

    RCLCPP_INFO(this->get_logger(), "Sending goal");

    auto send_goal_options =
        rclcpp_action::Client<MoveRobot>::SendGoalOptions();
    send_goal_options.goal_response_callback =
        std::bind(&ActionControl01::goal_response_callback, this, _1);
    send_goal_options.feedback_callback =
        std::bind(&ActionControl01::feedback_callback, this, _1, _2);
    send_goal_options.result_callback =
        std::bind(&ActionControl01::result_callback, this, _1);
    this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
  }

 private:
  rclcpp_action::Client<MoveRobot>::SharedPtr client_ptr_;
  rclcpp::TimerBase::SharedPtr timer_;

  void goal_response_callback(GoalHandleMoveRobot::SharedPtr goal_handle) {
    if (!goal_handle) {
      RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
    } else {
      RCLCPP_INFO(this->get_logger(),
                  "Goal accepted by server, waiting for result");
    }
  }

  void feedback_callback(
      GoalHandleMoveRobot::SharedPtr,
      const std::shared_ptr<const MoveRobot::Feedback> feedback) {
    RCLCPP_INFO(this->get_logger(), "Feedback current pose:%f", feedback->pose);
  }

  void result_callback(const GoalHandleMoveRobot::WrappedResult& result) {
    switch (result.code) {
      case rclcpp_action::ResultCode::SUCCEEDED:
        break;
      case rclcpp_action::ResultCode::ABORTED:
        RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
        return;
      case rclcpp_action::ResultCode::CANCELED:
        RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
        return;
      default:
        RCLCPP_ERROR(this->get_logger(), "Unknown result code");
        return;
    }

    RCLCPP_INFO(this->get_logger(), "Result received: %f", result.result->pose);
    // rclcpp::shutdown();
  }
};  // class ActionControl01


int main(int argc, char** argv) {
  rclcpp::init(argc, argv);
  auto action_client = std::make_shared<ActionControl01>("action_robot_cpp");
  rclcpp::spin(action_client);
  rclcpp::shutdown();
  return 0;
}
 

开发机器人节点

#include "example_action_rclcpp/robot.h"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "robot_control_interfaces/action/move_robot.hpp"

// 创建一个ActionServer类
class ActionRobot01 : public rclcpp::Node {
 public:
  using MoveRobot = robot_control_interfaces::action::MoveRobot;
  using GoalHandleMoveRobot = rclcpp_action::ServerGoalHandle<MoveRobot>;

  explicit ActionRobot01(std::string name) : Node(name) {
    RCLCPP_INFO(this->get_logger(), "节点已启动:%s.", name.c_str());

    using namespace std::placeholders;  // NOLINT

    this->action_server_ = rclcpp_action::create_server<MoveRobot>(
        this, "move_robot",
        std::bind(&ActionRobot01::handle_goal, this, _1, _2),
        std::bind(&ActionRobot01::handle_cancel, this, _1),
        std::bind(&ActionRobot01::handle_accepted, this, _1));
  }

 private:
  Robot robot;
  rclcpp_action::Server<MoveRobot>::SharedPtr action_server_;

  rclcpp_action::GoalResponse handle_goal(
      const rclcpp_action::GoalUUID& uuid,
      std::shared_ptr<const MoveRobot::Goal> goal) {
    RCLCPP_INFO(this->get_logger(), "Received goal request with distance %f",
                goal->distance);
    (void)uuid;
    if (fabs(goal->distance > 100)) {
      RCLCPP_WARN(this->get_logger(), "目标距离太远了,本机器人表示拒绝!");
      return rclcpp_action::GoalResponse::REJECT;
    }
    RCLCPP_INFO(this->get_logger(),
                "目标距离%f我可以走到,本机器人接受,准备出发!",
                goal->distance);
    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
  }

  rclcpp_action::CancelResponse handle_cancel(
      const std::shared_ptr<GoalHandleMoveRobot> goal_handle) {
    RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
    (void)goal_handle;
    robot.stop_move(); /*认可取消执行,让机器人停下来*/
    return rclcpp_action::CancelResponse::ACCEPT;
  }

  void execute_move(const std::shared_ptr<GoalHandleMoveRobot> goal_handle) {
    const auto goal = goal_handle->get_goal();
    RCLCPP_INFO(this->get_logger(), "开始执行移动 %f 。。。", goal->distance);

    auto result = std::make_shared<MoveRobot::Result>();
    rclcpp::Rate rate = rclcpp::Rate(2);
    robot.set_goal(goal->distance);
    while (rclcpp::ok() && !robot.close_goal()) {
      robot.move_step();
      auto feedback = std::make_shared<MoveRobot::Feedback>();
      feedback->pose = robot.get_current_pose();
      feedback->status = robot.get_status();
      goal_handle->publish_feedback(feedback);
      /*检测任务是否被取消*/
      if (goal_handle->is_canceling()) {
        result->pose = robot.get_current_pose();
        goal_handle->canceled(result);
        RCLCPP_INFO(this->get_logger(), "Goal Canceled");
        return;
      }
      RCLCPP_INFO(this->get_logger(), "Publish Feedback"); /*Publish feedback*/
      rate.sleep();
    }

    result->pose = robot.get_current_pose();
    goal_handle->succeed(result);
    RCLCPP_INFO(this->get_logger(), "Goal Succeeded");
  }

  void handle_accepted(const std::shared_ptr<GoalHandleMoveRobot> goal_handle) {
    using std::placeholders::_1;
    std::thread{std::bind(&ActionRobot01::execute_move, this, _1), goal_handle}
        .detach();
  }
};

int main(int argc, char** argv) {
  rclcpp::init(argc, argv);
  auto action_server = std::make_shared<ActionRobot01>("action_robot_01");
  rclcpp::spin(action_server);
  rclcpp::shutdown();
  return 0;
}
 

编译、运行

source install/setup.bash 
ros2 run example_action_rclcpp  action_robot_01


source install/setup.bash 
ros2 run example_action_rclcpp action_control_01

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#中的时间数据格式化详解与应用示例

文章目录 1、基本概念基本格式化方法 2、实用的时间格式化方法格式化日期格式化时间格式化时间戳解析日期时间字符串 3、实际应用4、应用示例结论 在软件开发中&#xff0c;时间数据是无处不在的。无论是用户登录时间、数据备份时间&#xff0c;还是日志记录&#xff0c;都需要…

NSE and KGE

NSE&#xff08;Nash-Sutcliffe Efficiency&#xff09;&#xff1a; 解释&#xff1a;NSE 是衡量水文模型模拟结果与观测值之间拟合程度的指标。它计算模拟值与观测值之间的均方误差&#xff0c;并将其与观测值的方差进行比较。NSE 的取值范围为-∞至 1&#xff0c;值越接近 1…

natvicat为什么连不上linux上的mysql?

老规矩&#xff0c;废话不多说&#xff0c;直接上教程。 号外&#xff0c;数据库管理工具领域的知名品牌Navicat&#xff0c;推出其免费版本——Navicat Premium Lite&#xff0c;用户可从Navicat官网下载体验这款软件。 https://www.navicat.com.cn/download/navicat-premium-…

vue3 动态配置element 的table

需求 合并行、合并标题、列宽可调整、列顺序可调整、可以控制列是否显示、列布局可保存、导出excel… 参考效果 代码 引入 npm i xlsx npm install element-plus --savetable组件 <template><div><div class"table-btn"><el-tooltip conte…

开发一套java语言的智能导诊需要什么技术?java+ springboot+ mysql+ IDEA互联网智能3D导诊系统源码

开发一套java语言的智能导诊需要什么技术&#xff1f;java springboot mysql IDEA互联网智能3D导诊系统源码 医院导诊系统是一种基于互联网和3D人体的智能化服务系统&#xff0c;旨在为患者提供精准、便捷的医院就诊咨询服务。该系统整合了医院的各种医疗服务资&#xff1b;智慧…

selenium 简介以及 selenium 环境配置

文章目录 一、初识 selenium1.selenium 简介2.selenium 三大组件3.selenium工作过程和原理4.selenium自动化测试流程5.selenium优点 二、自动化测试1.UI自动化本质2.UI自动化的前提3.适用场景4.UI自动化的原则5.UI自动化的覆盖率 三、selenium 环境配置 一、初识 selenium 1.s…

Win11找不到组策略编辑器(gpedit.msc)解决

由于需要同时连接有线网络和无线网络&#xff0c;且重启后双网络都自动连接&#xff0c;因此需要配置组策略。 但是win11找不到组策略编辑器。 灵感来源&#xff1a;Win11找不到组策略编辑器&#xff08;gpedit.msc&#xff09;解决教程 - 知乎 (zhihu.com) 在Win11中&#…

安装KB5039212更新卡在25% 或者 96% 进度

系统之家7月1日消息&#xff0c;微软在6月11日的补丁星期二活动中&#xff0c;为Windows 11系统推出了KB5039212更新。然而&#xff0c;部分用户在Windows社区中反映&#xff0c;安装过程中出现失败&#xff0c;进度条在25%或96%时卡住。对于遇到此类问题的Windows 11用户&…

创意无界:探索国产创成式填充的无限潜力

在数字艺术与设计的世界中&#xff0c;创新技术不断涌现&#xff0c;而"创成式填充"无疑是其中的一颗璀璨新星。今天米兔要安利的这款国产ps插件-StartaAI拥有强大的AI功能&#xff0c;其AI扩图和局部重绘更是成为PS创成式填充的国产平替。 什么是创成式填充&#x…

Linux运维:mysql高级查询语句(2)

目 录 一、创建数据库&#xff1a; 二、创建表结构&#xff1a;DDL 2.1 学生表s&#xff1a; 2.2 成绩表sc&#xff1a; 2.3 课程表c&#xff1a; 三、录入数据&#xff1a;DML 3.1 对学生表s的数据录入&#xff1a; 3.2 对成绩表sc的数据录入&#xff1a; 3.3 对课…

Linux内核——Linux内核体系模式(二)

1 Linux系统的中断机制 Linux内核将中断分为两类&#xff1a;硬件中断和软件中断&#xff08;异常&#xff09;。每个中断是由0-255之间的一个数字进行标识。 中断int0-int31&#xff08;0x00-0x1f&#xff09;作为异常int32-int255由用户自己设定 int32-int47对应与8259A中断…

4PCS点云配准算法实现

4PCS点云配准算法的C实现如下&#xff1a; #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/common/common.h> #include <pcl/common/distances.h> #include <pcl/common/transforms.h> #in…

经典案列|淘宝商品数据爬取与分析

商品详情页 API接口测试代码 -- 请求示例 url 默认请求参数已经URL编码处理 curl -i "https://api-服务器.cn/taobao/item_get/?key<您自己的apiKey>&secret<您自己的apiSecret>&num_iid45887133725&is_promotion1" API测试页 商品详情页返…

解析 Ferret-UI:多模态大模型在移动用户界面理解中的应用

移动应用的爆炸性增长&#xff0c;用户界面&#xff08;UI&#xff09;的设计越来越复杂&#xff0c;功能也越来越丰富。但现有的多模态大模型&#xff08;MLLMs&#xff09;在理解用户界面时存在局限&#xff0c;尤其是在处理具有特定分辨率和包含众多小型对象&#xff08;如图…

重生之算法刷题之路之链表初探(三)

算法刷题之路之链表初探&#xff08;三&#xff09; 今天来学习的算法题是leecode2链表相加&#xff0c;是一道简单的入门题&#xff0c;但是原子在做的时候其实是有些抓耳挠腮&#xff0c;看了官解之后才恍然大悟&#xff01; 条件 项目解释 有题目可以知道&#xff0c;我们需…

EAGLE-2:一种高效无损的推测性采样方法,提升LLM的推理速度。

欢迎关注我的公众号&#xff1a;Halo咯咯 01。概述 北京大学的研究人员联合微软研究院、滑铁卢大学以及Vector研究所共同推出了EAGLE-2&#xff0c;这是一种利用上下文感知的动态草图树来增强推测性采样的方法。EAGLE-2在先前的EAGLE方法基础上进行了改进&#xff0c;不仅显著…

运维锅总详解RocketMQ

本文尝试从Apache RocketMQ的简介、主要组件及其作用、3种部署模式、Controller集群模式工作流程、最佳实践等方面对其进行详细分析。希望对您有所帮助&#xff01; 一、Apache RocketMQ 简介 Apache RocketMQ 是一个开源的分布式消息中间件&#xff0c;由阿里巴巴集团开发并…

uniapp微信小程序电子签名

先上效果图&#xff0c;不满意可以直接关闭这页签 新建成单独的组件&#xff0c;然后具体功能引入&#xff0c;具体功能点击签名按钮&#xff0c;把当前功能页面用样式隐藏掉&#xff0c;v-show和v-if也行&#xff0c;然后再把这个组件显示出来。 【签名-撤销】原理是之前绘画时…

JVM与Java体系结构

1.JVM与Java体系结构 1.1. 前言 作为Java工程师的你曾被伤害过吗&#xff1f;你是否也遇到过这些问题&#xff1f; 运行着的线上系统突然卡死&#xff0c;系统无法访问&#xff0c;甚至直接OOM想解决线上JVM GC问题&#xff0c;但却无从下手新项目上线&#xff0c;对各种JVM…

运算放大器重要参数详解

运算放大器是一种用于放大电压并实现信号处理和放大的电子设备。以下是运算放大器的一些重要参数及其详解: 增益(Gain): 定义:增益是运算放大器输出电压与输入电压之比,表示运算放大器在输入信号上的放大倍数。重要性:增益决定了信号的放大程度,是运算放大器的基本功能…