[ROS2] --- action

1 action介绍

ROS通信机制也会被常常用到——那就是动作。从这个名字上就可以很好理解这个概念的含义,这种通信机制的目的就是便于对机器人某一完整行为的流程进行管理。

1.1 客户端/服务器模型

动作和服务类似,使用的也是客户端和服务器模型,客户端发送动作的目标,想让机器人干什么,服务器端执行动作过程, 控制机器人达到运动的目标,同时周期反馈动作执行过程中的状态。
在这里插入图片描述
客户端发送一个运动的目标,想让机器人动起来,服务器端收到之后,就开始控制机器人运动,一边运动,一边反馈当前的状态,如果是一个导航动作,这个反馈可能是当前所处的坐标,如果是机械臂抓取,这个反馈可能又是机械臂的实时姿态。当运动执行结束后,服务器再反馈一个动作结束的信息。整个通信过程就此结束。

1.2 action通信特点

  • 一对多通信
    和服务一样,动作通信中的客户端可以有多个,大家都可以发送运动命令,但是服务器端只能有一个,毕竟只有一个机器人,先执行完成一个动作,才能执行下一个动作。

  • 同步通信
    既然有反馈,那动作也是一种同步通信机制,之前我们也介绍过,动作过程中的数据通信接口,使用.action文件进行定义。

  • 由服务和话题合成
    大家再仔细看下上边的动图,是不是还会发现一个隐藏的秘密。
    动作的三个通信模块,竟然有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应带,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。
    没错,动作是一种应用层的通信机制,其底层就是基于话题和服务来实现的。

2 action自定义通信接口

延续上一讲[ROS2] — action,中创建的自定义接口功能包,在src目录下创建action/Concatenate.action文件
Concatenate.action

int16 num_concatenations
---
string final_concatenation
---
string partial_concatenation

3 action编码示例

这里创建功能包名为,learning04_action

3.1 class_action_client.cpp

/*** @file class_action_client.cpp** @brief A class defined ROS2 action client node that sends as goal the number of string*        concatenation the action server should perform. *        The server will send back feedbacks and the final result** @author Antonio Mauro Galiano* Contact: https://www.linkedin.com/in/antoniomaurogaliano/**/#include "custom_interface/action/concatenate.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"class ConcatenateActionClient : public rclcpp::Node
{
public:using Concatenate = custom_interface::action::Concatenate;using GoalHandleConcatenate = rclcpp_action::ClientGoalHandle<Concatenate>;explicit ConcatenateActionClient(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions()): Node("class_action_client", node_options), goalDone_(false){this->clientPtr_ = rclcpp_action::create_client<Concatenate>(this->get_node_base_interface(),this->get_node_graph_interface(),this->get_node_logging_interface(),this->get_node_waitables_interface(),"concatenation");this->timer_ = this->create_wall_timer(std::chrono::milliseconds(500),std::bind(&ConcatenateActionClient::SendGoal, this));}bool GoalDone() const;void SendGoal();private:rclcpp_action::Client<Concatenate>::SharedPtr clientPtr_;rclcpp::TimerBase::SharedPtr timer_;bool goalDone_;void FeedbackCallback(GoalHandleConcatenate::SharedPtr,const std::shared_ptr<const Concatenate::Feedback> feedback);void ResultCallback(const GoalHandleConcatenate::WrappedResult & result);// be sure to define the parameter as it's here// more info at the declarationvoid GoalResponseCallback(const GoalHandleConcatenate::SharedPtr &goalHandle);
};bool ConcatenateActionClient::GoalDone() const
{return this->goalDone_;
}void ConcatenateActionClient::SendGoal()
{using namespace std::placeholders;this->timer_->cancel();this->goalDone_ = false;if (!this->clientPtr_){RCLCPP_ERROR(this->get_logger(), "Action client not initialized");}if (!this->clientPtr_->wait_for_action_server(std::chrono::seconds(10))){RCLCPP_ERROR(this->get_logger(), "!!ATTENTION!! Action server not available");this->goalDone_ = true;return;}auto goalMsg = Concatenate::Goal();goalMsg.num_concatenations = 9;RCLCPP_INFO(this->get_logger(), "Sending goal");auto send_goal_options = rclcpp_action::Client<Concatenate>::SendGoalOptions();send_goal_options.feedback_callback =std::bind(&ConcatenateActionClient::FeedbackCallback, this, _1, _2);send_goal_options.result_callback =std::bind(&ConcatenateActionClient::ResultCallback, this, _1);// send_goal_options.goal_response_callback =//   std::bind(&ConcatenateActionClient::GoalResponseCallback, this, _1);auto goal_handle_future = this->clientPtr_->async_send_goal(goalMsg, send_goal_options);
}void ConcatenateActionClient::FeedbackCallback(rclcpp_action::ClientGoalHandle<Concatenate>::SharedPtr,const std::shared_ptr<const Concatenate::Feedback> feedback)
{RCLCPP_INFO(this->get_logger(),"Feedback received: %s",feedback->partial_concatenation.c_str());
}void ConcatenateActionClient::ResultCallback(const GoalHandleConcatenate::WrappedResult & result)
{this->goalDone_ = true;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");for (auto number : result.result->final_concatenation){RCLCPP_INFO(this->get_logger(), "%d", number);}
}// defining the parameter directly as a GoalHandleConcatenate::SharedPtr goalHandle
// it's wrong for the send_goal_options.goal_response_callback
// so it doesnt compile
void ConcatenateActionClient::GoalResponseCallback(const GoalHandleConcatenate::SharedPtr &goalHandle){if (!goalHandle){RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");} else{RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");}}int main(int argc, char ** argv)
{rclcpp::init(argc, argv);auto action_client = std::make_shared<ConcatenateActionClient>();while (!action_client->GoalDone()){rclcpp::spin_some(action_client);}rclcpp::shutdown();return 0;
}

