Как работает ультразвуковой дальномер
HC-SR04 измеряет расстояние эхолокацией: посылает короткий ультразвуковой импульс и слушает отражение. Чем дальше объект — тем дольше возвращается эхо. Точность ±3 мм в диапазоне 2–400 см — за копеечную цену это лучший датчик расстояния для начинающих.
У датчика четыре вывода: VCC (5 В), Trig (вход — запуск импульса), Echo (выход — длительность эха), GND.
Подключение
Arduino 5V ── VCC
Arduino D7 ── TRIG
Arduino D6 ── ECHO (см. про делитель ниже!)
Arduino GND ── GND
Важный нюанс: ECHO выдаёт 5 В. Для Uno это нормально, но для ESP32/ESP8266 (3.3 В логика) нужен делитель напряжения — резисторы 1 кОм + 2 кОм сигнал до 3.3 В, иначе спалите вход ESP.
Код: pulseIn и расчёт
Импульс запускаем 10-микросекундным фронтом на TRIG, длительность эха читаем pulseIn:
const int TRIG = 7;
const int ECHO = 6;
void setup() {
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
Serial.begin(9600);
}
long measureCm() {
// запускаем импульс
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
// длительность эха в мкс
long us = pulseIn(ECHO, HIGH, 30000); // таймаут 30 мс — макс ~5 м
if (us == 0) return -1; // таймаут — объекта нет
return us / 58; // перевод в сантиметры
}
void loop() {
long cm = measureCm();
if (cm < 0) Serial.println("нет эха");
else { Serial.print(cm); Serial.println(" см"); }
delay(100);
}
Магия числа 58: звук проходит 1 см за ~29.15 мкс в одну сторону; эхо идёт туда-обратно — 58.3 мкс на сантиметр пути до объекта. Отсюда cm = us / 58. Для дюймов — us / 148.
Таймаут и ошибки
pulseIn без таймаута виснет до секунды, если эха нет. Всегда задавайте третий аргумент — максимальную длительность в мкс:
- 30 000 мкс ≈ 5 м — предел датчика;
- возврат 0 — таймаут, объект не пойман;
- NaN показаний не бывает, но случайные выбросы — да.
Фильтрация показаний
Ультразвук шумит — показания скачут. Стандартные приёмы:
long medianCm(int n = 5) {
long v[5];
for (int i = 0; i < n; ++i) { v[i] = measureCm(); delay(10); }
// сортировка пузырьком для маленького массива
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n; ++j)
if (v[j] < v[i]) { long t = v[i]; v[i] = v[j]; v[j] = t; }
return v[n / 2]; // медиана — устойчива к выбросам
}
Медиана из 3–5 измерений отсекает единичные выбросы. Скользящее среднее сглаживает, но медленнее реагирует.
Ограничения датчика
- Минимум ~2 см — ближе эхо сливается с излучением.
- Мягкие поверхности (ткань, поролон) поглощают звук — эхо слабое.
- Углы — эхо уходит мимо приёмника, показания больше реальных.
- Узкий луч ~15° — «видит» конусом, не точкой.
- Помехи между датчиками — два HC-SR04 рядом мешают друг другу; опрашивайте по очереди с паузой.
Практический проект: радар на серво
Серво + HC-SR04 = сканирующий радар с выводом в Serial (можно визуализировать в Processing):
#include <Servo.h>
Servo scan;
void setup() {
scan.attach(9);
pinMode(7, OUTPUT); pinMode(6, INPUT);
Serial.begin(9600);
}
void loop() {
for (int a = 15; a <= 165; a += 15) {
scan.write(a);
delay(100); // серво доехало
long cm = measureCm();
Serial.print(a); Serial.print(",");
Serial.println(cm);
}
}
Типичные проблемы
- Всегда 0 или мусор: перепутаны TRIG/ECHO, нет общего GND, нет таймаута.
- ECHO 5В в ESP32: делитель напряжения обязателен.
- Показания пляшут: медиана/усреднение, жёсткая поверхность, убрать мягкие предметы вокруг.
- Первое чтение мусор: пауза 50–100 мс после включения.
- Два датчика бьются: разносить по углам, опрашивать последовательно.
Итог
HC-SR04 — импульс на TRIG, длительность на ECHO, us/58 в сантиметры. Три правила: таймаут у pulseIn, фильтрация через медиану, делитель для 3.3 В плат. С этим датчиком делают парктроник, радар, уровень воды, счётчик посетителей — всё, что измеряется по расстоянию.
Полный скетч с фильтрацией
const int TRIG = 9, ECHO = 10;
long readEcho() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
return pulseIn(ECHO, HIGH, 30000UL); // timeout 30мс
}
void setup() {
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
Serial.begin(9600);
}
void loop() {
long us = readEcho();
float cm = us * 0.0343f / 2;
if (us == 0) Serial.println("нет эха");
else Serial.printf("%.1f см\n", cm);
delay(60); // не чаще 60 мс — иначе эхо путается
}
Медианный фильтр для стабильности
Одиночные выбросы типичны — берите медиану трёх измерений:
float median3() {
float a[3];
for (auto& x : a) { x = readEcho() * 0.0343f / 2; delay(10); }
std::sort(a, a + 3);
return a[1];
}
Проекты с HC-SR04
- Датчик уровня в баке/кормушке — смотрит вниз.
- Сигнализация приближения — пищалка по расстоянию.
- Парктроник — чем ближе, тем чаще звук.
- Открывание двери по жесту руки.
- Робот, объезжающий препятствия (с серво для панорамирования).
HC-SR04 против альтернатив
- HC-SR04 — 2–400 см, ~±3 мм, дёшев, но узкий луч и страдает от мягких поверхностей.
- JSN-SR04T — влагозащищённый, для улицы и воды.
- VL53L0X / VL53L1X (ToF) — лазерный датчик, 4–200 см, I2C, точнее и без выступающего «ушка».
- Sharp GP2Y0A21 — ИК-датчик 10–80 см, аналоговый выход, нет эха — надёжнее на тканях.
Безопасные практики
- Питание от 5 В, не от 3.3 В.
- Echo-пин выдаёт 5 В — для ESP32 (3.3 В логика) нужен делитель 1k+2k.
- Держите питание отдельным от силовых нагрузок — наводки мешают точности.
Полный пример: парктроник
const int TRIG = 9, ECHO = 10, BUZZER = 8;
long readEcho() {
digitalWrite(TRIG, LOW); delayMicroseconds(2);
digitalWrite(TRIG, HIGH); delayMicroseconds(10);
digitalWrite(TRIG, LOW);
return pulseIn(ECHO, HIGH, 30000UL);
}
void loop() {
long us = readEcho();
float cm = us * 0.0343f / 2;
if (cm < 10) tone(BUZZER, 1000, 200); // близко — пищим
else if (cm < 30) tone(BUZZER, 500, 100); // средне — коротко
else if (cm < 100) tone(BUZZER, 200, 50); // далеко — редко
delay(60);
}
HC-SR04 против альтернатив
- JSN-SR04T — влагозащищённый, для улицы.
- VL53L0X — лазерный ToF, 4–200 см, I2C, точнее.
- Sharp GP2Y0A21 — ИК, 10–80 см, аналоговый выход.
- HC-SR04P — 3.3–5 В, для ESP32 без делителя.
Ограничения
- Мягкие поверхности поглощают ультразвук — заниженное расстояние.
- Угол раскрытия ~15° — близкие объекты могут «теряться».
- Минимальная дистанция ~2 см — ближе эхо сливается с импульсом.