【ROS入门】使用 ROS 动作(Action)机制实现目标请求、进度与完成结果的反馈

文章结构

  • 任务要求
  • 话题模型
  • 实现步骤
    • 定义action文件
      • 按照固定格式创建action文件
      • 编辑配置文件
      • 编译生成中间文件
    • 编写服务端和客户端
      • vscode配置
      • 服务端
      • 客户端
      • 编译配置文件
      • 执行

任务要求

使用 ROS 动作(Action)机制实现目标请求、进度与完成结果的反馈:

  • 创建服务端,注册 Action
  • 客户端发送action 请求检测 40个零件
  • 服务端接收后,每隔 1s 检测一个零件 (每检测一个打印1次),并实时给客户端返回检测进度(客户端打印进度百分比),并在检测完毕时告知客户端目标完成。

话题模型

action 是一种类似于服务通信的实现,其实现模型也包含请求和响应,但是不同的是,在请求和响应的过程中,服务端还可以连续的反馈当前任务进度,客户端可以接收连续反馈并且还可以取消任务。

action结构图解:

请添加图片描述

action结构图解:
请添加图片描述

实现步骤

定义action文件

action、srv、msg 文件内的可用数据类型一致,且三者实现流程类似

按照固定格式创建action文件

首先新建功能包,并导入依赖: roscpp rospy std_msgs actionlib actionlib_msgs

然后功能包下新建 action 目录,新增 check.action文件。

action 文件内容组成分为三部分:请求目标值、最终响应结果、连续反馈,三者之间使用—分割

内容如下:
在这里插入图片描述

编辑配置文件

CMakeLists.txt

find_package
(catkin REQUIRED COMPONENTSroscpprospystd_msgsactionlibactionlib_msgs
)
add_action_files(FILEScheck.action
)
generate_messages(DEPENDENCIESstd_msgsactionlib_msgs
)
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES demo04_actionCATKIN_DEPENDS roscpp rospy std_msgs actionlib actionlib_msgs
#  DEPENDS system_lib
)

编译生成中间文件

编译后会生成一些中间文件。

msg文件(…/工作空间/devel/share/包名/msg/xxx.msg):

在这里插入图片描述

C++ 调用的文件(…/工作空间/devel/include/包名/xxx.h):

在这里插入图片描述

Python 调用的文件(…/工作空间/devel/lib/python3/dist-packages/包名/msg/xxx.py):

在这里插入图片描述

编写服务端和客户端

vscode配置

{"configurations": [{"browse": {"databaseFilename": "${default}","limitSymbolsToIncludedHeaders": false},"includePath": ["/opt/ros/noetic/include/**","/home/chenyikeng/demo01_ws/src/helloworld/include/**","/home/chenyikeng/ROS_Topic_Demo/src/topic_demo/include/**","/usr/include/**","/home/chenyikeng/ROS_Topic_Demo/devel/include"],"name": "ROS","intelliSenseMode": "gcc-x64","compilerPath": "/usr/bin/gcc","cStandard": "gnu11","cppStandard": "c++14"}],"version": 4
}

服务端

