ROS2使用Python开发动作通信

1.创建接口节点

cd chapt4_ws/


ros2 pkg create robot_control_interfaces --build-type ament_cmake --destination-directory src --maintainer-name "joe" --maintainer-email "1027038527@qq.com"


mkdir -p src/robot_control_interfaces/action
touch src/robot_control_interfaces/action/MoveRobot.action

# Goal: 要移动的距离
float32 distance
---
# Result: 最终的位置
float32 pose
---
# Feedback: 中间反馈的位置和状态
float32 pose
uint32 status
uint32 STATUS_MOVEING = 3
uint32 STATUS_STOP = 4

修改package.xml

  <depend>rosidl_default_generators</depend>
  <member_of_group>rosidl_interface_packages</member_of_group>


修改CMakeLists.txt
find_package(rosidl_default_generators REQUIRED)


rosidl_generate_interfaces(${PROJECT_NAME}
  "action/MoveRobot.action"
)

编译节点

colcon build --packages-select robot_control_interfaces
 

2.创建Python Action节点

cd chapt4_ws/


ros2 pkg create example_action_rclpy --build-type ament_python --dependencies rclpy robot_control_interfaces --destination-directory src --node-name action_robot_02   --maintainer-name "joe" --maintainer-email "1027038527@qq.com"

# 手动再创建action_control_02节点文件
touch src/example_action_rclpy/example_action_rclpy/action_control_02.py

import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
# 导入Action接口
from robot_control_interfaces.action import MoveRobot

class ActionControl02(Node):
    """Action客户端"""

    def __init__(self, name):
        super().__init__(name)
        self.get_logger().info(f"节点已启动:{name}!")
        self.action_client_ = ActionClient(self, MoveRobot, 'move_robot')
        self.send_goal_timer_ = self.create_timer(1, self.send_goal)

    def send_goal(self):
        """发送目标"""
        self.send_goal_timer_.cancel()
        goal_msg = MoveRobot.Goal()
        goal_msg.distance = 5.0
        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(f'Result: {result.pose}')

    def feedback_callback(self, feedback_msg):
        """获取回调反馈"""
        feedback = feedback_msg.feedback
        self.get_logger().info(f'Received feedback: {feedback.pose}')


def main(args=None):
    """主函数"""
    rclpy.init(args=args)
    action_robot_02 = ActionControl02("action_control_02")
    rclpy.spin(action_robot_02)
    rclpy.shutdown()
 


#手动创建机器人类robot.py
touch src/example_action_rclpy/example_action_rclpy/robot.py


 

#!/usr/bin/env python3

import time
# 导入rclpy相关库
import rclpy
from rclpy.node import Node
from rclpy.action import ActionServer
from rclpy.action.server import ServerGoalHandle
# 导入接口
from robot_control_interfaces.action import MoveRobot
# 导入机器人类
from example_action_rclpy.robot import Robot
#from rclpy.executors import MultiThreadedExecutor
#from rclpy.callback_groups import MutuallyExclusiveCallbackGroup

class ActionRobot02(Node):
    """机器人端Action服务"""

    def __init__(self,name):
        super().__init__(name)
        self.get_logger().info(f"节点已启动:{name}!")

        self.robot_ = Robot()

        self.action_server_ = ActionServer(
            self, MoveRobot, 'move_robot', self.execute_callback
            # ,callback_group=MutuallyExclusiveCallbackGroup()
        )

    def execute_callback(self, goal_handle: ServerGoalHandle):
        """执行回调函数,若采用默认handle_goal函数则会自动调用"""
        self.get_logger().info('执行移动机器人')
        feedback_msg = MoveRobot.Feedback()
        self.robot_.set_goal(goal_handle.request.distance)

        # rate = self.create_rate(2)
        while rclpy.ok() and not self.robot_.close_goal():
            # move
            self.robot_.move_step()
            # feedback
            feedback_msg.pose = self.robot_.get_current_pose()
            feedback_msg.status = self.robot_.get_status()
            goal_handle.publish_feedback(feedback_msg)
            # cancel check
            if goal_handle.is_cancel_requested:
                result = MoveRobot.Result()
                result.pose = self.robot_.get_current_pose()
                return result
            # rate.sleep() # Rate会造成死锁,单线程执行器时不能使用
            time.sleep(0.5)

        goal_handle.succeed()
        result = MoveRobot.Result()
        result.pose = self.robot_.get_current_pose()
        return result

        
def main(args=None):
    """主函数"""
    rclpy.init(args=args)
    action_robot_02 = ActionRobot02("action_robot_02")
    # 采用多线程执行器解决rate死锁问题
    # executor = MultiThreadedExecutor()
    # executor.add_node(action_robot_02)
    # executor.spin()
    rclpy.spin(action_robot_02)
    rclpy.shutdown()
 

