EP_ROS2的相机视频流传递说明

ROS2 三相机感知模块接口说明文档

项目名称 :机器人多相机感知模块

ROS 版本 :ROS2 Humble

传输方案 :image_transport + JPEG 压缩图像流;内参、外参采用 ROS 标准消息

相机清单:前视相机、左手臂相机、右手臂相机

相机内外参数说明:

  1. 相机内参(CameraInfo):使用 Topic 发布
    内参在标定完成后固定不变,但遵循 ROS 标准范式,通过/cameraXXX/camera_info持续周期发布;支持订阅节点随时获取,兼容 image_pipeline、calibration 工具链。
  2. 相机外参(相对于 base_link 的 TF / 静态外参):优先 TF2 + static_transform_publisher;动态外参(机械臂末端相机随臂移动)使用 TF 动态广播
    • 静态外参(相机固定在机身,位置不变):static_transform_publisher 发布静态 TF,一次性发布,DDS 自动维护;
    • 动态外参(左右臂末端相机,随机械臂关节运动实时变化):TF2 动态广播;
    • 备选方案:如果业务必须以消息数据包形式拿到外参矩阵(4×4 齐次变换矩阵),可以新增自定义 Topic 发布外参矩阵消息;
      协议原则:遵循 ROS 视觉生态标准,尽量复用原生消息,最小化自定义消息,保证和 image_pipeline、rviz、标定工具直接兼容

1 通信总览表

表格

相机名称 原始图像 Topic (raw) JPEG 压缩图像 Topic (image_transport) 相机内参 Topic TF 光学坐标系 父坐标系
前视相机 /camera_front/image_raw /camera_front/image_raw/compressed /camera_front/camera_info camera_front_optical_frame base_link
左手臂相机 /camera_left_arm/image_raw /camera_left_arm/image_raw/compressed /camera_left_arm/camera_info camera_left_arm_optical_frame left_arm_end_link
右手臂相机 /camera_right_arm/image_raw /camera_right_arm/image_raw/compressed /camera_right_arm/camera_info camera_right_arm_optical_frame right_arm_end_link

补充 TF 链路:

  • 前视:base_link → camera_front_optical_frame(静态,固定外参)

  • 左臂:base_link → left_arm_end_link(由机械臂状态发布动态 TF)→ camera_left_arm_optical_frame(手眼标定得到,相对于末端的静态变换)

  • 右臂:base_link → right_arm_end_link(机械臂动态 TF)→ camera_right_arm_optical_frame(手眼标定静态变换)
    消息 QoS 统一约定:

  • 图像 Topic、camera_info 内参 Topic:rclcpp::SensorDataQoS()(BestEffort,适合传感器数据流)

  • TF 消息:TF2 内置 QoS(默认 RELIABLE,少量数据,无带宽压力)

2 消息结构定义

2.1 图像消息(复用 sensor_msgs)

  1. raw 图像:sensor_msgs/msg/Image

  2. JPEG 压缩图像:sensor_msgs/msg/CompressedImage

    std_msgs/msg/Header header
    string format # "jpeg"
    uint8[] data # JPEG二进制字节

2.2 相机内参消息 sensor_msgs/msg/CameraInfo(标准 ROS 消息,内参 Topic 使用)

复制代码
# 相机标定内参消息,/cameraXXX/camera_info 的消息定义
std_msgs/msg/Header header

uint32 height                  # 图像高度 px
uint32 width                   # 图像宽度 px
string distortion_model        # 畸变模型:plumb_bob(径向+切向畸变)
double[] D                     # 畸变系数 D[0~4]

# 内参矩阵 K (3x3 相机内参)
# K = [fx,  0, cx;
#       0, fy, cy;
#       0,  0,  1 ]
double[9] K

# 相机校正矩阵 R(立体相机使用,单目相机填单位矩阵)
double[9] R

# 投影矩阵 P (3x4)
# P = K * [R | t],单目相机R为单位矩阵,t=0
double[12] P

uint32 binning_x
uint32 binning_y
sensor_msgs/msg/RegionOfInterest roi

字段说明:

  • header.frame_id:与对应图像 topic 保持一致(camera_xxx_optical_frame),时间戳和图像帧对齐;
  • 单目相机 distortion_model 固定为plumb_bob;
  • 内参标定后固定不变,节点可按 1Hz~10Hz 周期持续发布(无需和图像帧率完全对齐,推荐 10Hz)

2.3 外参方案 A:TF2(无需自定义 msg)

TF 消息类型:tf2_msgs/msg/TFMessage

包含多个geometry_msgs/msg/TransformStamped

