ros2 学习11-通信中动作的定义及自定义action 交互示例

机器人是一个复杂的智能系统,并不仅仅是键盘遥控运动、识别某个目标这么简单,我们需要实现的是送餐、送货、分拣等满足具体场景需求的机器人。

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

通信模型

举个例子,比如我们想让机器人转个圈,这肯定不是一下就可以完成的,机器人得一点一点旋转,直到360度才能结束,假设机器人并不在我们眼前,发出指令后,我们根本不知道机器人到底有没有开始转圈,转到哪里了?

在这里插入图片描述

OK,现在我们需要的是一个反馈,比如每隔1s,告诉我们当前转到多少度了,10度、20度、30度,一段时间之后,到了360度,再发送一个信息,表示动作执行完成。

这样一个需要执行一段时间的行为,使用动作的通信机制就更为合适,就像装了一个进度条,我们可以随时把控进度,如果运动过程当中,我们还可以随时发送一个取消运动的命令。

客户端/服务器模型

动作和服务类似,使用的也是客户端和服务器模型,客户端发送动作的目标,想让机器人干什么,服务器端执行动作过程, 控制机器人达到运动的目标,同时周期反馈动作执行过程中的状态。

在这里插入图片描述

客户端发送一个运动的目标,想让机器人动起来,服务器端收到之后,就开始控制机器人运动,一边运动,一边反馈当前的状态,如果是一个导航动作,这个反馈可能是当前所处的坐标,如果是机械臂抓取,这个反馈可能又是机械臂的实时姿态。当运动执行结束后,服务器再反馈一个动作结束的信息。整个通信过程就此结束。

一对多通信

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

同步通信

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

由服务和话题合成

大家再仔细看下上边的动图,是不是还会发现一个隐藏的秘密。

动作的三个通信模块,竟然有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应带,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。

没错,动作是一种应用层的通信机制,其底层就是基于话题和服务来实现的。

示例:小海龟的动作

ros2 run turtlesim turtlesim_node

在这里插入图片描述

重新开命令框启动键控节点

ros2 run turtlesim turtle_teleop_key
ros2 action info /turtle1/rotate_absolute
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}"
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: -1.57}" --feedback

在这里插入图片描述
在这里插入图片描述

案例2: 实现一个小车画圆的动作

通信模型
在这里插入图片描述

  1. 接口aciton 定义

例程使用的动作并不是ROS中的标准定义,我们通过MoveCircle.action进行自定义:

learning_interface/action/MoveCircle.action

bool enable     # 定义动作的目标,表示动作开始的指令
---
bool finish     # 定义动作的结果,表示是否成功执行
---
int32 state     # 定义动作的反馈,表示当前执行到的位置

在这里插入图片描述

修改配置文件,新增 “action/MoveCircle.action”

在这里插入图片描述

重新编译learning_interface 功能包

colcon build --packages-select learning_interface

在这里插入图片描述

新增learning_action 功能包

ros2 pkg create --build-type ament_python learning_action

新增服务器server代码

learning_action/action_move_server.py

import timeimport rclpy                                      # ROS2 Python接口库
from rclpy.node   import Node                     # ROS2 节点类
from rclpy.action import ActionServer             # ROS2 动作服务器类
from learning_inteface.action import MoveCircle  # 自定义的圆周运动接口class MoveCircleActionServer(Node):def __init__(self, name):super().__init__(name)                   # ROS2节点父类初始化self._action_server = ActionServer(      # 创建动作服务器(接口类型、动作名、回调函数)self,MoveCircle,'move_circle',self.execute_callback)def execute_callback(self, goal_handle):            # 执行收到动作目标之后的处理函数self.get_logger().info('Moving circle...')feedback_msg = MoveCircle.Feedback()            # 创建一个动作反馈信息的消息for i in range(0, 360, 30):                     # 从0360度,执行圆周运动,并周期反馈信息feedback_msg.state = i                      # 创建反馈信息,表示当前执行到的角度self.get_logger().info('Publishing feedback: %d' % feedback_msg.state)goal_handle.publish_feedback(feedback_msg)  # 发布反馈信息time.sleep(0.5)goal_handle.succeed()                           # 动作执行成功result = MoveCircle.Result()                    # 创建结果消息result.finish = True                            return result                                   # 反馈最终动作执行的结果def main(args=None):                                    # ROS2节点主入口main函数rclpy.init(args=args)                               # ROS2 Python接口初始化node = MoveCircleActionServer("action_move_server") # 创建ROS2节点对象并进行初始化rclpy.spin(node)                                    # 循环等待ROS2退出node.destroy_node()                                 # 销毁节点对象rclpy.shutdown()                                    # 关闭ROS2 Python接口

