Skip to content

ROS2 RViz2 可视化 ​

一、RViz2 是什么 ​

写机器人程序最难受的一点是:数据全是数字。话题里流过的是一串串坐标、点云、矩阵,你盯着 ros2 topic echo 的滚动输出,很难判断"机器人现在到底是不是歪了"。

RViz2 解决的就是这个问题:它订阅你指定的话题,把数据画成三维图形。机器人模型、坐标轴、激光点、相机画面、规划出的路径——全部可视化。

说明一个关键认知:RViz2 不产生数据 RViz2 是纯粹的消费者。它只订阅话题、把已有数据画出来,自己不会发布任何东西(除了几个交互工具,比如"在地图上点一个目标点")。 所以当 RViz2 里什么都没显示时,问题几乎从来不在 RViz 本身,而在"上游有没有数据在发"。

RViz2 与 Gazebo 的区别 ​

这两个常被新手搞混,但职责完全不同:

RViz2Gazebo
性质可视化工具物理仿真器
是否计算物理不计算计算重力、碰撞、摩擦
数据来源订阅真实或仿真话题自己就是数据源头
典型用途调试、看数据、验证算法在没有真机时跑完整系统
能否替代对方不能不能

实践中经常两个一起开:Gazebo 里跑仿真产生数据,RViz2 里看这些数据。

二、界面结构 ​

启动方式:

bash
# 直接启动(空白界面)
ros2 run rviz2 rviz2

# 加载一份已有配置启动
ros2 run rviz2 rviz2 -d /path/to/my_config.rviz

界面主要分成四块:

text
┌──────────────────────────────────────────────────────────┐
│  顶部工具栏:视角操作(移动/旋转/缩放)+ 交互工具           │
├────────────────┬─────────────────────────────────────────┤
│                │                                          │
│  Displays 面板 │            3D 视图区                      │
│  (左侧)       │        (所有东西都画在这里)             │
│                │                                          │
│  管理所有显示项 │                                          │
│                │                                          │
├────────────────┴─────────────────────────────────────────┤
│  状态栏:显示当前 ROS 时间、帧率                            │
└──────────────────────────────────────────────────────────┘

Displays 面板(左侧)是核心。这里有:

Global Options——全局设置,其中 Fixed Frame 最关键,后面单讲。

显示项列表——每一个显示项代表"我要看某个话题的某种数据"。用左下角的 Add 按钮添加,用 Remove 删除。

每个显示项展开后都有两个通用设置:

设置含义
Topic订阅哪个话题。如果这里下拉列表是空的,说明当前没有任何节点在发布该类型的消息
Status状态。显示 Ok 说明正常;黄色或红色表示有问题,鼠标悬停能看到具体原因
Reliability / DurabilityQoS 设置。如果发布端用的是特殊 QoS,这里要对上,否则收不到数据

3D 视图操作(顶部工具栏最左边几个图标):

操作鼠标方式
旋转视角左键拖动
平移视角中键拖动(或 Shift + 左键)
缩放滚轮
视角复位顶部工具栏的 "Focus" 或快捷键 F

三、常用 Display 详解 ​

RViz2 内置几十种显示类型,日常真正高频的就是下面这些:

Display画什么需要的话题 / 参数
Grid地面参考网格无(纯参考)
TF坐标树:每个坐标系画成一组 RGB 三色轴(红=x,绿=y,蓝=z)/tf、/tf_static
RobotModel机器人模型本体参数 robot_description + /joint_states
LaserScan单线激光雷达的扫描点通常是 /scan
PointCloud2三维点云通常是 /points
Image摄像头画面/image_raw 之类的图像话题
Odometry里程计轨迹箭头/odom
Path一串位姿连成的路径导航的 /plan 等
Marker / MarkerArray程序自己画的各种图形/visualization_marker

1. TF:排查坐标问题的第一现场 ​

加上 TF 显示后,场景里每个坐标系都会画成一小撮三色轴:红是 x、绿是 y、蓝是 z。想让某个坐标系看得清楚,可以在它的属性里把 Marker Scale 调大。

它会帮你瞬间定位问题:某个轴没出现 → 该坐标系没人发布;轴的位置明显不对 → 发出来的变换数值有问题;轴在闪烁抖动 → 发布时间戳或者频率不稳定。

另外,TF 显示的属性里可以勾选 Show Names,把坐标系名字直接标在旁边。