/*
流程:1.包含头文件;2.初始化ROS节点;3.创建NodeHandle;4.创建action服务对象;5.处理请求,产生反馈与响应;a.获取并解析提交的目标值b.产生连续反馈c.最终结果响应6.spin().
*/#include "ros/ros.h"
#include "actionlib/server/simple_action_server.h"  //actionlib里头服务端的库
#include "action_demo/checkAction.h"    //自定义action文件时编译生成的库// 使用模板创建action服务对象并定义
typedef actionlib::SimpleActionServer<action_demo::checkAction> Server;//请求处理(a.解析提交的目标值;b.产生连续反馈;c.最终结果响应) --- 回调函数
void callBack(const action_demo::checkGoalConstPtr &goalPtr, Server*  server)
{// a.获取并解析提交的目标值int goal_num = goalPtr -> num;ROS_INFO("客户端提交的目标值是: %d",goal_num);// b.产生连续反馈ros::Rate rate(1); //1Hzint result = 0;for(int i = 1; i<= goal_num; i++){// 累加result ++;// 休眠rate.sleep();//产生(封装)连续反馈//创建feedback对象action_demo::checkFeedback fb;fb.progress_bar = i / (double)goal_num;//发送server->publishFeedback(fb);//打印ROS_INFO("检测%d个零件", result);}// c.最终结果响应// 创建result对象ROS_INFO("检测完成");action_demo::checkResult r;r.result = result;server -> setSucceeded(r);
}int main(int argc, char *argv[])
{setlocale(LC_ALL,"");ros::init(argc,argv,"check_server");ros::NodeHandle n;// 创建action服务对象/*SimpleActionServer(ros::NodeHandle n,     #句柄std::string name,       #话题名称boost::function<void (const action_demo::checkGoalConstPtr &)> execute_callback,    #回调函数,可以解析传入的目标值,产生连续反馈,以及响应最终结果bool auto_start)        #布尔值,是否自动启动*/Server server(n,"check",boost::bind(&callBack,_1,&server),false);//如果auto_start为false,那么需要手动调用该函数启动服务server.start();     ROS_INFO("服务启动……");//spin()回旋ros::spin();return 0;
}

客户端

/*
流程:1.包含头文件;2.初始化ROS节点;3.创建NodeHandle;4.创建action客户端对象;5.发送目标,处理反馈以及最终结果;a.连接建立 --- 回调函数b.处理连续反馈 --- 回调函数c.处理最终响应 --- 回调函数6.spin().
*/
#include "ros/ros.h"
#include "actionlib/client/simple_action_client.h"  //actionlib里头服务端的库
#include "action_demo/checkAction.h"    //自定义action文件时编译生成的库// 创建action客户端对象
typedef actionlib::SimpleActionClient<action_demo::checkAction> Client;// 服务端返回最终响应结果时候触发的回调
void done_cb(const actionlib::SimpleClientGoalState &state, const action_demo::checkResultConstPtr &result)
{// 判断响应状态是否成功if (state.state_ == state.SUCCEEDED)ROS_INFO("检测完成");else ROS_INFO("任务失败!");
}// 连接被激活的时候触发的回调
void active_cb()
{ROS_INFO("服务已经被激活....");
}// 连续反馈时的回调函数
void feedback_cb(const action_demo::checkFeedbackConstPtr &feedback)
{   float progress_bar_percentage = feedback->progress_bar*100;if(progress_bar_percentage-(int)progress_bar_percentage==0)ROS_INFO("当前进度:%d%%",(int)progress_bar_percentage);elseROS_INFO("当前进度:%.1f%%",progress_bar_percentage);
}int main(int argc, char *argv[])
{setlocale(LC_ALL,"");ros::init(argc,argv,"check_client");ros::NodeHandle n;// 创建action客户端对象;// SimpleActionClient(ros::NodeHandle & n, const std::string & name, bool spin_thread = true)// actionlib::SimpleActionClient<demo01_action::AddIntsAction> client(nh,"addInts");Client client(n,"check",true);//等待服务启动ROS_INFO("等待服务器启动……");client.waitForServer();// 发送目标,处理反馈以及最终结果;/*  void sendGoal(const demo01_action::AddIntsGoal &goal, boost::function<void (const actionlib::SimpleClientGoalState &state, const demo01_action::AddIntsResultConstPtr &result)> done_cb, 用于处理最终响应boost::function<void ()> active_cb, 连接被激活的时候使用的回调boost::function<void (const demo01_action::AddIntsFeedbackConstPtr &feedback)> feedback_cb)处理连续反馈时相关的回调函数*/// 设置目标值:40个零件// 声明对象action_demo::checkGoal goal;goal.num = 40;// 发送目标数据client.sendGoal(goal,&done_cb,&active_cb,&feedback_cb);// spin()回旋ros::spin();return 0;
}

编译配置文件

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

执行

首先启动 roscore,然后分别启动action服务端与action客户端,最终运行结果与案例类似。