新增客户端代码
learning_action/action_move_client.py

import rclpy                                      # ROS2 Python接口库
from rclpy.node   import Node                     # ROS2 节点类
from rclpy.action import ActionClient             # ROS2 动作客户端类from learning_inteface.action import MoveCircle  # 自定义的圆周运动接口class MoveCircleActionClient(Node):def __init__(self, name):super().__init__(name)                   # ROS2节点父类初始化self._action_client = ActionClient(      # 创建动作客户端(接口类型、动作名)self, MoveCircle, 'move_circle') def send_goal(self, enable):                 # 创建一个发送动作目标的函数goal_msg = MoveCircle.Goal()             # 创建一个动作目标的消息goal_msg.enable = enable                 # 设置动作目标为使能,希望机器人开始运动self._action_client.wait_for_server()    # 等待动作的服务器端启动self._send_goal_future = self._action_client.send_goal_async(   # 异步方式发送动作的目标goal_msg,                                                   # 动作目标feedback_callback=self.feedback_callback)                   # 处理周期反馈消息的回调函数self._send_goal_future.add_done_callback(self.goal_response_callback) # 设置一个服务器收到目标之后反馈时的回调函数def goal_response_callback(self, future):           # 创建一个服务器收到目标之后反馈时的回调函数goal_handle = future.result()                   # 接收动作的结果if not goal_handle.accepted:                    # 如果动作被拒绝执行self.get_logger().info('Goal rejected :(')returnself.get_logger().info('Goal accepted :)')                            # 动作被顺利执行self._get_result_future = goal_handle.get_result_async()              # 异步获取动作最终执行的结果反馈self._get_result_future.add_done_callback(self.get_result_callback)   # 设置一个收到最终结果的回调函数 def get_result_callback(self, future):                                    # 创建一个收到最终结果的回调函数result = future.result().result                                       # 读取动作执行的结果self.get_logger().info('Result: {%d}' % result.finish)                # 日志输出执行结果def feedback_callback(self, feedback_msg):                                # 创建处理周期反馈消息的回调函数feedback = feedback_msg.feedback                                      # 读取反馈的数据self.get_logger().info('Received feedback: {%d}' % feedback.state) def main(args=None):                                       # ROS2节点主入口main函数rclpy.init(args=args)                                  # ROS2 Python接口初始化node = MoveCircleActionClient("action_move_client")    # 创建ROS2节点对象并进行初始化node.send_goal(True)                                   # 发送动作目标rclpy.spin(node)                                       # 循环等待ROS2退出node.destroy_node()                                    # 销毁节点对象rclpy.shutdown()                                       # 关闭ROS2 Python接口

设置setup.py

         'action_move_client = learning_action.action_move_client:main','action_move_server = learning_action.action_move_server:main',

在这里插入图片描述

编译

 colcon build --packages-select learning_action

设置环境变量

source install/local_setup.bash

测试验证:

ros2 action list                  # 查看服务列表

启动action 服务节点

ros2 run learning_action action_move_server

启动action 客户端节点

ros2 run learning_action action_move_client

运行结果如下:

可以看到有一个action list 有一个新增的 /move_circle
在这里插入图片描述
同时也可以看到服务端和客户端有一个数据交互反馈的日志输出
在这里插入图片描述

查看下/move_circle 的服务列表情况

ros2 action info /move_circle

运行结果如下:
在这里插入图片描述

动作命令的常用操作如下:

$ ros2 action list                  # 查看服务列表
$ ros2 action info <action_name>    # 查看服务数据类型
$ ros2 action send_goal <action_name> <action_type> <action_data>   # 发送服务请求

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

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

相关文章

我的创作纪念日- 从第一天到今天

