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

news2024/11/17 1:33:11

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

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

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

相关文章

Linux:系统安全及应用

目录 一、系统账号管理 1.1、系统账号清理 1.2、密码安全控制 1.3、命令历史限制 二、限制su命令用户 三、PAM安全认证 四、sudo机制提升权限 4.1、sudo机制介绍 4.2、用户别名案例 4.3、启用sudo操作日志 4.4、其他案列sudo 4.5、开关机安全控制 4.6、限制更改GR…

ElasticSearch 6.5.4 安装中文分词器 IK

1.docker在线安装 1.1进入Elasticsearch容器 docker exec -it elasticsearch的容器ID /bin/bash 注意&#xff1a;如果进入Elasticsearch之后&#xff0c;自动退出&#xff0c;说明内存不够&#xff0c;先关闭虚拟机&#xff0c;然后 把内存调大之后在启动虚拟机。 1.2在线下…

【普中】基于51单片机的7人多数投票表决器设计( proteus仿真+程序+设计报告+讲解视频)

投票表决器设计 1.主要功能&#xff1a;讲解视频&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单&&下载链接 【普中】基于51单片机的7人多数投票表决器设计 ( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus8.16(有低版本) 程序编译器&am…

暑期自学IT:从基础到实战的完美指南

高考终于结束了&#xff0c;你是否正在为如何度过这个漫长的暑假而发愁呢&#xff1f;与其天天躺在床上刷剧&#xff0c;不如趁着这段宝贵的时间&#xff0c;开启一段IT世界的奇妙探险之旅吧&#xff01;无论你是对计算机科学充满好奇&#xff0c;还是已经决定未来要在IT领域大…

java生成excel,uniapp微信小程序接收excel并打开

java引包&#xff0c;引的是apache.poi <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency> 写一个测试类&#xff0c;把excel输出到指定路径 public s…

优盘有盘符显示0字节:故障解析与数据恢复策略

一、优盘有盘符显示0字节现象描述 在使用优盘的过程中&#xff0c;我们有时会遇到一种令人困惑的情况&#xff1a;插入优盘后&#xff0c;电脑能正常识别到优盘的盘符&#xff0c;但当我们尝试访问其中的数据时&#xff0c;却发现优盘的容量显示为0字节&#xff0c;无法读取或…

VUE3解决跨域问题

本文基于vue3 vite element-plus pnpm 报错&#xff1a;**** has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource. 原因&#xff1a;前端不能直接访问其他IP&#xff0c;需要用vite.config.ts &#xff0…

API-Window对象

学习目标&#xff1a; 掌握Window对象 学习内容&#xff1a; BOM&#xff08;浏览器对象模型&#xff09;定时器-延时函数JS执行机制location对象navigation对象history对象 BOM&#xff08;浏览器对象模型&#xff09;&#xff1a; BOM是浏览器对象模型。 window对象是一个全…

每个App下载收费3.88元,苹果太强势被开2800亿罚单

刚刚开完 WWDC2024 大会&#xff0c;苹果就被欧盟找上了麻烦。 欧盟认为苹果涉嫌违反涉嫌违反《数字市场法案》&#xff08;Digital Markets Act&#xff09;&#xff0c;造成垄断。 来源&#xff1a;欧盟委员会 明确指出苹果在 Apple Store 里面对开发者的限制不合理。 在最…

栈的概念和实现

1.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&…

侯捷C++面向对象高级编程(上)-6-三大函数:拷贝构造、拷贝复制、析构

1. 2.三个特殊函数 3.构造函数和析构函数 4.浅拷贝&#xff08;系统默认仅把指针拷贝过去&#xff09; 5.拷贝构造函数&#xff08;深拷贝&#xff0c;拷贝的内容&#xff0c;重写string函数&#xff09; 6.拷贝赋值

阿里云 CosyVoice 语音合成大模型 API 实践

前言 最近大模型这么火&#xff0c;就想着玩一下&#xff0c;作为非 AI 从业者&#xff0c;最好的方式就是调用云服务的 API 来构建自己的 AI 应用。首选当然是国外的 ChatGPT API&#xff0c;但是说实话那个玩意有点贵&#xff0c;而且最近国内也被封禁不让调用了&#xff0c…

诊所运营效率提升方法有哪些?

随着医疗行业的快速发展和市场竞争的加剧&#xff0c;诊所运营效率的提升成为了众多医疗机构关注的焦点。高效的诊所运营不仅能够提升患者的就医体验&#xff0c;还能帮助诊所实现可持续发展。那么&#xff0c;诊所运营效率提升的方法有哪些呢&#xff1f; 1、优化管理流程 诊…

项目经验-不同行业、不同风格的网站设计

网站UI设计的首要考虑点是布局与导航。合理的布局能够确保信息清晰呈现&#xff0c;使用户能够快速定位所需内容。同时&#xff0c;简洁明了的导航设计能够引导用户流畅浏览&#xff0c;减少迷失感。通过精心设计的布局和导航&#xff0c;可以提升用户体验&#xff0c;增强用户…

一、安全完善度等级SIL(Safety Integrity Level)介绍

目录 一、背景 二、定义 2.1 相关概念介绍如下&#xff1a; 2.2 扩展 2.3 注意事项 一、背景 在轨道交通行业中&#xff0c;安全完善度等级&#xff08;SIL&#xff0c;Safety Integrity Level&#xff09;是一个至关重要的概念&#xff0c;它用于评估安全相关系统&#x…

vue3.0 + vant实现下拉刷新上拉加载

在vue中使用vant组件库有个van-pull-refresh下拉组件&#xff0c;配合van-list列表组件实现页面的下拉刷新和上拉加载&#xff0c;原理简单&#xff0c;适用场景在列表页面内容展示。 下拉刷新 PullRefresh 实现下拉刷新的效果。 PullRefresh组件中的searchRefreshing属性&…

Open3D Ransac点云配准算法(粗配准)

目录 一、概述 1.1简介 1.2RANSAC在点云粗配准中的应用步骤 二、代码实现 2.1关键函数 2.2完整代码 2.3代码解析 2.3.1计算FPFH 1. 法线估计 2. 计算FPFH特征 2.3.2 全局配准 1.函数&#xff1a;execute_global_registration 2.距离阈值 3.registration_ransac_b…

为什么企业应用开发,c++干不过java?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; C/C这种东西&#xff0c;根本…

面向阿克曼移动机器人(自行车模型)的LQR(最优二次型调节器)的路径跟踪方法

线性二次调节器&#xff08;Linear Quadratic Regulator&#xff0c;LQR&#xff09;是针对线性系统的最优控制方法。LQR 方法标准的求解体系是在考虑到损耗尽可能小的情况下, 以尽量小的代价平衡其他状态分量。一般情况下&#xff0c;线性系统在LQR 控制方法中用状态空间方程描…

Docker 一篇到位

目录 01. Docker使用导航 02. Build Share Run 样例 03. 理解容器 04. 安装 Docker 05. Docker 样例&#xff08;常见命令使用&#xff09; 下载镜像 启动容器 修改页面 保存镜像 docker commit docker save docker load 分享社区 docker login docker tag do…