2. RobotModel:显示 URDF 描述的机器人 ​

它不订阅话题,而是读参数服务器上的 robot_description(就是上一节 robot_state_publisher 从 URDF 解析出来的那份内容)。

属性里有两个开关很实用:

Visual Enabled / Collision Enabled——可以只看外观、只看碰撞体、或者都看。对着一比,就能发现"碰撞体是不是比外观大了一圈"这种问题。

Alpha——整体透明度。调试时把它调到 0.5,能同时看清内部的坐标系轴。

3. Marker:在算法里自己画东西 ​

前面几个都是"把已有话题画出来",Marker 则允许你在代码里主动画点东西——画一个目标位置的小球、画一条预测轨迹、标出检测到的障碍物框。

python
from visualization_msgs.msg import Marker

marker = Marker()
marker.header.frame_id = 'base_link'
marker.header.stamp = self.get_clock().now().to_msg()
marker.ns = 'demo'
marker.id = 0                          # 同一 ns 下 id 相同的会互相覆盖
marker.type = Marker.SPHERE
marker.action = Marker.ADD
marker.pose.position.x = 1.0           # 在 base_link 前方 1 米处
marker.pose.orientation.w = 1.0
marker.scale.x = 0.2                   # 球形直径
marker.scale.y = 0.2
marker.scale.z = 0.2
marker.color.r = 1.0
marker.color.g = 0.0
marker.color.b = 0.0
marker.color.a = 1.0                   # 透明度,1 为不透明

self.marker_pub.publish(marker)

几个容易忽略的点:header.frame_id 决定了画在哪个坐标系里;action 除了 ADD 还有 DELETE 和 DELETEALL,用它来清除旧图形;color.a 是透明度,忘了它是新手最常犯的错——设成默认的 0 就什么都看不见,还以为程序没跑。

四、Fixed Frame:九成"看不见"的元凶 ​

RViz2 画任何东西之前都要先回答一个问题:**以谁为基准?**这个"谁"就是 Fixed Frame(固定坐标系)。

它决定了整个 3D 视图的原点和朝向。RViz2 会把所有数据都变换到这个坐标系下再画出来。如果它设成了一个不存在、或者和其他坐标系之间没有连通路径的坐标系,那所有需要坐标变换的显示项都会直接失败。

⚠️ 警告典型症状 显示项状态显示 Fixed Frame [xxx] does not exist,或者干脆一片黑、模型不出现。改 Fixed Frame 通常是第一件该做的事。

该设成什么?原则是:设成你所有数据都能追溯到的那棵树上的一个节点。

看 URDF 模型时,设成 base_link(URDF 的根节点);看激光和地图时,设成 map 或 odom。如果拿不准,跑一次 view_frames,看树的根是什么。

一套固定的排查流程 ​

RViz2 里什么都没显示时,按这个顺序走,基本能定位到问题:

text
1. 看左侧显示项的 Status 是不是 Ok
   └─ 红黄字?鼠标移上去看具体报错
       ├─ "Fixed Frame ... does not exist"  → 改 Fixed Frame
       └─ "No messages received"            → 往下走第 2 步

2. 确认话题真的在发数据
   ros2 topic list          ← 有没有你要的那个话题
   ros2 topic hz /话题名     ← 有没有数据在流

3. 话题在发但 RViz 收不到?
   └─ 多半是 QoS 不匹配(比如发布端用了 transient_local)
      → 在显示项的 Reliability / Durability 里对齐设置

4. 都正常但还是看不见
   └─ 视角问题:按 F 键或点 Focus,让视图聚焦到物体上
   └─ 可能画在了视野外:调小 Marker Scale、或者旋转视角找找

五、保存与加载配置 ​

手工添加一堆显示项、调好颜色和参数,如果每次启动都要重来一遍,那是不可接受的。RViz2 支持把整套配置存成 .rviz 文件(本质是 YAML)。

菜单 File → Save Config As,存到功能包的 rviz/ 目录下,比如 rviz/display.rviz。之后启动时用 -d 指定即可:

bash
ros2 run rviz2 rviz2 -d $(ros2 pkg prefix --share my_robot_description)/rviz/display.rviz

这行命令值得记住:$(ros2 pkg prefix --share 包名) 会展开成该功能包的安装路径,这样不用写死绝对路径。官方包(比如 turtle_tf2)的 RViz 配置就是这么启动的。

更常见的做法是直接写进 launch 文件:

python
Node(
    package='rviz2',
    executable='rviz2',
    arguments=['-d', os.path.join(pkg_share, 'rviz', 'display.rviz')],
    output='screen',
)

鼠标交互工具 ​

除了看,RViz2 顶部工具栏还有几个能"发送指令"的工具,导航调试时常用:

工具作用
2D Pose Estimate在地图上点一下并拖出朝向,告诉系统"机器人现在大概在这儿",用于重置定位
2D Goal Pose在地图上点一个目标位置,让机器人自己规划过去
Publish Point点一下把该点的三维坐标发到 /clicked_point 话题

这三个工具默认是灰的,只有相关话题有节点在监听时才会激活。

六、学习内容:把上一节的机器人显示出来 ​

接着上一节的小车模型,我们走一遍完整的可视化流程。

第一步:启动模型与关节控件 ​

bash
cd ~/ros_code
source install/setup.bash
ros2 launch my_robot_description display.launch.py

RViz2 会打开一个空白界面(因为还没告诉它要显示什么)。

第二步:添加显示项 ​

在左侧 Displays 面板:

**1. 先把 Fixed Frame 改掉。**Global Options → Fixed Frame,把默认的 map 改成 base_link。这一步不做,后面加什么都不会显示。

**2. 添加 Grid。**点 Add → 找到 Grid → OK。此时能看到地面网格了,说明视图坐标系工作正常。

**3. 添加 RobotModel。**Add → RobotModel → OK。展开它的属性,把 Description Topic 设为 /robot_description。小车应该立刻出现在视野里。

**4. 添加 TF。**Add → TF → OK。展开属性,勾上 Show Names,把 Marker Scale 调到 0.5 左右。你会看到 base_link、left_wheel、right_wheel、laser、caster 各自的三色坐标轴。

**5. 验证它是活的。**拖动 joint_state_publisher_gui 的滑块(左轮、右轮的关节),RViz2 里的轮子会跟着转,对应的 TF 轴也在转。这就说明 URDF → TF → 可视化这条链路完全打通了。

第三步:换个视角仔细看 ​

鼠标左键拖动旋转、滚轮缩放。留意几个细节:

激光雷达(那个红色小圆柱)应该在车体前方偏上——对应 URDF 里 laser_joint 的 origin xyz="0.10 0.0 0.10"。万向轮在车尾下方——对应 xyz="-0.15 0.0 -0.075"。

如果发现某个部件的位置和你预期的不一样,直接回去改 URDF 里的 <origin>,重新编译再看。这种"改一处、看一眼"的循环,就是 URDF 调试的日常。

第四步:保存配置 ​

File → Save Config As,存到 ~/ros_code/src/my_robot_description/rviz/display.rviz。

然后把 launch 文件里那个 rviz2 节点改成带 -d 参数的版本(参照上一节第五部分的写法),重新编译一次。下次启动就自动带好所有显示项了。

七、调试速查 ​

现象排查方向
整个视图一片黑,加什么都不显示先改 Fixed Frame。再按 F 聚焦视图
显示项状态为红色 / 黄色鼠标悬停在 Status 上看具体报错,多半是坐标系不存在或话题没数据
话题下拉列表是空的没有节点在发布该类型消息。用 ros2 topic list 确认
话题有数据但 RViz 收不到QoS 不匹配。在显示项属性里把 Reliability / Durability 调成和发布端一致
Marker 画了却看不见检查 color.a(透明度)是不是 0;检查 frame_id 是否有效;检查 scale 是不是太小
模型显示但不动/joint_states 没数据。joint_state_publisher_gui 是否启动?或者全是 fixed 关节
点云刷起来很卡在显示项里调大 Decay Time 或限制点数;关掉不需要的显示项
改了配置但重启又变回默认没保存 Config,或者 launch 文件里没加 -d 参数

说明本节小结 RViz2 是纯消费者,不产生数据——所以"看不见"的问题,绝大多数在上游或者 Fixed Frame,而不是 RViz 本身。

日常高频的四个显示项:Grid(参考)、TF(坐标树)、RobotModel(模型)、Marker(自定义)。记住排查四连:看 Status → 查话题 → 对 QoS → 调视角。

到这里,"机器人三件套"就齐了:TF2 描述空间关系,URDF 描述身体,RViz2 把两者画出来。有了这三样,后面不管接传感器、做导航还是调机械臂,都有了可看、可验的基础。