当前位置: 首页 > news >正文

【ROS2】中级:tf2-编写监听器(Python)

目标:学习如何使用 tf2 获取帧变换。

教程级别:中级

 时间:10 分钟

 目录

  •  背景

  •  先决条件

  •  任务

    • 1. 编写监听节点

    • 2. 更新启动文件

    • 3. 构建

    • 4. 运行

  •  摘要

 背景

在之前的教程中,我们创建了一个 tf2 广播器来发布乌龟的姿态到 tf2

在本教程中,我们将创建一个 tf2 监听器以开始使用 tf2

 先决条件

本教程假设您已经完成了 tf2 静态广播器教程(Python)和 tf2 广播器教程(Python)。在上一个教程中,我们创建了一个 learning_tf2_py 包,我们将继续在此基础上进行工作。

 任务

1. 编写监听节点

让我们首先创建源文件。转到我们在上一个教程中创建的 learning_tf2_py 包。在 src/learning_tf2_py/learning_tf2_py 目录中,通过输入以下命令下载示例监听器代码:

wget https://raw.githubusercontent.com/ros/geometry_tutorials/ros2/turtle_tf2_py/turtle_tf2_py/turtle_tf2_listener.py

现在使用您喜欢的文本编辑器打开名为 turtle_tf2_listener.py 的文件。

