ROS Action

在 ROS 中,Action 是一种支持长时间异步任务的通信机制。与 Service 不同,Action 允许客户端发起一个请求,并在任务执行的过程中不断接收反馈,直到任务完成。这种机制非常适用于可能需要较长时间来完成的任务,比如机器人移动、导航或复杂的传感器数据采集。

ROS Action 的工作原理

Action 的通信流程由三个主要组成部分:Goal(目标)Feedback(反馈)Result(结果)。在 ROS 中,Action 通常包含以下几个节点角色:

  • Action Server(服务器):负责执行具体的任务,并将执行过程中的反馈和最终结果发送给客户端。
  • Action Client(客户端):发起任务请求,发送目标并接收服务器的反馈和结果。

1. ROS Action 的基本组成

每个 ROS Action 包括以下几个部分:

  • Goal(目标):客户端发送的目标数据,定义了任务的具体内容。
  • Feedback(反馈):服务器在执行过程中可以发送实时反馈,告知任务进展。
  • Result(结果):服务器在任务完成后返回的最终结果。

2. 定义 ROS Action

在 ROS 中,我们使用 .action 文件定义 Action 的数据格式,它类似于 .srv 文件,包含三部分:GoalFeedbackResult,各部分使用 --- 分隔。

示例:定义一个计数器的 Action

假设我们想定义一个计数器的 Action,它接收一个目标数字并从 0 计数到该数字,期间不断提供进度反馈,并在完成后返回最终结果。

首先我们先创建一个my_action的功能包,进入到自己的ros工作空间下面,执行:

catkin_create_pkg my_action roscpp actionlib actionlib_msgs std_msgs

在建立的功能包下再创建一个action文件夹,用来存放“.action”文件

定义 Countdown.action 文件:

# CountToNumber.action

# Goal: 目标数字
int32 target_number

---
# Result: 操作结果(是否成功)
bool success

---
# Feedback: 当前计数
int32 current_count

这意味着我们将向 Action 服务器发送一个目标数字,服务器会从 0 开始计数并每次提供当前的计数进度,最后返回一个表示成功的布尔值。

3. 配置 CMakeLists.txt 和 package.xml

然后,像之前的例子一样,我们需要更新 CMakeLists.txtpackage.xml 文件,确保 Action 文件被编译并生成相应的消息类型。

  • CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
  actionlib
  actionlib_msgs
  roscpp 
  std_msgs
)

add_action_files(
  FILES
  CountToNumber.action
)

generate_messages(
  DEPENDENCIES
  actionlib_msgs
  std_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES my_action
  CATKIN_DEPENDS roscpp rospy std_msgs actionlib actionlib_msgs
#  DEPENDS system_lib
)
  • package.xml
<buildtool_depend>catkin</buildtool_depend>
<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<build_export_depend>actionlib</build_export_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>
<exec_depend>std_msgs</exec_depend>

确保上述内容无误后,回到工作空间编译我们的my_action功能包

cd ~/catkin_ws/
catkin_make -DCATKIN_WHITELIST_PACKAGES=my_action

(编译你可以直接使用catkin_make,这里我加 -DCATKIN_WHITELIST_PACKAGES

=my_action表示只编译my_action功能包)

编译通过后你就可以在工作空间目录下的devel/include/my_action路径中找到自定义的action的头文件

4. 实现 Action 服务器

接下来,我们实现 Action 服务器,接收目标数字并从 0 开始计数,定期提供反馈,直到计数完成或被取消。我们在my_action功能包的src下创建一个countdown_server.cpp

#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include <my_action/CountToNumberAction.h>

class CountToNumberAction
{
protected:
  ros::NodeHandle nh_;   // ROS节点句柄,用于与ROS系统交互
  actionlib::SimpleActionServer<my_action::CountToNumberAction> as_;  // Action 服务器对象,类型是自定义的 `CountToNumberAction`
  std::string action_name_;   // Action的名称
  my_action::CountToNumberFeedback feedback_;   // 存储反馈的对象
  my_action::CountToNumberResult result_;   // 存储结果的对象

public:
  CountToNumberAction(std::string name) :
    as_(nh_, name, boost::bind(&CountToNumberAction::executeCB, this, _1), false),
    action_name_(name)
  {
    as_.start();
  }

