第三章 传感器数据采集:I2C/SPI/UART通信协议、超声波模块驱动编写、激光雷达点云数据解析、IMU数据滤波

各位同学,欢迎来到第三章。这一章我们聊聊传感器数据采集。说实话,这部分是避障系统的「眼睛」和「耳朵」。数据采不准,后面路径规划再漂亮也是白搭。我见过太多项目,算法调得天花乱坠,结果传感器数据一塌糊涂——飞控直接炸机。

这一章我们聚焦四个核心点:通信协议、超声波驱动、激光雷达点云、IMU滤波。每个点我都会结合项目经验来讲。准备好了吗?我们开始。

3.1 通信协议:I2C、SPI、UART 怎么选?

先问个问题:为什么无人机上要用三种不同的通信协议?

答案很简单——没有一种协议是万能的。我早期做飞控时,总想着「一个协议打天下」,结果发现I2C挂太多设备就卡死,SPI线太长就丢数据,UART速率上不去。后来学乖了,该用哪个用哪个。

3.1.1 I2C:适合短距离、低速、多设备

I2C只有两根线:SCL(时钟)和SDA(数据)。所有设备挂在同一条总线上,靠地址区分。优点是接线少,缺点是速率慢(标准模式100kHz,快速模式400kHz)。

我在项目中遇到过:用I2C挂了三个传感器——气压计、磁力计、温度计。结果发现磁力计和气压计地址冲突了。嗯,I2C设备地址是7位,理论上128个地址,但很多厂家默认地址一样。解决办法?要么换地址引脚,要么加I2C多路复用器。

我的习惯:I2C总线上设备不要超过4个。超过4个,总线电容会变大,信号容易畸变。实在要挂多个,加个TCA9548A多路复用器。

3.1.2 SPI:高速、全双工、点对点

SPI有四根线:MOSI、MISO、SCLK、CS。每个设备一个片选引脚。速率可以跑到几十MHz,适合激光雷达、IMU这类高速传感器。

避坑指南:我曾经在SPI线上接了10cm的杜邦线,结果数据全是乱码。为什么?SPI对信号完整性要求高,长线会导致反射和串扰。后来换成双绞线,问题解决。记住:SPI线长不要超过20cm,最好用屏蔽线。

3.1.3 UART:简单、远距离、异步

UART只需要TX和RX两根线。没有时钟线,靠波特率同步。适合GPS模块、数传电台这类设备。

UART有个坑:波特率必须匹配。我见过有人把GPS设成115200,飞控设成9600,结果数据全是乱码。嗯,这种低级错误我也犯过。

协议 线数 速率 距离 典型设备
I2C 2 100kHz-400kHz 几十厘米 气压计、磁力计
SPI 4+ 10MHz-80MHz 20cm以内 IMU、激光雷达
UART 2 9600-921600bps 几米 GPS、超声波

3.2 超声波模块驱动编写

超声波模块,说白了就是「发个声波,听个回声」。HC-SR04是最常见的,便宜、皮实,但精度一般。

驱动逻辑很简单:

  1. Trig引脚拉高10us,触发发射
  2. Echo引脚等待高电平
  3. 测量高电平持续时间
  4. 距离 = 时间 × 声速 / 2

代码实现(STM32 HAL库):

// 超声波测距函数
float ultrasonic_get_distance(void) {
    uint32_t pulse_time = 0;
    
    // 触发发射
    HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
    delay_us(10);
    HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
    
    // 等待Echo高电平,超时1ms
    uint32_t timeout = 1000;
    while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_RESET) {
        if(timeout-- == 0) return -1.0f;  // 超时返回-1
    }
    
    // 测量高电平宽度
    timeout = 10000;  // 最大测量距离约1.7m
    while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_SET) {
        pulse_time++;
        delay_us(1);
        if(timeout-- == 0) return -1.0f;
    }
    
    // 计算距离(单位:cm)
    float distance = (float)pulse_time * 0.034 / 2.0f;
    return distance;
}
注意:超声波有盲区,通常2cm以内测不准。另外,两个超声波同时工作会互相干扰。我试过在四旋翼上装4个超声波,结果它们互相「吵架」,数据全乱。解决办法:分时触发,或者用不同频率的探头。

