最近终于把折腾了很久的 RVizWeb 整理成正式版开源了,趁着这个节点,记录一下这个项目的来龙去脉,也算是给自己一个交代(~毕竟 commit 都 180 个了~)。
项目地址:https://github.com/sheetung/rviz-web
0. 为什么会有这个东西
做无人机相关的工作,几乎绕不开 RViz。仿真、真机调试的时候,点云、轨迹、Marker、位姿这些数据,都得在 RViz 里盯着。但 RViz 的痛点也很明显:它绑定桌面环境,人要坐在工控机前面看;多台设备想同时看,每台都得装一整套 ROS 图形环境;碰上没装图形界面的板子或者服务器(比如鲁班猫这种嵌入式开发板),基本就干瞪眼了。
浏览器方案其实早就有了,rosbridge_server + roslibjs 那套。但用起来总觉得隔了一层:要额外跑一个 rosbridge 服务,消息类型、TF 转换全得自己处理,交互体验和 RViz 也差挺远,用着用着就想自己搞一个。
这个项目最初的参考是 lovelyyoshino/RVIZ-RQT-VISUAL,一个把 RViz 功能往网页上搬的项目。git 历史里还能看到上游早期的提交:增加轨迹线、增加2D 3D激光的可视化小功能、修复rqt问题,目前可以比较好使用 之类的。我在它的基础上面向 ROS2 做了重构和大量扩展,慢慢长成了现在的 RVizWeb。
1. RVizWeb 是什么
一句话:面向 ROS2 的浏览器可视化前端,用来查看点云、激光、里程计、路径、Marker 等数据,同时带无人机位姿显示、期望目标输入、实时数据图表和 RViz 风格的 Displays 管理。
技术栈:
- 前端:Vue 3 + Vite + Three.js + Element Plus + Pinia
- 后端:Python 3.10–3.12 + FastAPI + Uvicorn + rclpy
- 通信:WebSocket(
/ws)+ HTTP(/api/v1/*)
关键点是后端用 rclpy 直接加入 ROS2 图,不依赖独立的 rosbridge_server,少一层服务就少一堆配置和兼容性问题。
2. 架构
浏览器
├── HTTP /api/v1/* ── FastAPI ── 配置文件与 ROS2 查询接口
└── WebSocket /ws ── RosbridgeService ── rclpy ── ROS2 图- 前端负责 3D 场景(Three.js)、Displays 面板、数据图表和布局。
- 后端负责话题发现、订阅/发布、消息转换、配置文件和 RTSP 转流。
- 可视化配置保存在
rvizweb_configs/*.rvizweb,一套配置绑定一个机器人的显示布局,换机子直接换配置。
下面两张图是它在普罗米修斯(Prometheus)工程下的实际使用场景:无人机 SLAM 建图、点云显示、位姿监控、目标发布和数据图表都在一个页面里。
3. 功能速览
- RViz 风格 Displays:从当前 ROS2 图读取话题并添加显示项,眼睛图标控制显隐;Add 弹窗支持
By topic和By display type,类型列表只包含当前图里真实存在的话题。隐藏或删除 Display 时会同步清理消息缓存,TF 更新不会把已隐藏的对象重新建出来。 - 3D 显示类型:
PointCloud2、LaserScan、Odometry、Path、Marker/MarkerArray、OccupancyGrid。自动订阅/tf和/tf_static转换到 Fixed Frame,找不到 TF 链时隐藏错误坐标的数据并在对应 Display 里说明原因(这个细节当时调了很久)。 - 工具与相机:移动、选择、聚焦、2D 位姿估计、2D 目标;快捷键
M/S/F/P/G/Esc;Orbit 操作左键旋转、中键平移、滚轮缩放;俯视预设用正交相机。 - 截图与录像:一键把 3D 画布截成 PNG;30 FPS 录制 WebM(按浏览器能力自动选 VP9 / VP8 / 普通 WebM)。
- RTSP 视频:后端用 FFmpeg 把 RTSP 转成浏览器能放的 MJPEG,页面里直接拖拽、缩放、重连;连接失败时只报错不创建空白窗口。
- 无人机位姿:选 odom 话题后显示位姿数值,内置无人机模型(默认隐藏,选中后才启用),轨迹显示可保留 10–100 个点。
- 期望目标:输入
X/Y/Z,展示只在点云视图里预览,发布才向配置的话题发布geometry_msgs/msg/PoseStamped,默认方向+X。 - 数据图表:底部可调高度 Dock,从当前 ROS2 图选话题数值字段画多曲线,10 秒到 10 分钟时间范围,滚轮缩放、拖动看历史、暂停只冻结画面后台继续缓存。
- 布局与主题:右侧面板拖拽高度、Global Options 和每个 Display 独立展开/收起、深色/浅色主题,网格、坐标轴、视角、相机状态都能保存。
4. 一些折腾过的设计
4.1 点云性能链路
高频点云是最大的性能敌人。从 v1.2.0 开始做整条链路改造:
- 后端把 PointCloud2 紧凑为 XYZ 字段,通过独立的二进制 WebSocket 帧发送,不走 Base64 JSON;
- 前端在 Web Worker 里解码,GPU 缓冲区复用,点云几何体、实例矩阵、材质都改成更新而非重建;
- 每个 Display 可独立开稀疏显示,每 2–32 个点保留 1 个点;
- 慢客户端用有界发送队列隔离,一个浏览器卡了不阻塞其他客户端。
值得一提:稀疏显示发生在前端 Worker 解码阶段,不改变后端二进制传输,所以网络开销完全不变,只是省了浏览器解码后的工作量。Boxes 用 InstancedMesh 渲染真实三维体素(适合占用地图),Points 适合高频大规模实时点云。
4.2 安全边界
应用层不提供登录鉴权(个人工具,搞登录太重了),默认只绑定 127.0.0.1。安全靠几层兜底:
- WebSocket Origin 校验;
- ROS 发布白名单,默认只允许
/goal_pose、/initialpose、/cmd_vel; - RTSP 地址做 DNS/IP 策略检查,防 DNS 重绑定;用户名密码和查询令牌不写入配置文件,只在当前页面生命周期内使用;
.env权限收紧到0600;- 要开放局域网就设
APP_HOST=0.0.0.0,但访问边界交给防火墙 / VPN,不能把端口直接暴露到公网。
4.3 配置管理
.rvizweb 的保存是同目录临时文件 + 原子替换,覆盖和删除前自动备份到 rvizweb_configs/backups/。读取旧配置时会自动迁移历史字段、清理废弃的布局字段,无法识别的旧顶层字段存到 extensions.legacy,配置读失败时前端保持当前状态不变——不会因为一份坏配置把整个界面搞崩。
4.4 TF 插值
动态 TF 每条坐标边保留最近 10 秒、最多 200 个样本,按显示消息的时间戳做平移线性插值 + 旋转四元数球面插值。早于或晚于缓存范围的查询目前用最邻近样本,还没有实现 tf2/RViz 等价的外推错误语义,算是已知边界。
4.5 一些踩过的坑
- WebSocket JSON 整数赋给 ROS2 浮点字段时会静默保留为 0——目标点、初始位姿、Pose、Twist 的整数坐标全中招,v1.0.2 专门修了这个问题;
- PX4 自定义消息里的
NaN/Infinity会导致浏览器拒绝整条 JSON 消息,图表直接断掉; - Marker 的 TF 刷新如果重建对象,
lifetime会被反复重置,改成原位更新才解决; - 隐藏 Display 被后续 TF 更新重新创建、切换 odom 后残留旧轨迹、坐标轴关闭了 XYZ 标签还在……都是一些"看起来简单调起来费劲"的东西。
5. git 历史与版本演进
仓库一共 180 个提交。git 历史能看出两条线:上游作者 2025 年 9 月的早期提交(增加轨迹线、增加2D 3D激光的可视化小功能、修复rqt问题),以及 2026 年 7 月我这边的大规模重构——7 月 12 日当天集中提交了 UI overhaul:CSS token system(35+ 设计 token)、可折叠侧面板、图标工具栏,然后发布 v1.0.0。
版本演进(CHANGELOG 摘录):
| 版本 | 日期 | 要点 |
|---|---|---|
| v1.0.0 | 2026-07-12 | 首个正式版:话题发现/订阅/发布、核心 3D 显示、Displays、TF 插值、.rvizweb 配置管理、统一启动脚本 |
| v1.0.2 | 2026-07-13 | 修复 JSON 整数 → ROS 浮点字段被静默置 0 |
| v1.1.0 | 2026-07-14 | 点云 Points/Boxes 渲染,Boxes 用 InstancedMesh 批量渲染体素 |
| v1.1.1 | 2026-07-14 | 可配置 RTSP 视频入口 + 系统状态查询 |
| v1.1.5 | 2026-07-18 | 修复话题发现覆盖配置、订阅清理、异步初始化竞争等 |
| v1.2.0 | 2026-07-22 | 二进制点云帧 + Worker 解码、WebSocket 队列隔离、Docker 重写、安全边界收紧 |
| v1.3.0 | 2026-07-25 | 每 Display 稀疏显示、配置自动迁移、Global Options、无人机模型平滑 |
中间还有个细节:v1.3.0 把产品名从 "RViz2 Web" 统一成了 RVizWeb。8 月初又整理了一次环境配置,目前 v1.3.0 是正式版本,发布 9 个 tag。
6. 怎么跑起来
环境要求:ROS2(默认加载 Humble)、Python 3.10+、Node.js 20.19+、FFmpeg(RTSP 用)、curl。
cd <your_workspace>/rviz-web
cp .env.example .env
# 通常只需改 ROS_DOMAIN_ID;局域网访问再设 APP_HOST=0.0.0.0
./start.sh sync # 首次使用或依赖变化后
./start.sh local # 正常启动(不传参数默认也是 local)
./start.sh dev # 前端热更新开发换不同机器人的配置:
RVIZWEB_CONFIG=xxx.rvizweb ./start.sh local启动脚本会读取 .env、加载 ROS2 环境、检查端口和依赖、等前后端健康检查,日志统一写进 logs/,Ctrl+C 会清理整个进程组。部署只需要访问前端地址,API 和 WebSocket 走同源代理,不需要配置后端 IP 或 CORS。
7. 已知限制和后续计划
- TF 还没有外推错误语义,超出缓存范围直接用最邻近样本;
- 前端只有单元测试(18 个测试文件),没有组件和端到端测试,ROS2 实时链路靠人工集成验证;后端 66 项 pytest 覆盖了配置、安全、WebSocket 等基础回归;
- Dockerfile 已按 Node 22 + uv 锁文件 + Nginx 同源代理重写,但 DDS 容器网络还没在目标设备上完整验证;
- 录像用浏览器原生
MediaRecorder,页面降频或后台化时时间线可能不均匀; - 当前
/ws后端是 rclpy,只支持 ROS2;后续接入 ROS1 建议加独立的/ws/ros1适配器路由。
计划里排了:TF 外推错误状态、WebSocket 重连和真实 ROS2 图的自动化集成测试、清理未引用的历史组件。
8. 结尾
如果它对你的无人机或者机器人调试有帮助,欢迎 Star / 提 Issue,也欢迎直接拿去改。
- 仓库:https://github.com/sheetung/rviz-web
- 文档:README.md / PROJECT_GUIDE.md / PROJECT_STATUS.md(仓库内)
本文作者:sheetung
本文链接:https://moontung.top/archives/rvizweb.html
版权声明:转载时须注明出处(包括原作者和文章链接)及本声明


