ROS action简单使用示例

news2024/12/26 11:05:56

1、为什么要用action

在ros中,大部分情况下的信息我们使用publisher与subscriber的机制来处理,也就是topic的机制。它能处理一些不用带状态返回的数据处理。当涉及到需要数据返回的节点间数据交互时,首选也可以采用servicer的机制进行处理与结果的返回。

但是存在一种使用上述两种方式都不是很合适的情况:当一个节点向另一个节点请求处理数据,但是另一个节点在处理该请求时需要花费很长的等待时间。这时候如果前一个节点一直处于一种等待的情况无法知道对方的处理情况的话就会很糟糕。一种极端的情况就是处理数据的节点陷入死循环了请求的节点一直收不到结果,程序就会卡死。

而ROS action在一定程度上就弥补了这个问题,相对于service它更适合用于处理这种长时间处理的情况,首先在action中是可以带feedback反馈的,能够在一定程度上知道运行程度的。其次在action中,是可以通过cancel取消当前在执行的action的。像是在service中,当我们请求一个程序运行的时候,如果中途我们发现运行的轨迹偏离了预期,是无法请求停止的,需要让其主动返回失败才可以。但是在cation中,如果我们发现运行的结果偏离预期,可以请求取消继续执行。所以改机制在很多场景下都是比topic以及service更加适合。

2、建立一个action消息

之前用过msg也用过service,其实很多地方都有类似的。一点小小的区别可能再于msg只有一个类,而service有两个类:请求的request部分以及返回的response。而action则包含了三个部分:请求的goal、返回的result以及执行过程中的feedback

简单的写一个action如下:

首先建立一个action文件:

catkin_create_pkg action_test roscpp rospy message_generation
cd action_test
mkdir action
cd cation
gedit Actiontest.action

然后在Actiontest.action中输入:

#goal definition
int32 numb
---
#result definition
bool result
---
#feedback
int32 temp_sum

同样修改cmakelist文件与package.xml文件。

对于cmakelist文件,需要修改三个地方:

1、find_package中添加最后两行

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  tf
  actionlib_msgs
  actionlib
)

2、add_action_files中添加action的名称

 add_action_files(
   FILES
   XunJiePhoto.action
   #DIRECTORY
 )

3、generate_messages中添加actionlib_msgs

 generate_messages(
   DEPENDENCIES
   actionlib_msgs
 )

对于package.xml文件需要添加下面内容:

  <build_depend>actionlib</build_depend>
  <build_depend>actionlib_msgs</build_depend>
  <build_export_depend>actionlib</build_export_depend>
  <build_export_depend>actionlib_msgs</build_export_depend>
  <exec_depend>actionlib</exec_depend>
  <exec_depend>actionlib_msgs</exec_depend>
  <exec_depend>message_runtime</exec_depend>
  <build_depend>message_generation</build_depend>

不过似乎上面六行我没加编译也成功了,不知道会不会对执行产生影响,为了保险起见建议还是加一下。

完成上述部分后,catkin_make编译即可生成对应的.h文件:
在这里插入图片描述

3、如何使用一个action

action机制部分跟service类似,也是需要一个客户端一个服务端。首先我们先写一个自加的服务端:

3.1、action服务端

我们同样使用C++来完成这部分代码:

#include "ros/ros.h"
#include "action_test/ActiontestAction.h"
#include "action_test/ActiontestGoal.h"
#include <actionlib/server/simple_action_server.h>
#include <actionlib/client/simple_action_client.h>
class action_server
{
private:
    /* data */
    ros::NodeHandle n;
    action_test::ActiontestResult add_sum;
    action_test::ActiontestFeedback add_feedback;
    actionlib::SimpleActionServer<action_test::ActiontestAction> as_;
public:
    action_server(/* args */);
    ~action_server();
    void actioncb(const actionlib::SimpleActionServer<action_test::ActiontestAction>::GoalConstPtr& goal);
};

action_server::action_server(/* args */):
as_(n, "test_add", boost::bind(&action_server::actioncb, this, _1),false)
{
    as_.start();
}

