EP:Engineer and Program
ROS2 跨 IP 传输相机图像核心结论
ROS2 图像优先用 Topic(发布订阅)。
Topic:持续流式推送图像(相机这种连续数据流,标准方案)
Service:一问一答,适合单次请求抓一张图片,不适合实时视频流
ROS2 底层是 DDS 中间件(FastDDS/CycloneDDS) ,DDS 自动完成跨 IP 网络发现、UDP 组播 / 单播传输,不需要你手动写 IP 套接字;只要两台机器网络互通、配置一致,发布节点推图像,任意 IP 上的订阅节点就能收到图像 topic。
一、ROS2 图像消息类型 & image_transport(图片传输协议层)
1)原生消息
sensor_msgs/msg/Image:raw 原始图,BGR8/RGB8,不带压缩,体积巨大(1080p 一帧几 MB),局域网短距离可用,WiFi 跨 IP 很容易带宽爆满。sensor_msgs/msg/CompressedImage:JPEG/PNG 压缩图像,image_transport插件自动生成,推荐跨网络使用。
2)image_transport 插件系统
image_transport 是 ROS2 图像传输抽象层,插件化切换传输编码协议,不用改业务节点代码ROS
raw:默认,原始Image消息compressed:JPEG/PNG(最常用,开箱即用)ffmpeg_image_transport:H.264/H.265 硬件编码(NVIDIA GPU 硬编,高分辨率、高帧率首选)
原理:相机驱动发布基础 topic
/camera/image;image_transport 自动派生:
/camera/image/compressed(jpeg)、/camera/image/ffmpeg(h264)订阅端选择对应的 transport,自动解码。
安装:
# 基础压缩插件
sudo apt install ros-humble-image-transport ros-humble-image-transport-plugins
# ffmpeg硬件编码插件(NVIDIA)
sudo apt install ros-humble-ffmpeg-image-transport
查看本机支持哪些图像传输协议:
ros2 run image_transport list_transports
二、跨 IP 多机通信配置(场景:相机端 IP A,接收端 IP B)
前提:两边机器可以互相 ping 通
-
关闭本地回环限制(两边机器都执行)
unset ROS_LOCALHOST_ONLY
-
统一 ROS_DOMAIN_ID(两边必须相同,0~101,推荐 42)
export ROS_DOMAIN_ID=42
-
RMW 中间件保持一致,默认 FastDDS
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
-
复杂多网卡必配,指定 DDS 绑定网卡
FastDDS 可以配置 xml,强制 DDS 使用enP1p1s0网卡,防止 DDS 在多个网卡之间乱发现,找不到远端 IP。
写到
~/.bashrc永久生效,source 后生效。两边配置好后,重启 ros2 daemon:
ros2 daemon stop && ros2 daemon start
测试连通性
-
相机端(发布端):启动 usb_cam /realsense 等相机驱动,发布
/camera/image -
远端接收机:
查看能否发现topic
ros2 topic list
订阅图像
ros2 run rqt_image_view rqt_image_view
三、两种通信选型:Topic(推荐) vs Service(仅快照)
Topic 流式视频(正常摄像头实时传输)
相机节点持续 publish 图像消息到 topic;远端任意 IP 的节点订阅。
支持多接收端:1 个相机发布,多台 IP 机器同时订阅。
QoS 配置非常关键:图像大数据一般用 SENSOR_DATA QoS(best effort,丢帧优先保实时),不要用 RELIABLE,否则网络抖动直接卡顿、堆积。
Service:按需单次抓图(不做实时流)
定义服务,client(远端 IP)发一次请求,server(相机端)捕获一张图返回。适合 "远程点一下,拍一张照片",不适合连续视频 。
自定义 srv 消息,把CompressedImage作为返回字段。
四、如何自定义 / 修改图片传输协议(image_transport 插件开发)
如果自己定义图像编码协议 (自定义压缩 / 自定义二进制打包),需要开发image_transport插件:
- 新建 ROS2 功能包,继承
image_transport::PublisherPlugin/SubscriberPlugin - 实现:编码函数(cv::Mat → 自定义二进制包)、解码函数(自定义包 → cv::Mat)
- 注册插件,编译,两边机器安装插件
- 启动节点时,指定
image_transport:=你的插件名
绝大多数工程不需要从零开发协议 ,直接用
compressed(jpeg)或者ffmpeg(h264/h265)足够;ffmpeg 插件支持 NVIDIA 硬件编解码,大幅降低 CPU 负载。
五、关键踩坑(适配你当前 NVIDIA 机器 + 双网卡环境)
-
双网卡 DDS 发现混乱 :FastDDS 默认会在所有网卡广播,多网卡环境容易发现失败,必须用 FastDDS XML 配置锁定网卡
enP1p1s0。 -
原始图像太大:720p/1080p 不要直接 raw 跨 IP,带宽爆炸,一定要开 compressed 或者 h264。
-
QoS 不匹配 :发布 / 订阅 QoS 不一致,topic 看得见但收不到图像,图像传输推荐 QoS
SENSOR_DATA。 -
防火墙:两台 ubuntu 关闭 ufw,或者放行 UDP 端口(DDS 使用 UDP)
sudo ufw disable
-
可以把相机发布节点封装成 systemctl service,上电自动启动摄像头 topic 发布。
六、最小示例:USB 相机发布压缩图像
# 安装usb_cam
sudo apt install ros-humble-usb-cam
# 启动相机,自动发布 /camera/image 和 /camera/image/compressed
ros2 run usb_cam usb_cam_node_exe
远端机器查看压缩流:
ros2 topic echo /camera/image/compressed
七、补充:如果需要公网跨 IP(不在同一个局域网)
DDS 默认组播无法跨公网,两种方案:
- 部署 DDS Router,转发 DDS 流量;
- 写 bridge 节点:本机订阅 ROS2 图像 topic,转成 RTSP/WebSocket,远端拉流(脱离原生 DDS)。