第三节:传感器选型与接口——摄像头、激光雷达、IMU、GPS
好,咱们进入实战环节的第一个硬骨头:传感器选型与接口。说实话,很多做融合的新手,算法写得挺漂亮,结果一接真实传感器,数据死活读不上来。为什么?接口没搞对。
我个人习惯,在项目启动前,先把每个传感器的接口协议、带宽、时序理清楚。这步省了,后面调试能省一半时间。今天咱们就挨个过一遍:摄像头、激光雷达、IMU、GPS。每个我都会讲讲接口选型、实际接线、还有我踩过的坑。
核心原则:接口选型不是越新越好,而是看你的主控能不能扛得住、数据能不能实时传。
3.1 摄像头:USB vs MIPI
摄像头是视觉融合的主力。但接口选错了,帧率直接腰斩。
USB 摄像头
USB 摄像头最大的好处是即插即用。你想想看,一根 USB 线,供电、数据全搞定。我早期做室内机器人时,直接拿个罗技 C920 就上了。但注意,USB 2.0 的带宽只有 480 Mbps,跑 1080p@30fps 勉强够,要是上 4K 或者多路摄像头,就得用 USB 3.0。
实际项目中,我遇到过 USB 线太长导致信号衰减的问题。超过 3 米,建议加个有源延长线或者用 USB 中继器。
// USB 摄像头常用配置(V4L2 接口)
// 设置分辨率 1280x720,帧率 30fps
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 1280;
fmt.fmt.pix.height = 720;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
ioctl(fd, VIDIOC_S_FMT, &fmt);
MIPI 摄像头
MIPI 是嵌入式平台的主流选择。说白了,MIPI 就是为摄像头量身定做的接口,延迟低、带宽高。我做过一个自动驾驶小车,用的就是 OV5640 MIPI 摄像头,直接接到 i.MX6 的 CSI 口上。
但 MIPI 有个麻烦:线序必须严格匹配。我曾经因为排线方向接反,烧了一个摄像头模组。嗯,这里要注意,MIPI 的 CLK 和 DATA 线不能交叉,否则信号根本锁不住。
| 接口类型 | 带宽 | 最大距离 | 适用场景 |
|---|---|---|---|
| USB 2.0 | 480 Mbps | 5 米(无中继) | 原型验证、低分辨率 |
| USB 3.0 | 5 Gbps | 3 米(无中继) | 高清多路摄像头 |
| MIPI CSI-2 | 1 Gbps/lane | 0.3 米(板内) | 嵌入式、低延迟 |
我的建议:如果只是做桌面原型,用 USB 摄像头最省事。如果要做量产产品,MIPI 是更可靠的选择。
3.2 激光雷达:以太网 vs UART
激光雷达的数据量比摄像头小,但精度要求高。接口选型直接影响点云数据的实时性。
以太网接口
现在主流的 16 线、32 线激光雷达,基本都用以太网。为什么?因为点云数据量大,UART 根本扛不住。我记得第一次用 Velodyne VLP-16,一秒钟产生 30 万个点,UART 的 115200 波特率连零头都跑不动。
以太网接口要注意的是:必须配置静态 IP。我见过有人用 DHCP,结果雷达 IP 每次重启都变,程序直接崩了。还有,网线要用屏蔽线,工业现场电磁干扰很严重。
// 激光雷达 UDP 数据接收(简化版)
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(2368); // Velodyne 默认端口
addr.sin_addr.s_addr = inet_addr("192.168.1.201");
bind(sock, (struct sockaddr*)&addr, sizeof(addr));
// 循环接收点云数据包
while(1) {
recvfrom(sock, buffer, 1206, 0, NULL, NULL);
// 解析 12 个数据包,每个包含 32 个点
}
UART 接口
UART 适合单线激光雷达,比如 RPLIDAR A1。数据量小,一根 TX、一根 RX 就能搞定。但注意,UART 没有流控,如果主控处理不过来,数据会丢包。
我曾经在 STM32 上接 RPLIDAR,波特率设到 115200,结果 CPU 中断太频繁,导致其他任务卡死。后来改成 DMA 接收,才解决问题。
避坑指南:UART 的波特率越高,抗干扰能力越差。工业环境建议不超过 115200。如果必须高速,用 RS485 或者 CAN。
3.3 IMU:I2C vs SPI
IMU 是融合的核心,提供加速度和角速度。但接口选错了,数据延迟会让你怀疑人生。
I2C 接口
I2C 的好处是接线简单:SDA、SCL 两根线,还能挂多个设备。我最早用 MPU6050,就是 I2C 接口,Arduino 上直接调库就能用。
但 I2C 有个致命问题:速度慢。标准模式只有 100 kHz,快速模式 400 kHz。如果你要 1 kHz 的 IMU 数据,I2C 的带宽可能不够。我做过一个飞控,I2C 读 IMU 时,CPU 要等 ACK,导致控制周期抖动很大。
SPI 接口
SPI 就快多了,几十 MHz 的时钟,全双工通信。像 ICM-20948 这种高端 IMU,我建议用 SPI。为什么?因为 SPI 没有 I2C 的地址仲裁,数据吞吐量高,延迟低。
但 SPI 的接线多:MOSI、MISO、SCLK、CS。每个设备还要单独一根片选线。我有个项目接了 3 个 IMU,光片选线就占了 3 个 GPIO。
| 接口 | 最大速度 | 接线数 | 适用场景 |
|---|---|---|---|
| I2C | 400 kHz | 2 根 | 低速、多设备 |
| SPI | 50 MHz | 4 根 + 每设备 1 CS | 高速、低延迟 |
我的经验:如果 IMU 数据用于姿态解算,必须用 SPI。I2C 的延迟在 100 Hz 以上时,误差会明显增大。
3.4 GPS:UART 接口
GPS 模块几乎清一色用 UART。为什么?因为 GPS 数据是 NMEA 0183 协议,纯文本,每秒输出一次,数据量很小。
我常用的 GPS 模块是 u-blox NEO-M8N,UART 波特率 9600 或 115200。注意,GPS 的 TX 接主控的 RX,别接反了。我曾经接反过一次,调试了一整天,最后发现是线序问题。
// GPS NMEA 数据解析(伪代码)
// 典型输出:$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
char buffer[256];
uart_read(buffer, sizeof(buffer));
if (strstr(buffer, "$GPGGA")) {
// 解析经纬度、海拔、卫星数
parse_gpgga(buffer, &lat, &lon, &alt);
}
这里有个坑:GPS 的冷启动时间很长,有时要 1 分钟以上。我建议在系统启动时,先给 GPS 模块供电预热,等收到有效定位后再开始融合。
注意:GPS 天线要放在开阔处,金属遮挡会严重影响信号。我有个项目把天线放在金属外壳里,结果定位精度从 2 米掉到 50 米。
知识体系总览
下面这张图,是我自己总结的传感器接口选型逻辑。你照着这个思路走,基本不会错。
说白了,选接口就是三个字:够用就行。别为了炫技上高速接口,结果主控跑不动。也别为了省事用低速接口,结果数据丢包。
好了,这一节的内容就到这儿。下一节咱们开始讲数据同步,那才是融合的真正难点。