🧭 ROS 2 坐标变换工具 TF 笔记

TF(Transform)用于描述 多个坐标系之间的空间关系,是机器人感知、定位、导航的核心基础之一。


📦 环境与依赖安装

Python 发布 TF 所需库

1
2
sudo apt install ros-$ROS_DISTRO-tf-transformations
sudo pip install transforms3d

📌 说明:

  • tf_transformations:ROS 封装的坐标变换工具
  • transforms3d:底层数学库(欧拉角 / 四元数等)

🧱 静态坐标变换(Static TF)

适用于固定不变的坐标关系(如雷达相对机体)

▶️ 发布静态变换

示例:发布 base_link → base_laser

1
2
3
4
5
ros2 run tf2_ros static_transform_publisher \
--x 0 --y 0 --z 0 \
--roll 0 --pitch 0 --yaw 0 \
--frame-id base_link \
--child-frame-id base_laser

📐 参数说明:

  • x y z:平移(单位:米)
  • roll pitch yaw:旋转(弧度)
  • frame-id:父坐标系
  • child-frame-id:子坐标系

🔍 查询坐标变换

1
ros2 run tf2_ros tf2_echo frame_a frame_b

👉 实时输出两个坐标系之间的变换关系


🌳 查看 TF 变换树

1
ros2 run tf2_ros view_frames

📄 说明:

  • 在当前目录生成 frames.pdfframes.gv
  • 用于整体检查坐标系结构是否合理

🔄 动态坐标变换(Dynamic TF)

适用于随时间变化的坐标关系(如运动目标、机械臂)


🛠 创建功能包

1
2
3
ros2 pkg create pkg_name \
--build-type ament_python \
denpendencies rclpy tf2_ros tf_transformations geometry_msgs

📦 依赖说明:

  • tf2_ros:TF 广播 / 监听
  • tf_transformations:姿态计算
  • geometry_msgs:TransformStamped 消息

📡 动态 TF 广播节点(Python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import rclpy
import math
from rclpy.node import Node
from tf2_ros import TransformBroadcaster
from geometry_msgs.msg import TransformStamped
from tf_transformations import quaternion_from_euler


class DynamicTFBroadcaster(Node):
"""
动态 TF 广播器
功能:发布一个围绕 base_link 旋转的子坐标系
"""

def __init__(self):
super().__init__('dynamic_tf_broadcaster')

self.tf_broadcaster = TransformBroadcaster(self)
self.timer = self.create_timer(0.1, self.publish_frame) # 10 Hz
self.angle = 0.0

def publish_frame(self):
t = TransformStamped()

t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = 'base_link'
t.child_frame_id = 'moving_frame'

# 圆周运动
t.transform.translation.x = math.cos(self.angle)
t.transform.translation.y = math.sin(self.angle)
t.transform.translation.z = 0.0

# 欧拉角 → 四元数
q = quaternion_from_euler(0, 0, self.angle)
t.transform.rotation.x = q[0]
t.transform.rotation.y = q[1]
t.transform.rotation.z = q[2]
t.transform.rotation.w = q[3]

self.tf_broadcaster.sendTransform(t)
self.angle += 0.05


def main(args=None):
rclpy.init(args=args)
node = DynamicTFBroadcaster()
rclpy.spin(node)
rclpy.shutdown()


if __name__ == '__main__':
main()

✨ 效果:

  • moving_framebase_link 做圆周运动
  • 常用于 TF 学习 / 调试验证

👂 订阅 TF(TF Listener)

用于查询并使用已有的坐标变换


🛠 创建功能包

1
2
3
ros2 pkg create pkg_name \
--build-type ament_python \
denpendencies rclpy tf2_ros tf_transformations geometry_msgs

📥 TF 监听节点(Python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import rclpy
from rclpy.node import Node
from tf2_ros import Buffer, TransformListener


class TFListenerNode(Node):
"""
TF 监听节点
功能:获取 base_link → moving_frame 的变换
"""

def __init__(self):
super().__init__('tf_listener_node')

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

self.timer = self.create_timer(1.0, self.get_transform)

def get_transform(self):
try:
result = self.tf_buffer.lookup_transform(
'base_link',
'moving_frame',
rclpy.time.Time()
)

self.get_logger().info(
f'📐 坐标变换 base_link → moving_frame\n'
f' 平移: '
f'x={result.transform.translation.x:.3f}, '
f'y={result.transform.translation.y:.3f}, '
f'z={result.transform.translation.z:.3f}\n'
f' 旋转: '
f'x={result.transform.rotation.x:.3f}, '
f'y={result.transform.rotation.y:.3f}, '
f'z={result.transform.rotation.z:.3f}, '
f'w={result.transform.rotation.w:.3f}'
)

except Exception as e:
self.get_logger().warning(f'⚠️ 无法获取 TF: {e}')


def main(args=None):
rclpy.init(args=args)
node = TFListenerNode()
rclpy.spin(node)
rclpy.shutdown()


if __name__ == '__main__':
main()

❗ 常见失败原因:

  • 坐标系尚未发布
  • 名称拼写错误
  • TF 数据未缓存
  • 时间戳问题

🖥 GUI 工具:rqt

📦 安装

1
2
3
4
5
6
sudo apt install \
ros-$ROS_DISTRO-rqt \
ros-$ROS_DISTRO-rqt-common-plugins \
ros-$ROS_DISTRO-rqt-graph

rm -rf ~/.config/ros.org/rqt_gui.ini

▶️ 启动

1
rqt

🧩 常用插件

  • 📊 Graph:节点 / 话题拓扑
  • ⚙️ Parameter:参数查看与修改
  • 📡 Topics:话题监控

💾 布局保存:
File → Save Layout


🌈 可视化工具:RViz2

📦 安装

1
sudo apt install ros-$ROS_DISTRO-rviz2

▶️ 启动

1
rviz2

🧠 使用要点

  • 添加 Displays:TF / LaserScan / PointCloud
  • 设置 Fixed Frame(通常为 base_linkmap
  • 支持保存 .rviz 配置文件

✅ 总结一句话

TF 是 ROS 的”空间语言”,
静态描述结构,动态描述运动,
rqt 看关系,RViz 看世界。
🌍✨