# 版权 2021 开源机器人基金会,公司。
#
# 根据Apache许可证版本2.0(“许可证”)许可;
# 除非符合许可证,否则不得使用此文件。
# 您可以在以下位置获取许可证副本:
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# 除非适用法律要求或书面同意,否则在许可证下分发的软件
# 将按“原样”基础分发,无任何形式的明示或暗示
# 保证或条件。有关在许可证下管理权限和
# 限制的语言,请参阅许可证。import math  # 导入数学库from geometry_msgs.msg import Twist  # 从geometry_msgs包导入Twist消息import rclpy  # 导入ROS客户端库
from rclpy.node import Node  # 从rclpy.node导入Node类from tf2_ros import TransformException  # 从tf2_ros导入TransformException异常
from tf2_ros.buffer import Buffer  # 从tf2_ros.buffer导入Buffer类
from tf2_ros.transform_listener import TransformListener  # 从tf2_ros.transform_listener导入TransformListener类from turtlesim.srv import Spawn  # 从turtlesim.srv导入Spawn服务class FrameListener(Node):  # 定义FrameListener类,继承自Node类def __init__(self):  # 定义初始化函数super().__init__('turtle_tf2_frame_listener')  # 调用父类初始化函数,设置节点名为'turtle_tf2_frame_listener'# 声明并获取`target_frame`参数self.target_frame = self.declare_parameter('target_frame', 'turtle1').get_parameter_value().string_value  # 声明并获取'target_frame'参数,默认值为'turtle1'self.tf_buffer = Buffer()  # 创建tf缓冲区self.tf_listener = TransformListener(self.tf_buffer, self)  # 创建tf监听器# 创建一个客户端来生成一个turtle # 在ROS中创建了一个客户端,用于调用名为 'spawn' 的服务。self.spawner = self.create_client(Spawn, 'spawn')  # 创建一个Spawn服务的客户端,服务名为'spawn'# 布尔值用于存储信息# 如果生成turtle的服务可用self.turtle_spawning_service_ready = False  # 初始化turtle生成服务状态为不可用# 如果turtle成功生成self.turtle_spawned = False  # 初始化turtle生成状态为未生成# 创建turtle2速度发布器self.publisher = self.create_publisher(Twist, 'turtle2/cmd_vel', 1)  # 创建一个Twist消息的发布器,话题名为'turtle2/cmd_vel',QoS设置为1# 每秒调用一次on_timer函数self.timer = self.create_timer(1.0, self.on_timer)  # 创建一个定时器,每秒调用一次on_timer函数def on_timer(self):  # 定义定时器回调函数# 将帧名存储在变量中,这些变量将用于# 计算变换from_frame_rel = self.target_frame  # 设置源帧为目标帧to_frame_rel = 'turtle2'  # 设置目标帧为'turtle2'if self.turtle_spawning_service_ready:  # 如果turtle生成服务可用if self.turtle_spawned:  # 如果turtle已经生成# 查找目标帧和turtle2帧之间的变换# 并发送速度命令使turtle2达到目标帧try:t = self.tf_buffer.lookup_transform(to_frame_rel,from_frame_rel,rclpy.time.Time())  # 尝试查找目标帧和turtle2帧之间的变换except TransformException as ex:  # 如果查找失败,抛出TransformException异常self.get_logger().info(f'无法将 {to_frame_rel} 变换到 {from_frame_rel}: {ex}')  # 记录无法进行变换的信息return  # 返回,不执行后续代码msg = Twist()  # 创建一个Twist消息scale_rotation_rate = 1.0  # 设置旋转速度比例因子msg.angular.z = scale_rotation_rate * math.atan2(t.transform.translation.y,t.transform.translation.x)  # 计算并设置z轴的角速度scale_forward_speed = 0.5  # 设置前进速度比例因子msg.linear.x = scale_forward_speed * math.sqrt(t.transform.translation.x ** 2 +t.transform.translation.y ** 2)  # 计算并设置x轴的线速度self.publisher.publish(msg)  # 发布Twist消息else:  # 如果turtle未生成if self.result.done():  # 如果服务调用完成self.get_logger().info(f'成功生成 {self.result.result().name}')  # 记录成功生成turtle的信息self.turtle_spawned = True  # 设置turtle生成状态为已生成else:  # 如果服务调用未完成self.get_logger().info('生成未完成')  # 记录生成未完成的信息else:  # 如果turtle生成服务不可用if self.spawner.service_is_ready():  # 如果服务可用# 使用turtle名和坐标初始化请求# 注意在turtlesim/srv/Spawn中,x、y和theta被定义为浮点数request = Spawn.Request()  # 创建一个Spawn请求request.name = 'turtle2'  # 设置turtle名为'turtle2'request.x = 4.0  # 设置turtle的x坐标为4.0request.y = 2.0  # 设置turtle的y坐标为2.0request.theta = 0.0  # 设置turtle的theta值为0.0# 调用请求self.result = self.spawner.call_async(request)  # 异步调用服务,发送请求self.turtle_spawning_service_ready = True  # 设置turtle生成服务状态为可用else:  # 如果服务不可用# 检查服务是否准备好self.get_logger().info('服务未准备好')  # 记录服务未准备好的信息def main():  # 定义主函数rclpy.init()  # 初始化ROS客户端库node = FrameListener()  # 创建一个FrameListener节点try:rclpy.spin(node)  # 让节点保持运行,处理回调函数except KeyboardInterrupt:  # 如果收到键盘中断信号pass  # 不做任何操作rclpy.shutdown()  # 关闭ROS客户端库

2cff245540fea0346817250072279e7d.png

d9cdb03d0feee99bbb6c3fd753529dcb.png

1.1 检查代码

要了解生成海龟服务背后的工作原理,请参阅编写一个简单的服务和客户端(Python)教程 https://docs.ros.org/en/jazzy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Service-And-Client.html 。

现在,让我们来看一下与获取帧转换相关的代码。 tf2_ros 包提供了一个 TransformListener 的实现,以帮助简化接收转换的任务。

from tf2_ros.transform_listener import TransformListener

在这里,我们创建一个 TransformListener 对象。监听器创建后,它开始通过网络接收 tf2 变换,并将它们缓冲最多 10 秒。

self.tf_listener = TransformListener(self.tf_buffer, self)

最后,我们查询监听器以获取特定转换。我们调用 lookup_transform 方法,传入以下参数:

  1.  目标框架

  2.  来源框架

  3. 我们想要转变的时间

提供 rclpy.time.Time() 将只会得到最新可用的转换。所有这些都包装在一个 try-except 块中,以处理可能的异常。

