超声波测距模块 HC-SR04 进阶应用:精度优化与多传感器融合

为什么你的 HC-SR04 测距不准?

HC-SR04 可能是最便宜的超声波测距模块了,淘宝上 5 块钱包邮。但很多人买回去一测:误差大到怀疑人生。明明目标在 1 米处,读数却在 80cm 到 120cm 之间跳变。

问题不在模块,而在使用方法。今天这篇就来聊聊 HC-SR04 的进阶用法,让你把 5 块钱的模块用出 50 块钱的精度。

硬件清单

型号数量单价备注
HC-SR04 超声波模块2¥5建议买带支架的
Arduino Nano1¥15或 ESP32
DS18B20 温度传感器1¥3用于温度补偿
0.96 寸 OLED 显示屏1¥8可选,用于显示
杜邦线若干¥5公对母
总计¥36不含显示屏¥28

HC-SR04 工作原理速览

HC-SR04 的工作流程很简单:

  1. $1

  2. $1

  3. $1

  4. $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

  2. $1

  3. $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

  2. $1

  3. $1

希望这篇博客文章对您有所帮助!