目录 机缘 收获 持续学习和探索新技术 深化现有知识 代码里有所有 日常 扩大影响力 维护创作的质量和一致性 反馈和自我反思 憧憬 在这平凡的一天里&#xff0c;我选择赋予它特殊的意义。这不仅仅是我的创作旅程的一个节点&#xff0c;更是我个人成长和技术进步的见证…

HEA---code

import matplotlib.pyplot as pltimport numpy as npfrom matplotlib.animation import FuncAnimationfrom matplotlib.offsetbox import OffsetImage, AnnotationBbox# 创建一个画布和坐标轴对象 fig, ax plt.subplots() # 创建一个参数t&#xff0c;范围是0到2π t np.lins…

「工业遥测」图表控件LightningChart在水工业中的应用

LightningChart.NET完全由GPU加速&#xff0c;并且性能经过优化&#xff0c;可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D&#xff0c;高级3D&#xff0c;Polar&#xff0c;Smith&#xff0c;3D饼/甜甜圈&#xff0c;地理地图和GIS图表以及适用于科学…

图像ISP处理——自动对焦AF算法

自动对焦算法是在数码相机、摄像机和其他图像采集设备中常见的技术之一&#xff0c;它通过调整镜头位置或其他光学参数来确保拍摄的图像在焦点上清晰。 以下是一些常见的自动对焦算法&#xff1a; 对比度检测对焦&#xff08;Contrast Detection Autofocus&#xff0c;CDAF&am…

表格实现合并单元格

实现的效果 一、列合并 此需求的列合并比较简单, 直接使用el-table-column包括即可 <el-table-column align"center" sortable label"目标"><el-table-column prop"target1" sortable label"预设目标" /><el-table-c…

4. 可用性

文章目录 4. 第4章 可用性4.1. 可用性一般场景4.2. 可用性策略故障检测&#xff08;Detect Faults&#xff09;故障恢复&#xff08;Recover from Faults &#xff09;故障预防&#xff08;Prevent Faults&#xff09; 4.3. 基于策略的可用性调查表4.4. 可用性模式4.5. 扩展阅读…

【pentaho】kettle读取Hive表不支持bigint和timstamp类型解决。

一、bigint类型 报错: Unable to get value BigNumber(16) from database resultset显示kettle认为此应该是decimal类型(kettle中是TYPE_BIGNUMBER或称BigNumber)&#xff0c;但实际hive数据库中是big类型。 修改kettle源码解决&#xff1a; kettle中java.sql.Types到kettle…

仓储1、10、11代电子标签接口文档

标签注册 仓储1代注册 侧面按钮连按三次&#xff0c; 注册成功&#xff1a;红灯变绿灯 仓储10代注册 右下角左下角组合按键触发注册 注册成功&#xff1a;右上角绿灯变红灯 仓储11代注册 磁体靠近条码附近&#xff0c;触发标签注册到系统 注册成功&#xff1a;闪红灯边绿…

Ubuntu20.04 及深度学习环境anaconda、cuda、cudnn、pytorch、paddle2.3安装记录

学习目标&#xff1a; Ubuntu20.04下装好torch、paddle深度学习环境。 选择的版本环境是 &#xff1a;最新的nvidia驱动、cuda 11.1 、cudnn v8.1.1&#xff0c;下面会说为啥这么选。 学习内容&#xff1a; 1. Ubuntu20.04仓库换源 本节参考Ubuntu 20.04 Linux更换源教程 2…

C/C++ 块作用域的静态变量static的应用

块作用域的静态变量 静态变量(static variable)听起来自相矛盾&#xff0c;像是一个不可变的变量。实际上&#xff0c;静态的意思是该变量在内存中原地不动&#xff0c;并不是说它的值不变。具有文件作用域的变量自动具有&#xff08;也必须是&#xff09;静态存储器。创建的具…

Go语言与HTTP/2协议的实践探索

随着互联网技术的发展&#xff0c;HTTP/2协议逐渐成为主流。Go语言作为一种高效、简洁的编程语言&#xff0c;与HTTP/2协议的结合具有很大的潜力。本文将探讨Go语言与HTTP/2协议的实践探索。 一、HTTP/2协议的优势 HTTP/2协议相比HTTP/1.1协议&#xff0c;具有以下优势&#…

PCB变压器相关记录

PCB平面变压器设计指南--转载自21世纪电源网_北京泰科斯德技术有限公司 PCB变压器电流密度