【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客户端库
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
方法,传入以下参数:
目标框架
来源框架
我们想要转变的时间
提供 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
您应该看到有两只乌龟的 turtle sim。在第二个终端窗口中输入以下命令:
ros2 run turtlesim turtle_teleop_key
要查看事物是否正常工作,只需使用箭头键驾驶第一只乌龟(确保您的终端窗口处于活动状态,而不是您的模拟器窗口),您会看到第二只乌龟跟随第一只乌龟!
摘要
在本教程中,您学习了如何使用 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框架,后台只需一个工具类即可实现下载 后端下载实现 依赖 pom.xml <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependen…...
C#,开发过程中技术点GPT问答记录
6、为什么说GUI编程是事件驱动的? GUI(图形用户界面)编程是一种以图形方式构建用户界面的编程方法,它主要采用事件驱动模型进行程序逻辑的组织。在事件驱动的编程中,程序并不按照固定的顺序线性执行,而是等…...
wifi中的PSR技术
在Wi-Fi网络中,PSR(Preferred Spatial Reuse)是一种新兴技术,旨在提高频谱利用效率,特别是在高密度网络环境中。PSR通过允许多个接入点(AP)和设备在相同频谱资源上同时进行通信,从而…...

电子签章 签到 互动 打卡 创意印章 支持小程序 H5 App
电子签章 签到 互动 打卡 创意印章 支持小程序 H5 App 定制化...
Vscode插件推荐——智能切换输入法(Smart IME)
前言 相信广大程序员朋友在写代码的时候一定会遇到过一个令人非常头疼的事情——切换输入法,特别是对于那些勤于写注释的朋友,简直就是噩梦,正所谓懒人推动世界发展,这不,今天就向大家推荐一款好用的vscode插件&#…...

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

我们水冷使制动电阻功率密度成倍增加-水冷电阻设计工厂
先进陶瓷 我们后来发现工业应用中对占用空间最小的水冷电阻器的工业需求,推出了适用于中压工业应用的水冷电阻器。它的特点是两块由具有特殊性能的先进陶瓷制成的板。 使用工业电驱动装置的一个重要好处是,可靠的再生和动态制动系统可以补充或取代传统…...
模板语法指令语法——02
//指令语法: 1.什么是指定,有什么作用? 指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式的作用语DOM 2.vue框架中的所有指令的名字都以v-开始的 3.插值是写在标签当中用的,指令…...

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

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

Docker 基本管理及部署
目录 1.Docker概述 1.1 Docker是什么? 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页面中,如果你想要改变部分内容而不是整个页面,有几种方法可以实现这一目标,主要包括: JavaScript 的 DOM 操作 JavaScript允许你动态地修改HTML文档中的元素内容。你可以使用document.getElementB…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...