t = self.tf_buffer.lookup_transform(to_frame_rel,from_frame_rel,rclpy.time.Time())
1.2 添加一个入口点 

要允许 ros2 run 命令运行您的节点,您必须将入口点添加到 setup.py (位于 src/learning_tf2_py 目录中)。

在 'console_scripts': 括号之间添加以下行:

'turtle_tf2_listener = learning_tf2_py.turtle_tf2_listener:main',

2. 更新启动文件

打开位于 src/learning_tf2_py/launch 目录中名为 turtle_tf2_demo_launch.py 的启动文件,用你的文本编辑器,向启动描述中添加两个新节点,添加一个启动参数,并添加导入。结果文件应该看起来像:

from launch import LaunchDescription  # 从launch包导入LaunchDescription类
from launch.actions import DeclareLaunchArgument  # 从launch.actions导入DeclareLaunchArgument类
from launch.substitutions import LaunchConfiguration  # 从launch.substitutions导入LaunchConfiguration类from launch_ros.actions import Node  # 从launch_ros.actions导入Node类def generate_launch_description():  # 定义generate_launch_description函数return LaunchDescription([  # 返回一个LaunchDescription对象Node(  # 创建一个Node对象package='turtlesim',  # 设置包名为'turtlesim'executable='turtlesim_node',  # 设置可执行文件名为'turtlesim_node'name='sim'  # 设置节点名为'sim'),Node(  # 创建一个Node对象package='learning_tf2_py',  # 设置包名为'learning_tf2_py'executable='turtle_tf2_broadcaster',  # 设置可执行文件名为'turtle_tf2_broadcaster'name='broadcaster1',  # 设置节点名为'broadcaster1'parameters=[  # 设置参数{'turtlename': 'turtle1'}  # 设置'turtlename'参数为'turtle1']),DeclareLaunchArgument(  # 创建一个DeclareLaunchArgument对象'target_frame', default_value='turtle1',  # 设置参数名为'target_frame',默认值为'turtle1'description='Target frame name.'  # 设置参数描述为'Target frame name.'),Node(  # 创建一个Node对象package='learning_tf2_py',  # 设置包名为'learning_tf2_py'executable='turtle_tf2_broadcaster',  # 设置可执行文件名为'turtle_tf2_broadcaster'name='broadcaster2',  # 设置节点名为'broadcaster2'parameters=[  # 设置参数{'turtlename': 'turtle2'}  # 设置'turtlename'参数为'turtle2']),Node(  # 创建一个Node对象package='learning_tf2_py',  # 设置包名为'learning_tf2_py'executable='turtle_tf2_listener',  # 设置可执行文件名为'turtle_tf2_listener'name='listener',  # 设置节点名为'listener'parameters=[  # 设置参数{'target_frame': LaunchConfiguration('target_frame')}  # 设置'target_frame'参数为LaunchConfiguration对象,参数名为'target_frame']),])

这将声明一个 target_frame 启动参数,启动第二只乌龟的广播器,我们将生成这只乌龟,并启动一个监听器来订阅那些变换。

 3.构建

在工作区的根目录运行 rosdep 以检查缺失的依赖项。

rosdep install -i --from-path src --rosdistro jazzy -y

仍在工作区的根目录下,构建您的包:

colcon build --packages-select learning_tf2_py

打开一个新的终端,导航到工作区的根目录,然后加载设置文件:

. install/setup.bash

4. 运行

现在您已准备好开始完整的海龟演示:

ros2 launch learning_tf2_py turtle_tf2_demo_launch.py

897099ee0990886e7fbfc9a1a25c898b.png

您应该看到有两只乌龟的 turtle sim。在第二个终端窗口中输入以下命令:

ros2 run turtlesim turtle_teleop_key

要查看事物是否正常工作,只需使用箭头键驾驶第一只乌龟(确保您的终端窗口处于活动状态,而不是您的模拟器窗口),您会看到第二只乌龟跟随第一只乌龟!

b7b30ad2a5752b99b92253e8fc9df841.png

 摘要