复制代码
std_msgs/msg/Header header
string child_frame_id
string parent_frame_id
geometry_msgs/msg/Transform transform
# transform包含平移(xyz) + 四元数(xyzw)旋转
  • 平移:transform.translation.x/y/z 单位 m
  • 旋转:transform.rotation.x/y/z/w 四元数

使用方式

  1. 前视相机:静态外参,launch 中使用static_transform_publisher一次性发布base_link → camera_front_optical_frame
  2. 左右臂相机:手眼标定得到left_arm_end_link→camera_left_arm_optical_frame静态 TF;机械臂驱动发布base_link到left_arm_end_link动态 TF;TF 树自动拼接,任意节点可直接查询base_link到相机光学坐标系的完整 4×4 变换矩阵。

优势:RViz 原生支持、ROS2 所有视觉库原生支持,直接调用 tf2_geometry_msgs 完成坐标点变换,不用手动解析矩阵。

2.4 外参方案 B:自定义 Topic(业务必须直接拿到 4×4 齐次外参矩阵时启用,备选方案)

适用场景:业务算法需要直接接收 4×4 齐次变换矩阵,不方便调用 TF2 查询;非必需,优先 TF

新建自定义消息包 robot_calibration_msgs,新建 msg 文件 ExtrinsicMatrix.msg

文件:robot_calibration_msgs/msg/ExtrinsicMatrix.msg

复制代码
# 相机外参齐次4×4变换矩阵,child_frame相对于parent_frame
std_msgs/msg/Header header
string parent_frame_id       # 参考坐标系,一般 base_link
string child_frame_id        # 相机光学坐标系 camera_xxx_optical_frame
double[16] matrix            # 4x4齐次变换矩阵,行优先排列
# T = [R t; 0 0 0 1],16个元素:[m00,m01,m02,m03, m10,m11,m12,m13, m20,m21,m22,m23, m30,m31,m32,m33]

对应 topic 命名(如果启用此方案)

表格

相机 自定义外参矩阵 Topic 消息类型
前视 /camera_front/extrinsic_matrix robot_calibration_msgs/msg/ExtrinsicMatrix
左手臂 /camera_left_arm/extrinsic_matrix robot_calibration_msgs/msg/ExtrinsicMatrix
右手臂 /camera_right_arm/extrinsic_matrix robot_calibration_msgs/msg/ExtrinsicMatrix

发布频率:和机械臂状态同步,推荐 100Hz;静态相机可以低频 1~10Hz 发布。

注意:尽量避免同时开启 TF + 自定义外参 topic,两份数据必须保持一致,避免两套外参冲突。

3 节点发布约定

3.1 相机驱动节点

  1. camera_front_driver_node
    • 发布:/camera_front/image_raw(image_transport 自动生成 compressed 压缩图)
    • 发布:/camera_front/camera_info(内参)
    • 外参:static_transform_publisher 发布静态 TF,不属于相机驱动节点
  2. camera_left_arm_driver_node
    • 发布:/camera_left_arm/image_raw、compressed 压缩流
    • 发布:/camera_left_arm/camera_info(内参)
    • 外参:static_transform_publisher 发布静态 TFleft_arm_end_link→camera_left_arm_optical_frame
  3. camera_right_arm_driver_node
    • 发布:/camera_right_arm/image_raw、compressed 压缩流
    • 发布:/camera_right_arm/camera_info(内参)
    • 外参:static_transform_publisher 发布静态 TFright_arm_end_link→camera_right_arm_optical_frame

3.2 机械臂驱动节点

  • 发布机械臂关节状态,广播动态 TF:base_link → left_arm_end_link、base_link → right_arm_end_link

4 Topic vs Service 选型详细论证

内参:Topic

  • 理由:感知节点持续运行,随时可能读取内参;Topic 订阅被动接收,低开销;原生兼容 ROS 标定、image_proc 去畸变节点。
  • 缺点:固定参数周期性发送,微小带宽开销(极小,消息体很小)

外参:TF2

  • 静态相机:static TF,仅发布一次,几乎无开销
  • 机械臂末端动态相机:TF 持续广播末端位姿,全 ROS 生态原生支持坐标变换

内外参不推荐实时业务使用 Service

  • Service 工作模式:Client 主动请求,Server 返回一次参数;
  • 问题:
    1. 实时感知流水线,每一帧图像都要请求外参,会引入 RTT 延迟;
    2. 多订阅节点(检测、SLAM、手眼)会并发调用 service,造成服务阻塞;
    3. 无法做到图像时间戳和外参时间戳自动对齐;

