第三章 超声波传感器详解:工作原理、测距公式、常见型号(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的驱动时序其实很简单,就三步:
- 拉高Trig引脚10μs以上,触发测距
- 等待Echo引脚变高,开始计时
- 等待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 知识体系总览
下面这张图总结了超声波传感器从原理到应用的核心逻辑:
3.7 实际项目中的注意事项
最后聊几个我在项目中踩过的坑:
- 多传感器串扰:如果你在机器人上装了多个超声波模块,它们同时发射会互相干扰。我建议采用分时触发策略,每个模块间隔50ms以上。
- 盲区问题:HC-SR04有2cm左右的盲区,太近的障碍物测不到。解决办法是配合红外传感器或者TOF激光测距模块互补使用。
- 软表面吸收:海绵、布料、毛绒玩具会吸收超声波,导致回波太弱测不到。我遇到过机器人对着沙发靠垫发呆的情况,后来加了红外传感器才解决。
- 安装角度:超声波波束角约15°,安装时稍微向下倾斜5-10°,可以避免打到天花板产生误报。
总结一句话:超声波传感器是机器人避障的「眼睛」,便宜好用但别指望它完美。理解它的脾气秉性,才能用好它。