结果如下:

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

推荐算法——Apriori算法原理

0、前言&#xff1a; 首先名字别读错&#xff1a;an pu ruo ao rui 【拼音发音】Apriori是一种推荐算法推荐系统&#xff1a;从海量数据中&#xff0c;帮助用户进行信息的过滤和选择。主要推荐方法有&#xff1a;基于内容的推荐、协同过滤推荐、基于关联规则的推荐、基于知识的…

leetCode 53.最大子数和 图解 + 贪心算法/动态规划+优化

53. 最大子数组和 - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入…

字符串,字符数组,类型转换,整数越界,浮点数,枚举

目录 自动类型转换 强制类型转换 数据类型 sizeof 数据类型所占字节数 整数越界 浮点数 字符型 字符串变量 ​编辑字符串的输入输出 main函数的参数 &#xff0c;argc,argv 单个字符输入输出 putchar getchar strlen,strcmp,strcat,strchr,strstr strlen 求字…

BASH shell脚本篇4——函数

这篇文章介绍下BASH shell中的函数。之前有介绍过shell的其它命令&#xff0c;请参考&#xff1a; BASH shell脚本篇1——基本命令 BASH shell脚本篇2——条件命令 BASH shell脚本篇3——字符串处理 函数是代码重用的最重要方式。Bash函数可以定义为一组命令&#xff0c;在b…

【STM32 CubeMX】移植u8g2(一次成功)

文章目录 前言一、下载u8g2源文件二、复制和更改文件2.1 复制文件2.2 修改文件u8g2_d_setup文件u8g2_d_memory 三、编写oled.c和oled.h文件3.1 CubeMX配置I2C3.2 编写文件oled.holed.c 四、测试代码main函数测试代码 总结 前言 在本文中&#xff0c;我们将介绍如何在STM32上成…

电脑显示系统错误怎么办?

有时我们在开机时会发现电脑无法开机&#xff0c;并显示系统错误&#xff0c;那么这该怎么办呢&#xff1f;下面我们就一起来了解一下。 方法1. 替换SAM文件解决问题 1. 重启电脑并进入安全模式。 Win8/10系统&#xff1a;在启动电脑看到Windows标志时&#xff0c;长按电源键…

gradle中主模块/子模块渠道对应关系通过配置实现

前言&#xff1a; 我们开发过程中&#xff0c;经常会面对针对不同的渠道&#xff0c;要产生差异性代码和资源的场景。目前谷歌其实为我们提供了一套渠道包的方案&#xff0c;这里简单描述一下。 比如我主模块依赖module1和module2。如果主模块中声明了2个渠道A和B&#xff0c…

【Java 进阶篇】JDBC ResultSet 遍历结果集详解

在Java数据库编程中&#xff0c;经常需要执行SQL查询并处理查询结果。ResultSet&#xff08;结果集&#xff09;是Java JDBC中用于表示查询结果的关键类之一。通过遍历ResultSet&#xff0c;我们可以访问和操作从数据库中检索的数据。本文将详细介绍如何使用JDBC来遍历ResultSe…

手把手教你做个智能加湿器(一)

一、前言 目前常见的加湿器类电子产品一般是由PCBA和外壳组成&#xff0c;我们将从PCB设计&#xff0c;然后编写软件&#xff0c;接着设计外壳&#xff0c;设计出一个完整的产品出来。 需要使用到软件&#xff1a; Altium Designer 17 SolidWorks 2019 Keil 4 二…

Error: node: unknown or unsupported macOS version: :dunno 错误解决

一、原因 今天安装 brew install node报错了&#xff0c;错误信息如下&#xff1a; 二、解决方案 1&#xff09;查找homebrew-cask安装位置 echo $(brew --repo homebrew/homebrew-cask) // 输出 /opt/homebrew/Library/Taps/homebrew/homebrew-cask2&#xff09;使用 gi…

selenium下载安装 -- 使用谷歌驱动碰到的问题

