用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/MIUAV/vibe-coding-ros2 --skill tf-visualization命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | tf-visualization |
| description | RViz2 TF 可视化技能 - 坐标变换显示、帧调试、时间轴可视化 |
| argument-hint | rviz tf OR 坐标变换 OR tf调试 |
| user-invocable | true |
用于在 RViz2 中可视化坐标变换关系
当需要以下帮助时使用此技能:
import rclpy
from rclpy.node import Node
from tf2_ros import TransformBroadcaster
from geometry_msgs.msg import TransformStamped
class TFBroadcaster(Node):
def __init__(self):
super().__init__('tf_broadcaster')
self.broadcaster = TransformBroadcaster(self)
def broadcast_tf(self, parent, child, x, y, z, qx, qy, qz, qw):
t = TransformStamped()
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = parent
t.child_frame_id = child
t.transform.translation.x = x
t.transform.translation.y = y
t.transform.translation.z = z
t.transform.rotation.x = qx
t.transform.rotation.y = qy
t.transform.rotation.z = qz
t.transform.rotation.w = qw
self.broadcaster.sendTransform(t)
map
└── odom (里程计)
└── base_link (机器人基座)
├── base_scan (激光雷达)
├── camera_link (相机)
├── imu_link (IMU)
├── wheel_left (左轮)
└── wheel_right (右轮)
# RViz TF 显示配置
TF:
Frame Timeout: 10 # 帧超时时间 (秒)
All Frames: True # 显示所有帧
Frames:
All Enabled: True
Show Names: True
Show Axes: True
Show Arrows: True
Tree:
map:
enabled: true
parent: '' # 无父节点
odom:
enabled: true
parent: map
base_link:
enabled: true
parent: odom
Axes:
Frame: base_link
Length: 1.0 # 轴长度
Radius: 0.1 # 轴半径
TF:
Show Axes: True # 显示坐标轴
Show Names: True # 显示帧名称
Show Arrows: True # 显示箭头
Axis Length: 1.0 # 默认轴长度
Axis Radius: 0.05 # 默认轴半径
Head Length: 0.2 # 箭头头部长度
Head Width: 0.1 # 箭头头部宽度
Shaft Length: 0.8 # 箭头杆长度
Shaft Width: 0.05 # 箭头杆宽度
# 查看所有 TF 帧
ros2 run tf2_ros view_frames
# 监听 TF 变换
ros2 run tf2_ros tf2_echo source_frame target_frame
# 示例
ros2 run tf2_ros tf2_echo base_link map
from tf2_ros import TransformBroadcaster, Buffer, TransformListener
# 创建缓冲区
buffer = Buffer()
listener = TransformListener(buffer)
# 查找变换
try:
transform = buffer.lookup_transform(
'target_frame',
'source_frame',
rclpy.time.Time()
)
print(f"Transform: {transform}")
except Exception as e:
print(f"Error: {e}")
# 启动节点时启用仿真时间
ros2 run my_node my_node --ros-args -p use_sim_time:=true
# 在 RViz 中启用
# Global Options -> Use Simulation Time: True
# 检查变换时间戳
transform = buffer.lookup_transform('base_link', 'scan', rclpy.time.Time())
now = node.get_clock().now()
age = now - transform.header.stamp
print(f"TF age: {age.nanoseconds / 1e9} seconds")
# 问题 1: TF 不可用
# 解决方案: 检查变换是否发布
# 问题 2: TF 时间过期
# 解决方案: 调整 TF 缓冲区大小
# 问题 3: 循环依赖
# 解决方案: 简化 TF 树结构
# 增加超时时间
TF:
Frame Timeout: 30
from geometry_msgs.msg import TransformStamped
from tf2_ros import StaticTransformBroadcaster
static_broadcaster = StaticTransformBroadcaster(node)
# 发布静态变换
transform = TransformStamped()
transform.header.frame_id = "base_link"
transform.child_frame_id = "laser"
transform.transform.translation.x = 0.2
transform.transform.translation.y = 0.0
transform.transform.translation.z = 0.1
static_broadcaster.sendTransform(transform)
# 定时发布
timer = node.create_timer(0.1, publish_transform)
def publish_transform(self):
# 计算当前变换
t = TransformStamped()
t.header.stamp = self.get_clock().now().to_msg()
t.header.frame_id = "odom"
t.child_frame_id = "base_link"
# 设置变换
t.transform.translation.x = current_x
t.transform.translation.y = current_y
t.transform.translation.z = 0.0
self.broadcaster.sendTransform(t)
TF:
Tree:
map:
Color: 255; 0; 0; 255 # 红色
odom:
Color: 0; 255; 0; 255 # 绿色
base_link:
Color: 0; 0; 255; 255 # 蓝色
TF:
Labels:
Show: True
Color: 255; 255; 255; 255
Size: 12
解决方案:检查传感器数据延迟,调整滤波器参数
解决方案:检查外参是否正确,确认父坐标系设置