  void executeCB(const my_action::CountToNumberGoalConstPtr &goal)
  {
    int target = goal->target_number;   // 获取目标数字
    ROS_INFO("Counting to %d", target);  // 打印目标数字

    // 从 0 开始计数并提供反馈
    for (int i = 0; i <= target; ++i) {
      if (as_.isPreemptRequested()) {
        ROS_INFO("%s: Preempted", action_name_.c_str());
        as_.setPreempted();   // 如果请求了中断,则设置为已中断
        return;
      }

      feedback_.current_count = i;  // 更新当前计数
      as_.publishFeedback(feedback_);   // 发布反馈
      ros::Duration(1.0).sleep();  // 每秒更新一次反馈
    }

    // 返回结果
    result_.success = true;  // 设置操作成功
    as_.setSucceeded(result_);  // 设置 Action 成功并返回结果
  }
};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "count_to_number_action_server");   // 初始化ROS节点
  CountToNumberAction count_to_number_action("count_to_number");  // 创建 Action 服务器实例
  ros::spin();  // 进入 ROS 事件循环,等待请求
  return 0;
}

代码我已经注释好,就不用过多篇幅重复介绍了,只想插一嘴构造函数中表现的回调函数机制,因为最近面试被问到了

这段内容可以通过目录选择性阅读哈

扩展:C++的回调函数机制

CountToNumberAction(std::string name) :
  as_(nh_, name, boost::bind(&CountToNumberAction::executeCB, this, _1), false),
  action_name_(name)
{
  as_.start();
}

解释:

  • 构造函数接收一个字符串 name 作为参数,指定 Action 的名称。
  • as_(nh_, name, boost::bind(&CountToNumberAction::executeCB, this, _1), false)
    • actionlib::SimpleActionServer 需要三个参数:
      1. nh_:ROS节点句柄,负责通信。
      2. name:Action 名称。
      3. 回调函数:使用 boost::bind 绑定一个成员函数 executeCB,这是处理客户端请求的回调函数。_1 表示传递给回调函数的第一个参数(即 Goal 对象)。
    • false:这是一个布尔参数,表示是否立即启动服务器。这里设置为 false,表示服务器启动后不会自动开始等待请求,而是通过调用 as_.start() 来启动。
  • as_.start():启动 Action 服务器,开始监听客户端请求。

在 ROS 的 Action 服务器中,boost::bind 是一种通过将成员函数或普通函数转换为可调用对象(仿函数)的方式。这样做的目的是为了实现回调机制,尤其是在 actionlib::SimpleActionServer 中。

这段代码通过 boost::bindCountToNumberAction::executeCB 成员函数转换成一个可以作为回调的函数对象(仿函数)。让我们逐步分析:

  • boost::bind 的作用

    • boost::bind 用来将一个成员函数绑定到特定的对象上,并且返回一个可调用对象(仿函数)。这个对象可以像普通函数一样被调用。

    • &CountToNumberAction::executeCB:这是 CountToNumberAction 类的成员函数 executeCB 的指针。

    • this:它是指向当前对象的指针,告诉 boost::bind 成员函数是作用于哪个对象。

    • _1:这是一个占位符,表示传递给回调函数的第一个参数(即 goal)。在实际调用时,_1 会被替换为客户端发送的目标(Goal)。

  • actionlib::SimpleActionServer

    • actionlib::SimpleActionServer 构造函数接受一个回调函数作为参数,这个回调函数会在 Action 服务器收到目标请求时被调用。
    • 在这个例子中,回调函数是 CountToNumberAction::executeCB,通过 boost::bind 转换成了一个仿函数,它接收 goal 作为输入并处理相关逻辑。
  • 仿函数的调用

    • 当 Action 服务器接收到客户端请求时,它会调用绑定的回调函数(仿函数),从而触发计数逻辑的执行。这个回调会处理客户端的目标请求并定期向客户端发送反馈。

