ROS2 RViz2 可视化
一、RViz2 是什么
写机器人程序最难受的一点是:数据全是数字。话题里流过的是一串串坐标、点云、矩阵,你盯着 ros2 topic echo 的滚动输出,很难判断"机器人现在到底是不是歪了"。
RViz2 解决的就是这个问题:它订阅你指定的话题,把数据画成三维图形。机器人模型、坐标轴、激光点、相机画面、规划出的路径——全部可视化。
说明一个关键认知:RViz2 不产生数据 RViz2 是纯粹的消费者。它只订阅话题、把已有数据画出来,自己不会发布任何东西(除了几个交互工具,比如"在地图上点一个目标点")。 所以当 RViz2 里什么都没显示时,问题几乎从来不在 RViz 本身,而在"上游有没有数据在发"。
RViz2 与 Gazebo 的区别
这两个常被新手搞混,但职责完全不同:
| RViz2 | Gazebo | |
|---|---|---|
| 性质 | 可视化工具 | 物理仿真器 |
| 是否计算物理 | 不计算 | 计算重力、碰撞、摩擦 |
| 数据来源 | 订阅真实或仿真话题 | 自己就是数据源头 |
| 典型用途 | 调试、看数据、验证算法 | 在没有真机时跑完整系统 |
| 能否替代对方 | 不能 | 不能 |
实践中经常两个一起开:Gazebo 里跑仿真产生数据,RViz2 里看这些数据。
二、界面结构
启动方式:
# 直接启动(空白界面)
ros2 run rviz2 rviz2
# 加载一份已有配置启动
ros2 run rviz2 rviz2 -d /path/to/my_config.rviz界面主要分成四块:
┌──────────────────────────────────────────────────────────┐
│ 顶部工具栏:视角操作(移动/旋转/缩放)+ 交互工具 │
├────────────────┬─────────────────────────────────────────┤
│ │ │
│ Displays 面板 │ 3D 视图区 │
│ (左侧) │ (所有东西都画在这里) │
│ │ │
│ 管理所有显示项 │ │
│ │ │
├────────────────┴─────────────────────────────────────────┤
│ 状态栏:显示当前 ROS 时间、帧率 │
└──────────────────────────────────────────────────────────┘Displays 面板(左侧)是核心。这里有:
Global Options——全局设置,其中 Fixed Frame 最关键,后面单讲。
显示项列表——每一个显示项代表"我要看某个话题的某种数据"。用左下角的 Add 按钮添加,用 Remove 删除。
每个显示项展开后都有两个通用设置:
| 设置 | 含义 |
|---|---|
Topic | 订阅哪个话题。如果这里下拉列表是空的,说明当前没有任何节点在发布该类型的消息 |
Status | 状态。显示 Ok 说明正常;黄色或红色表示有问题,鼠标悬停能看到具体原因 |
Reliability / Durability | QoS 设置。如果发布端用的是特殊 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 则允许你在代码里主动画点东西——画一个目标位置的小球、画一条预测轨迹、标出检测到的障碍物框。
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 里什么都没显示时,按这个顺序走,基本能定位到问题:
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 指定即可:
ros2 run rviz2 rviz2 -d $(ros2 pkg prefix --share my_robot_description)/rviz/display.rviz这行命令值得记住:$(ros2 pkg prefix --share 包名) 会展开成该功能包的安装路径,这样不用写死绝对路径。官方包(比如 turtle_tf2)的 RViz 配置就是这么启动的。
更常见的做法是直接写进 launch 文件:
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 话题 |
这三个工具默认是灰的,只有相关话题有节点在监听时才会激活。
六、学习内容:把上一节的机器人显示出来
接着上一节的小车模型,我们走一遍完整的可视化流程。
第一步:启动模型与关节控件
cd ~/ros_code
source install/setup.bash
ros2 launch my_robot_description display.launch.pyRViz2 会打开一个空白界面(因为还没告诉它要显示什么)。
第二步:添加显示项
在左侧 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 把两者画出来。有了这三样,后面不管接传感器、做导航还是调机械臂,都有了可看、可验的基础。