元器件 · 传感器
HC-SR04 超声波传感器
HC-SR04 是大多数机器人用来测量距离的超声波传感器。本文讲回声测距的原理、它的真实量程和盲区,以及该怎么接线。
它是什么
HC-SR04 是超声波测距传感器——就是那块带两个银色圆柱、看起来像机器人眼睛的小板。它像蝙蝠或潜艇那样测距:发出一串人耳听不见的声音,听回波,计时往返要多久。花几块钱就能让机器人感知到前方的空间,所以它几乎成了每个人做的第一台避障车的默认传感器。
两个圆柱是发射器和接收器。一个负责发声,另一个负责听。板上其余部件全是计时电路,把回波变成单片机能量出来的信号。
工作原理
传感器说简单的双线语言:
- Trigger 脚拉 HIGH 10 微秒。
- 传感器打出八个 40 kHz 超声脉冲,Echo 脚拉高。
- 回波回来 Echo 拉回 LOW。
- 量 Echo 高了多久。
脉宽就是往返时间。空气声速约 343 m/s,距离 =(回波时间 × 343)/ 2——除二因为声音去又回。大多数 Arduino 代码 pulseIn() 加减算术包了。
读数会随温度轻微漂移(暖空气里声速更快)。对一台躲墙的机器人来说这点误差可以忽略;但要精确测距就很重要,那时你需要做温度补偿。
什么时候用它
机器人需要知道最近的物体大概有多远时,就用 HC-SR04——避障、沿墙走、“别开下桌子”的保险,或者在有东西靠近时触发某个行为。这里宽波束其实是好事:障碍很难被漏掉。
要精确距离、窄波束、快更新看别处。飞行时间传感器用光不用声音,又窄又快毫米级——建图或判断具体间隙更好。
接线与坑
- **Echo 是 5 V 引脚。**在 Arduino Uno 这样的 5 V 板子上没问题。但在 ESP32 这样的 3.3 V 板子上,要给 Echo 加一个分压器,否则有可能烧掉引脚。
- **注意盲区和锥角。**比约 2 cm 更近的东西测不到,而约 15° 的波束意味着传感器报的是锥形区域里最近的东西——旁边一条桌腿就能触发它。
- **柔软和倾斜的目标会骗人。**泡沫、布料,或者以很陡的角度遇到的墙,会把回波散射到接收器收不到的方向,于是传感器读出“很远”或者干脆没有。它在正对着的平整硬表面上表现最好。
- **别轮询太快。**两次读数之间留出约 60 ms,让上一个回波彻底消散;发射太勤,杂散回波就会造成错误读数。对数据流做滤波会有帮助——见驯服传感器噪声。
引脚
| 引脚 | 名 | 方向 | 作用 |
|---|---|---|---|
| 1 | VCC | 进 | 5 V。板子约 15 mA,打脉冲尖峰 |
| 2 | Trig | 进 | 拉 HIGH 10 µs 启动测量 |
| 3 | Echo | 出 | 打出拉高,回来拉低。5 V 输出 |
| 4 | GND | — | 地 |
四脚永远这顺序,模块几乎永远换能器反面朝脚,VCC 在看“眼睛”时左边。
接到 Arduino
| HC-SR04 | Arduino Uno | ESP32 |
|---|---|---|
| VCC | 5 V | 5 V(走 VIN,不走 3.3 V 轨) |
| Trig | 任一数字脚 | 任一 GPIO |
| Echo | 任一数字脚 | 经分压——见下 |
| GND | GND | GND |
3.3 V 问题
Echo 引脚输出满 5 V,而 ESP32 或树莓派的 GPIO 额定只有 3.3 V。把 5 V 灌进去超出了它的绝对最大值,虽然往往一时没事,但确实在损伤引脚。用两个电阻就能解决:
Echo ──┬── 1 kΩ ──┬── to 3.3 V GPIO
│ │
│ 2 kΩ
│ │
└──────────┴── GND
分压 5 V × 2/(1+2) = 3.33 V。任何接近 2:1 的比例都行——1 kΩ 配 2 kΩ,或者 10 kΩ 配 20 kΩ。不要用大于约 20 kΩ 的阻值,否则引脚的输入电容会把边沿拖得足够慢,破坏你正要测量的时序。
距离算术,以及错哪
distance = (echo_microseconds x speed_of_sound) / 2
20 °C 声速 343 m/s,即 0.0343 cm/µs。人人用的常数:回波时间除 58.2 得厘米。
声速随温度,约:
speed (m/s) = 331.3 + 0.606 x temperature_celsius
| 温度 | 声速 | 假设 20 °C 的误差 |
|---|---|---|
| 0 °C | 331 m/s | 读远 3.5% |
| 20 °C | 343 m/s | — |
| 40 °C | 356 m/s | 读近 3.7% |
在 2 m 的距离上,这意味着冬天的车库和温暖的房间之间大约差 7 cm。对避障来说无关紧要。但要测量间隙就得补偿——而且如果机器人上有 MPU-6050 或任何一款 I²C 传感器,你其实已经有一个温度读数了。
能跑的最小代码
const int TRIG = 9, ECHO = 10;
const unsigned long TIMEOUT_US = 25000UL; // ~4.3 m, past the sensor's range
void setup() {
Serial.begin(115200);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
}
// Returns centimetres, or -1 when nothing came back.
float pingCm() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned long us = pulseIn(ECHO, HIGH, TIMEOUT_US);
if (us == 0) return -1.0f; // timeout: no echo, NOT "zero distance"
return us / 58.2f;
}
// Median of three kills the occasional wild reading.
float pingMedianCm() {
float a = pingCm(); delay(60);
float b = pingCm(); delay(60);
float c = pingCm();
if (a > b) { float t = a; a = b; b = t; }
if (b > c) { float t = b; b = c; c = t; }
if (a > b) { float t = a; a = b; b = t; }
return b;
}
void loop() {
float cm = pingMedianCm();
if (cm < 0) Serial.println("no echo");
else Serial.println(cm);
delay(60);
}
这里有三个细节,决定了传感器能用还是不能用:
**超时不是可选项。**没有超时的 pulseIn 会一直阻塞到回波到来,而在柔软或倾斜的表面上,回波永远不会来。机器人会毫无规律地卡住,而原因看上去什么都不像传感器。
**零不是距离。**超时是“没回来”,一般最近的东西很远或看不见——零的反面。当 0 cm 的代码空房间急停。
三取中值能丢掉这类传感器经常出现的单个离谱读数。在空旷环境里,一个假的 20 cm 读数,就足以把机器人拐到墙上。
老实读波束图
规格 15° 听着手电窄束。不是——主瓣半角,实践 1 m 处传感器听约 50 cm 宽的锥。
| 距离 | 锥宽约 |
|---|---|
| 20 cm | 约 10 cm |
| 50 cm | 约 26 cm |
| 1 m | 约 53 cm |
| 2 m | 约 105 cm |
传感器报锥内最近,不说锥内哪。这就是 HC-SR04 发现定位不了的门框,边上桌腿触发停车的原因。
在房间里四处游走时,这是个优点——障碍很难被漏掉。但如果要测量到某个特定目标的距离,这一点就是致命的,你要的是 VL53L0X。
它看不见什么
物理,不是缺陷,绕着设计是活:
| 表面 | 发生什么 | 原因 |
|---|---|---|
| 超约 45° 的墙 | 读远,或没有 | 声音反射到别处,像镜子反光 |
| 垫子帘子泡沫 | 读没有 | 材料吸收脉冲不反射 |
| 很近的物体 | 约 2 cm 以内读不到 | 发射脉冲的余音未消,接收器还处于失聪状态 |
| 细的物体(正侧对着的椅子腿) | 能检测到但位置算错 | 锥角太宽;回波是真的,方位是假的 |
| 附近有另一只 HC-SR04 | 随机出现离谱读数 | 它听到了另一只传感器的脉冲——把两者的触发时间错开 |
只靠超声波测距的机器人,早晚会把窗帘一直推到某个东西让步为止。这正是碰撞开关是整台机器人上最便宜的可靠性保障的原因。
故障排查
| 现象 | 可能原因 | 解决 |
|---|---|---|
| 永远读 0 | 把超时当成了距离 | 返回一个哨兵值,并显式处理“没有回波”这种情况 |
| 机器人随机卡死 | pulseIn 没有超时 |
传入超时值——25000 µs 覆盖全部量程 |
| 读数乱跳 | 轮询快于约 60 ms | 等上一个回波彻底消散 |
| 稳但差几个百分点 | 温度 | 声速公式补偿 |
| 台架好装车跪 | 5 V 轨电机噪声 | 传感器电源去耦;线远离电机线 |
| 两传感器互扰 | 互相听到 | 轮流触发,绝不同时 |
| ESP32 引脚没反应 | 5 V 的 Echo 进了 3.3 V 的 GPIO | 加分压——并检查引脚是否还正常 |
| 检测不在前面的东西 | 15° 锥 | 正常;机械缩可用角或激光传感器 |
HC-SR04 还是 VL53L0X?
| HC-SR04 | VL53L0X | |
|---|---|---|
| 方法 | 40 kHz 声音 | 940 nm 激光飞行时间 |
| 量程 | 2 cm – 4 m | 3 cm – 2 m(最好 4 m) |
| 波束 | 约 15° 半角——宽锥 | 视场约 25°,但实际有效的是个窄点 |
| 更新率 | 约 16 Hz(60 ms 周期) | 最高 50 Hz |
| 看不见 | 软和大角度表面 | 黑哑光镜面、烈日 |
| 接口 | 两脚,不用库 | I²C |
| 价格 | 约$2 | 约$5 |
它们在相反的材料上失效,所以只要了解房间环境,选择就很容易。声呐能看见激光看不见的黑布包箱子;激光能看见声呐看不见的、斜着遇到的玻璃门。在一台必须可靠的机器人上,诚实的答案往往是两个都用——再加一个碰撞开关,应付两个传感器同时失灵的情况。
探索关联图谱
用到它的搭建
包含 HC-SR04 超声波传感器 的项目、学习路线和模拟器。
对比
替代方案
问题
HC-SR04 超声波传感器 常见问题
HC-SR04 超声波传感器是什么?
HC-SR04 是一种低成本的测距传感器,它向物体发出一串超声波,再根据反射回来的回波测出物体有多远——这与蝙蝠和声呐用的是同一个原理。大多数入门机器人都用它来检测和躲避障碍物。
HC-SR04 是怎么工作的?
你向它的 Trigger 引脚发送一个短脉冲。传感器会发出八个 40 kHz 的超声波脉冲,并把 Echo 引脚拉高,直到反射波返回。你测量 Echo 保持高电平的时间;由于声音的传播速度约为 343 m/s,距离就等于这段时间乘以声速,再除以二,因为声音走了一个来回。
HC-SR04 的最大量程是多少?
HC-SR04 的测量范围大约是 2 cm 到 4 m。它在 5 cm 到 2 m 这一段最准确;接近 4 m 上限时读数会变得不可靠,而比约 2 cm 更近的物体落在它的盲区内,无法测量。
HC-SR04 准确可靠吗?
用于避障足够准确——对正对着它的平整坚硬目标,分辨率约为 3 mm。它对付不了柔软或倾斜的表面(这些表面会把回波散射掉),会受温度影响,而且波束很宽,约 15°,所以它感知的是一个锥形区域,而不是一个点。
HC-SR04 怎么接到 Arduino?
VCC 接 5 V,GND 接地,Trigger 接任意一个数字输出引脚,Echo 接一个数字输入引脚。有一点要注意:Echo 输出的是 5 V,所以如果你用的是 ESP32 这样的 3.3 V 板子,读取之前要先用分压器把它降下来。
HC-SR04 和 US-100,哪个更好?
US-100 是它的近亲,带有温度补偿模式,可选串口接口,并能在 3.3–5 V 下工作,因此更准确,在 3.3 V 板子上也更好用。HC-SR04 更便宜,教程也更多。用来学习,HC-SR04 就够了;追求精度的话,US-100 略胜一筹。
怎么检查我的超声波传感器是否正常工作?
把测得的距离打印到串口监视器上,然后让手朝传感器靠近、再远离——读数应该平滑地跟着变化。如果它卡在零或某个最大值上,就检查 Trigger 和 Echo 的接线,确认它有稳定的 5 V 供电,并确保你的超时时间足够长,能覆盖完整的 4 m 量程。
延伸阅读