在本教程中,您学习了如何使用 tf2 来获取帧变换的访问权限。您还完成了编写您在 tf2 教程https://docs.ros.org/en/jazzy/Tutorials/Intermediate/Tf2/Introduction-To-Tf2.html 介绍中首次尝试的 turtlesim 演示。

相关文章:

【ROS2】中级:tf2-编写监听器(Python)

目标:学习如何使用 tf2 获取帧变换。 教程级别:中级 时间:10 分钟 目录 背景 先决条件 任务 1. 编写监听节点2. 更新启动文件3. 构建4. 运行 摘要 背景 在之前的教程中,我们创建了一个 tf2 广播器来发布乌龟的姿态到 tf2。 在本教…...

用QFramework重构飞机大战(Siki Andy的)(下02)(06-0? 游戏界面及之后的所有面板)

用QFramework重构飞机大战(Siki Andy的)(下02)(06-0? 游戏界面及之后的所有面板) GitHub // 官网的 全民飞机大战(第一季)-----框架设计篇(Unity 2017.3) 全民飞机大战&…...

Apifox报错404:网络错误,请检查网络,或者稍后再试的解决办法

详细报错如图: 解决办法: 1、检查 请求方法(get,post)是否正确,请求的URL是否正确,如果不正确,修改后重新发起请求;如果都正确,再参考2 2、复制curl用postm…...

腾讯混元大模型集成LangChain

腾讯混元大模型集成LangChain 获取API密钥 登录控制台–>访问管理–>API密钥管理–>新建密钥,获取到SecretId和SecretKey。访问链接:https://console.cloud.tencent.com/cam/capi python SDK方式调用大模型 可参考腾讯官方API import json…...

C++心决之stl中那些你不知道的秘密(string篇)

目录 1. 为什么学习string类? 1.1 C语言中的字符串 2. 标准库中的string类 2.1 string类 2.2 string类的常用接口说明 1. string类对象的常见构造 2. string类对象的操作 3.vs和g下string结构的说明 3. string类的模拟实现 3.2 浅拷贝 3.3 深拷贝 3.4 写…...

date 命令学习

文章目录 date 命令学习1. 命令简介2. 语法参数2.1 使用语法2.2 说明2.3 参数说明 3. 使用案例:arrow_right: 星期名缩写 %a:arrow_right: 星期名全写 %A:arrow_right: 月名缩写 %b:arrow_right: 月名全称 %B:arrow_right: 日期和时间 %c:arrow_right: 世纪 %C:arrow_right: 按…...

前端vue后端java使用easyexcel框架下载表格xls数据工具类

一 使用alibaba开源的 easyexcel框架&#xff0c;后台只需一个工具类即可实现下载 后端下载实现 依赖 pom.xml <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependen…...

C#,开发过程中技术点GPT问答记录

6、为什么说GUI编程是事件驱动的&#xff1f; GUI&#xff08;图形用户界面&#xff09;编程是一种以图形方式构建用户界面的编程方法&#xff0c;它主要采用事件驱动模型进行程序逻辑的组织。在事件驱动的编程中&#xff0c;程序并不按照固定的顺序线性执行&#xff0c;而是等…...

wifi中的PSR技术

在Wi-Fi网络中&#xff0c;PSR&#xff08;Preferred Spatial Reuse&#xff09;是一种新兴技术&#xff0c;旨在提高频谱利用效率&#xff0c;特别是在高密度网络环境中。PSR通过允许多个接入点&#xff08;AP&#xff09;和设备在相同频谱资源上同时进行通信&#xff0c;从而…...

电子签章 签到 互动 打卡 创意印章 支持小程序 H5 App

电子签章 签到 互动 打卡 创意印章 支持小程序 H5 App 定制化...

Vscode插件推荐——智能切换输入法(Smart IME)

前言 相信广大程序员朋友在写代码的时候一定会遇到过一个令人非常头疼的事情——切换输入法&#xff0c;特别是对于那些勤于写注释的朋友&#xff0c;简直就是噩梦&#xff0c;正所谓懒人推动世界发展&#xff0c;这不&#xff0c;今天就向大家推荐一款好用的vscode插件&#…...