3.2 class_action_server.cpp

/*** @file class_action_server.cpp** @brief A class defined ROS2 action server node that concatenates a string *         based on the number of string concatenation sent by a client within a goal request** @author Antonio Mauro Galiano* Contact: https://www.linkedin.com/in/antoniomaurogaliano/**/#include "custom_interface/action/concatenate.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"class ConcatenateActionServer : public rclcpp::Node
{
public:using Concatenate = custom_interface::action::Concatenate;using GoalHandleConcatenate = rclcpp_action::ServerGoalHandle<Concatenate>;explicit ConcatenateActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions()): Node("class_action_server", options){using namespace std::placeholders;this->actionServer_ = rclcpp_action::create_server<Concatenate>(this->get_node_base_interface(),this->get_node_clock_interface(),this->get_node_logging_interface(),this->get_node_waitables_interface(),"concatenation",std::bind(&ConcatenateActionServer::HandleGoal, this, _1, _2),std::bind(&ConcatenateActionServer::HandleCancel, this, _1),std::bind(&ConcatenateActionServer::HandleAccepted, this, _1));}private:rclcpp_action::Server<Concatenate>::SharedPtr actionServer_;rclcpp_action::GoalResponse HandleGoal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Concatenate::Goal> goal);rclcpp_action::CancelResponse HandleCancel(const std::shared_ptr<GoalHandleConcatenate> goalHandle);void execute(const std::shared_ptr<GoalHandleConcatenate> goalHandle);void HandleAccepted(const std::shared_ptr<ConcatenateActionServer::GoalHandleConcatenate> goalHandle);
};rclcpp_action::GoalResponse ConcatenateActionServer::HandleGoal(const rclcpp_action::GoalUUID & uuid,std::shared_ptr<const Concatenate::Goal> goal)
{RCLCPP_INFO(rclcpp::get_logger("server"),"Got goal request with %d string concatenations",goal->num_concatenations);(void)uuid;// conditional to reject numbers of concatenationsif ((goal->num_concatenations > 10) && (goal->num_concatenations < 2)) {return rclcpp_action::GoalResponse::REJECT;}return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
}rclcpp_action::CancelResponse ConcatenateActionServer::HandleCancel(const std::shared_ptr<GoalHandleConcatenate> goalHandle)
{RCLCPP_INFO(rclcpp::get_logger("server"), "Got request to cancel goal");(void)goalHandle;return rclcpp_action::CancelResponse::ACCEPT;
}void ConcatenateActionServer::execute(const std::shared_ptr<GoalHandleConcatenate> goalHandle)
{RCLCPP_INFO(rclcpp::get_logger("server"), "Executing the concatenation");rclcpp::Rate loop_rate(1);const auto goal = goalHandle->get_goal();auto feedback = std::make_shared<Concatenate::Feedback>();std::string myString = "HELLOWORLD";auto &concatenation = feedback->partial_concatenation;concatenation = myString;concatenation = concatenation + " " + myString;auto result = std::make_shared<Concatenate::Result>();for (int i = 1; (i < goal->num_concatenations) && rclcpp::ok(); ++i){// check if there is a cancel requestif (goalHandle->is_canceling()){result->final_concatenation = concatenation;goalHandle->canceled(result);RCLCPP_INFO(rclcpp::get_logger("server"), "Goal Canceled");return;}// update the final concatenationconcatenation = concatenation + " " + myString;// update and publish feedback of the partial concatenationgoalHandle->publish_feedback(feedback);RCLCPP_INFO(rclcpp::get_logger("server"), "Publish Feedback");loop_rate.sleep();}// check if goal is doneif (rclcpp::ok()){result->final_concatenation = concatenation;goalHandle->succeed(result);RCLCPP_INFO(rclcpp::get_logger("server"), "Goal Succeeded");}
}void ConcatenateActionServer::HandleAccepted(const std::shared_ptr<GoalHandleConcatenate> goal_handle)
{using namespace std::placeholders;// this needs to return quickly to avoid blocking the executor, so spin up a new threadstd::thread{std::bind(&ConcatenateActionServer::execute, this, _1), goal_handle}.detach();
}int main(int argc, char ** argv)
{rclcpp::init(argc, argv);auto action_server = std::make_shared<ConcatenateActionServer>();rclcpp::spin(action_server);rclcpp::shutdown();return 0;
}

3.3 CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(learning04_action)# Default to C99
if(NOT CMAKE_C_STANDARD)set(CMAKE_C_STANDARD 99)
endif()# Default to C++14
if(NOT CMAKE_CXX_STANDARD)set(CMAKE_CXX_STANDARD 14)
endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")add_compile_options(-Wall -Wextra -Wpedantic)
endif()# find dependencies
find_package(ament_cmake REQUIRED)
find_package(custom_interface REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(rclcpp_components REQUIRED)# add_executable(simple_action_server src/simple_action_server.cpp)
# ament_target_dependencies(simple_action_server
#   "rclcpp"
#   "rclcpp_action"
#   "custom_interface")add_executable(class_action_server src/class_action_server.cpp)
ament_target_dependencies(class_action_server"rclcpp""rclcpp_action""custom_interface")# add_executable(simple_action_client src/simple_action_client.cpp)
# ament_target_dependencies(simple_action_client
#   "rclcpp"
#   "rclcpp_action"
#   "custom_interface")add_executable(class_action_client src/class_action_client.cpp)
ament_target_dependencies(class_action_client"rclcpp""rclcpp_action""custom_interface")if(BUILD_TESTING)find_package(ament_lint_auto REQUIRED)ament_lint_auto_find_test_dependencies()
endif()install(TARGETS# simple_action_serverclass_action_server# simple_action_clientclass_action_clientDESTINATION lib/${PROJECT_NAME})ament_package()

3.4 package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3"><name>learning04_action</name><version>0.0.0</version><description>Action based tutorial</description><maintainer email="user@todo.todo">Antonio Mauro Galiano</maintainer><license>TODO: License declaration</license><buildtool_depend>ament_cmake</buildtool_depend><depend>custom_interface</depend><depend>rclcpp</depend><depend>rclcpp_action</depend><depend>rclcpp_components</depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><export><build_type>ament_cmake</build_type></export>
</package>

4 编译运行

# 编译
colcon build# source环境变量
source install/setup.sh# 运行publisher
ros2 run learning04_action class_action_client# 运行subsriber
ros2 run learning04_action class_action_server

5 action常用指令

# 查看action信息
ros2 action info /turtle/roate_absolute# 设置action通信结构
ros2 interface show /turtle/roate_absolute# 发送action请求
ros2 action send_goal <action_name> <action_type> <values>
ros2 action send_goal /turtle/roate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}"
ros2 action send_goal /turtle/roate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}" --feedback

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

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

相关文章

数据结构中处理散列冲突的四种方法

1 开放定址法 1.1 定义 开放定址法就是一旦发生了冲突&#xff0c;就去寻找下一个空的散列地址 1.2 要求 只要散列表足够大 空的散列地址总能找到&#xff0c;并将记录存入 1.3 线性探测法 使用该公式用于解决冲突的开放定址法称为线性探测法 对于线性探测法&#xff0c…

通过kubeadm方式安装k8s

虚拟机最少是 2 core&#xff0c;master内存最小3G&#xff0c;node内存最小2G. 要求的Docker版本是18.03&#xff0c;如果不是安装的docker ce&#xff0c;版本是过旧的&#xff0c;可以选择删除后重新安装&#xff1b; 也可以重新创建一个虚拟机执行以下命令。 简单方法&am…

线性代数基础【1】行列式

第一节 行列式的基本概念和性质 一、基本概念 ①逆序 1,2和2,1是一对逆序 ②逆序数 1,2,3,5,4的逆序数为1;1,3,2,5,4逆序数为4; ③行列式 ④余子数和代数余子数 行列式挖掉一个数(例如aij),将原行列式去掉i行j列的行列式M,则M为余子数,代数余子数记为Aij,如果(ij)为偶数…

云LIS实验室信息管理系统源码——实验室信息管理解决方案

云LIS&#xff08;Cloud Laboratory Information System&#xff09;是一种为区域医疗提供临床实验室信息服务的计算机应用程序&#xff0c;其主要功能是协助区域内所有临床实验室相互协调并完成日常检验工作&#xff0c;对区域内的检验数据进行集中管理和共享&#xff0c;通过…

高通CRM的v4l2驱动模型

概述下crm中v4l2框架的初始化创建流程&#xff1a; 对于CRM主设备的v4l2框架创建过程&#xff1a; 1、分配和初始化v4l2 device对象 2、分配和初始化media device对象&#xff0c;然后将v4l2 device中mdev绑定到media device上 3、分配和初始化video device对象&#xff0c…

Python:核心知识点整理大全9-笔记

目录 ​编辑 5.2.4 比较数字 5.2.5 检查多个条件 1. 使用and检查多个条件 2. 使用or检查多个条件 5.2.6 检查特定值是否包含在列表中 5.2.7 检查特定值是否不包含在列表中 banned_users.py 5.2.8 布尔表达式 5.3 if 语句 5.3.1 简单的 if 语句 5.3.2 if-else 语句 …

YOLOv8改进 | 2023 | RCS-OSA替换C2f实现暴力涨点(减少通道的空间对象注意力机制)

一、本文介绍 本文给大家带来的改进机制是RCS-YOLO提出的RCS-OSA模块&#xff0c;其全称是"Reduced Channel Spatial Object Attention"&#xff0c;意即"减少通道的空间对象注意力"。这个模块的主要功能是通过减少特征图的通道数量&#xff0c;同时关注空…

Android Studio APK打包指定包名

在最近写的一个案列中尝试用最新版的Android studio对项目进行打包测试&#xff0c;想要指定打包的包名这样便于区分的时候发现以前的许多方法都过时了&#xff0c;查了很多资料才弄明白each被抛弃了。本教程建议先看第三步。 目录 一、配置根目录下gradle.build 二、通过bui…

Billu_b0x

信息收集 #正常进行信息收集就好Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-18 22:07 CST Nmap scan report for 192.168.182.142 (192.168.182.142) Host is up (0.00073s latency).PORT STATE SERVICE 22/tcp open ssh 80/tcp open http | http-cookie-flags:…

VSC改造MD编辑器及图床方案分享

VSC改造MD编辑器及图床方案分享 用了那么多md编辑器&#xff0c;到头来还是觉得VSC最好用。这次就来分享一下我的blog文件编辑流吧。 这篇文章包括&#xff1a;VSC下md功能扩展插件推荐、图床方案、blog文章管理方案 VSC插件 Markdown All in One Markdown Image - 粘粘图片…

【电子通识】为什么电阻都是2.2、3.3、4.7、5.1这样的小数,而不是整数?

刚开始接触电路设计可能会对市面上已经有的电阻值如&#xff1a;2.2Ω、4.7Ω、5.1Ω、22Ω、47Ω、51Ω&#xff0c;通常都不是整数觉得非常困惑&#xff0c;所以查阅了一些资料&#xff0c;总结如下&#xff1a; 电阻是使用指数分布来设计生产的&#xff0c;即遵循国际电工委…

基于STM32 + DMA介绍,应用和步骤详解(ADC多通道)

前言 本篇博客主要学习了解DMA的工作原理和部分寄存器解析&#xff0c;针对ADC多通道来对代码部分&#xff0c;应用部分作详细讲解&#xff0c;掌握代码编程原理。本篇博客大部分是自己收集和整理&#xff0c;如有侵权请联系我删除。 本次博客开发板使用的是正点原子精英版&am…

23种策略模式之策略模式

文章目录 前言优缺点使用场景角色定义UML模拟示例小结 前言 在软件开发中&#xff0c;设计模式是为了解决常见问题而提供的一套可重用的解决方案。策略模式&#xff08;Strategy Pattern&#xff09;是其中一种常见的设计模式&#xff0c;它属于行为型模式。该模式的核心思想是…

Java程序设计实验6 | 集合类

*本文是博主对Java各种实验的再整理与详解&#xff0c;除了代码部分和解析部分&#xff0c;一些题目还增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人自己的补充&#xff0c;以方便大家额外学习、参考。 &#xff08;解…

基于ssm的大型商场会员管理系统论文

摘 要 进入信息时代以来&#xff0c;很多数据都需要配套软件协助处理&#xff0c;这样可以解决传统方式带来的管理困扰。比如耗时长&#xff0c;成本高&#xff0c;维护数据困难&#xff0c;数据易丢失等缺点。本次使用数据库工具MySQL和编程框架SSM开发的大型商场会员管理系统…

【漏洞复现】FLIR AX8红外线热成像仪命令执行漏洞

漏洞描述 eledyne FLIR 设计、开发、制造以及强大的传感和意识技术。自透射热图像、可见光图像、可见频率分析、来自测量和诊断的先进威胁测量系统以及日常生活的创新解决方案。 Teledyne FLIR 提供多种产品用于政府、国防、工业和商业市场。我们的产品,紧急救援人员,军事人…

插入排序与希尔排序(C语言实现)

1.插入排序 由上面的动图可以知道插入排序的逻辑就是从第一个元素开始往后遍历&#xff0c;如果找到比前一个元素小的&#xff08;或者大的&#xff09;就往前排&#xff0c;所以插入排序的每一次遍历都会保证前面的数据是有序的&#xff0c;接下类用代码进行讲解。 我们这里传…

智能优化算法应用:基于浣熊算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于浣熊算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于浣熊算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.浣熊算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

解决HTTP错误500.19 - internal server error -内部服务器错误的终极指南

在开发和维护网络应用程序时&#xff0c;难免会遇到各种HTTP错误代码。其中&#xff0c;HTTP错误500.19 - 内部服务器错误可谓是最令人头痛的问题之一。当你的应用程序遇到这个错误时&#xff0c;它似乎就像一道墙壁&#xff0c;挡住了你前进的道路。但别担心&#xff0c;本篇技…

react-photo-view 的介绍、安装、使用。

目录 基本介绍 安装 使用 基本介绍 react-photo-view 是一个基于 React 的图片查看器组件&#xff0c;用于在网页上展示和浏览图片。该组件提供了用户友好的界面和交互&#xff0c;可以轻松地在应用程序中集成并使用。 支持触摸手势&#xff0c;拖动/平移/物理效果滑动…