void action_server::actioncb(const actionlib::SimpleActionServer<action_test::ActiontestAction>::GoalConstPtr& goal)
{
    int numb = goal->numb;
    int sum = 0;
    for(int i=0;i<numb;i++)
    {
        sum+=i;
        add_feedback.temp_sum = sum;
        as_.publishFeedback(add_feedback);
        if (as_.isPreemptRequested())
        {
            add_sum.result = sum;
            as_.setPreempted(add_sum);
			return;
        }
        ros::Duration(0.2).sleep();
    }
    add_sum.result = sum;
    as_.setSucceeded(add_sum);
}
action_server::~action_server()
{
}
int main(int argc, char **argv)
{
    ros::init(argc, argv,"action_server");
    action_server action_server;
    ros::spin();  
    return 0;
}

首先在最上面我们需要添加几个头文件,这里比service或者topic要多一点:

#include "action_test/ActiontestAction.h"
#include "action_test/ActiontestGoal.h"
#include <actionlib/server/simple_action_server.h>
#include <actionlib/client/simple_action_client.h>

这里:

#include "action_test/ActiontestGoal.h"

好像不是必要的。
然后声明一个类,在类函数中需要声明你的action:

actionlib::SimpleActionServer<action_test::ActiontestAction> as_;

前面是固定格式<>中是action消息类型。以及需要一个对应的处理函数:

void actioncb(const actionlib::SimpleActionServer<action_test::ActiontestAction>::GoalConstPtr& goal);

另外这里还声明了两个变量,当然如果不使用的话也不影响。

    action_test::ActiontestResult add_sum;
    action_test::ActiontestFeedback add_feedback;

上面一个作为最后的返回值result的,下面一个是反馈值feedback。

接下来我们需要启动这个action:

action_server::action_server(/* args */):
as_(n, "test_add", boost::bind(&action_server::actioncb, this, _1),false)
{
    as_.start();
}

注意到:

as_(n, "test_add", boost::bind(&action_server::actioncb, this, _1),false)

是写在“{}“外面的,刚开始不是很理解,但是看了这篇博客后也还是不是特别理解,不过确实是应该这么写的,否则是无法通过编译的。

最后看一下处理函数中用到的一些东西。本身逻辑很简单,从0开始0.2秒加一次,一直加到给定的数值。最后通过setSucceeded函数返回。但是在其中我们需要注意两个函数:

publishFeedback(add_feedback)

以及

isPreemptRequested()

前面我们提到action相对于service的区别再于action有反馈以及可以中途停止。其中action的反馈就是通过publishFeedback函数实现的。前面我们定义了一个action_test::ActiontestFeedback add_feedback,所以在使用时给add_feedback赋值然后通过publishFeedback函数发布出来就可以了。

而下面的isPreemptRequested则是用来中止的,action函数的中止通过client发送canceled消息执行,而server端的判断通过isPreemptRequested判断。当收到中止指令时,isPreemptRequested为true。然后我们可以使用setPreempted(add_sum)函数返回当前结果然后退出循环。

编译上述代码后运行,其一共会生成5个topic:
在这里插入图片描述
这里面cancel是用来取消当前action的,goal是用来接收cation的。这两个由client发布server接收。而feedback用来实时反馈当前情况,status也是状态的一种,代表当前action状态。运行中是1,被取消时变成2,空闲时为3,abort时会变成4。result则是返回最后的结果。

我们可以使用rqt测试server。在rqt中添加goal的topic。goal给100,如下:
在这里插入图片描述当我们执行该topic时,echo几个话题可以得到对应的数据:像publishFeedback由于回调函数中是循环发布的所以它会一直更新:
在这里插入图片描述
而result设置了结束时候发布一次,所以当程序结束时它会被发布:
在这里插入图片描述
另外注意到cliect端还可以用于控制action在特定的时候关闭,比如运行到一半的时候,不想继续执行的时候我们可以通过cancel的topic停止当前循环,在isPreemptRequested()函数接收到cancel请求时会进入函数处理。在rqt测试时需要注意cancel的goal_id必须跟上面是一样的,要不然是不会生效的。比如我们在程序运行中执行一下cancel:
在这里插入图片描述会发现终端中的输出如下:

在这里插入图片描述
可以看到result本来应该是4950的但是由于执行了cancel所以提前退出了,最后的结果通过setPreempted(add_sum)发布。

3.1、action客户端

客户端比服务端简洁一点,因为它没有回调函数:

#include "ros/ros.h"
#include "action_test/ActiontestAction.h"
#include "action_test/ActiontestGoal.h"
#include <actionlib/server/simple_action_server.h>
#include <actionlib/client/simple_action_client.h>
using namespace std;
class action_client
{
 private:
    /* data */
    ros::NodeHandle n;
 public:
    action_client();
    ~action_client();
    void action_call();
    actionlib::SimpleActionClient<action_test::ActiontestAction> action_test_;
};
 
