第三章 超声波传感器详解:工作原理、测距公式、常见型号(HC-SR04)、接线与驱动

3.1 超声波测距的基本原理

超声波传感器,说白了就是模仿蝙蝠的声呐系统。它通过发射一束人耳听不到的高频声波(通常40kHz),然后等待这束声波碰到障碍物反弹回来。我们只要记录下从发射到接收的时间差,就能算出距离。

我个人习惯把超声波测距比作「喊山」——你对着山谷喊一声,听到回声的时间越长,说明山离你越远。道理一模一样。

这里有个关键点:超声波在空气中的传播速度受温度影响很大。我在项目中遇到过冬天室外测试,测距误差突然变大,查了半天才发现是没做温度补偿。你想想看,0℃时声速约331m/s,30℃时就变成349m/s了,差了将近5%。

核心公式:

距离 = (声速 × 时间) / 2

其中时间是从发射到接收的总时长,除以2是因为声波走了个来回。

3.2 测距公式与温度补偿

实际工程中,我们用的声速计算公式是这样的:

c = 331.3 × sqrt(1 + T/273.15)

其中T是摄氏温度。嗯,这里要注意,如果你用的是华氏度,记得先转换。

我建议在代码里直接写一个温度补偿函数:

float getSoundSpeed(float temperature) {
    return 331.3 * sqrt(1.0 + temperature / 273.15);
}

float getDistance(float timeUs, float tempC) {
    float speed = getSoundSpeed(tempC);
    // timeUs是微秒,转换成秒
    return (speed * timeUs / 1000000.0) / 2.0;
}

为什么要做温度补偿?我曾经在夏天调试一台户外巡检机器人,正午地表温度接近50℃,没做补偿时测距误差达到了8厘米。对于避障来说,这个误差足以让机器人撞上障碍物。

小技巧:如果不想用温度传感器,也可以取一个折中值343m/s(20℃时的声速),室内环境基本够用。但户外场景强烈建议加装DS18B20这类数字温度传感器。

3.3 常见型号:HC-SR04

HC-SR04是市面上最常见的超声波模块,没有之一。它的参数如下:

参数 数值
工作电压 5V DC
工作电流 15mA
超声波频率 40kHz
测距范围 2cm - 400cm
测距精度 ±3mm(理想条件)
测量角度 约15°(有效锥角)
触发信号 10μs TTL高电平
回响信号 脉宽与距离成正比

为什么HC-SR04这么流行?说白了就是便宜、皮实、资料多。我手头至少有二十个不同批次的HC-SR04,测下来一致性还不错,±3mm的精度对于避障来说绰绰有余。

避坑指南:我曾经遇到过一批HC-SR04,在强光直射下测距值突然跳变。后来发现是模块上的接收探头被阳光干扰了。解决办法很简单——给探头加个遮光罩,或者调整安装角度避免正对阳光。

3.4 接线方式

HC-SR04有四个引脚,接线非常简单:

  • VCC → 5V电源(注意不是3.3V,否则测距会严重缩水)
  • GND → 地线
  • Trig → 触发引脚(接单片机GPIO)
  • Echo → 回响引脚(接单片机GPIO)

这里有个坑:Echo引脚输出的是5V电平,如果你的单片机是3.3V的(比如ESP32、STM32),直接接上去可能会烧引脚。我建议用电阻分压或者电平转换模块。

电平转换方案:

用一个2kΩ电阻串联Echo引脚,再并联一个1kΩ电阻到GND,这样5V就被分压到约1.67V,3.3V单片机可以安全读取。

3.5 驱动时序与代码实现

HC-SR04的驱动时序其实很简单,就三步:

  1. 拉高Trig引脚10μs以上,触发测距
  2. 等待Echo引脚变高,开始计时
  3. 等待Echo引脚变低,停止计时

我写了个标准驱动函数,你可以直接拿去用:

#include <Arduino.h>

#define TRIG_PIN 9
#define ECHO_PIN 10

void setup() {
    pinMode(TRIG_PIN, OUTPUT);
    pinMode(ECHO_PIN, INPUT);
    Serial.begin(115200);
}

float readDistance() {
    // 确保Trig为低电平
    digitalWrite(TRIG_PIN, LOW);
    delayMicroseconds(2);
    
    // 发送10μs高电平触发信号
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);
    
    // 读取回响信号脉宽(单位:微秒)
    long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 超时30ms
    
    if (duration == 0) {
        return -1.0; // 超时或超出量程
    }
    
    // 计算距离(单位:厘米)
    float distance = duration * 0.034 / 2.0;
    return distance;
}

void loop() {
    float dist = readDistance();
    if (dist > 0) {
        Serial.print("距离: ");
        Serial.print(dist);
        Serial.println(" cm");
    } else {
        Serial.println("超出量程或测量失败");
    }
    delay(100);
}

为什么用30ms超时?因为HC-SR04最大测距4米,声波来回一趟大约需要23.5ms,我留了点余量。如果超过30ms还没收到回波,说明要么超出量程,要么障碍物表面吸音太强。

经验之谈:pulseIn()函数在阻塞式编程里没问题,但如果你用RTOS或者需要多任务处理,建议改用外部中断+定时器的方式。我在一个四驱机器人项目里就吃过这个亏——pulseIn阻塞导致其他传感器数据更新不及时。

3.6 知识体系总览

下面这张图总结了超声波传感器从原理到应用的核心逻辑:

超声波传感器知识体系 工作原理 声波发射→反射→接收 测距公式 d = (c × t) / 2 常见型号 HC-SR04 等 接线方式 VCC/GND/Trig/Echo 驱动时序 10μs触发→脉宽测量 代码实现 Arduino/STM32/ESP32 机器人避障应用

3.7 实际项目中的注意事项

最后聊几个我在项目中踩过的坑:

  • 多传感器串扰:如果你在机器人上装了多个超声波模块,它们同时发射会互相干扰。我建议采用分时触发策略,每个模块间隔50ms以上。
  • 盲区问题:HC-SR04有2cm左右的盲区,太近的障碍物测不到。解决办法是配合红外传感器或者TOF激光测距模块互补使用。
  • 软表面吸收:海绵、布料、毛绒玩具会吸收超声波,导致回波太弱测不到。我遇到过机器人对着沙发靠垫发呆的情况,后来加了红外传感器才解决。
  • 安装角度:超声波波束角约15°,安装时稍微向下倾斜5-10°,可以避免打到天花板产生误报。

总结一句话:超声波传感器是机器人避障的「眼睛」,便宜好用但别指望它完美。理解它的脾气秉性,才能用好它。

可可精品资料库