【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…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...