3.3 激光雷达点云数据解析

激光雷达比超声波高级多了。它发射激光束,测量反射时间,得到精确的距离值。单线雷达(如RPLIDAR A1)每秒能测几千个点,形成一圈点云。

点云数据通常通过UART或USB传输。数据格式各家不同,但核心思路一致:

  • 每个数据包包含起始标志、角度、距离、信号质量
  • 角度范围0-360度,分辨率通常0.5度或1度
  • 距离单位毫米,有效范围0.15m-12m

解析代码片段(以RPLIDAR为例):

typedef struct {
    float angle;      // 角度(度)
    float distance;   // 距离(毫米)
    uint8_t quality;  // 信号质量(0-255)
} LidarPoint_t;

// 解析一帧数据
int parse_lidar_frame(uint8_t *buffer, int len, LidarPoint_t *points) {
    int point_count = 0;
    int i = 0;
    
    while(i < len - 5) {
        // 查找起始标志 0xFA 0xA5
        if(buffer[i] == 0xFA && buffer[i+1] == 0xA5) {
            // 解析角度和距离(具体格式参考数据手册)
            uint16_t raw_angle = (buffer[i+2] << 8) | buffer[i+3];
            uint16_t raw_dist  = (buffer[i+4] << 8) | buffer[i+5];
            
            points[point_count].angle    = raw_angle / 64.0f;
            points[point_count].distance = raw_dist;
            points[point_count].quality  = buffer[i+6];
            
            point_count++;
            i += 7;  // 跳到下一个数据点
        } else {
            i++;
        }
    }
    return point_count;
}

我踩过的坑:激光雷达在强光下会失效。有一次在正午阳光下测试,雷达直接「瞎了」,距离全报0。后来加了遮光罩,问题解决。另外,雷达旋转时会产生振动,影响IMU数据。建议用橡胶垫减震。

3.4 IMU数据滤波

IMU(惯性测量单元)包含加速度计和陀螺仪。原始数据噪声很大,直接使用会导致飞控震荡。滤波是必须的。

常用的滤波方法:

  • 低通滤波:简单、计算量小,适合加速度计
  • 互补滤波:融合加速度计和陀螺仪,适合姿态估计
  • 卡尔曼滤波:精度高,但计算量大,适合高端飞控

我个人习惯用互补滤波,性价比最高。代码实现:

// 互补滤波,融合加速度计和陀螺仪
void complementary_filter(float acc_angle, float gyro_rate, float dt, float *angle) {
    float alpha = 0.98f;  // 权重系数
    
    // 陀螺仪积分
    float gyro_angle = *angle + gyro_rate * dt;
    
    // 互补融合
    *angle = alpha * gyro_angle + (1.0f - alpha) * acc_angle;
}

alpha值怎么调?我一般从0.98开始试。alpha越大,越信任陀螺仪(动态响应快);alpha越小,越信任加速度计(静态精度高)。

核心要点:IMU滤波不是越复杂越好。对于四旋翼避障,互补滤波完全够用。卡尔曼滤波虽然精度高,但调参麻烦,而且计算量大,会占用MCU资源。你想想看,飞控还要跑路径规划算法,CPU不能全耗在滤波上。

3.5 本章知识体系

下面这张图展示了传感器数据采集的整体流程。从物理层到应用层,每一层都有坑,每一层都要细心。

传感器数据采集知识体系 物理层:通信协议 I2C(低速多设备) SPI(高速点对点) UART(简单远距离) 传感器层:数据采集 超声波(声波测距) 激光雷达(激光点云) IMU(加速度+角速度) 数据处理层:解析与滤波 点云解析(角度/距离提取) 互补滤波(姿态估计) 低通滤波(噪声抑制) 应用层:避障路径规划

从图中可以看到,数据从物理层一路向上,经过传感器采集、数据处理,最终服务于避障路径规划。每一层都有坑,每一层都要细心。

好了,第三章的内容就到这里。传感器数据采集是避障系统的基石,基础打牢了,后面才能飞得稳。下一章我们聊聊路径规划的核心算法——A*和Dijkstra,敬请期待。


公众号:蓝海资料掘金营,微信deep3321