action_client::action_client():
action_test_("test_add",true)
{
}
void action_client::action_call()
{
   cout<<"call server"<<endl;
   action_test::ActiontestGoal addgoal;
   addgoal.numb = 100;
   action_test_.sendGoal(addgoal);
   //action_test_.sendGoalAndWait(addgoal);
}
action_client::~action_client()
{
}
int main(int argc,char **argv)
{
   ros::init(argc, argv,"action_client");
   action_client action_client;
   ros::spinOnce();
   action_client.action_test_.waitForServer();
   action_client.action_call();
   ros::spin();  
   return 0; 
}

这个代码比较简单,可以参考server端的解释。它的效果是请求一个goal给server,可以起到跟上面的rqt同样的效果。需要注意的是其中这一行:

action_client.action_test_.waitForServer();

比较特殊,在服务端不加这个似乎会出现bug,就是服务端客户端都正常打开但是服务端收不到客户端发送的Goal。所以保险起见还是加一下。

https://docs.ros.org/en/kinetic/api/actionlib/html/classactionlib_1_1SimpleActionServer.html
https://docs.ros.org/en/kinetic/api/actionlib/html/classactionlib_1_1SimpleActionClient.html
https://blog.csdn.net/qq_42145185/article/details/107508640

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

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

相关文章

图解Redisson如何实现分布式锁、锁续约?

文章目录一、基础0&#xff09;Redisson版本说明、案例案例1&#xff09;Redisson连接Redis的方式2&#xff09;用到的Redis命令3&#xff09;用到的lua脚本语义二、源码分析1、RLock获取RLock对象2、加锁流程0&#xff09;加锁流程图1&#xff09;加锁到哪台机器2&#xff09;…

一行代码获取股票、基金数据,并绘制K线图

大家好&#xff0c;今天这篇文章和大家分享一下如何利用Python获取股票、基金数据&#xff0c;并进行可视化&#xff0c;为金融分析&可视化先导篇&#xff0c;欢迎大家学习、点赞、收藏支持。 一、基础准备 环境&#xff1a;python 3.7 需要安装第三方模块&#xff1a;mpl…

Spring源码深度解析:十六、@Aspect方式的AOP下篇 - createProxy

一、前言 文章目录&#xff1a;Spring源码深度解析&#xff1a;文章目录 我们上篇已经分析到了 Spring将已经找到所有适用于当前bean 的Advisor 集合。下面就要创建代理对象了&#xff0c;而代理对象的创建是从 AbstractAutoProxyCreator#createProxy()开始。下面我们就来看看…

Spring Cloud实现Zuul自带的Debug功能

Zuul 中自带了一个 DebugFilter&#xff0c;一开始笔者也没明白这个 DebugFilter 有什么用&#xff0c;看名称很容易理解&#xff0c;它是用来调试的&#xff0c;可是你看它的源码几乎没什么逻辑&#xff0c;就 set 了两个值而已&#xff0c;代码如下所示。 Overridepublic Obj…

流媒体协议分析之webrtc之rtcp

TCP作为RTP控制协议&#xff0c;对于弱网下音视频质量和会话控制具有重要的作用。 1. RTCP Header V&#xff1a;RTCP的版本号&#xff0c;一定等于2&#xff1b; P&#xff1a;如果设置&#xff0c;填充位表示数据包包含末尾的附加填充八位字节&#xff0c;不属于控制信息&am…

CV-对比学习:概述【通过自监督学习,充分挖掘模型从海量无标注数据中学习通用知识的能力】

对比学习从目标来看&#xff0c;是要做在NLP类型类似Bert预训练的事&#xff0c;即通过自监督学习&#xff0c;充分挖掘模型从海量无标注数据中学习通用知识的能力。 大致分类 对比学习目前可大致可分为 基于负例的对比学习方法基于对比聚类的方法基于不对称网络结构的方法基…

PLC SECS/GEM解决方案,设计与应用

1 适用性 金南瓜SECS是最适应于全自动智能设备的选择。 适用行业&#xff1a;半导体、光伏、PCB等 全面支持E5、E30、E37、E40、E87、E90、E94、E116 PLC SECS/GEM具有怪兽级的强劲性能&#xff0c;处理性能高达10ms/条&#xff0c;全面升级的高适应性&#xff0c;易用友好的S…

