ROS 2 RViz 实战:模型、TF、传感器与空白画面排查

话题里明明有点云,RViz 却什么也不显示;模型出来了,腿却不动;雷达数据有了,位置却跟着机身乱跑。解决这类问题,要沿着 数据 → 坐标系 → 时间 → 显示设置 检查,而不是反复重启窗口。

本文以 Ubuntu 22.04 + ROS 2 Humble 的 RViz2 为基线,核对日期为 2026-10-12。先用一个静态坐标系和一个点建立直觉,再迁移到机器人模型、传感器与 rosbag。通信图、数值曲线和日志见 rqt 实战。

一、RViz 显示的是什么

RViz 是 ROS 数据的三维可视化工具:上游节点给出模型、变换、点云或路径,RViz 根据消息和配置把它们画出来。它本身不负责物理仿真,也不会凭 URDF 自动算出机器人真实运动。

可以把它理解为“具有坐标和时间语义的观察窗口”。同一幅漂亮画面,可能来自真机,也可能来自仿真、录包回放或手工发布的消息;画面不能单独证明动力学正确。

在已经配置 Humble apt 源的环境中,缺少工具时安装:

sudo apt update
sudo apt install ros-humble-rviz2 ros-humble-tf2-ros

每个新 Bash 终端先加载环境,再启动:

source /opt/ros/humble/setup.bash
ros2 run rviz2 rviz2

WSL 需要可用的图形环境和 OpenGL 支持;Docker 还需要显式配置显示连接。若窗口都打不开,先区分 display、显卡渲染或 Qt 插件问题,暂时不必追查机器人 TF。

二、先认识这几个显示项

Display 输入与用途 首先确认
Grid 空间参考网格 网格尺寸、所用坐标系
TF 坐标轴和父子关系 帧名是否正确、变换是否持续更新
RobotModel URDF 外观与各 link 位姿 模型描述、资源路径、TF
LaserScan 二维扫描距离 话题、量程、frame_id
PointCloud2 三维点云 话题、颜色字段、点大小
Image / Camera 图像 / 带相机几何关系的显示 后者还依赖标定信息与相关 TF
Path / Marker 规划路径 / 自定义调试几何体 消息坐标、时间、尺寸和透明度

添加 Display 后,展开它的 Status。错误通常比画面的外观更能说明问题。具体显示类型与配置见 RViz 官方用户指南。

RViz 并非所有功能都只读。工具栏中的初始位姿、目标点或交互标记可能发送消息;是否真的让机器人运动,取决于上游导航/控制节点。连接真机时应知道每个按钮会发到哪里。

三、Fixed Frame 和“相机跟着谁”不是一回事

Global Options 里的 Fixed Frame 是把空间数据统一画到哪个参考系。对移动机器人,常用候选有:

  • odom:适合观察局部连续运动,但会随估计误差漂移。
  • map:适合观察全局地图与定位;定位修正可能使机器人位姿发生跳变。
  • base_link:适合观察机身局部关系,不适合当成静止世界来积累环境数据。

这不是说这些帧一定存在。先检查自己的 TF 树和定位配置,不能因为教程写了 map 就直接填写它。

View 的 Target Frame 则主要控制观察视角。想让镜头跟着机器人,同时保留世界中的点云和轨迹,通常应保持合适的世界 Fixed Frame,再配置跟随目标,而不是把两者混为一谈。

更重要的是时间:RViz 需要把消息的 header.frame_id 在其时间戳处转换到 Fixed Frame。帧名正确,但这个时刻的变换不可用,仍会显示失败;详细原理见 TF2 实战。

四、不用 URDF,先显示一个坐标明确的点

以下例子不连接硬件。为避免与已有项目的 base_link 冲突,使用独立 ROS 域;在每个示例终端中运行:

source /opt/ros/humble/setup.bash
export ROS_DOMAIN_ID=42
export ROS_LOCALHOST_ONLY=1

42 只是示例值;如果本机已有程序用这个域,请为本例换一个空闲域。实验结束后关闭这些终端,避免把隔离设置带进日常工程。

终端 A:声明传感器位于基座前方 0.3 m、上方 0.2 m,方向一致。

ros2 run tf2_ros static_transform_publisher \
--x 0.3 --y 0 --z 0.2 \
--roll 0 --pitch 0 --yaw 0 \
--frame-id base_link --child-frame-id sensor_frame

终端 B:持续发布一个在传感器前方 1 m 的点。Humble 的 topic pub 支持用 now 填入当前时间戳。

ros2 topic pub --rate 5 /rviz_demo/point geometry_msgs/msg/PointStamped \
"{header: {stamp: now, frame_id: sensor_frame}, point: {x: 1.0, y: 0.0, z: 0.0}}"

终端 C:启动 RViz。

ros2 run rviz2 rviz2

在界面里设置:

  1. Fixed Frame 填 base_link;本例基座不动,所以可以作为参考。
  2. Add → TF,展开并显示名称,观察 base_link 和 sensor_frame。
  3. Add → PointStamped,Topic 选择 /rviz_demo/point。
  4. 把点的 Radius 调成例如 0.05 m,并调整视角。

本例没有旋转,点在基座坐标系下应为:

p_base = p_sensor + t_base_sensor
= (1.0, 0.0, 0.0) + (0.3, 0.0, 0.2)
= (1.3, 0.0, 0.2) m

想独立确认变换和消息,在同域的另一个终端运行以下命令;第一条会持续输出,按 Ctrl+C 后再运行第二条:

ros2 run tf2_ros tf2_echo base_link sensor_frame
ros2 topic echo /rviz_demo/point --once

这个例子刻意把模型、驱动、定位全部拿掉:如果点看不见,排查范围就只有消息、TF、时间和 Display。结束时,在所有发布与查看终端按 Ctrl+C。

五、RobotModel 为什么有外观,却没有正确姿态

机器人模型显示涉及两类不同的数据:

URDF ───────────────────────────────→ RViz RobotModel:长什么样
└→ robot_state_publisher + joint_states → TF → RViz:各 link 在哪里
定位 / 里程计 ───────────────────────→ 机身相对 map / odom 的 TF

Humble 的 robot_state_publisher 从 URDF 和 joint_states 计算 link 变换,并发布模型描述话题。RViz 的 RobotModel 选择正确的 Description Source / Description Topic 后,还需要匹配的 TF;它不是直接把 joint_states 当成完整世界位姿来画。robot_state_publisher 的 Humble 说明

对四足机器人尤其要区分:

  • 四条腿的关节状态决定机身内部的相对形状。
  • 机身在世界中的位置与朝向,来自定位、状态估计或仿真等上游。
  • 有完整关节状态,不代表已经有 odom → base_link。

模型缺一块时,先看 link 状态和 mesh 加载错误。另一台电脑可能缺少 package:// 指向的模型包,或者没有加载工作空间环境;.rviz 配置并不包含所有 mesh 文件。

六、有话题却不显示:先检查 QoS,再检查 TF

例如点云话题名和消息类型都正确,但 Display 仍显示 No messages received,先看发布者实际提供了什么:

# 这里的 /points 替换为驱动实际发布的话题
ros2 topic info /points --verbose

若发布端是 Best Effort,而 RViz 这个 Display 请求 Reliable,则应把该 Display 的 Reliability 改成 Best Effort。不要不分情况修改全部节点。

对于需要在“晚加入”时收到已有内容的描述、地图等话题,还要检查 Durability 是否与发布者的 Transient Local 策略及需求相匹配。这和点云的持续流不是同一个问题。QoS 兼容表

收到消息之后,再按报错继续:

现象或状态 优先检查
Fixed Frame 不存在 帧名拼写、TF 发布者是否启动、是否处于同一 ROS 域
消息有了,但无法转换到目标帧 frame_id 到 Fixed Frame 的整条链,不能只看其中一段
Extrapolation into future / past 消息与 TF 时间、缓存范围、仿真时间是否一致
点云在意料外的位置 外参方向、单位、轴约定、选择的 Fixed Frame
Status 正常但几乎看不到 镜头位置、点大小、颜色范围、裁剪距离
Marker 不出现 alpha 是否大于零、scale 是否有效、lifetime/action 是否符合预期

不要为了消除报错临时补一条全零静态 TF 到真实运动链上。它可能让画面出现,却掩盖定位或外参的问题。Marker 的透明度和尺寸字段可查 官方 Marker 说明。

七、回放 rosbag 时统一时间

历史消息带的是记录时的时间戳。若其他节点仍用当前系统时间,就可能出现 TF 外推错误。常见做法是在一个终端回放并发布时钟:

# 替换成自己的 bag 目录
ros2 bag play ./bags/run01 --clock

另一个终端让 RViz 使用仿真时间:

ros2 run rviz2 rviz2 --ros-args -p use_sim_time:=true

参与回放分析的其他相关节点也要采用一致的时钟;只有 RViz 改成 true 不一定足够。如果没有 /clock 发布者,仿真时间不会正常推进。

另外,包中没有录到必要的 TF、静态外参或模型描述,改时间参数也补不回来。循环回放发生时间倒退时,还需要留意缓存重置。开始分析前,先用 ros2 bag info 看包里到底录了哪些话题,再决定需要补哪些已知配置。

八、把可重复的视图放进工程

通过 File → Save Config As 保存 .rviz,以后直接加载:

# 路径替换成自己的配置
ros2 run rviz2 rviz2 -d ./config/robot_debug.rviz

可以分别保存“模型与关节”“定位与点云”“规划与路径”几个视图,避免一个窗口塞满所有 Display。跨 Windows/WSL 与 macOS/Linux 容器复用时,配置文件能共享,但双方仍要安装相应插件、模型资源并具备图形环境。

对一个新机器人,我会依次确认:TF 骨架 → RobotModel → 单个传感器 → 地图/里程计 → 路径与调试标记。这样一旦画面异常,容易找到是新增数据还是已有坐标链出了问题。

本文已核对本机 Humble 可执行入口、PointStamped 显示插件及发布/回放命令参数;这些检查不等同于全部 GUI 场景或真机验证。

继续阅读:rqt:通信与数值排查 · TF2:坐标树与时间排查 · 返回 ROS 与仿真

知识共享许可协议