touch src/example_action_rclpy/example_action_rclpy/robot.py

from robot_control_interfaces.action import MoveRobot
import math

class Robot():
    """机器人类,模拟一个机器人"""

    def __init__(self) -> None:
        self.current_pose_ = 0.0
        self.target_pose_ = 0.0
        self.move_distance_ = 0.0
        self.status_ = MoveRobot.Feedback

    def get_status(self):
        """获取状态"""
        return self.status_

    def get_current_pose(self):
        """获取当前位置"""
        return self.current_pose_

    def close_goal(self):
        """接近目标"""
        return math.fabs(self.target_pose_ - self.current_pose_) < 0.01

    def stop_move(self):
        """停止移动"""
        self.status_ = MoveRobot.Feedback.STATUS_STOP

    def move_step(self):
        """移动一小步"""
        direct = self.move_distance_ / math.fabs(self.move_distance_)
        step = direct * math.fabs(self.target_pose_ - self.current_pose_) * 0.1
        self.current_pose_ += step  # 移动一步
        print(f"移动了:{step}当前位置:{self.current_pose_}")
        return self.current_pose_

    def set_goal(self, distance):
        """设置目标"""
        self.move_distance_ = distance
        self.target_pose_ += distance  # 更新目标位置

        if self.close_goal():
            self.stop_move()
            return False

        self.status_ = MoveRobot.Feedback.STATUS_MOVEING  # 更新状态为移动
        return True

编辑package.xml

  <depend>robot_control_interfaces</depend>

编辑setup.py

    'action_robot_02 = example_action_rclpy.action_robot_02:main',
    'action_control_02 = example_action_rclpy.action_control_02:main'

3.编译、运行节点
colcon build --packages-up-to example_action_rclpy


# 运行机器人节点
source install/setup.bash 
ros2 run example_action_rclpy  action_robot_02


# 新终端
source install/setup.bash 
ros2 run example_action_rclpy  action_control_02


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【微服务】微服务之Feign 与 Ribbon

文章目录 强烈推荐引言优点Feign示例什么是Ribbon&#xff1f;Ribbon 的优点Netflix Feign 和 Ribbon整合Feign 与 Ribbon 的关系Feign 与 Ribbon 结合使用的示例配置文件&#xff08;application.yml&#xff09;说明&#xff1a; Feign 与 Ribbon 结合使用的应用场景1. 动态服…

XD3C03P1G、XD3C01N3F比例方向控制阀放大板

XD3A01N2G、XD3A03N2G、XD3C03N1F、XD3C03P1G、XD3C01N3F、XD3C03N2F、XD3C01P4G、XD3C03P3G、XD3C03N2F、XD3C03N2G、XDP3A01P1F、XDP3C03N2G、XDP3A03P3G、XDP3C01NAF、XDP3C03P6G、XDP3A03PAG、XDP3A03N3F液压比例方向阀是液压系统中的关键元件&#xff0c;用于实现对流量、…

C#/WPF 自制截图工具

在日常使用电脑办公时&#xff0c;我们经常遇到需要截图然后保存图片&#xff0c;我们往往需要借助安装截图工具才能实现&#xff0c;现在我们通过C#自制截图工具&#xff0c;也能够轻松进行截图。 我们可以通过C#调用WindousAPI来实现截图&#xff0c;实例代码如下&#xff1a…

Three.js 中的光照模型

Three.js 中的光照模型 Three.js 的一个伟大抽象就是统一了所有材质的光照模型, 无论 PBR 或者 Phong。都只用两个函数给全部囊括了。 就是 RE_Direct(直接反射) 和 RE_IndirectDiffuse(间接反射)。真正做到了大一统。下面以Phong为例,具体看一下如何落地。 省流版本: // 直接…

CSF视频文件格式转换WMV格式(2024年可用)

如果大家看过一些高校教学讲解视频的话&#xff0c;很可能见过这样一个难得的格式&#xff0c;".csf "&#xff0c;非常漂亮 。 用暴风影音都可以打开观看&#xff0c;会自动下载解码。 但是一旦我们想要利用或者上传视频的时候就麻烦了&#xff0c;一般网站不认这…

开放式耳机哪个品牌质量最好最耐用?2024热门红榜耳机真实测评

随着人们生活质量的提高&#xff0c;喜爱运动的小伙伴也越来越多了&#xff0c;开放式蓝牙耳机的佩戴舒适度与稳定性这两个优势在很多运动场景中可以为用户带来更好的使用体验。此外&#xff0c;我们的音频使用、通话、游戏等应用场景在不断拓宽&#xff0c;蓝牙耳机的使用时间…

qt可点击的QLabel

需求——问题与思路 使用wpf实现一个可点击的超链接label相当简单&#xff08;如下图&#xff09;&#xff0c;但是qt的QLabel不会响应点击事件&#xff0c;那就从QLabel继承一个类&#xff0c;然后在该类中重写mousePressEvent函数&#xff0c;并在该函数中对左键点击事件做响…

