时间 --- 多相机传感时间误差分析 在机器人开发系统中本文讨论的多相机场景限定为主流 GigE 工业相机以Basler、海康等工业面阵相机为主要参照Linux 厂商 SDK ROS2 驱动相机驱动层负责调 SDK 取图再发布sensor_msgs/Image重点分析硬件同步触发下从“触发”到“工控机拿到图/ROS2发出图”的所有时间误差。1. 在传感链路中误差时间分成两类第一类真实拍摄时刻误差它决定“多台相机是不是在同一时刻看到了场景”。这类误差主要来自触发信号分发路径相机输入口响应相机内部开始曝光延迟快门类型尤其 rolling shutter第二类主机拿到图像的时刻误差它决定“Linux/ROS2 什么时候看到这张图”。这类误差主要来自传感器读出相机缓存与启动发包时机网口带宽、包大小、包间隔Linux 网络栈 / SDK 线程 / ROS2 发布链路这两类误差经常不是一个数量级前者常见是ns 到几十 µs后者常见是ms 到几十 ms。也就是说相机可能拍得很同步但电脑收到图并不同时。Basler 的时序文档把链路明确拆成Exposure Start Delay、Sensor Readout Time、Frame Transmission Time、Transmission Start DelayROS 的sensor_msgs/Image又明确要求header.stamp应当是采集时刻而不是“ROS 节点收到时刻”。2. 从触发到 ROS2 图像的完整时间链一次采图的整个时间流程可以写成这条链TROS图像到达T触发分发T输入响应T开始曝光延迟T曝光T读出T发包启动T整帧传输TLinux/SDK/ROS2T_{\text{ROS图像到达}}T_{\text{触发分发}} T_{\text{输入响应}} T_{\text{开始曝光延迟}} T_{\text{曝光}} T_{\text{读出}} T_{\text{发包启动}} T_{\text{整帧传输}} T_{\text{Linux/SDK/ROS2}}TROS图像到达​T触发分发​T输入响应​T开始曝光延迟​T曝光​T读出​T发包启动​T整帧传输​TLinux/SDK/ROS2​但对于“真实拍摄时刻”真正重要的是前半段global shutter真实拍摄中心时刻约等于T触发分发T输入响应T开始曝光延迟T曝光2T_{\text{触发分发}} T_{\text{输入响应}} T_{\text{开始曝光延迟}} \frac{T_{\text{曝光}}}{2}T触发分发​T输入响应​T开始曝光延迟​2T曝光​​rolling shutter第 (i) 行第 (i) 行拍摄中心时刻约等于T0i⋅tRowT曝光2T_0 i \cdot t_{Row} \frac{T_{\text{曝光}}}{2}T0​i⋅tRow​2T曝光​​rolling shutter 天生就不是“整帧同一时刻”。rolling shutter 定义为各行以tRow的时间偏移顺序曝光3. 分阶段误差分析3.1 外部硬触发源到各相机输入端触发分发误差这是最前面的误差源包含触发源本身的边沿抖动分配器 / 扇出器各路不一致线缆长度不一致信号完整性不好导致阈值 crossing时刻漂移。分配器 / 扇出器就是把一路触发信号复制并分发成多路输出让多台相机或设备能同时接收同一个触发脉冲的硬件。阈值 crossing一个电信号的电压从低到高或从高到低变化时经过接收端判定阈值电压的那个瞬间如果是铜缆类分发链路传播延迟可按约 5 ns/m粗估。所以两路线长差 2 m就是大约10 ns的固定偏差差 10 m就是大约50 ns量级。这个误差通常不大但它是真正同时曝光能力的第一个底噪。这部分误差的特点是主要是固定偏差不是大抖动一旦布线固定重复性通常很好但如果触发边沿很慢、带振铃阈值 crossing 会漂误差会放大成亚微秒到微秒级。所以从“真实同步”角度看分发链路是ns 级到亚 µs 级的问题。振铃信号本来应该“一下子稳定到目标电压”结果却在目标值附近来回波动几下像铃铛余振一样。3.2 相机输入口响应GPIO / 光耦输入延迟触发信号到达相机引脚后不是立刻被内部逻辑当成“有效触发”中间还隔着输入电路。同类工业相机的量级里GPIO 输入线的快速边沿传播延迟通常很少超过 1 µs光耦输入线通常更慢快速边沿传播延迟很少超过 15 µs。相机固有的 I/O jitter 小于100 ns peak-to-peak峰峰值但前提是触发边沿要足够陡最好短于500 ns。I/O jitter 就是相机的输入口或输出口对同一个事件的响应时刻每次都不完全一样这种时间上的微小来回波动就叫 I/O 抖动。这意味着GPIO 触发通常是亚微秒到 1 µs 级光耦触发更可能是几微秒到十几微秒级同批次相机即便条件一样也可能因器件离散性出现不同传播延迟。3.3 相机内部“接受触发”到“开始曝光”开始曝光延迟Exposure Start Delay是检测到触发信号到实际开始曝光之间的时间并且如果用了硬触发、去抖、触发延迟这些时间都要加进去。基础开始曝光延迟18 µs输入响应1.5 µsLineDebouncerTime5 µsTriggerDelay200 µs总启动延迟就是181.55200224.5 μs18 1.5 5 200 224.5\ \mu s181.55200224.5μs这是一个非常典型的误差预算公式。Trigger Delay触发信号收到后到触发真正生效之间可人为加入延迟单位就是 µsLine Debouncer Time范围0 到 1,000,000 µs如果设置的Line Debouncer Time大于触发脉宽这次触发会被直接忽略。所以这一段要分成三类A. 固有开始曝光延迟这是相机架构、传感器、位深、模式决定的。典型是几微秒到几十微秒。B. 人为配置延迟Trigger Delay设多少就几乎等价地增加多少固定延迟Line Debouncer Time设多少也会几乎等价地增加多少固定延迟。C. 触发过载 / 触发缓存带来的“排队误差”海康的Trigger Cache明确说相机最多可以保存并处理3 个触发信号。如果在前一帧流程还没走完时又来了新触发开启缓存和关闭缓存会得到完全不同的结果关闭时后续触发可能被过滤开启时后续触发可能被缓存等前一个处理完再执行。这意味着一旦系统进入过触发状态后续帧的时刻就不再简单等于“外部触发边沿时刻”而变成了“触发进入相机内部排队系统后的出队时刻”。这不是微小 jitter而是离散的阶段性延后。3.4 曝光窗口本身global shutter 与 rolling shutter3.4.1 Global shutterglobal shutter 下所有像素同时开始曝光、同时结束曝光然后再逐行读出。因此多相机硬触发时只要前面的触发链路误差小整帧在光学意义上就是同步的。读出发生在曝光之后不改变“真实拍到”的时刻。3.4.2 Rolling shutterrolling shutter 下各行以tRow的时间偏移逐行开始曝光。第 1 行开始曝光过1 × tRow第 2 行开始再过1 × tRow第 3 行开始直到最后一行。并且读出结束的时间偏移与开始曝光的偏移是同一个tRow体系。这意味着即使两台相机外部触发完全同时rolling shutter 也只保证“第 1 行大致同时开始”不保证整帧同时采样。很多 rolling 机型的tRow给到6–7 µs。这就意味着ROI 高度 1000 行首尾行时间差约6–7 msROI 高度 2048 行首尾行时间差约12.3–14.3 ms这已经远大于硬触发链路前面那几个微秒级误差。也就是说对 rolling shutter 相机多机硬触发误差的主导项经常不是触发线而是行扫描本身。3.4.3Exposure Active/Exposure Start Active的特殊含义海康提供Exposure Start Active和Exposure End Active输出用于把“开始曝光”和“停止曝光”的事件打到外部设备上。在 rolling shutter 相机上Exposure Active高电平会从第一行开始曝光持续到最后一行结束曝光因此它的脉宽会大于单行曝光时间。拿示波器量Exposure Active时一定要知道量到的是整帧曝光窗口不是“某个像素的唯一曝光时刻”。3.5 ROI、OffsetY、位深、长曝光模式引入的附加时序偏差某些机型还要考虑图像 ROI 曝光起始延迟它与OffsetY有关可按额外延迟OffsetY×tRow\text{额外延迟} OffsetY \times tRow额外延迟OffsetY×tRow原因是某些实现里虽然只取 ROI但传感器仍按整片的时序组织曝光/读出。与此同时开始曝光延迟还可能随着位深、长曝光模式等设置变化。这类误差的特点是主要是固定偏差但如果两台相机 ROI 配置不一致哪怕触发完全一样也会出现系统性时差在 rolling shutter 上尤其敏感。3.6 曝光结束到相机开始往电脑发读出与发包启动误差曝光结束以后图不会瞬间出现在网口。中间至少还有两段A. 传感器读出时间Sensor Readout Time这是把图像数据从传感器读出来所需的时间。global shutter 也是曝光结束后逐行读rolling shutter 则本身就是行级错位曝光读出。读出时间和ROI 高度强相关。B. 发包启动延迟Transmission Start Delay这是从“开始从传感器读出”到“开始向主机发数据”的时间。这个时间对 GigE / USB3 相机来说会在帧间变化而且很大程度上取决于主机何时开始请求/接收数据。这说明两件事主机拿到图的时刻天然不稳定哪怕曝光时刻很稳这部分不稳定性已经不是外部触发线能解决的了。3.7 相机网口到主机整帧传输误差对 GigE 相机这一段经常直接上升到毫秒级。海康手册在传输层控制里明确给出GEV Link Speed网口协商速率MbpsGEV SCPS Packet Size每个流包大小默认 payload 是1464 B推荐设到8164 B提高传输性能若包大小大于1500网卡和交换机都必须支持jumbo frameGEV SCPD包间延迟在每个包之间插入延迟有Auto SCPD可自动调节有效带宽由包大小、包间隔、预留带宽、链路速率共同决定。Frame Transmission Time是相机把整帧从内部 buffer 传到主机所需时间对 GigE / USB3相邻帧的传输时间会变化并且部分取决于主机何时调用数据传输。Jumbo Frame巨型帧 是指有效负载超过 IEEE 802.3 以太网标准规定的 1500 字节 MTU最大传输单元 的以太网帧通常整体帧长超过 1518 字节含 14 字节头部 4 字节 CRC 校验。给一个非常贴近工业现场的数量级例子5 MP 图像假设 2448 × 2048Mono8数据量约 (2448 \times 2048 5,013,504) byte约5.0 MB理想化按1 Gbit/s串行化不计协议开销最短也要约40.1 ms如果是 12bit/16bit 格式、带更多开销、没有开 jumbo frame、还加了SCPD实际只会更长。因此GigE 相机的“主机收图时间”通常是 ms 到几十 ms 问题不是 µs 问题。如果两台相机是同一时刻硬触发但同时把大图塞进同一条受限链路曝光可以很同步收图顺序却可能明显错开。3.8 Linux 主机、厂商 SDK、ROS2 驱动主机侧时间误差在 Linux 厂商 SDK ROS2 结构里图像一般会经历网卡收包内核网络栈 / 驱动缓冲厂商 SDK 线程取帧用户态缓冲区拷贝 / 像素格式处理ROS2 消息构造publish()这部分对真实拍摄时刻没有影响但对ROS2 里看到的header.stamp和回调到达时间影响极大。ROS 的sensor_msgs/Image明确规定header.stamp应该是图像采集时刻。但实际驱动未必都做得理想。以 ROS2 的spinnaker_camera_driver为例默认情况下驱动会把 ROSheader.stamp设成图像被 SDK 交付的时刻这种时间戳不够精确而且会随着主机 CPU 负载产生滞后驱动支持使用相机传感器提供的时间戳再估计相机时钟与 ROS 时钟的偏移进行转换。如果驱动拿的是“SDK 回调到图时刻”那ROS2 看到的时间不是曝光时刻而是“图到主机后的某个时刻”。所以在 Linux/ROS2 侧误差通常分两层A. 到达时间误差这是网络、主机负载、线程调度造成的通常比相机内触发误差大得多。B. 时间戳语义误差这是“开发者给 ROS 图像打的时间到底是不是采样时刻”的问题。如果用 host arrival time它可能偏移很大如果用 sensor timestamp / PTP 对齐时钟才更接近真实采样时间。4. 精确时间协议PTP Precision Time ProtocolPTP 解决的是“时间基准同步”硬触发解决的是“开始曝光同步”。两者不是一个层面。PTP 能让多机的 timestamp 可比或者让调度命令更准但它不等于多台相机一定在同一瞬间曝光。在 ROS2 驱动层这个区别也很明显。spinnaker_camera_driver支持use_ieee_1588用 PTP 时间来填header.stamp而专门的spinnaker_synchronized_camera_driver则进一步把同一个同步脉冲触发的图像赋予相同的 header 时间戳。这恰恰说明仅有网络时间同步还不够驱动还得知道“哪些帧是同一个 sync pulse 触发出来的”。5. 误差归纳5.1 ns 级到亚 µs 级这部分通常来自触发分发线长差触发器边沿一致性相机固有 I/O jitter。如果系统做得好这一层通常不是主导误差。5.2 亚 µs 到十几 µs这部分通常来自GPIO / 光耦输入响应差异触发沿选择不当相机内部基础开始曝光延迟的差异。对global shutter 硬同步这部分经常就是“真实同步精度”的主体。5.3 几十 µs 到几百 µs甚至更大这部分通常来自TriggerDelayLineDebouncerTimeROI/OffsetY 导致的附加 start delay触发缓存 / 排队效应。这类误差大多是固定偏差或离散排队延迟不是小 jitter。5.4 ms 到十几 ms甚至几十 ms这部分通常来自rolling shutter 的行时差传感器读出发包启动GigE 整帧传输Linux / SDK / ROS2 主机侧链路。对“主机何时拿到图”来说这部分经常才是主导项。6. 主导误差项场景 Aglobal shutter GPIO 硬触发 独立带宽充足主导项通常是触发分发差异输入响应差异相机内部开始曝光延迟差异这时真实曝光同步有机会做到微秒级甚至更低。但“主机收图同步”仍可能是毫秒级。场景 Brolling shutter 硬触发主导项通常变成tRow × 行号带来的行时差ROI / OffsetY 引入的附加时序也就是说哪怕触发精度做到很好整帧也不是真正同一时刻。对快速运动物体这往往是最大误差源。场景 CGigE 大图 多相机同时发流 Linux/ROS2主导项通常变成传感器读出发包启动传输序列化SDK 到图时间ROS2 打时间戳方式这时如果只看 ROS topic 到达时间很容易误判成“相机没同步”其实可能只是网络和主机没同步。总结1、硬触发真正同步的是“开始曝光事件”不是“电脑收到图事件”。如果讨论“多个相机同一时刻开始拍”应该关注的是触发分发、输入响应、开始曝光延迟、快门类型。2、对 global shutter相机侧误差通常是 µs 级对 rolling shutter整帧内部时差可以轻易上升到 ms 级。rolling shutter 在运动场景下常常是比触发线误差更大的主导项。3、Linux/SDK/ROS2 看到的图像到达时刻通常是“读出 传输 主机处理”后的结果常见是 ms 到几十 ms 问题。所以 ROS2 topic 的先后不足以直接判断真实曝光是否同步。4、PTP/IEEE1588 主要是对齐时间戳基准不替代硬触发。它能让多机 timestamp 更可比但不自动保证多机在同一瞬间曝光。5、在海康这类 GigE 工业相机场景里最需要实测的不是“有没有 TriggerDelay 这种参数”而是输入口真实响应延迟多机之间固定 start offsetrolling shutter 的实际行时差影响主机收图与 ROS2 时间戳语义是否正确因为手册给了参数入口但没有把所有固有时序常数都公开出来。