第 4 章 可视化与观测工具¶
机器人系统的调试高度依赖"看见"——看见 TF 树是否正确、看见激光雷达点云是否成形、看见控制信号是否按预期变化。ROS 2 生态的可视化工具按观察对象分为三类:三维场景观察器(RViz2、Foxglove)、时间序列绘图器(PlotJuggler、rqt_plot)、结构图与日志查看器(rqt_graph、rqt_console)。选对工具比熟练操某一个工具更重要——本章末尾给出按问题类型选择工具组合的经验路径。
1. RViz2:三维场景观察器¶
RViz2 是 ROS 2 的默认三维可视化前端。其定位是观察器而非仿真器——它渲染话题中携带的几何数据(点云、网格、标记),不参与物理计算,也不驱动关节运动。
1.1 Displays 体系¶
左侧面板的 Displays 列表决定了 3D 视口中渲染的内容。每个 Display 订阅一个或多个话题,将其解释为某种可视化图元:
| Display 类型 | 订阅话题 | 渲染内容 |
|---|---|---|
| TF | /tf, /tf_static |
坐标系树(箭头 + 名称标签) |
| RobotModel | /robot_description + /joint_states |
URDF 网格 + 关节位置 |
| LaserScan | /scan |
二维激光点(扇形分布) |
| PointCloud2 | /points2 |
三维点云 |
| Image | /camera/image_raw |
摄像头图像(嵌入式窗口) |
| Path | /plan |
路径(折线 + 箭头) |
| Marker | /visualization_marker |
用户自定义图元(球、箭头、文本等) |
| Map | /map |
占用栅格地图(SLAM 结果) |
| Pose | /goal_pose |
单个位姿(六面体 + 坐标轴) |
常用交互工具(3D 视口上方工具栏):
- Interact:拖拽机器人模型(发布
/joint_states改变视觉位置,不驱动真实硬件)。 - 2D Goal Pose:点击地图设一个目标位姿,发布
/goal_pose(Nav2 用此接收导航目标)。 - Measure:点击两点测距离,结果直接显示在状态栏。
1.2 配置文件与启动¶
RViz2 的显示配置保存为 .rviz 文件(YAML 格式),用 -d / --display-config 参数指定:
## 加载已有配置启动
rviz2 -d $(ros2 pkg prefix my_bringup)/share/my_bringup/config/my_view.rviz
## 运行中保存当前配置:File → Save Config As
配置文件记录了 Fixed Frame(TF 参考坐标系)、各 Display 的话题映射与渲染参数。启动后若视口一片黑或"Frame [map] not found",首要检查 Fixed Frame 是否与 TF 树中某个 frame 名一致(详见第 5 章)。
1.3 Marker 消息¶
程序化地在 RViz 中绘制几何图形,通过 visualization_msgs/msg/Marker 实现:
from visualization_msgs.msg import Marker
from geometry_msgs.msg import Point
from builtin_interfaces.msg import Duration # 注意:这是消息类型,字段是 .sec / .nanosec
marker = Marker()
marker.header.frame_id = 'base_link'
marker.ns = 'my_objects'
marker.id = 0
marker.type = Marker.SPHERE # 球体;
其他:CUBE, ARROW, LINE_LIST, TEXT_VIEW_FACING…
marker.action = Marker.ADD
marker.pose.position = Point(x=1.0, y=0.0, z=0.5)
marker.scale.x = marker.scale.y = marker.scale.z = 0.2 # 直径 20cm
marker.color.r, marker.color.g, marker.color.b, marker.color.a = 1.0, 0.0, 0.0, 0.8
marker.lifetime = Duration(sec=0) # 0 = 永不过期
lifetime=0 时 Marker 持久显示(直到同名 ns + id 的 Marker 被 DELETE 或 RViz 重启)。MarkerArray(/visualization_marker_array)用于一帧批量发布多个 Marker。调试定位目标、标注障碍物、可视化坐标系关系都用 Marker 实现。
坑:RViz 只是观察器
RViz 不推进仿真、不产生数据:画面不动先查数据源与 TF,而不是调 RViz 本身;它的定位是“看”,不是“算”。
2. Foxglove Studio:通用数据可视化¶
Foxglove 是不绑定 ROS 的数据可视化与监控平台(支持 ROS 1/ROS 2/MCAP/自定义 JSON schema),有桌面版与 Web 版。与 RViz2 的分工:
| 维度 | RViz2 | Foxglove |
|---|---|---|
| 三维场景 | 强项(原生 URDF/TF 渲染) | 支持(通过 3D panel),插件化 |
| 面板类型 | 仅 3D 视口 | 3D、图像、表格、原始消息、日志、数据流图、仪表盘 |
| 数据源 | 实时 DDS topic | bridge 实时 / MCAP 离线 / rosbag 回放 |
| 自定义面板 | 需写 RViz 插件(C++/Python) | Web 技术栈(React),或用内置 panel 组合 |
| 部署 | 桌面 GUI | 桌面版 / Web 版(浏览器直接打开) |
2.1 连接方式¶
通过 foxglove_bridge 包与 ROS 2 实时数据桥接。Humble 二进制仓库提供 ros-humble-foxglove-bridge(3.6.0,随发行版更新),launch 入口为 foxglove_bridge_launch.xml,port(默认 8765)、address、tls 与各白名单(topic_whitelist 等)均为可覆盖参数:
sudo apt install -y ros-humble-foxglove-bridge
ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765
Foxglove 客户端中 Add Connection → 选 Foxglove Bridge → 输入 ws://localhost:8765。连接后可浏览所有话题、订阅并实时渲染(客户端侧操作以 Foxglove 文档为准)。
MCAP 文件可直接在 Foxglove 中打开做离线回放,无需 ROS 环境——适合作为实验记录的可视化归档格式。
2.2 典型面板组合¶
- 3D Panel:加载 TF + URDF + PointCloud2 + Marker(等效 RViz 场景)。
- Plot Panel:时间序列曲线(等效 PlotJuggler 的基本功能),可叠加多话题多字段。
- Raw Message Panel:查看单条消息的完整字段值,调试接口字段含义。
- Image Panel:显示相机话题,支持 compressed 与 raw。
- Teleop Panel:按钮/滑杆控件发布
/cmd_vel,做遥控测试。
3. PlotJuggler:时间序列分析¶
PlotJuggler 是专门做时间序列曲线可视化的工具,支持直接连接 ROS 2 topic 流或加载 rosbag/MCAP 日志。与 rqt_plot 的对比:
| 维度 | PlotJuggler | rqt_plot |
|---|---|---|
| 数据源 | topic / bag / CSV / 二进制日志 | 仅 topic |
| 曲线数量 | 数十通道不卡顿 | 超过 5 条明显卡顿 |
| 游标/缩放 | 支持框选缩放、多游标对齐 | 基本缩放 |
| 导出 | PNG / CSV / SVG | PNG |
| 离线分析 | 直接打开 bag/CSV | 不支持 |
典型用法——同时观察 PID 控制器的设定值、反馈值与误差:
## 启动 PlotJuggler
plotjuggler
## 在 Data Streams 面板选 ROS 2 → Topic 模式
## 订阅 /cmd_vel.linear.x 和 /odom.twist.twist.linear.x
## 两条例入同一曲线面板,观察跟踪偏差
PlotJuggler 的 TF 变换面板可直接订阅 /tf 话题并绘制某两个 frame 之间的位置/姿态随时间变化,省去手写 listener 脚本。
4. rqt 工具集¶
rqt 是 Qt 插件框架,ROS 2 保留了 ROS 1 时期的核心 rqt 工具:
| 工具 | 命令 | 用途 |
|---|---|---|
| rqt_graph | rqt_graph |
可视化计算图(节点 + 话题 + 服务连接关系) |
| rqt_console | rqt_console |
实时日志过滤查看(按级别、节点、话题筛选) |
| rqt_bag | rqt_bag |
bag 文件可视化(时间轴上显示消息流、手动截取片段) |
| rqt_plot | rqt_plot |
轻量时间曲线(适合 1~3 条快速查看) |
| rqt_reconfigure | rqt_reconfigure |
动态调参 GUI(列出所有节点参数,滑杆/输入框即时生效) |
sudo apt install -y ros-humble-rqt-graph ros-humble-rqt-console ros-humble-rqt-reconfigure
rqt_graph 切换 Topic / Node / Topic (nodewide) 三种视图可分别观察数据流拓扑、节点连接和跨命名空间的完整图。节点名旁的颜色标识通信类型:实线为 topic、虚线为 service。
四类工具接的是同一批数据源,差别在呈现形式与是否要求实时:
flowchart LR
live["实时 topic"] --> rviz["RViz2<br/>空间与图像"]
live --> fox["Foxglove Studio<br/>面板监控"]
live --> plot["PlotJuggler<br/>时序曲线"]
live --> rqt["rqt 系列<br/>图 / 日志 / 调参"]
bag["rosbag2 / MCAP 文件"] --> fox
bag --> plot
bag --> rqt
5. 工具选择组合经验¶
按调试问题的类型选择工具组合:
| 问题类型 | 工具组合 | 操作要点 |
|---|---|---|
| "话题存在但没数据" | ros2 topic info --verbose + rqt_graph |
确认 QoS 与类型匹配(第 2 章排障清单),rqt_graph 看连接是否建立 |
| "机器人模型显示错误" | RViz2 RobotModel + TF Display | 检查 URDF 是否加载、joint_states 是否在发、TF 树是否完整 |
| "传感器数据是否正确" | RViz2 (LaserScan/PointCloud2) + Foxglove Image | 实时观察空间分布;图像通道用 Foxglove 或 RViz Image Display |
| "控制量跟踪不好" | PlotJuggler 多通道曲线 | 订阅 cmd + feedback,观察超调、稳态误差与振荡 |
| "参数需要反复调" | rqt_reconfigure | 动态改参数即时生效,无需重启节点 |
| "整体系统结构梳理" | rqt_graph + ros2 node list |
先图观全貌,再逐个 node info 看订阅发布细节 |
| "实验数据归档与离线分析" | ros2 bag record + Foxglove (MCAP) |
录制用 mcap 格式;离线打开 Foxglove 可回看全话题时序 |
判据:按问题类型选工具
结构问题开 rqt_graph,空间与图像开 RViz / Foxglove,时序与跟踪误差开 PlotJuggler;三者解决的不是同一类问题,混用只会增加窗口数量。
6. 远程观测与静态出图¶
远程看机器人画面、把实验数据落成图,是工具链里的两个外围但高频需求:前者走图像流协议,后者走出图库。
6.1 远程图像流三路线¶
| 路线 | 组成 | 适用 |
|---|---|---|
| Foxglove WebSocket | foxglove_bridge(上文「连接方式」一节)+ Foxglove 客户端 |
已在用 Foxglove 调话题,顺带看图像;浏览器直接开 |
| WebRTC | aiortc 起信令与媒体轨,av(PyAV)做编解码 |
要低延迟与双向(遥操作、远程驾驶);浏览器原生 <video> 播放 |
| MJPEG/HTTP | aiohttp 起 HTTP 服务,av 把帧编码成 JPEG 流 |
单流、单向、局域网;十分钟内出画面的最小实现 |
三条路线的区别在协议栈的厚度:Foxglove 路线复用现有话题通路,代价是带宽与延迟不为一帧图像优化;WebRTC 有拥塞控制、丢帧恢复与抖动缓冲,代价是信令与 ICE 要自己搭;MJPEG 就是一行 HTTP header + 连续 JPEG,没有重传与自适应码率——别在它上面做多路并发与弱网。
6.2 静态出图与缩略图¶
matplotlib 管的是离线图:把 /joint_states、/odom 一类录下的数据画成 PNG/PDF——时序曲线、误差分布、地图预览。它与 PlotJuggler 的分工是“归档图 vs 实时曲线”:前者要可复现、可入报告,后者要低延迟交互。地图侧的 PGM + YAML 预览也走这条:读 PGM 像素画进 matplotlib,比开 RViz 轻得多(地图归档格式见第 10 章「地图保存与加载」)。
一条纪律:实时回路里不用 matplotlib 画帧——每帧重建 figure 的代价远高于画布更新,也挡在循环里;实时看用 PlotJuggler/rqt_plot,事后出图用 matplotlib。
6.3 算法内部量的可视化:rerun¶
上面三条远程路线与静态出图都围绕 ROS 话题;而调感知/学习算法时,要看的往往是话题之外的东西:中间特征图、点云配准的对应线、策略输出的动作分布。这类需求用 rerun(pip install rerun-sdk):它在本地起一个查看器,SDK 把图像、点云、张量、时序按时间轴记下,事后拖动时间轴回放:
import rerun as rr
rr.init("perception_demo", spawn=True) # 起本地查看器(离线改用 rr.save("run.rrd"))
rr.log("camera/image", rr.Image(rgb)) # 图像
rr.log("world/points", rr.Points3D(xyz, colors=rgb_flat)) # 点云(带颜色)
rr.log("train/loss", rr.Scalars(loss)) # 标量曲线
几何体、图像、张量、标量共用同一个时间轴,这是它相对“存图 + 存 npz”的核心差别——回放时各模态对齐到同一时刻。与 Foxglove/MCAP 的分工:话题流用 Foxglove + MCAP(ROS 消息的天然载体,录制回放与团队共享);算法中间量用 rerun(不依赖 ROS,任意张量与几何体都能记)。两者不冲突——同一个实验可以 MCAP 录话题、rerun 记中间量,各管一段。
7. 要点¶
- RViz2 是三维场景观察器,不执行物理计算;配置文件的 Fixed Frame 与 TF 树一致性是"画面全黑"的第一排查点。
- Marker 消息是程序化可视化的核心途径,
ns + id构成唯一键,lifetime=0持久显示。 - Foxglove 覆盖 RViz 之外的面板类型需求(表格、日志、仪表盘),同时支持 MCAP 离线回放;与 RViz 互补而非替代。
- 时间序列分析优先 PlotJuggler(通道多、不卡顿、离线数据源);快速查看单参数变化可用 rqt_plot。
- rqt_graph 是梳理计算图拓扑的最快方式;rqt_reconfigure 是运行期动态调参的 GUI 入口。
- 按"连接性 → 空间几何 → 时域曲线 → 参数交互 → 离线归档"五类问题选工具,避免用单一工具解决全部需求。