FPGA工程师有前途吗 ?FPGA崛起之路

全球 FPGA 市场规模犹如滚雪球般逐年扩大。 根据Gartner Group预测&#xff0c;2020-2026年全球FPGA市场规模从55.85亿美元增至96.9亿美元&#xff0c;年均复合增长率为9.6%。 众多国际知名科技企业&#xff0c;如赛灵思、Lattice等&#xff0c;纷纷加大在 FPGA 研发和应用方…

linux操作系统数据盘挂载目录home改到www

云服务器开通后安装宝塔面板&#xff0c;数据盘默认挂载在 /home目录&#xff0c;通常这个目录不是我们需要的&#xff0c;数据盘需要挂载更换到/www目录。 如图所示数据盘/dev/mapper/ao-home 挂载到/home目录 但是我们需要它挂载到/www目录 以下操作是将数据盘/dev/mapper/…

希尔排序的实现

引言 排序在我们生活中十分常见&#xff0c;无论是购物软件中的商品推荐还是名次、排名都与排序算法息息相关。希尔排序是排序中较快的一种&#xff0c;而希尔排序实现的基础是插入排序。 排序的实现 插入排序&#xff08;以升序为例&#xff09; 插入排序的原理是从第二个数…

非静压模型SWASH学习(8)——三维孤立波在锥形岛屿上的爬坡过程(Runup of solitary waves on a conical island)

三维孤立波在锥形岛屿上的爬坡过程&#xff08;Runup of solitary waves on a conical island&#xff09; 算例简介模型配置网格及参数设置网格与地形初始条件与边界条件数值求解方法输出设置模拟时间 波浪&#xff08;孤立波&#xff09;入射边界的时间序列.bnd文件模拟结果注…

基于OpenCV与Keras的停车场车位自动识别系统

本项目旨在利用计算机视觉技术和深度学习算法&#xff0c;实现对停车场车位状态的实时自动识别。通过摄像头监控停车场内部&#xff0c;系统能够高效准确地辨认车位是否被占用&#xff0c;为车主提供实时的空闲车位信息&#xff0c;同时为停车场管理者提供智能化的车位管理工具…

Python基础小知识问答系列-记录最后N个元素

1. 问题&#xff1a; 怎么复制变量内容&#xff1f; 进行可迭代的操作过程中&#xff0c;如何记录最后几次操作的内容&#xff1f; 2. 解决方式&#xff1a; 对于非数值类型的变量&#xff0c;复制变量内容时&#xff0c;使用"*"。 记录最后n个元素&#xff…

重大丨深中通道今通车!继港珠澳大桥后,三思再度点亮世界工程

6月30日下午3时&#xff0c;国家重大工程深中通道正式通车试运营&#xff0c;向世界再次展示中国智慧和基建实力。已承接过包括港珠澳大桥海底隧道在内2500多条隧道照明工程的上海三思电子工程有限公司&#xff0c;为这座超级工程提供了LED隧道照明、东西人工岛照明及显示、管理…

【力扣】赎金信

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ 给你两个字符串…

私有云统一多云管理平台主要服务内容

私有云统一多云管理平台&#xff0c;作为企业IT架构现代化的关键组成部分&#xff0c;旨在为企业提供高效、灵活、安全的云计算资源管理解决方案。这类平台通过整合和优化不同云环境(包括私有云、公有云、混合云)的管理&#xff0c;帮助企业打破云孤岛&#xff0c;实现资源的统…

【MySQL备份】Percona XtraBackup增量备份实战篇

目录 1.前言 2.准备工作 2.1.环境信息 2.2.创建备份目录 2.3.配置/etc/my.cnf文件 2.4.授予root用户BACKUP_ADMIN权限 3.增量备份 3.1.第一步&#xff1a;全量备份 3.2.第二步&#xff1a;增量备份 3.3.第三步&#xff1a;再次增量备份 4.准备备份 4.1.准备全量备…

秋招Java后端开发冲刺——基础篇5(String集合)

一、String String类是Java中字符串操作类&#xff0c;位于java.lang包下String类型对象的底层使用字符数组char[]存储字符串&#xff0c;由final修饰且没有提供公共的修改方法&#xff0c;因此String对象是不可变的。常见方法 方法名作用trim()去掉字符串首尾空字符split(分…

【面试系列】产品经理高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

我在国企当合同工的那段日子

心血来潮 25号考完了&#xff0c;非常不理想&#xff0c;果然700页的东西不是一个月能搞完的。不对&#xff0c;我今儿写日志是为了纪念一下我的第一家公司&#xff0c;咋扯到别的了…言归正传&#xff0c;我在第一家公司待了仨年&#xff0c;可能是年纪到了(26岁咋还不退休啊…