元器件 · 传感器

HC-SR04 超声波传感器

HC-SR04 是大多数机器人用来测量距离的超声波传感器。本文讲回声测距的原理、它的真实量程和盲区,以及该怎么接线。

它是什么

HC-SR04 是超声波测距传感器——就是那块带两个银色圆柱、看起来像机器人眼睛的小板。它像蝙蝠或潜艇那样测距:发出一串人耳听不见的声音,听回波,计时往返要多久。花几块钱就能让机器人感知到前方的空间,所以它几乎成了每个人做的第一台避障车的默认传感器。

两个圆柱是发射器和接收器。一个负责发声,另一个负责听。板上其余部件全是计时电路,把回波变成单片机能量出来的信号。

HC-SR04 接单片机图:彩色 VCC、Trigger、Echo、GND 线接到传感器四脚;传感器发超声波经物体反射,距离等于回波时间乘声速除二。
Trigger 打脉冲,计时回波往返换算距离——四根线是电源、地、触发、回波。 下载 SVG

工作原理

传感器说简单的双线语言:

  1. Trigger 脚拉 HIGH 10 微秒。
  2. 传感器打出八个 40 kHz 超声脉冲,Echo 脚拉高。
  3. 回波回来 Echo 拉回 LOW。
  4. 量 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 量程。

延伸阅读

参考资料