ROS 2 是为分布式系统而构建的,但其默认网络模型在局域网中效果最佳。将机器人连接到远程操作员、云服务或另一网络上的另一台机器人时,团队往往不得不围绕 ROS 图自行构建并维护传输层。
今天,我们发布 LiveKit Portal for ROS 2。它是一个独立的 ROS 2 节点,可将 ROS 图连接到 LiveKit 房间。它借助 LiveKit 的实时网络,为 ROS 和非 ROS 参与者提供了一种通过 WebRTC 交换话题、服务调用和视频的通用方式。

LiveKit Portal for ROS 2 让你无需跨网络暴露 DDS、无需更改机器人上已运行的节点,也无需自行构建和维护传输层,即可构建远程机器人系统。
将你的 ROS 图连接到任何 LiveKit 参与者#链接到本节
ROS Portal 节点会发现本地 ROS 图中已配置的话题,并将它们发布为 LiveKit 轨道。发布后,另一个 ROS Portal 节点可以订阅这些轨道,并将它们重新发布到自己的图中。此外,在机器人系统与非 ROS 客户端通信的场景中,Web 应用、云服务和其他 LiveKit 客户端无需运行 ROS 即可消费相同的数据。
ROS Portal 支持四种主要数据路径:
- ROS 话题。通过 LiveKit DataTracks双向转发话题。ROS Portal 在运行时发现消息类型,并为每条轨道通告一个 schema。
- ROS 服务。通过 LiveKit RPC 将已配置的服务调用路由到特定的 LiveKit 参与者。
- ROS 图像。将
sensor_msgs/msg/Image或sensor_msgs/msg/CompressedImage话题作为 LiveKit VideoTracks ,并支持可配置的编解码器和比特率选项。 - 视频源。绕过 ROS,直接将视频发布为 LiveKit VideoTracks。
ROS Portal 将每个话题的消息 schema 存储在其各自的 DataTrack 中,因此每个订阅者都知道如何读取数据:
- 对于 ROS 到 ROS 的连接,消息保持 ROS 原生 CDR 格式,无需逐消息转换。在转发话题之前,ROS Portal 会检查两个图是否使用相同的消息定义。
- 对于 ROS 到非 ROS 的连接,ROS Portal 可以将话题编码为 JSON,并发布根据 ROS 消息类型生成的 JSON Schema,这样浏览器应用或云服务无需 ROS 工具即可读取。

