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

news2024/11/24 10:39:52

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

在这些应用功能的实现中,另外一种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 time

import 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 :(')
            return

        self.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.coloradmin.cn/o/1327885.html

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

相关文章

【krita】实时绘画 入门到精通 海报+电商+装修+人物

安装插件 首先打开comfyUI&#xff0c;再打开krita&#xff0c;出现问题提示&#xff0c; 打开 cd custom_nodes 输入命令 安装控件 git clone https://github.com/Acly/comfyui-tooling-nodes.git krita基础设置 设置模型 设置lora &#xff08;可设置lora强度 增加更多…

解锁高效工作!5款优秀工时管理软件推荐

工时管理&#xff0c;一直是让许多企业和团队头疼的问题。传统的纸质工时表、复杂的电子表格&#xff0c;不仅操作繁琐&#xff0c;还容易出错。幸好&#xff0c;随着科技的进步&#xff0c;我们迎来了工时管理软件的春天。今天&#xff0c;就让我们一起走进这个新时代&#xf…

蛮力法之背包问题

问题: 有 n 个重量分别是 w1,w2....,wn 的物品&#xff08;物品编号为 1-n&#xff09;它们的价值分别为 v1,v2,...,vn 给定一个容量为 W 的背包。设计从这些物品中选取一部分放入该背包的方案。 每个物品要么选中要么不选中【其实每个物品只有 1 件】&#xff0c;要求选中…

智慧互联网银行引领金融变革,开源网安VulHunter护航数字化发展

某银行作为国内知名的互联网银行&#xff0c;以构建“智慧型互联行”为总体战略目标&#xff0c;始终坚持科技赋能金融的理念。通过AI、大数据、云计算等数字技术与金融业务的探索融合&#xff0c;实现以更低的成本为客户提供便捷、高效和优质体验的互联网金融服务。 架构升级助…

基于ssm+vue的在线听书网站论文

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;书籍信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广大…

如何利用烛龙和谷歌插件优化CLS(累积布局偏移) | 京东云技术团队

简介 CLS 衡量的是页面的整个生命周期内发生的每次意外布局偏移的最大突发性_布局偏移分数_。布局变化的发生是因为浏览器倾向于异步加载页面元素。更重要的是&#xff0c;您的页面上可能存在一些初始尺寸未知的媒体元素。这种组合意味着浏览器在加载完成之前无法确定单个元素…

HarmonyOS快速入门之开发准备

开发准备 本文档适用于HarmonyOS应用开发的初学者。通过构建一个简单的具有页面跳转/返回功能的应用&#xff08;如下图所示&#xff09;&#xff0c;快速了解工程目录的主要文件&#xff0c;熟悉HarmonyOS应用开发流程。 在开始之前&#xff0c;您需要了解有关HarmonyOS应用的…

EOCR-i3M420/iFM420施耐德智能通讯保护继电器产品简介

EOCR-i3M420/iFM420是施耐德EOCR的新一代电子式电动机保护器产品&#xff0c;具有过电流、欠电流、缺相、逆相、堵转、失速、三相不平衡等保护功能&#xff0c;并具有4-20mA电流输出功能。EOCR-i3M420/iFM420是通讯型产品&#xff0c;提供Modbus RTU通讯协议&#xff0c;RS485接…

nodejs+vue+微信小程序+python+PHP兴趣趣班预约管理系统设计与实现-计算机毕业设计推荐

当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。 软件信息技术能够覆盖社会各行业领域是时代的发展要求&…

Shiro的认证与授权过程的401自定义信息返回格式

spring boot与shiro整合的很多这个不用多赘述&#xff0c;主要分享下过滤器这块 shiro中的部分过滤器 anon过滤器&#xff1a;用于处理匿名访问&#xff0c;即不需要身份验证的URL。 authc过滤器&#xff1a;用于进行身份验证&#xff0c;如果身份验证失败&#xff0c;将会返…

ModuleNotFoundError: No module named ‘tensorflow‘

直接运行pip install tensorflow安装成功之后&#xff0c;发现版本是tensorflow2.15.0 python的版本是3.9版本 导入包&#xff1a;import tensorflow 打包xxx.exe,调用之后提示错误 ModuleNotFoundError: No module named tensorflow 最后发现特定的python的版本对应特定的t…

Qt 6.3 学习笔记

文章目录 Qt的安装和配置创建一个Qt项目信号和槽布局和控件绘图和动画数据库和网络 Qt是一个跨平台的C图形用户界面应用程序开发框架。它提供了创建GUI应用程序的工具和库。Qt 6.3是Qt的最新版本&#xff0c;引入了许多新特性和改进。在这个章节中&#xff0c;我们将详细介绍如…

DRF从入门到精通二(Request源码分析、DRF之序列化、反序列化、反序列化校验、序列化器常用字段及参数、source、定制字段、保存数据)

文章目录 一、Request对象源码分析区分原生request和新生request新的request还能像原来的reqeust一样使用吗源码片段分析总结&#xff1a; 二、DRF之序列化组件序列化介绍序列化步骤序列化组件的基本使用反序列化基本使用反序列化的新增反序列化的新增删除单条 反序列化的校验序…

109基于MATLAB 中的设施布局设计和位置分配

基于MATLAB 中的设施布局设计和位置分配&#xff0c;通过PSO算法进行最佳位置匹配。程序已调通&#xff0c;可直接运行。 109设施布局设计和位置分配通 (xiaohongshu.com)

2023光伏“洗牌”,鼎捷数智方案如何助力企业抓住时代契机?

2023年的光伏行业正进入重新“洗牌”的阶段&#xff01; 一方面&#xff0c;在“双碳政策”和全球能源危机的双重驱动下&#xff0c;我国光伏全产业链迎来高速增长&#xff0c;成为外贸出口“新三样”之一。光伏发电正加速取代传统化石能源&#xff0c;在电网中发挥着日益重要的…

vue3+Ts

安装 命令含义可参考typescript文章中的自动编译部分 npm create vitelatest vuets-project -- --template vue-tsvs code插件 Vue Language Features (Volar)对.vue文件进行实时的类型错误反馈TypeScript Vue Plugin (Volar) 用于支持在TS中import*.vue文件&#xff08;mai…

【2023年网络安全优秀创新成果大赛专刊】银行数据安全解决方案(天空卫士)

在2023年网络安全优秀创新成果大赛&#xff0c;成都分站中&#xff0c;天空卫士银行数据安全方案获得优秀解决方案奖。与此同时&#xff0c;天空卫士受信息安全杂志邀请&#xff0c;编写《银行数据安全解决方案》。12月6日&#xff0c;天空卫士编写的《银行数据安全解决方案》做…

Debezium发布历史20

原文地址&#xff1a; https://debezium.io/blog/2017/09/25/streaming-to-another-database/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 将数据流式传输到下游数据库 九月 25, 2017 作者&#xff1a; Jiri…

期货交易策略模拟测试-基于CLBISO01策略-2023.12.22

采取与昨天同样的策略进行盘中模拟测试&#xff0c;今天行情还可以&#xff0c;挺“顺溜”。

1. 结构型模式 - 适配器模式

亦称&#xff1a; 封装器模式、Wrapper、Adapter 意图 适配器模式是一种结构型设计模式&#xff0c; 它能使接口不兼容的对象能够相互合作 问题 假如你正在开发一款股票市场监测程序&#xff0c; 它会从不同来源下载 XML 格式的股票数据&#xff0c; 然后向用户呈现出美观的图…