安装教程参考: http://c.biancheng.net/python_spider/selenium.html 1. 谷歌浏览器和谷歌驱动版本要对应(但是最新版本谷歌对应的驱动是没有的,因此要下载谷歌历史其他版本): 谷歌浏览器历史版本下载: https://www.chromedownloads.net/chrome64win/谷歌浏览器驱动下载: http:…

计算机网络分层结构

一、OSI参考模型(法定标准) 1.由国际标准化组织(ISO)提出的开放系统互连(OSI)参考模型 2.OSI七层结构&#xff1a; 3.通信过程&#xff1a; 4.各层功能 应用层-能和用户交互产生网络流量(需要联网)的程序&#xff0c;常见协议有文件传输(FTP)、电子邮件(SMTP)、万维网(HTTP)…

SpringCloud(一)Eureka、Nacos、Feign、Gateway

文章目录 概述微服务技术对比 Eureka服务远程调用服务提供者和消费者Eureka注册中心搭建注册中心服务注册服务发现Ribbon负载均衡负载均衡策略饥饿加载 NacosNacos与Eureka对比Nacos服务注册Nacos服务分集群存储NacosRule负载均衡服务实例权重设置环境隔离 Nacos配置管理配置热…

算法精品讲解(2)——DP问题入门(适合零基础者,一看就会)

目录 前言 DP问题它是什么&#xff08;了解&#xff09; 从中学的例题谈起 再来说一下&#xff0c;DP问题的核心思想&#xff08;理解&#xff09; DP问题的解决方法 先说方法论&#xff1a; 再说具体的例子 例一&#xff1a; 例二&#xff1a; 例三&#xff1a; DP和…

使用ExLlamaV2在消费级GPU上运行Llama2 70B

Llama 2模型中最大也是最好的模型有700亿个参数。一个fp16参数的大小为2字节。加载Llama 270b需要140 GB内存(700亿* 2字节)。 只要我们的内存够大&#xff0c;我们就可以在CPU上运行上运行Llama 2 70B。但是CPU的推理速度非常的慢&#xff0c;虽然能够运行&#xff0c;速度我…

postgresql-管理数据表

postgresql-管理数据表 创建表数据类型字段约束表级约束模式搜索路径 修改表添加字段删除字段添加约束删除约束修改字段默认值修改字段数据类型重命名字段重命名表 删除表 创建表 在 PostgreSQL 中&#xff0c;使用 CREATE TABLE 语句创建一个新表&#xff1a; CREATE TABLE …

量化交易全流程(四)

本节目录 数据准备&#xff08;数据源与数据库&#xff09; CTA策略 数据源&#xff1a; 在进行量化分析的时候&#xff0c;最基础的工作是数据准备&#xff0c;即收集数据、清理数据、建立数据库。下面先讨论收集数据的来源&#xff0c;数据来源可分为两大类&#xff1a;免…

nodejs开发环境搭建

Nodejs是一个开源的、跨平台JavaScript运行时环境&#xff0c;其使用V8引擎对JavaScript脚本执行解释&#xff0c;在前后端分离的应用架构设计中&#xff0c;其既能支持web页面服务应用的开发、也能支持后端接口服务应用的开发&#xff0c;类似于Java语言的J2EE运行时环境&…

Django基础入门操作 (Django-01)

一 背景介绍 Django是一个开源的 Web应用框架&#xff0c;由Python写成。采用了MTV的框架模式&#xff0c;它最初是被用来做CMS&#xff08;内容管理系统&#xff09;软件。 官方中文文档&#xff1a;Django 文档 | Django 文档 | Django 应用&#xff1a;做内容管理系统(新…

Swing程序设计(4)JLabel标签和导入图片

文章目录 前言一、JLabel标签 1.介绍2.实例展示二、JLabel中绘图和导入图片 1.自定义绘图2.导入图片总结 前言 本文介绍了Swing程序中JLabel标签的使用&#xff0c;以及在标签中导入图片和自定义图标的方法。 一、JLabel标签的使用 1.介绍 JLabel标签&#xff1a;在Swing程序中…