使用 ROS Portal 可以构建什么#链接到本节
借助 Portal,DDS 仍保留在每个机器人本地的 ROS 网络内。LiveKit 负责处理参与者之间的广域连接,包括加密、拥塞控制和选择性订阅。每个远程参与者只订阅自己需要的轨道。
该模型支持几种常见用例:
- 遥操作。将视频和传感器数据流式传输到操作员界面,然后将控制话题发送回机器人。
- 远程推理。在远程机器上运行计算密集型的 ROS 组件或原生 LiveKit 客户端。
- 车队协调。在机器人之间交换选定的话题和服务调用,而无需加入它们的 DDS 网络。
- 监控。将诊断信息和状态以带 schema 描述的 JSON 形式发送到浏览器仪表板或云服务。
控制哪些内容可以跨越网络#链接到本节
ROS Portal 使用 YAML 配置文件来定义哪些话题和服务可以跨越 LiveKit 连接。话题规则支持正则表达式、方向控制、速率限制、schema 编码、锁存投递和视频选项。
以下配置在两个方向上发布测试话题、限制 IMU 流、接收远程速度命令,并直接在 LiveKit VideoTrack:
1ros_portal:2 version: '0.0.1'3 4 topics:5 - topic: '/test/.*'6 direction: 'bidirectional'7 8 - topic: '/imu/data_raw'9 direction: 'out'10 max_rate_hz: 1011 encoding: 'jsonschema'12 13 - topic: '/remote/cmd_vel'14 direction: 'in'15 16 services:17 - service: '/navigate_to_pose'18 direction: 'out'19 participant: 'robot-a'20 msg_type: 'nav2_msgs/srv/NavigateToPose'21 22 video_sources:23 - track_name: 'stereo_camera'24 source:25 type: 'gstreamer'26 pipeline: >-27 v4l2src device=/dev/video0 ! videoconvert !28 x264enc name=lk_encoder tune=zerolatency ! h264parse !29 appsink name=lk_appsink30 codec: 'h264'31 resolution:32 width: 256033 height: 72034 rate_control:35 element: 'lk_encoder'36 property: 'bitrate'37 unit: 'kbps'38 publish_options:39 max_bitrate_bps: 400000040 max_framerate: 30
上发布立体相机。只转发应用程序所需的话题和方向。这样可以避免不必要的流量占用受限的机器人链路,并限制 ROS 图的远程暴露面。
演示:将 SLAM 卸载到远程 GPU#链接到本节
本演示将三个用例结合在一起:遥操作、远程推理和监控。一辆漫游车通过 LiveKit 流式传输其立体相机画面,一名不运行 ROS 的操作员在场景中驾驶它。一个拥有桌面 GPU 的 ROS 参与者执行 SLAM 和密集场景重建。最后,机器人的位姿和不断增长的 3D 地图被发送到 LiveKit 房间,并由另一个 ROS 参与者进行可视化。
漫游车是一台 Waveshare Cobra Flex ,搭载 Jetson Orin Nano 和一款相对便宜的 USB 立体相机。Jetson 运行驱动栈,但它没有足够的 GPU 余量来进行学习式深度估计。一台配备 NVIDIA RTX 5090 的台式机改为完成这项工作。边缘设备本身也无法实现远程查看或控制。这些机器不共享本地网络或 DDS 域。
该演示有四个 LiveKit 参与者:
- 机器人。 cobra_flex_ros Docker Compose 栈运行漫游车驱动程序和 ROS Portal。ROS Portal 将立体相机发布为 LiveKit VideoTrack,并将传入的速度命令重新发布为 ROS
cmd_vel话题。 - 操作端。一个使用 LiveKit JS SDK 构建的浏览器应用, 遥操作,显示摄像头画面并发送摇杆和键盘命令。它不运行 ROS。
- SLAM 主机。该 remote_ros_slam Docker Compose 栈运行 ROS Portal, RTAB-Map 立体 SLAM,以及 ScaRF-SLAM 桌面端进行场景重建。
- 可视化端。一台 Mac 运行 ROS Portal 和 Foxglove Bridge。ROS Portal 将位姿和地图话题重新发布到 Mac 的本地 ROS 图中,并且 Foxglove 将其渲染出来。
SLAM 主机如何构建 3D 地图#链接到本节
每个相机帧将左右图像并排保存,因此两只眼睛共享同一个时间戳。SLAM 主机上的 ROS Portal 接收 VideoTrack,并将其重新发布为 ROS 图像话题。SLAM 节点像读取任何本地相机一样读取该话题。
该漫游车没有 IMU,因此 RTAB-Map 通过立体视觉里程计和回环检测来计算位姿。ScaRF-SLAM 接收 RTAB-Map 的关键帧,在 GPU 上估计稠密深度,并在漫游车行驶过程中分批添加到地图中。地图会比漫游车滞后几秒。
SLAM 主机上的 ROS Portal 配置接收摄像头输入,并且只将结果发送出去:
1ros_portal:2 version: '0.0.1'3 4 topics:5 - topic: '/stereo_camera'6 direction: 'in'7 8 # Transforms: map -> odom -> stereo_link from RTAB-Map, and the camera9 # frames from the launch file.10 - topic: '/tf'11 direction: 'out'12 13 - topic: '/tf_static'14 direction: 'out'15 latched: true16 17 # Loop-corrected trajectory.18 - topic: '/rtabmap/mapPath'19 direction: 'out'20 21 - topic: '/rtabmap/map'22 direction: 'out'23 max_rate_hz: 0.524 25 - topic: '/scarf_slam/submaps/.*'26 direction: 'out'27 28 - topic: '/scarf_slam/slam_poses'29 direction: 'out'
SLAM 主机不发布视频。想要获取摄像头画面的参与者订阅机器人的 stereo_camera 直接通过 LiveKit 跟踪,从而省去了 SLAM 主机用于地图数据的上行链路。
完整的 ScaRF-SLAM 地图每条消息会增长到数兆字节,因此它保留在 SLAM 主机的本地图中。主机改为发送体素化、压缩后的数据块,每块最大 32 KB,各自位于独立的话题上。
该 /scarf_slam/submaps/.* 规则会在新的分块话题出现时将其转发。Foxglove 会保留每个话题上的最新消息,因此这些分块合在一起就能渲染出完整的地图。
三视图演示。左上:遥操作员在浏览器中的视图,来自一个不运行 ROS 的参与者。左下:一个 ROS 参与者在 Foxglove 中看到的实时视频视图。右:Foxglove 对场景重建的视图。
没有任何 SLAM 节点知道 LiveKit 的存在。它们读写普通的 ROS 话题,而 ROS Portal 的配置决定哪些内容会跨越网络。你可以对其他重型组件采用同样的模式,例如感知模型、规划器或策略推理。
使用 Docker 在本地试用 ROS Portal#链接到本节
ROS Portal 以 Docker 镜像和 Debian 软件包的形式提供,适用于受支持的 ROS 2 发行版和架构。你可以将其连接到 LiveKit Cloud 或自托管的 LiveKit 服务器。
对于本地环境,请启动一个启用了参与者数据 blob 的 LiveKit 服务器:
1livekit-server --dev --enable_participant_data_blob
然后为 ROS Portal 参与者创建一个令牌:
1export LIVEKIT_URL=ws://127.0.0.1:78802export LIVEKIT_TOKEN="$(lk token create \3 --join \4 --room robo_room \5 --identity ros-portal \6 --allow-update-metadata \7 --valid-for 24h \8 --token-only \9 --yes \10 --dev)"
创建 /tmp/all_topics.yaml 以便进行快速的本地测试:
1echo 'ros_portal:2 version: "0.0.1"3 topics:4 - topic: ".*"5 direction: "bidirectional"' > /tmp/all_topics.yaml
为你的 ROS 发行版运行容器:
1docker run --rm \2 --network host \3 --env LIVEKIT_URL \4 --env LIVEKIT_TOKEN \5 --volume /tmp/all_topics.yaml:/config/ros_portal.yaml:ro \6 livekit/ros-portal:<ros_distro> \7 ros2 launch ros_portal ros_portal.launch.py \8 config_path:=/config/ros_portal.yaml
当前版本支持 ROS 2 Humble、Jazzy、Kilted 和 Lyrical。
后续步骤#链接到本节
该仓库包含安装指南、完整的配置参考、Docker 使用说明,以及一个用于连接两个 ROS 图的 Turtlesim 教程。
在 GitHub 上查看 ROS Portal
按照 Turtlesim 教程操作