5. 实现 Action 客户端

接下来,我们实现客户端来发送目标数字并接收进度反馈和最终结果。

我们在my_action功能包的src下创建一个countdown_client.cpp

#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <my_action/CountToNumberAction.h>  //包含自定义 Action 类型的头文件,CountToNumberAction 这个类型定义了目标(Goal)、反馈(Feedback)和结果(Result)结构。


typedef actionlib::SimpleActionClient<my_action::CountToNumberAction> Client;

// doneCb - 任务完成后的回调
void doneCb(const actionlib::SimpleClientGoalState& state,
            const my_action::CountToNumberResultConstPtr& result)
{
  ROS_INFO("Finished in state: %s", state.toString().c_str());
  if (result->success)
    ROS_INFO("Counting completed successfully!");
  else
    ROS_WARN("Counting failed.");
}

/**
 * activeCb:当目标开始被服务器处理时触发。此回调表示目标已经被接受并正在处理。
   它简单地打印一条信息,表示目标正在被处理。
 */
void activeCb()
{
  ROS_INFO("Goal is being processed...");
}

// feedbackCb - 反馈更新的回调
void feedbackCb(const my_action::CountToNumberFeedbackConstPtr& feedback)
{
  ROS_INFO("Current count: %d", feedback->current_count);
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "count_to_number_action_client");

  // 创建一个客户端,连接到服务器
  Client ac("count_to_number", true);
  ROS_INFO("Waiting for action server to start...");
  ac.waitForServer();  // 等待服务器启动

  my_action::CountToNumberGoal goal;
  goal.target_number = 10;  // 设置目标数字

  // 发送目标并设置回调函数
  ac.sendGoal(goal, &doneCb, &activeCb, &feedbackCb);

  ros::spin();
  return 0;
}
  • 这段代码实现了一个 ROS Action 客户端,连接到名为 "count_to_number" 的服务器并发送目标(goal.target_number = 10)。
  • 客户端使用三个回调函数:
    1. doneCb:处理任务完成后的状态和结果。
    2. activeCb:处理目标开始被服务器处理时的状态。
    3. feedbackCb:处理服务器发送的反馈信息(当前计数值)。
  • 客户端通过调用 ac.sendGoal 发送目标,并且使用 ros::spin() 保持客户端运行,接收和处理服务器的反馈和状态。

(关于C++回调函数机制的设计,我会单独再写一篇)

6. 再次配置CMakeList.txt

接下来,在CMakeList.txt的末尾添加以下内容