SpringBoot实战:轻松实现接口数据脱敏

一、接口数据脱敏概述 1.1 接口数据脱敏的定义 接口数据脱敏是Web应用程序中一种保护敏感信息不被泄露的关键措施。在API接口向客户端返回数据时&#xff0c;系统会对包含敏感信息&#xff08;如个人身份信息、财务数据等&#xff09;的字段进行特殊处理。这种处理通过应用特…...

我们水冷使制动电阻功率密度成倍增加-水冷电阻设计工厂

先进陶瓷 我们后来发现工业应用中对占用空间最小的水冷电阻器的工业需求&#xff0c;推出了适用于中压工业应用的水冷电阻器。它的特点是两块由具有特殊性能的先进陶瓷制成的板。 使用工业电驱动装置的一个重要好处是&#xff0c;可靠的再生和动态制动系统可以补充或取代传统…...

模板语法指令语法——02

//指令语法&#xff1a; 1.什么是指定&#xff0c;有什么作用&#xff1f; 指令的职责是&#xff0c;当表达式的值改变时&#xff0c;将其产生的连带影响&#xff0c;响应式的作用语DOM 2.vue框架中的所有指令的名字都以v-开始的 3.插值是写在标签当中用的&#xff0c;指令…...

Comparable 和 Comparator 接口的区别

Comparable 和 Comparator 接口的区别 1、Comparable 接口1.1 compareTo() 方法 2、Comparator 接口2.1 compare() 方法 3、 Comparable 和 Comparator 的区别总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;Compa…...

Python requests爬虫

Python的requests库是一个强大且易于使用的HTTP库&#xff0c;用于发送HTTP请求和处理响应。它是Python中最受欢迎的网络爬虫框架之一&#xff0c;被广泛用于从网页中提取数据、爬取网站和进行API调用。 使用requests库&#xff0c;你可以轻松地发送各种HTTP请求&#xff0c;包…...

Docker 基本管理及部署

目录 1.Docker概述 1.1 Docker是什么&#xff1f; 1.2 Docker的宗旨 1.3 容器的优点 1.4 Docker与虚拟机的区别 1.5 容器在内核中支持的两种技术 1.6 namespace的六大类型 2.Docker核心概念 2.1 镜像 2.2 容器 2.3 仓库 3.安装Docker 3.1 查看 docker 版本信息 4.…...

Ubuntu下安装配置和调优Docker,支持IPV6

今天在阿贝云的免费云服务器上折腾了一番Docker的配置和优化,这家免费云服务器可真不错啊。1核1G 10G硬盘,5M带宽,配置虽然简单但够用了。作为一个免费的云服务器,阿贝云的性能可以说是非常不错的了,完全能胜任日常的开发和部署工作。 让我们开始吧。首先,简单介绍一下Docker吧…...

Proteus + Keil单片机仿真教程(六)多位LED数码管的动态显示

上一节我们通过锁存器和八个八位数码管实现了多个数码管的静态显示,这节主要讲解多位数码管的动态显示,所谓的动态显示就是对两个锁存器的控制。考虑一个问题,现在给WS位锁存器增加一个循环,让它从1111 1110到0111 1111会发生什么事情?话不多说,先上代码: #include<…...

WEB开发-HTML页面更新部分内容

1 需求 2 接口 3 示例 在HTML页面中&#xff0c;如果你想要改变部分内容而不是整个页面&#xff0c;有几种方法可以实现这一目标&#xff0c;主要包括&#xff1a; JavaScript 的 DOM 操作 JavaScript允许你动态地修改HTML文档中的元素内容。你可以使用document.getElementB…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

前端开发者常用网站

Can I use网站&#xff1a;一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use&#xff1a;Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站&#xff1a;MDN JavaScript权威网站&#xff1a;JavaScript | MDN...

麒麟系统使用-进行.NET开发

文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的&#xff0c;如果需要进行.NET开发&#xff0c;则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET&#xff0c;所以要进…...