30.前端笔记-CSS-CSS3的新特性

1、CSS3新增选择器 属性选择器&#xff0c;权重为10结构伪类选择器&#xff0c;权重为10伪元素选择器&#xff0c;权重为10 1.1 属性选择器 用属性选择器可以不用借助类或id选择器 语法&#xff1a; 正则表达式&#xff1a;^表示开头&#xff0c;$表示结尾,*表示任意 /*标…

怎么提高客服人员效率?

为了给客户提供更好的服务&#xff0c;很多企业会为自己网站配置客服服务&#xff0c;方便随时和客户沟通。但是凡事有利便有弊。虽然和客户接触的机会变多了&#xff0c;但是沟通不及时、回答不专业、问题处理时间长等问题也可能随之出现&#xff0c;反而会给客户带来不好的印…

[附源码]Python计算机毕业设计Django的个人理财系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

OpenCV-Python小应用(七):获取图片ROI的HSV取值范围

OpenCV-Python小应用&#xff08;七&#xff09;&#xff1a;获取图片ROI的HSV取值范围前言前提条件实验环境获取图片ROI的HSV取值范围参考文献前言 本文是个人使用OpenCV-Python的应用案例&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩…

基于无人机的移动边缘计算网络研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

socket网络字节序以及大端序小端序

不同CPU中&#xff0c;4字节整数1在内存空间的存储方式是不同的。4字节整数1可用2进制表示如下&#xff1a; 00000000 00000000 00000000 00000001 有些CPU以上面的顺序存储到内存&#xff0c;另外一些CPU则以倒序存储&#xff0c;如下所示&#xff1a; 00000001 00000000 0…

【Spring】SpringBoot 配置 logback 日志

1. 概述 日志在一个业务系统重非常重要&#xff0c;包含有非常重要的数据&#xff0c;可以用于客户反馈问题的排查、线上问题的追踪&#xff0c;以及根据日志数据对业务情况进行有效的监控配置&#xff0c;及时发现线上问题。 常用的日志框架有好几种&#xff0c;但最常用的是…

[附源码]Node.js计算机毕业设计大学校园兼职网站Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

【观察】定义下一代云原生实时数仓,SelectDB Cloud“打了个样”

2020年&#xff0c;国家在《关于构建更加完善的要素市场化配置体制机制的意见》中&#xff0c;首次将数据与土地、资本、劳动力并列为关键生产要素&#xff0c;并提出加快培育数据要素市场的愿景&#xff0c;此举可谓意义重大。背后的原因是&#xff0c;当下中国企业正在加速从…

【车载开发系列】UDS诊断---写入内存($0x3D)

【车载开发系列】UDS诊断—写入内存&#xff08;$0x3D&#xff09; UDS诊断---写入内存&#xff08;$0x3D&#xff09;【车载开发系列】UDS诊断---写入内存&#xff08;$0x3D&#xff09;一.概念定义二.报文格式1&#xff09;请求报文2&#xff09;肯定响应3&#xff09;否定响…

Redis实战——消息队列

目录 1. 什么是消息队列&#xff1f; 2. 基于List结构模拟消息队列 3. 基于PubSub的消息队列 4. 基于Stream的消息队列 4.1 基于Stream的单消费者模式 4.2 基于Stream的消息队列-消费者组 1. 什么是消息队列&#xff1f; 字面意思就是存放消息的队列。最简单的消息队列模…

学习参数化计算优化风扇定位step by step

一、写在前面 本教程的目的是演示ANSYS Icepak的参数和优化功能。假定读者已经熟悉ANSYS Icepak界面&#xff0c;但是缺乏实战经验。 在这个案例中&#xff0c;读者可以掌握&#xff1a; 1、使用Network网络热阻Block来模拟IC芯片封装模型。 2、将变量定义为参数并通过参数…

算法竞赛入门【码蹄集进阶塔335题】(MT2226-2250)

算法竞赛入门【码蹄集进阶塔335题】(MT2226-2250&#xff09; 文章目录算法竞赛入门【码蹄集进阶塔335题】(MT2226-2250&#xff09;前言为什么突然想学算法了&#xff1f;为什么选择码蹄集作为刷题软件&#xff1f;目录1. MT2226 36进制22. MT2227 36进制33. MT2228 36进制44.…