超声波测距模块 HC-SR04 进阶应用:精度优化与多传感器融合
为什么你的 HC-SR04 测距不准?
HC-SR04 可能是最便宜的超声波测距模块了,淘宝上 5 块钱包邮。但很多人买回去一测:误差大到怀疑人生。明明目标在 1 米处,读数却在 80cm 到 120cm 之间跳变。
问题不在模块,而在使用方法。今天这篇就来聊聊 HC-SR04 的进阶用法,让你把 5 块钱的模块用出 50 块钱的精度。
硬件清单
| 型号 | 数量 | 单价 | 备注 |
|---|---|---|---|
| HC-SR04 超声波模块 | 2 | ¥5 | 建议买带支架的 |
| Arduino Nano | 1 | ¥15 | 或 ESP32 |
| DS18B20 温度传感器 | 1 | ¥3 | 用于温度补偿 |
| 0.96 寸 OLED 显示屏 | 1 | ¥8 | 可选,用于显示 |
| 杜邦线 | 若干 | ¥5 | 公对母 |
| 总计 | ¥36 | 不含显示屏¥28 |
HC-SR04 工作原理速览
HC-SR04 的工作流程很简单:
-
$1
-
$1
-
$1
-
$1
关键点:声速不是常数,它随温度变化。
声速 (m/s) = 331.4 + 0.606 × 温度 (°C)
20°C 时声速约 343m/s,但 0°C 时只有 331m/s,相差 3.5%。对于 2 米测距,这就是 7cm 的误差。
基础代码:为什么官方示例不够用
先看 Arduino 官方示例代码:
const int trigPin = 9;
const int echoPin = 10;
void setup() {
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = duration * 0.034 / 2;
Serial.print("Distance: ");
Serial.println(distance);
delay(100);
}
这段代码有三个问题:
-
$1
-
$1
-
$1
进阶方案一:温度补偿算法
加上 DS18B20 温度传感器,实时补偿声速:
#include
#include
#define ONE_WIRE_BUS 2
#define TRIG_PIN 9
#define ECHO_PIN 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float getTemperature() {
sensors.requestTemperatures();
return sensors.getTempCByIndex(0);
}
float getSpeedOfSound(float temp) {
return 331.4 + 0.606 * temp; // m/s
}
float measureDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms 超时
if (duration == 0) return -1; // 超时
float temp = getTemperature();
float speed = getSpeedOfSound(temp);
float distance = (duration / 1000000.0) * speed / 2 * 100; // cm
return distance;
}
void setup() {
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
sensors.begin();
}
void loop() {
float distance = measureDistance();
if (distance > 0) {
Serial.printf("Distance: %.2f cm (temp: %.1f°C)\n", distance, getTemperature());
} else {
Serial.println("Out of range");
}
delay(200);
}
加上温度补偿后,2 米范围内的误差可以从±5cm 降低到±1cm。
进阶方案二:中值滤波 + 滑动平均
单次测量容易受环境噪声干扰。更好的做法是连续测量多次,取中值后再做滑动平均:
#define NUM_SAMPLES 5
#define MEDIAN_WINDOW 5
float readings;
int readIndex = 0;
float compareFloats(const void* a, const void* b) {
float fa = *(const float*)a;
float fb = *(const float*)b;
return (fa > fb) - (fa 0 && distances distances) {
turnLeft(150);
delay(500);
} else {
turnRight(150);
delay(500);
}
} else {
moveForward(200);
}
delay(100);
}
void setup() {
Serial.begin(9600);
setupSensors();
setupMotors();
}
void loop() {
avoidObstacle();
}
常见问题排查
问题 1:读数一直为 0 或超小值
可能原因:
-
接线错误(Trig/Echo 接反)
-
供电不足(HC-SR04 需要 5V)
-
触发脉冲宽度不够(必须≥10μs)
解决: 用万用表检查电压,用示波器看 Trig 波形。
问题 2:读数在两个值之间跳变
可能原因:
-
被测物体表面不平整(声波散射)
-
环境噪声干扰
-
没有做滤波处理
解决: 加装中值滤波,或在目标物体上贴一层泡沫吸音。
问题 3:测量距离比实际短
可能原因:
-
没有温度补偿(低温环境)
-
传感器老化
解决: 加上 DS18B20 做温度补偿,或更换新模块。
问题 4:多个传感器互相干扰
可能原因:
-
同时触发多个传感器
-
触发间隔太短
解决: 依次触发,每个间隔至少 50ms。或者给每个传感器加隔音罩。
精度对比测试
| 方案 | 1 米误差 | 2 米误差 | 成本 |
|---|---|---|---|
| 官方示例(无补偿) | ±5cm | ±10cm | ¥5 |
| + 温度补偿 | ±2cm | ±4cm | ¥8 |
| + 中值滤波 | ±1.5cm | ±3cm | ¥8 |
| + 滑动平均 | ±1cm | ±2cm | ¥8 |
花 3 块钱加个温度传感器,精度提升 5 倍。
总结
HC-SR04 虽然便宜,但用对方法也能达到不错的精度。关键三点:
-
$1
-
$1
-
$1
希望这篇博客文章对您有所帮助!