4、硬件触发同步:硬件触发原理、PWM信号与PPS信号、多传感器硬触发方案设计
各位同行,今天我们来聊聊硬件触发同步。说实话,这是多传感器融合里最「硬核」的一块。软件同步做得再好,到了微秒级精度,还是得靠硬件说话。我自己踩过不少坑,今天把这些经验掰开揉碎讲给你听。
4.1 硬件触发原理:为什么非它不可?
先问个问题:为什么软件同步不够用?
你想想看,Linux 系统里一个线程调度,抖动就有几十微秒。对于激光雷达和相机这种需要微秒级对齐的传感器,这点抖动足以让点云和图像错位。我当年做园区无人车时,就吃过这个亏——软件时间戳对齐后,点云投影到图像上总是有 2-3 个像素的偏移,后来一查,就是系统调度延迟搞的鬼。
硬件触发的核心思路很简单:用一根物理信号线,让所有传感器在同一个时刻开始采集。这根线上传递的,通常是一个脉冲信号。传感器收到脉冲后,立即开始曝光或扫描。
硬件触发 vs 软件触发
- 精度:硬件触发可达纳秒级,软件触发通常毫秒级
- 确定性:硬件触发延迟固定,软件触发受系统负载影响
- 复杂度:硬件触发需要额外布线,软件触发只需代码
说白了,硬件触发就是给传感器们一个「预备——跑!」的指令。这个指令必须足够快、足够准。
4.2 PWM信号与PPS信号:两种常见的「指挥棒」
实际工程中,最常用的两种硬件触发信号是 PWM 和 PPS。它们各有各的脾气,我分别说说。
4.2.1 PPS 信号:秒级节拍器
PPS(Pulse Per Second)就是每秒一个脉冲。GPS 模块、授时服务器都会输出这个信号。它的上升沿代表整秒时刻,精度通常在几十纳秒以内。
我在项目中常用 PPS 来做长期同步。比如一个无人车跑 8 小时,所有传感器的时钟都会漂移。PPS 就像个「纪律委员」,每秒纠正一次。但注意,PPS 只提供秒级对齐,帧率对齐还得靠别的办法。
我的经验:PPS 信号最好用差分信号传输(比如 RS-422),抗干扰能力强。我见过有人用普通杜邦线拉 5 米长,结果信号反射导致误触发,排查了两天才找到原因。
4.2.2 PWM 信号:灵活的帧同步器
PWM(Pulse Width Modulation)信号就灵活多了。你可以调整它的频率和占空比,来匹配不同传感器的帧率。
举个例子:
- 相机需要 30 FPS,那就输出 30 Hz 的 PWM
- 激光雷达需要 10 Hz,那就输出 10 Hz 的 PWM
- IMU 需要 200 Hz,那就输出 200 Hz 的 PWM
每个传感器收到 PWM 的上升沿,就开始采集一帧数据。这样,所有传感器都在同一个「节拍」下工作。
注意:PWM 的占空比也有讲究。有些传感器要求高电平时间大于 1 ms,有些要求小于 500 μs。一定要看 datasheet!我曾经因为占空比设错了,导致某款工业相机一直处于触发状态,拍出来的全是黑图。
下面这张图展示了 PPS 和 PWM 在时间轴上的关系:
4.3 多传感器硬触发方案设计:从理论到实践
好了,原理讲完了,咱们来点实际的。一个典型的自动驾驶系统,可能有 1 个激光雷达、6 个相机、1 个 IMU。怎么让它们步调一致?
我常用的方案是主从触发架构:
- 主设备:通常是工控机或 FPGA,负责产生 PWM 信号
- 从设备:各传感器,接收 PWM 信号并响应
- 信号分配:通过触发信号分配板,将一路 PWM 复制成多路
下面是一个典型的连接方案:
3.3.1 方案设计要点
做硬触发方案时,有几个坑我帮你标出来:
避坑指南
- 信号电平匹配:3.3V 和 5V 的传感器混用时,一定要加电平转换。我曾经直接连,烧坏了一个相机的触发接口。
- 信号完整性:长距离传输用差分信号,短距离用推挽输出。别用开漏输出直接驱动多个负载。
- 触发延迟:不同传感器对触发信号的响应时间不同。LiDAR 可能延迟 10 μs,相机可能延迟 50 μs。这个固定延迟可以在软件里补偿。
3.3.2 代码示例:生成 PWM 信号
这里给一个用 Linux 的 GPIO 生成 PWM 的示例。我习惯用 libgpiod 库,比老的 sysfs 接口稳定得多。
// pwm_trigger.c
// 生成 10 Hz PWM 信号,占空比 50%
// 编译: gcc -o pwm_trigger pwm_trigger.c -lgpiod
#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#define PWM_PIN 17 // GPIO 17
#define FREQ_HZ 10 // 10 Hz
#define PERIOD_US 100000 // 100 ms
#define DUTY_CYCLE 0.5 // 50%
int main() {
struct gpiod_chip *chip;
struct gpiod_line *line;
int ret;
// 打开 GPIO 芯片
chip = gpiod_chip_open_by_number(0);
if (!chip) {
perror("Open chip failed");
return -1;
}
// 获取 GPIO 线
line = gpiod_chip_get_line(chip, PWM_PIN);
if (!line) {
perror("Get line failed");
gpiod_chip_close(chip);
return -1;
}
// 设置为输出
ret = gpiod_line_request_output(line, "pwm_trigger", 0);
if (ret < 0) {
perror("Request output failed");
gpiod_chip_close(chip);
return -1;
}
printf("Generating %d Hz PWM on GPIO %d...\n", FREQ_HZ, PWM_PIN);
// 生成 PWM
while (1) {
// 高电平
gpiod_line_set_value(line, 1);
usleep(PERIOD_US * DUTY_CYCLE);
// 低电平
gpiod_line_set_value(line, 0);
usleep(PERIOD_US * (1 - DUTY_CYCLE));
}
// 清理
gpiod_line_release(line);
gpiod_chip_close(chip);
return 0;
}
我的建议:实际项目中别用软件循环生成 PWM,抖动太大。最好用 FPGA 或 MCU 的硬件定时器来生成。上面这个代码只适合原型验证。
3.3.3 多传感器触发时序设计
不同传感器的帧率不同,怎么安排触发时序?我一般用分时触发策略:
| 传感器 | 帧率 | 触发时刻 (相对 PPS) | 曝光/扫描时间 |
|---|---|---|---|
| LiDAR | 10 Hz | 0 ms, 100 ms, 200 ms... | ~10 ms |
| Camera 1 | 30 Hz | 0 ms, 33 ms, 66 ms... | ~5 ms |
| Camera 2 | 30 Hz | 16 ms, 49 ms, 82 ms... | ~5 ms |
| IMU | 200 Hz | 0 ms, 5 ms, 10 ms... | ~1 ms |
为什么要错开?你想想看,如果 LiDAR 和 Camera 同时触发,LiDAR 的激光脉冲可能会干扰相机的曝光。错开 5-10 ms,就能避免这种干扰。我在做多线激光雷达和全局快门相机同步时,就遇到过这种问题——图像上出现周期性亮斑,后来发现是激光回波串扰。
4.4 小结
硬件触发同步,说白了就是给传感器们一个统一的「起跑线」。PPS 负责秒级对齐,PWM 负责帧级触发。设计时注意信号电平、传输距离和触发延迟,基本就能搞定大部分场景。
嗯,这里要特别提醒:硬件触发不是万能的。它解决了「同时采集」的问题,但没解决「数据时间戳」的问题。传感器收到触发信号后,内部还有处理延迟。这个延迟怎么补偿?我们下一节再聊。
核心要点回顾
- 硬件触发精度可达纳秒级,远优于软件触发
- PPS 提供秒级基准,PWM 提供帧级触发
- 主从架构 + 信号分配板是最实用的方案
- 注意信号电平匹配和传输距离
- 分时触发可避免传感器间干扰
公众号:蓝海资料掘金营,微信deep3321