Phantom Bridge 是 Phantom Cybernetics 推出的一个 ROS2 远程可视化与遥操作工具。作者 mirek 在 2025-12-20 的 Open Robotics Discourse 发布帖中,把它描述为一种新的 ROS2 实时数据可视化、视频流、遥操作、远程/本地调试和 observability 方案:机器人端运行 C++ Bridge Client,浏览器端打开 Web UI,中间通过 WebRTC、Socket.io、Bridge Server 和 TURN/STUN 完成低延迟连接。
| 项目 | 环境 |
|---|---|
| OS | Ubuntu 22.04 |
| ROS | ROS 2 Humble |
目录
- [0. Phantom Bridge Features](#0. Phantom Bridge Features)
- [1. 为什么用 WebRTC](#1. 为什么用 WebRTC)
- [2. 系统结构](#2. 系统结构)
- [3. 设置环境](#3. 设置环境)
- [4. 实验](#4. 实验)
- [5. 工具对比](#5. 工具对比)
- [6. 编译问题备忘](#6. 编译问题备忘)
- 参考
0. Phantom Bridge Features
- ROS2 Node、Topic 和 Service 发现。
- 二进制 ROS2 消息的快速流式传输(输入和输出)。
- 快速 H.264 视频流式传输(预编码的 FFmpeg 帧)。
- 将
Image与CompressedImage消息编码为 H.264 视频并进行流式传输(软件、CUDA 或 VAAPI 编码)。 - Docker 容器发现和控制。
- 通过 Socket.io 可靠调用 ROS2 Service。
- ROS2 运行时参数读取/写入 API。
- 可以轻松包含额外的 ROS2 package,以支持自定义消息和服务类型。
- 机器人 Wi-Fi 信号监控、扫描和漫游(通过 Agent,需要主机上的
wpa_supplicant)。 - 从任何正在运行的 Docker 容器中检索文件(例如通过 Agent 获取 URDF mesh)。
- 系统负载和 Docker stats 监控(通过 Agent)。
- P2P 连接;当无法建立 P2P 链路时,通过 TURN server 连接。
- 多个 peer 可以连接到同一台机器,并且只产生很低的额外 CPU 开销。
- 局域网约 5-10 ms RTT;通过 TURN server 远程操作时约 50 ms 以上 RTT。
- 可与 Rosbag 以及 Gazebo、Webots 等仿真环境配合使用。
- 支持 ROS2 Humble 及更新版本。
1. 为什么用 WebRTC

Reddit 讨论里有人问作者:设计时有没有考虑继续使用 DDS,而不是换成其他通信协议?作者的回答基本说明了 Phantom Bridge 的出发点。
他的判断是:如果两个端点经常在 NAT 后面、地址变化,或者希望公网自动建立连接,DDS-only 方案会很不实际。图像和视频本来就需要编码;浏览器又天然支持 WebRTC 和硬件加速视频解码。如果用 DDS 自己实现 NAT 穿透、媒体编码、浏览器解码、低延迟传输,最后很可能是在重新发明 WebRTC。
这个思路可以概括为:
text
ROS2 / DDS
适合机器人内部模块通信、局域网内 discovery、类型化消息传递。
WebRTC
适合浏览器、NAT 穿透、P2P、TURN fallback、媒体流、低延迟 data channel。
Phantom Bridge
在机器人端保留 ROS2 node,
在传输层使用 WebRTC,
在数据进入网络前按类型做压缩、转码、过滤和 UI 适配。
作者也提醒过,WebRTC RTT 不等于完整遥操作延迟。视觉遥操作还包括相机采集、编码、缓冲、解码和屏幕显示。作者给过一个非正式测试:多路相机、Pi 4/Pi 5、不同编码路径下,屏幕像素延迟约 104-116 ms,同时 WebRTC RTT 约 3-5 ms。
2. 系统结构
Phantom Bridge 的结构:

其中 phntm_bridge_client 是本文主要使用的部分, phntm_agent 则让 Web UI 可以看到 Docker、系统资源、Wi-Fi、文件等 ROS graph 以外的信息。
在线示例:https://docs.phntm.io/bridge/demos

3. 设置环境
本教程参考官方 PhantomCybernetics/phntm_bridge_client README 的 Install 流程,但把目标换成 Nav2 官方 TurtleBot3 Gazebo demo。
3.1 更新根证书
Bridge Client 需要访问 Bridge Server、容器镜像仓库和注册接口,先确认系统根证书是最新的:
bash
sudo apt update
sudo apt install ca-certificates
3.2 安装 Docker、Buildx 和 Compose
如果系统还没有 Docker,先按 Docker 官方文档安装 Docker Engine、Buildx 和 Compose v2。安装完成后,把当前用户加入 docker 组,重新登录后即可不带 sudo 运行 docker compose:
bash
sudo usermod -aG docker ${USER}
重新登录后验证:
bash
docker version
docker compose version
如果 docker compose 仍然不可用,优先检查 Compose v2 插件是否安装。在 Ubuntu 22.04 上,不同软件源里包名可能是 docker-compose-plugin 或 docker-compose-v2。
3.3 安装 Nav2 demo 依赖
安装 Nav2 官方 demo 和 Phantom Bridge 推荐的 Cyclone DDS 依赖:
bash
source /opt/ros/humble/setup.bash
sudo apt update
sudo apt install \
ros-$ROS_DISTRO-navigation2 \
ros-$ROS_DISTRO-nav2-bringup \
ros-$ROS_DISTRO-gazebo-ros-pkgs \
ros-$ROS_DISTRO-turtlebot3-gazebo \
ros-$ROS_DISTRO-rviz2 \
ros-$ROS_DISTRO-rmw-cyclonedds-cpp
额外安装 rmw_cyclonedds_cpp,是因为官方 README 推荐 Phantom Bridge 使用 Cyclone DDS。关键原则是:Nav2 这边和 Bridge 容器里要使用同一个 RMW 和同一个 ROS_DOMAIN_ID。
3.4 准备 Bridge Client 镜像
官方 README 提供两种方式:直接使用预构建镜像,或者从源码构建本地镜像。本文示例使用本地镜像名 phntm/bridge:humble;如果你已经有可用的官方镜像,也可以在 Compose 中把 image 改成对应的 ghcr.io/phantomcybernetics/phntm_bridge_client 镜像。
从源码构建时:
bash
cd ~
git clone git@github.com:PhantomCybernetics/phntm_bridge_client.git phntm_bridge_client
cd phntm_bridge_client
ROS_DISTRO=humble
docker build -f Dockerfile \
-t phntm/bridge:$ROS_DISTRO \
--build-arg ROS_DISTRO=$ROS_DISTRO \
.
如果源码构建遇到 phntm_interfaces 接口不匹配,先看本文第 6 节的编译问题备忘;若只是体验本文 Nav2 可视化流程,优先使用官方预构建镜像会更省事。
3.5 注册 Phantom Bridge 机器人
向 Bridge Server 注册一个机器人,并生成默认配置。这个步骤会生成唯一的 id_robot 和 key:
bash
wget -O ~/phntm_bridge.yaml 'https://register.phntm.io/robot?yaml'
打开 ~/phntm_bridge.yaml,建议至少确认或修改:
yaml
/**:
ros__parameters:
id_robot: '%ID_ROBOT%'
key: '%SECRET_KEY%'
name: 'Nav2 TurtleBot3 Demo'
maintainer_email: 'robot.master@example.com'

注册接口生成的 id_robot 和 key 不要发布到公开网络。为了能在 Web UI 中处理 Nav2 action 类型,可以在 extra_packages 里补充 Nav2 消息包。官方 README 说明这里写 ROS 包名即可,不需要写完整 apt 包名:
yaml
/**:
ros__parameters:
extra_packages:
- turtlebot3-gazebo
- turtlebot3-description
- nav2-msgs
- nav-msgs
- sensor-msgs
- map-msgs
- bond
重启docker:
bash
docker compose down
docker compose up -d --force-recreate
如果只看 /tf、/scan、/robot_description、/odom 等常见消息类型,这一步通常不是必须的;如果要在 Web UI 的 Services & Actions 菜单里调用 /navigate_to_pose、/navigate_through_poses 等 Nav2 action,Bridge Client 需要能找到对应 action 类型。
配置文件中还有几类常用字段可以按需确认:
| 字段 | 用途 |
|---|---|
bridge_server_address |
Bridge Server 地址,注册文件会自动生成。 |
discovery_period_sec |
ROS graph discovery 间隔。 |
stop_discovery_after_sec |
discovery 运行多久后停止;小于 0 表示持续发现。 |
/robot_description、/tf_static |
可设置 RELIABLE 和 TRANSIENT_LOCAL,便于 Web UI 后启动时仍能拿到静态信息。 |
wifi_interface、enable_wifi_scan、enable_wifi_roam |
Agent 的 Wi-Fi 监控和扫描能力;仿真 demo 通常可以保持默认或关闭。 |
docker_monitor_topic、enable_docker_control |
Agent 的 Docker 容器监控和控制能力。 |
input_drivers |
Web UI 输入控制驱动,例如 TwistInputDriver、JoyInputDriver。 |
修改 ~/phntm_bridge.yaml 后先保存;Bridge Client 容器的启动和必要的重启放到第 4.3 节处理。
3.6 编写 Compose 服务
官方 README 建议把 Bridge Client 和 Agent 放在同一个 Docker Compose service 中运行。下面示例按 Humble 和本文的 ROS_DOMAIN_ID=22 整理:
yaml
services:
phntm_bridge:
# 这里使用本地编译的 image
# image: ghcr.io/phantomcybernetics/phntm_bridge_client:main-jazzy
image: phntm/bridge:humble
container_name: phntm-bridge
hostname: phntm-bridge.local
restart: unless-stopped
privileged: true
network_mode: host
ipc: host
environment:
- RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
- ROS_DOMAIN_ID=22
volumes:
- /home/jay/phntm_bridge.yaml:/ros2_ws/phntm_bridge_params.yaml:ro
- /home/jay/phntm_bridge.yaml:/ros2_ws/phntm_agent_params.yaml:ro
- /var/run:/host_run
- /tmp:/tmp
#devices:
# - /dev:/dev
# logging:
# driver: local
command:
ros2 launch phntm_bridge client_agent_launch.py
把 /home/jay 改成你的实际用户目录。这里刻意使用绝对路径挂载参数文件,因为之前调试时遇到过 ~/phntm_bridge.yaml 在 sudo docker compose 下被解析错、Docker 自动创建同名目录,最终导致 ROS 报 Parameter file path is not a file / Is a directory。
4. 实验
环境设置完成后,再开始运行实验。实验顺序是:启动 Nav2/Gazebo,确认 ROS graph 和 TF,启动 Bridge Client,然后在浏览器里观察 Nav2 系统。
4.1 启动 Nav2 TurtleBot3 Gazebo
打开第一个终端,启动 Nav2/Gazebo:
bash
source /opt/ros/humble/setup.bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export ROS_DOMAIN_ID=22
export TURTLEBOT3_MODEL=waffle
ros2 launch nav2_bringup tb3_simulation_launch.py \
use_rviz:=True \
headless:=False
这个 launch 会启动:
- TurtleBot3 Waffle Gazebo 仿真。
- Nav2 getting started demo,包括 map server、AMCL、planner、controller、behavior server、BT navigator、waypoint follower、velocity smoother 等节点。
nav2_lifecycle_manager,负责把 Nav2 受管节点带到 active 状态。robot_state_publisher和 Gazebo 相关节点,用于发布机器人模型、TF、仿真时钟、里程计和激光数据。
启动后设置初始位姿。Nav2 需要 map -> odom -> base_link 这条 TF 链,AMCL 收到初始位姿后才会稳定发布 map -> odom。
4.2 启动 Phantom Bridge 并打开 Web UI
如果你已经把当前用户加入 docker 组并重新登录,可以不使用 sudo:
bash
docker compose up phntm_bridge
如果首次运行时 Bridge Client 因为安装 extra_packages 后退出,重新执行一次:
bash
docker compose up phntm_bridge
注册生成的 ~/phntm_bridge.yaml 顶部会包含机器人的 Web UI 地址,格式类似:
text
https://bridge.phntm.io/%YOUR_ID_ROBOT%
浏览器打开这个地址后,应该能看到 Phantom Bridge UI 连接到本文启动的 Nav2/Gazebo 系统。
4.4 在 Web UI 中验证
打开 Web UI 后,可以按下面顺序验证。
Graph View:确认 Nav2 系统被发现
在 Nodes & Topics 菜单中打开 Graph View。左边应能看到 Nav2、Gazebo、robot_state_publisher 等节点,右边能看到 /tf、/scan、/odom、/map、costmap、planner/controller 相关 topic。Graph View 的价值是快速确认两个问题:
- Bridge Client 是否和 Nav2 处在同一个 ROS graph 中。
- topic 的 publisher/subscriber 和 QoS 是否存在明显 mismatch。
World Model 3D:看机器人模型和激光
官方内置的 World Model 3D widget 会读取 /robot_description,再根据 /tf_static 和 /tf 更新机器人姿态。它还支持 LaserScan overlay,可以把 /scan 映射到机器人模型对应 frame 上。

Nav2 service:观察和调用
在 Services 菜单中可以看到自动发现的 ROS service 和 action。Phantom Bridge 支持给复杂 service/action 定义 JSON payload,并保存成按钮。
对 Nav2 demo,可以关注:
/navigate_to_pose/navigate_through_poses/follow_waypoints- lifecycle manager 相关 service

Runtime Parameters:看 Nav2 参数

Graph View 中节点名旁边的参数图标可以打开 Runtime Parameter Inspector。对 Nav2 来说,这适合观察 planner、controller、costmap、bt_navigator、waypoint_follower 等节点的运行时参数。
这比在远程终端里反复运行 ros2 param list/get 更直接,尤其适合演示"远程调试和 observability"这一类能力。
5. 工具对比
Phantom Bridge 和几类已有工具有关系,但关注点不同。
| 工具/工作 | 重点 | 和 Phantom Bridge 的关系 |
|---|---|---|
RViz |
本地 ROS 可视化和调试 | Phantom Bridge 在远程浏览器场景下补充/部分替代 RViz,但不等于完整替代 RViz 插件生态。 |
rosbridge / Robot Web Tools |
WebSocket/JSON,把 ROS 带进浏览器 | Phantom Bridge 继承"ROS to Web"的方向,但用 WebRTC/H.264/Socket.io 做更低延迟和媒体友好的方案。 |
Foxglove Bridge |
高性能 WebSocket 数据观察链路 | 更偏数据可视化和 observability;Phantom Bridge 更强调遥操作、视频和运维一体化。 |
6. 编译问题备忘
本仓库前面验证 phntm_bridge_client 时遇到过一个接口漂移问题,可以作为从源码构建时的排查线索。

Dockerfile 会拉最新的 phntm_interfaces main,但最新接口仓库已经把旧的:
text
phntm_interfaces/srv/FileRequest
删掉了,改成新的 message 接口:
text
phntm_interfaces/msg/FileExtractionRequest
phntm_interfaces/msg/FileExtractionResult
而当时 phntm_bridge_client main 代码还在 include 旧头文件:
cpp
#include "phntm_interfaces/srv/file_request.hpp"
所以编译时会报:
text
fatal error: phntm_interfaces/srv/file_request.hpp: No such file or directory
当时的解决方法是直接用 dev 分支构建:
bash
git fetch origin dev
git checkout dev
ROS_DISTRO=humble
docker build -f Dockerfile -t phntm/bridge:$ROS_DISTRO --build-arg ROS_DISTRO=$ROS_DISTRO .
如果之后再次复现,应优先检查 phntm_bridge_client、phntm_interfaces、phntm_agent 三个仓库的接口版本是否匹配,而不是只看最后的编译错误。若只是按本文教程体验 Nav2 可视化,优先使用官方预构建镜像会更省事。