ROS 2 TF 概述
TF(Transform) 是 ROS 中用于跟踪多个坐标系之间变换关系的库。在 ROS 2 中,TF 系统被重构为 TF2,提供了更高效、更灵活的坐标变换管理。
核心概念
1. 坐标系(Frame)
- 每个机器人部件、传感器或环境物体都有自己的坐标系
- 例如:
base_link(机器人基座)、laser(激光雷达)、(相机)
ROS 2 中 TF2 系统的核心概念与架构,包括坐标系、变换及变换树。详细阐述了 TF2 的组件如广播者和监听器,并提供了动态和静态变换发布的 Python 代码示例。此外,对比了 ROS 1 与 ROS 2 的差异,列出了常用工具命令及最佳实践,适用于传感器融合、导航规划等机器人应用场景。
TF(Transform) 是 ROS 中用于跟踪多个坐标系之间变换关系的库。在 ROS 2 中,TF 系统被重构为 TF2,提供了更高效、更灵活的坐标变换管理。
base_link(机器人基座)、laser(激光雷达)、(相机)cameraframe_B 相对于 frame_A 的位置和姿态map 或 odom)text
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ TF2 广播者 │ │ TF2 缓冲区 │ │ TF2 监听者 │
│ (Broadcaster) │────▶│ (Buffer) │◀────│ (Listener) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ 发布变换信息 │ │ 查询坐标变换 │
│ /tf 话题 │ │ lookupTransform │
└─────────────────┘ └─────────────────┘
| 组件 | 功能 | 对应类/节点 |
|---|---|---|
| Broadcaster | 广播坐标变换 | TransformBroadcaster |
| Static Broadcaster | 广播静态变换(固定关系) | StaticTransformBroadcaster |
| Listener | 监听并查询变换 | Buffer + TransformListener |
| Buffer | 存储变换历史 | tf2_ros::Buffer |
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import TransformStamped
import tf2_ros
import math
class DynamicFramePublisher(Node):
def __init__(self):
super().__init__('dynamic_frame_publisher')
# 创建 TF 广播者
self.br = tf2_ros.TransformBroadcaster(self)
# 定时发布
self.timer = self.create_timer(0.1, self.publish_transform)
self.t = 0.0
def publish_transform(self):
t = TransformStamped()
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = 'base_link' # 父坐标系
t.child_frame_id = 'rotating_laser' # 子坐标系
# 旋转运动
self.t += 0.1
t.transform.translation.x = 1.0
t.transform.translation.y = 0.0
t.transform.translation.z = 0.5
# 四元数表示旋转
t.transform.rotation.x = 0.0
t.transform.rotation.y = 0.0
t.transform.rotation.z = math.sin(self.t / 2)
t.transform.rotation.w = math.cos(self.t / 2)
self.br.sendTransform(t)
def main():
rclpy.init()
node = DynamicFramePublisher()
rclpy.spin(node)
rclpy.shutdown()
from tf2_ros.static_transform_broadcaster import StaticTransformBroadcaster
class StaticFramePublisher(Node):
def __init__(self):
super().__init__('static_frame_publisher')
self.static_br = StaticTransformBroadcaster(self)
# 只需要发布一次
static_transform = TransformStamped()
static_transform.header.stamp = self.get_clock().now().to_msg()
static_transform.header.frame_id = 'base_link'
static_transform.child_frame_id = 'camera_link'
static_transform.transform.translation.x = 0.5
static_transform.transform.translation.y = 0.0
static_transform.transform.translation.z = 0.3 # 修正变量名
# 相机朝向(旋转 90 度)
static_transform.transform.rotation.x = 0.0
static_transform.transform.rotation.y = 0.0
static_transform.transform.rotation.z = 0.707
static_transform.transform.rotation.w = 0.707
self.static_br.sendTransform(static_transform)
import tf2_ros
from tf2_ros import LookupException, ConnectivityException, ExtrapolationException
from rclpy.node import Node
class FrameListener(Node):
def __init__(self):
super().__init__('frame_listener')
# 创建 Buffer 和 Listener
self.tf_buffer = tf2_ros.Buffer()
self.tf_listener = tf2_ros.TransformListener(self.tf_buffer, self)
self.timer = self.create_timer(1.0, self.lookup_transform)
def lookup_transform(self):
try:
# 查询从 'base_link' 到 'laser' 的变换
transform = self.tf_buffer.lookup_transform(
'base_link', # 目标坐标系
'laser', # 源坐标系
rclpy.time.Time() # 最新时间
)
self.get_logger().info(f"Translation: [{transform.transform.translation.x:.2f}, "
f"{transform.transform.translation.y:.2f}, "
f"{transform.transform.translation.z:.2f}]")
except (LookupException, ConnectivityException, ExtrapolationException) as e:
self.get_logger().warn(f'Could not transform: {str(e)}')
# 查看当前 TF 树
ros2 run tf2_tools view_frames
# 查询特定变换
ros2 run tf2_ros tf2_echo base_link laser
# 发布静态变换
ros2 run tf2_ros static_transform_publisher 0 0 1 0 0 0 base_link camera
在 RViz2 中添加 TF 显示插件,可以实时可视化坐标系:
| 特性 | ROS 1 TF | ROS 2 TF2 |
|---|---|---|
| 默认库 | tf | tf2 |
| 时间处理 | 较简单 | 支持时间旅行(查询历史变换) |
| 数据类型 | 专用消息 | 与 ROS 2 消息系统更好集成 |
| 静态变换 | 混合处理 | 独立话题 /tf_static |
| 性能 | 一般 | 更高效,支持零拷贝 |
| Python 支持 | 较弱 | 原生支持,API 更友好 |
StaticTransformBroadcaster,减少网络负载map→odom→base_link)
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online