多台 D455 拍出同一时刻:librealsense 硬件同步从接线到验证
【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense
librealsense 的 D455 硬件同步(Hardware Sync)解决的是多相机"各拍各的"问题。两台 D455 之间 1ms 的时间戳差,落在 1m/s 的流水线上就是 1mm 的物体位移,多视点云直接对不上,拼接处出现重影。本文给出从主从接线到时间戳验证的最短路径。
为什么多机拼接需要硬件级同步
做三维重建时,3 台 D455 从不同角度围拍一个工件。如果各相机自由触发,每帧之间差 1ms,运动目标在两台相机里的位置就差 1mm 级;把多份点云叠在一起,工件边缘就会"裂开"。
软件对齐(比如rs2::align,把深度图按内参插值到另一路相机坐标系)解决的是"空间对不齐",解决不了"时间对不齐"。硬件同步的适用边界:单相机、或场景基本静止时,软件对齐就够;多台设备、有运动目标、且相机是全局快门型号(D455/D457/D409)时,才值得走硬件同步这条路。
先把线接对:主从拓扑与 D455 GPIO 接口速查
硬件同步的主从级联靠 D455 背面的 GPIO 扩展口:主相机输出触发信号,从相机输入后跟随曝光。🔌
| 信号 | 角色 | 说明 |
|---|---|---|
| GPIO0 | 从相机触发输入 | 主相机信号线的落点 |
| GPIO1 | 主相机触发输出 | 发出与帧同步的脉冲 |
| GND | 所有相机 | 必须共地互联 |
最小可用连接一句话:主相机触发输出接每台从相机 GPIO0,所有相机 GND 连在一起,走独立 5V 供电轨(扩展口取电能力有限,别指望它带动整组相机)。注意:INTER_CAM_SYNC_MODE选项只在支持CAP_INTERCAM_HW_SYNC的全局快门设备上注册,D405 和滚动快门型号没有这个选项。
接口示意图仓库内没有现成图,可先按上述拓扑接,参考 doc/rs400/rs400_advanced_mode.md。
三步把硬件同步跑起来
第一步:枚举设备,指定主从
rs2::context ctx; auto all_devices = ctx.query_devices(); std::vector<rs2::device> cams(all_devices.begin(), all_devices.end()); rs2::pipeline master_pipe(ctx); rs2::config cfg; cfg.enable_device(std::string(cams[0].get_info(RS2_CAMERA_INFO_SERIAL_NUMBER))); cfg.enable_depth_stream(1280, 720, RS2_FORMAT_Z16, 30); auto master_profile = master_pipe.start(cfg);取第一台当主,靠序列号锁定,不靠枚举顺序。跑不通先看:query_devices()数量是否为 0,串口供电是否到位。
第二步:配置 INTER_CAM_SYNC_MODE 触发模式
INTER_CAM_SYNC_MODE注册在深度传感器上,取值定义在 include/librealsense2/rs_option.h(RS2_D500_INTERCAM_SYNC_EXTERNAL_MASTER等)。
if (master_profile.get_device().is<rs2::depth_sensor>()) { auto depth = master_profile.get_device().first<rs2::depth_sensor>(); depth.set_option(RS2_OPTION_INTER_CAM_SYNC_MODE, RS2_D500_INTERCAM_SYNC_EXTERNAL_MASTER); }从相机保持RS2_D500_INTERCAM_SYNC_NONE(默认值),只需接好线。跑不通先看:depth.supports_option(RS2_OPTION_INTER_CAM_SYNC_MODE)是否为 true,固件版本是否 ≥ 5.12.12.100。
第三步:抓一帧验证时间戳
rs2::frameset master_fs = master_pipe.wait_for_frames(); double master_ts = master_fs.get_depth_frame().get_timestamp(); for (auto& pipe : slave_pipes) { rs2::frameset fs; if (pipe.poll_for_frames(&fs)) { double diff_ms = (fs.get_depth_frame().get_timestamp() - master_ts) / 1000.0; std::cout << "slave timestamp diff: " << diff_ms << " ms" << std::endl; } }get_timestamp()单位是微秒。主从偏差稳定在 0.1ms 以内,这次同步就成立。跑不通先看:从相机是否真的在出帧,线缆是否插在主相机输出端。
时间戳偏差验证:怎么确认真的同步了
🔧 判据就一条:连续抓多组帧,|slave_ts - master_ts|始终 ≤ 100μs(约 0.1ms)视为同步成功;偶发超差先查线,持续超差查固件。仓库自带工具能直接打印FRAME_TIMESTAMP/SENSOR_TIMESTAMP和时间戳域(HARDWARE_CLOCK),用来核对偏差比手抄方便:
高频故障对照:
| 现象 | 大概率原因 | 处理动作 |
|---|---|---|
| 从相机时间戳完全不动 | 共地没接 / 信号线接反 | 万用表量 GND 导通,确认线落在从相机 GPIO0 |
| 偏差随时间缓慢变大 | 两台固件版本不一致,或供电不稳 | 统一固件版本,换独立 5V 电源 |
| 偶发丢一帧触发 | 信号线过长或靠近 USB 线 | 走线缩到 10cm 内,远离 USB 线束 |
排障流程另见 doc/troubleshooting.md。
延伸一步:同步帧能做什么
同步之后的直接收益是多视点云拼接:同一时刻的多份点云合并,运动物体不会裂出重影,剩下的活只剩按相机位姿(外参)对齐坐标轴。示意:
rs2::pointcloud pc; for (auto& [serial, fs] : synced) merged_points += pc.calculate(fs.get_depth_frame());多相机取帧骨架参考 examples/multicam/rs-multicam.cpp,空间对齐思路参考 examples/align/rs-align.cpp。
绕回了开头那个 1mm 的重影:线接对、选项设对,时间戳差就能压到 0.1ms 内,拼接自然干净。下一步可以直接从 examples/multicam/ 改起来。你踩过什么同步的坑,欢迎补在评论区。
【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考