Service 仅推荐离线标定工具 使用:例如写一个get_camera_param服务,一次性读取标定文件,程序启动阶段调用一次,不是实时图像流水线使用。
【可选离线服务示例(仅调试)】

srv 文件 robot_calibration_msgs/srv/GetCameraParam.srv

复制代码
# request
string camera_name  # front / left_arm / right_arm
---
# response,一次性返回内参+外参
sensor_msgs/msg/CameraInfo intrinsic
robot_calibration_msgs/msg/ExtrinsicMatrix extrinsic

5 时间同步约定

  1. image_raw、camera_info消息 header.stamp 必须是同一帧图像采集的硬件时间戳;

  2. TF 变换查询时,使用图像 header.stamp 去 lookupTF,获取该图像时刻对应的相机外参;

    // C++查询某帧图像时刻,base_link到相机光学帧的变换
    tf2_ros::Buffer tf_buffer;
    auto transform = tf_buffer.lookupTransform(
    "base_link",
    msg->header.frame_id,
    msg->header.stamp,
    tf2::durationFromSec(0.1)
    );

6 测试命令

复制代码
# 查看所有相机topic
ros2 topic list | grep -E "image|camera_info|tf"

# 查看内参消息
ros2 topic echo /camera_front/camera_info

# 查看TF树
ros2 run tf2_tools view_frames

# 查询某时刻base_link到前视相机的变换
ros2 run tf2_ros tf2_echo base_link camera_front_optical_frame

# 图像可视化
ros2 run rqt_image_view rqt_image_view

7 性能与约束

  1. 图像:JPEG 压缩,QoS=SensorData(BestEffort);
  2. camera_info:消息体很小,带宽可忽略,1~10Hz 周期发布;
  3. TF:动态 TF(机械臂末端)推荐 100Hz;静态 TF 仅一次发布;
  4. 跨 IP 多机:ROS_DOMAIN_ID 统一,关闭 localhost_only,FastDDS 锁定网卡enP1p1s0;
  5. 时间同步:推荐使用 chrony 做机器时钟同步(多机跨 IP 部署必备)。

8 推荐 launch 文件结构简述

复制代码
<!-- 启动三个相机驱动,发布image + camera_info -->
<node pkg="camera_driver" exec="camera_front_driver_node"/>
<node pkg="camera_driver" exec="camera_left_arm_driver_node"/>
<node pkg="camera_driver" exec="camera_right_arm_driver_node"/>

<!-- 静态TF:手眼标定外参 -->
<node pkg="tf2_ros" exec="static_transform_publisher"
args="x y z qx qy qz qw base_link camera_front_optical_frame"/>

<node pkg="tf2_ros" exec="static_transform_publisher"
args="x y z qx qy qz qw left_arm_end_link camera_left_arm_optical_frame"/>

<node pkg="tf2_ros" exec="static_transform_publisher"
args="x y z qx qy qz qw right_arm_end_link camera_right_arm_optical_frame"/>

9 部署扩展

  • 相机驱动节点可封装为 systemctl service,上电自启(前文提到的方案)
  • 多机跨 IP:图像流(JPEG compressed)跨 DDS 传输;TF、camera_info 同步跨机共享;
  • 去畸变:订阅camera_info+ 原始图像,使用image_proc节点完成图像去畸变。
相关推荐
加强洁西卡1 小时前
【AI】机器学习常见的指标及其解释
人工智能·机器学习
面包狗AI4S2 小时前
【AI4S】生化环材高可信技术与产业周报(2026-10-03—2026-10-09)
人工智能·深度学习·机器学习·ai
田里的水稻2 小时前
EP_ROS框架---相机视频流交互二
人工智能·深度学习·数码相机·机器学习·迁移学习
Dfreedom.2 小时前
光谱定性分析中PCA、SVM与LDA方法的对比研究
机器学习·支持向量机·lda·pca·svm·化学计量学·光谱数据处理
光电的一只菜鸡3 小时前
相机光学(五十六)——DCIAF
数码相机
larance3 小时前
[菜鸟教程] 机器学习教程十一课-数据理解
人工智能·机器学习
Zldaisy3d4 小时前
北京理工大学 l 金属激光增材制造在线监测技术研究进展
数码相机·3d·制造
lhh_qrsly4 小时前
机器学习 深度学习 强化学习 都学啥 和 高等数学 线性代数 概率论数理统计 有啥关系
深度学习·线性代数·机器学习
workflower5 小时前
矿用机器人人工智能安全与治理体系
人工智能·安全·机器学习·机器人·云计算·无人机