add_executable(countdown_server src/countdown_server.cpp)
add_dependencies(countdown_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(countdown_server ${catkin_LIBRARIES})

add_executable(countdown_client src/countdown_client.cpp)
add_dependencies(countdown_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(countdown_client ${catkin_LIBRARIES})

此时功能包的目录结构大家可以对照看一下有没有问题

├── action
│   └── CountToNumber.action
├── CMakeLists.txt
├── include
│   └── my_action
├── package.xml
└── src
    ├── countdown_client.cpp
    └── countdown_server.cpp

4 directories, 5 files

7. 启动 ROS Action 节点

编译
cd ~/catkin_ws/
catkin_make -DCATKIN_WHITELIST_PACKAGES=my_action

编译通过后起一个终端,输入roscore回车,启动ros master

roscore

再起一个终端来启动服务端

rosrun my_action countdown_server

再起一个终端来启动客户端

rosrun my_action countdown_client 

客户端输出如下图

服务端打印信息如下图:

8. Action 的应用场景

  • 机器人运动控制:如导航到指定点,机器人可以通过 Action 接收目标位置,在运动过程中反馈进度。
  • 图像处理任务:复杂的图像处理任务(如识别、追踪)可能需要较长时间,可以通过 Action 提供进度反馈。
  • 传感器数据采集:采集数据并持续返回采集进度。

Action 与 Service 的区别

特性ServiceAction
通信方式请求-响应,同步通信目标-反馈-结果,异步通信
使用场景短时间任务长时间任务,提供进度反馈
回调机制单次回调多次反馈回调和结果回调
数据类型请求和响应目标、反馈和结果
中断任务不支持支持预取消和中断

总结

ROS Action 是 ROS 中一种异步的请求-反馈机制,适用于长时间运行任务。通过 Goal、Feedback 和 Result 的组合,Action 提供了一种更加灵活的任务管理方式,支持任务进度反馈和任务中断功能,使其在复杂的机器人任务中非常有用。

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

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

相关文章

23.UE5删除存档

2-25 删除存档制作_哔哩哔哩_bilibili 按照自己的风格制作删除按钮 这样该行的存档就被从存档列表中删除了&#xff0c;并且实际存档&#xff08;我的存档蓝图&#xff09;中也被删除了 但是存在一个问题&#xff0c;如果存档数据中存在索引为: 0 1 2 3的存档&#xff0c;当索…

LoFTR: Detector-Free Local Feature Matching with Transformers—特征点匹配算法系列

LoFTR: Detector-Free Local Feature Matching with Transformers 受到&#xff1a;受到开创性作品 SuperGlue 的启发 摘要总结&#xff1a; 提出了一种局部图像特征匹配的新方法。更为突出说明的是室内场景下的特征点的匹配问题。 不是依次执行图像特征检测、描述和匹配&#…

图像基础算法学习笔记

目录 概要 一、图像采集 二、图像标注 四、图像几何变换 五、图像边缘检测 Sobel算子 Scharrt算子 Laplacian算子 Canny边缘检测 六、形态学转换 概要 参考书籍&#xff1a;《机器视觉与人工智能应用开发技术》 廖建尚&#xff0c;钟君柳 出版时间&#xff1a;2024-…

排序算法 -归并排序

文章目录 1. 归并排序&#xff08;Merge Sort&#xff09;1.1 简介1.2 归并排序的步骤1.3 归并排序c 语言实现代码说明 1.4 时间复杂度1.5 空间复杂度1.6 动画 1. 归并排序&#xff08;Merge Sort&#xff09; 1.1 简介 归并排序&#xff08;Merge Sort&#xff09;是一种基于…

wireshark 基础

wireshark 基础 一、wireshark介绍 Wireshark&#xff08;前称Ethereal&#xff09;是一个网络封包分析软件。网络封包分析软件的功能是捕获网络封包&#xff0c;并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口&#xff0c;直接与网卡进行数据报文交换…

GIT 入门详解指南

前言&#xff1a; 注&#xff1a;本博客仅用于记录本人学习过程中对git的理解&#xff0c;仅供学习参考&#xff0c;如有异议请自行查资料求证 安装 使用git之前必须完成git的安装&#xff0c;Git 目前支持 Linux/Unix、Solaris、Mac和 Windows 平台上运行 git 安装教程 基本…

从 IDC 到云原生:稳定性提升 100%,成本下降 50%,热联集团的数字化转型与未来展望

作者&#xff1a;金峰&#xff08;项良&#xff09;、朱永林、赵世振&#xff08;寰奕&#xff09; 公司简介 杭州热联集团股份有限公司成立于 1997 年 10 月&#xff0c;是隶属杭州市实业投资集团的国有控股公司。公司专业从事国际、国内钢铁贸易黑色大宗商品及产业服务&…

【微软:多模态基础模型】(4)统一视觉模型

欢迎关注[【youcans的AGI学习笔记】](https://blog.csdn.net/youcans/category_12244543.html&#xff09;原创作品 【微软&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微…

机器学习——期末复习 重点题归纳

第一题 问题描述 现有如下数据样本&#xff1a; 编号色泽敲声甜度好瓜1乌黑浊响高是2浅白沉闷低否3青绿清脆中是4浅白浊响低否 &#xff08;1&#xff09;根据上表&#xff0c;给出属于对应假设空间的3个不同假设。若某种算法的归纳偏好为“适应情形尽可能少”&#xff0c;…

Web3浪潮下的区块链应用:从理论到实践的全面解析

随着Web3的兴起&#xff0c;区块链技术作为其核心支撑&#xff0c;正迎来前所未有的应用爆发。Web3不仅仅是技术的革新&#xff0c;更代表了一种去中心化、开放、透明的互联网愿景。在这一背景下&#xff0c;区块链技术的应用正从理论走向实践&#xff0c;推动着各行各业的数字…

学习大数据DAY61 宽表加工

目录 模型设计 加工宽表 任务调度&#xff1a; 大表 - 把很多数据整合起来 方便后续的明细查询和指标计算 模型设计 设计 建模 设计: excel 文档去编写 建模: 使用建模工具 PowerDesigner Navicat 在线画图工具... 把表结构给绘 制出来 共享\项目课工具\pd 加工宽表 数…

ChromeDriver驱动下载地址更新(保持最新最全)

说明&#xff1a; ChromeDriver 是 Selenium WebDriver 用于控制 Chrome 的独立可执行文件。 为了方便下载使用&#xff0c;本文保持ChromeDriver的最新版本更新&#xff0c;并提供115.0.5763.0-133.0.6841.0版本的下载地址&#xff1a; 所有版本和下载地址&#xff1a; &am…

QT基本绘图

QT绘图 1.概述 这篇文章介绍如何绘图 2.绘图基本操作 创建一个普通的widget类型的项目 在widget.h 文件中重写绘图事件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : p…

[ACTF2020]Upload 1--详细解析

信息收集 题目告诉我们是一道upload&#xff0c;也就是文件上传漏洞题目。 进入界面&#xff0c;是一个灯泡&#xff0c;将鼠标放在图标上就会出现文件上传的相应位置&#xff1a; 思路 文件上传漏洞&#xff0c;先看看有没有前端校验。 在js源码中找到了前端校验&#xff…

Android Studio开发学习(五)———LinearLayout(线性布局)

一、布局 认识了解一下Android中的布局&#xff0c;分别是: LinearLayout(线性布局)&#xff0c;RelativeLayout(相对布局)&#xff0c;TableLayout(表格布局)&#xff0c; FrameLayout(帧布局)&#xff0c;AbsoluteLayout(绝对布局)&#xff0c;GridLayout(网格布局) 等。 二、…

计算机视觉在自动驾驶汽车中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 计算机视觉在自动驾驶汽车中的应用 计算机视觉在自动驾驶汽车中的应用 计算机视觉在自动驾驶汽车中的应用 引言 计算机视觉在自动…

表格的选择弹窗,选中后返显到表格中

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 表格的下拉框可以直接显示选项&#xff0c;那如果选择框不是下拉的&#xff0c;而是弹窗&#xff0c;那么在表格中如何返显呢&#xff1f; 问题描述 如上图所示&#xff0c;点击表格中的选择&#xf…

金融领域先锋!海云安成功入选2024年人工智能先锋案例集

近日&#xff0c;中国人工智能产业发展联盟《2024年人工智能先锋案例集》&#xff08;以下简称“AIIA先锋案例集”&#xff09;在中国人工智能产业发展联盟第十三次全体会议上正式发布。该案例集由人工智能产业发展联盟&#xff08;AIIA&#xff09;、工业和信息化部新闻宣传中…

HarmonyOs鸿蒙开发实战(16)=>沉浸式效果第一种方案一窗口全屏布局方案

1.沉浸式效果的目的 开发应用沉浸式效果主要指通过调整状态栏、应用界面和导航条的显示效果来减少状态栏导航条等系统界面的突兀感&#xff0c;从而使用户获得最佳的UI体验。 2.窗口全屏布局方案介绍 调整布局系统为全屏布局&#xff0c;界面元素延伸到状态栏和导航条区域实现沉…

OpenAI震撼发布:桌面版ChatGPT,Windows macOS双平台AI编程体验!

【雪球导读】 「OpenAI推出ChatGPT桌面端」 OpenAI重磅推出ChatGPT桌面端&#xff0c;全面支持Windows和macOS系统&#xff01;这款新工具为用户在日常生活和工作中提供了前所未有的无缝交互体验。对于那些依赖桌面端进行开发工作的专业人士来说&#xff0c;这一更新带来了令人…