geometry_msgs/TransformStamped 消息,不需要手动拼矩阵。
world 或 map),每个子节点有且只有一个父节点。从根到任意节点的路径唯一,因此任意两个坐标系之间的变换都可以通过路径上的变换累乘得到。
tf2_ros::Buffer 在后台自动完成,开发者只需要调用 lookup_transform() 并提供目标坐标系、源坐标系和时间戳。
tf2_echo 工具检查时间戳是否连续。StaticTransformBroadcasterTransformBroadcasterlookup_transform()geometry_msgs/TransformStamped,包含三个关键字段:header.frame_id(父坐标系)、child_frame_id(子坐标系)以及 transform(平移+旋转)。监听器端通过 Buffer 接收后存入内存中的变换树,收到查询请求时从缓存中查找并计算。
# 广播器示例(Python)
import rclpy
from rclpy.node import Node
from tf2_ros import TransformBroadcaster
from geometry_msgs.msg import TransformStamped
class LaserBroadcaster(Node):
def __init__(self):
super().__init__('laser_broadcaster')
self.br = TransformBroadcaster(self)
self.timer = self.create_timer(0.1, self.publish_transform)
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 = 'laser_frame'
t.transform.translation.x = 0.2
t.transform.translation.y = 0.0
t.transform.translation.z = 0.1
t.transform.rotation.w = 1.0 # 无旋转
self.br.send_transform(t)
base_link 的变换,但激光雷达用 laser_frame、摄像头用 camera_frame,两个变换的时间戳相差了0.2秒,导致融合后的点云与图像偏差了几个厘米。排查时用 ros2 run tf2_tools tf2_echo base_link laser_frame 和 ros2 run tf2_tools tf2_echo base_link camera_frame 分别查看,发现时间戳不同步。解决方法是让两个广播器使用同一个时钟源,或者对时间戳进行对齐处理。
# 监听器示例(Python)——查询laser_frame中的点相对于base_link的位置
import rclpy
from rclpy.node import Node
from tf2_ros import Buffer, TransformListener
from tf2_ros.transform_listener import TransformListener as Listener
class TransformQueryNode(Node):
def __init__(self):
super().__init__('transform_query')
self.tf_buffer = Buffer()
self.tf_listener = Listener(self.tf_buffer, self)
self.timer = self.create_timer(0.5, self.query)
def query(self):
try:
trans = self.tf_buffer.lookup_transform(
'base_link', # 目标坐标系
'laser_frame', # 源坐标系
rclpy.time.Time()) # 最近可用时间
self.get_logger().info(f'平移: ({trans.transform.translation.x}, {trans.transform.translation.y})')
except Exception as e:
self.get_logger().warn(f'查询失败: {e}')
| 类型 | 数据变化频率 | 发布方式 | 典型场景 | 广播器API |
|---|---|---|---|---|
| 静态变换 | 从不变化 | 发布一次,TF2自动重发 | 传感器在机器人上的固定安装位置 | StaticTransformBroadcaster |
| 动态变换 | 周期性变化(如10Hz~100Hz) | 每个控制周期主动发布 | 机械臂关节角度、车辆转向轮偏角 | TransformBroadcaster |
| 近似变换 | 变化但允许少量误差 | 与动态变换相同 | 视觉SLAM位姿估计(有漂移) | TransformBroadcaster |
tf2_ros::StaticTransformBroadcaster 一次性发布,后续由TF2内部线程按固定间隔自动重发,不需要开发者维护定时器。动态变换必须由开发者按实际更新频率持续发布,否则监听端查询时会提示"变换过期"。
在已有的ROS2工作空间中创建两个节点:
base_link 到 laser_frame 的静态变换,平移量设为 x=0.2, y=0.0, z=0.1,无旋转。laser_frame 相对于 base_link 的变换,并打印平移量。ros2 run tf2_tools tf2_monitor 查看TF树的完整结构,确认父子关系正确。扩展任务:在同一个机器人上再添加一个 camera_frame,发布从 base_link 到 camera_frame 的变换(平移 x=0.1, y=0.15, z=0.05),然后在监听器中查询 camera_frame 到 laser_frame 的变换——观察TF2如何自动通过 base_link 计算出间接变换。
lookup_transform('base_link', 'laser_frame', time) 时,如果两个坐标系之间没有直接发布的变换,但通过 odom 节点可以连通,TF2会:TransformStamped 消息Buffer 自动接收并缓存所有变换,调用 lookup_transform() 即可查询任意两个坐标系之间的变换tf2_echo 和 tf2_monitor 工具进行诊断