HC-SR04 — дешёвый и очень распространённый ультразвуковой дальномер. Его ставят в роботов, автоматические крышки мусорных баков, сигнализацию парковки, бесконтактные дозаторы, измерители уровня воды и проекты, где нужно понять: «что-то передо мной есть?» или «на каком расстоянии находится объект?»
Модуль не умеет видеть цвет и почти не интересуется освещением: ему всё равно, темно в комнате или ярко. Зато он зависит от формы и материала объекта, угла поверхности, температуры воздуха и акустического шума. Это важно: HC-SR04 — не лазерная рулетка. Он хорош для грубой оценки расстояния в понятной геометрии, но не для точного измерения любого предмета в любых условиях.
Что такое HC-SR04
На лицевой стороне модуля находятся две круглые «банки», похожие на глаза:
- один излучатель отправляет ультразвук
- второй принимает отражённый сигнал
Ультразвук — звук с частотой выше диапазона человеческого слуха. HC-SR04 работает на частоте около 40 кГц, поэтому писк модуля мы не слышим. После запуска он посылает восемь периодов колебаний, ждёт отражение и сообщает результат длительностью импульса на выводе Echo.
Паспортные характеристики классического HC-SR04 обычно выглядят так:
| Параметр | Значение |
|---|---|
| Питание | 5 В DC, типично 15 мА |
| Частота ультразвука | 40 кГц |
| Диапазон по паспорту | 2–400 см |
| Заявленная точность | До ±3 мм в хороших условиях |
| Угол измерения | Около 15° |
| Запуск измерения | Импульс HIGH на Trig не менее 10 мкс |
| Выход | Импульс 5 В TTL на Echo, длина пропорциональна расстоянию |
| Интервал между измерениями | Не меньше примерно 60 мс |
Цифры из таблицы — ориентир, а не обещание для любой ситуации. В реальном проекте наиболее стабильная зона обычно заметно уже паспортных 2–400 см. Маленькие, мягкие, наклонные, пористые или неровные предметы отражают звук плохо; поверхность воды, ткань, ковёр и узкая ножка стула могут давать пропуски или скачки.
Как HC-SR04 измеряет расстояние
Рабочий цикл состоит из пяти шагов:
- Контроллер подаёт на
Trigвысокий уровень минимум на 10 мкс. - HC-SR04 отправляет восемь периодов ультразвука частотой 40 кГц.
- Ультразвук летит до объекта.
- Отражённая волна возвращается к приёмнику модуля.
- На
Echoпоявляется HIGH-импульс: его длительность равна времени пути звука туда и обратно.
Скорость звука в воздухе при 20 °C примерно равна 343 м/с, то есть 0,0343 см/мкс. Но звук проходит расстояние дважды, поэтому формула выглядит так:
D = (t · v) / 2
где:
D— расстояние до объектаt— длительность HIGH-импульсаEchoв микросекундахv— скорость звука
Для обычных условий формулу удобно свернуть:
Расстояние (см) ≈ время Echo (мкс) / 58
Например, если Echo держится HIGH 1450 мкс:
1450 / 58 = 25 см
Деление на два уже «спрятано» в числе 58. Если разделить время на 29, получится полный путь звука туда и обратно, то есть расстояние станет вдвое больше правильного.
Где формула начинает врать
Скорость звука зависит прежде всего от температуры воздуха. Приближённая формула:
v = 331,3 + 0,606 · T
где v — скорость в м/с, а T — температура в °C. При 0 °C звук летит около 331 м/с, при 30 °C — около 349 м/с. На дистанции 1–2 метра эта ошибка редко важна для бытового робота, но при измерении уровня или длинного расстояния она уже заметна.
Влажность и давление тоже влияют, но обычно гораздо слабее температуры. Для аккуратного измерителя можно подключить BME280, SHT31, DS18B20 и пересчитывать скорость звука по текущей температуре. Для простой автоматики достаточно константы 0,0343 см/мкс.
Распиновка HC-SR04
Если держать модуль «глазами» к себе, а контактами вниз, у классической версии выводы обычно расположены слева направо так:
VCC | Trig | Echo | GND| Контакт | Назначение | Что подключать |
|---|---|---|
VCC | Питание модуля | 5 В |
Trig | Вход запуска измерения | Любой цифровой выход контроллера |
Echo | Выход длительности эха | Цифровой вход; для ESP32 через делитель уровня |
GND | Общий провод | GND контроллера |
Не путайте Trig и Echo. Если поменять их местами, модуль не сломается, но измерений не будет.
Подключение к Arduino Uno и Nano
Arduino Uno и классический Arduino Nano работают с логическими уровнями 5 В, поэтому HC-SR04 подключается прямо, без дополнительных деталей.
| HC-SR04 | Arduino Uno / Nano |
|---|---|
VCC | 5V |
GND | GND |
Trig | D9 |
Echo | D10 |
Пины D9 и D10 выбраны только для примера. Можно использовать другие свободные цифровые пины, если изменить номера в скетче.
Первый скетч для Arduino
Этот пример запускает измерение раз в 100 мс, ждёт ответ максимум 30 мс и печатает расстояние в Serial Monitor.
constexpr byte TRIG_PIN = 9;
constexpr byte ECHO_PIN = 10;
float readDistanceCm() {
// Гарантируем короткий LOW перед запуском.
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
// Импульс запуска: минимум 10 мкс.
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// 30 000 мкс — тайм-аут примерно для дистанции до 5 м туда-обратно.
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) {
return -1.0; // Эхо не пришло: объект далеко, плохое отражение или ошибка подключения.
}
return duration * 0.0343f / 2.0f;
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
float distance = readDistanceCm();
if (distance < 0) {
Serial.println("Нет эха");
} else {
Serial.print("Расстояние: ");
Serial.print(distance, 1);
Serial.println(" см");
}
delay(100);
}Откройте Tools → Serial Monitor и выберите скорость 115200 бод. Если всё подключено верно, увидите значения вроде:
Расстояние: 37.6 см
Расстояние: 37.4 см
Расстояние: 37.7 смПодключение к ESP32: главное правило про Echo
ESP32 работает с логикой 3,3 В. Классический HC-SR04 питается от 5 В и выдаёт на выводе Echo высокий уровень, близкий к 5 В. Подать эти 5 В непосредственно на GPIO ESP32 нельзя: входы ESP32 не являются 5-вольтовыми tolerant-входами, и такой эксперимент может повредить микроконтроллер.
При этом сигнал Trig можно подать с GPIO ESP32 напрямую: уровень 3,3 В обычно распознаётся входом Trig как логическая единица. А вот Echo нужно понизить до безопасного уровня.
Делитель напряжения для Echo
Самый простой вариант — резистивный делитель:
HC-SR04 Echo ----[ 1 кОм ]----+---- GPIO19 ESP32
|
[ 2 кОм ]
|
GNDПри 5 В на входе такого делителя на GPIO получится:
5 В × 2 кОм / (1 кОм + 2 кОм) ≈ 3,33 В
Это безопасный уровень для ESP32. Номиналы не обязаны быть именно 1 кОм и 2 кОм: подойдут, например, 4,7 кОм + 10 кОм или 10 кОм + 20 кОм. Главное — сохранить отношение нижнего резистора к верхнему примерно 2:1 и не делать цепь слишком высокоомной без необходимости.
Нельзя надеяться на «встроенную защиту» GPIO. Она не предназначена для постоянной подачи 5 В. Делитель стоит копейки и защищает ESP32 от очень неприятной ошибки.
Схема HC-SR04 + ESP32
Ниже — безопасное подключение для ESP32 DevKit.
| HC-SR04 | ESP32 DevKit | Примечание |
|---|---|---|
VCC | 5V / VIN | Классическому HC-SR04 обычно нужно 5 В |
GND | GND | Земля должна быть общей |
Trig | GPIO18 | Можно напрямую |
Echo | GPIO19 через делитель | Нельзя подключать 5 В прямо к GPIO |
HC-SR04 ESP32 DevKit
------- -----------
VCC -------------------------- 5V / VIN
GND -------------------------- GND
Trig -------------------------- GPIO18
Echo ----[1 кОм]----+---------- GPIO19
|
[2 кОм]
|
GND --------------+---------- GND
Для первого проекта выбирайте GPIO, которые не мешают загрузке ESP32. GPIO18 и GPIO19 подходят для большинства DevKit-плат.
Код для ESP32 в Arduino IDE
Создайте новый скетч, выберите свою ESP32-плату в меню Tools → Board, подключите модуль по схеме выше и загрузите код:
constexpr int TRIG_PIN = 18;
constexpr int ECHO_PIN = 19;
float readDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Тайм-аут не даёт зависнуть, если Echo не вернулся.
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) {
return -1.0;
}
return duration * 0.0343f / 2.0f;
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
float distance = readDistanceCm();
if (distance < 0) {
Serial.println("Нет эха: объект вне диапазона или сигнал не отразился");
} else {
Serial.printf("Расстояние: %.1f см\n", distance);
}
// HC-SR04 нужен интервал между циклами; 60 мс — безопасный минимум.
delay(100);
}
Код намеренно использует pulseIn() с тайм-аутом. Без третьего параметра функция может ждать слишком долго, если объект не отражает звук, датчик отключён или провод Echo выпал из макетки. Для простых проектов pulseIn() удобно и достаточно понятно; в роботе с несколькими датчиками, Wi-Fi, дисплеем и другой параллельной логикой лучше перейти на неблокирующее измерение по прерыванию или на отдельную задачу FreeRTOS.
Мини-проект: парковочный индикатор с LED и зуммером
Идея проста: чем ближе препятствие, тем чаще пищит зуммер. Подходит для макета парковочного радара, робота или проверки работы датчика.
Подключение к Arduino
- HC-SR04: как в первой схеме (
TrigD9,EchoD10) - Пьезо-зуммер:
+к D6,−к GND - Светодиод: анод через резистор 220–1000 Ом к D5, катод к GND
constexpr byte TRIG_PIN = 9;
constexpr byte ECHO_PIN = 10;
constexpr byte LED_PIN = 5;
constexpr byte BUZZER_PIN = 6;
float readDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) return -1.0;
return duration * 0.0343f / 2.0f;
}
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
}
void loop() {
float distance = readDistanceCm();
if (distance < 0 || distance > 150) {
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
delay(100);
return;
}
if (distance < 15) {
digitalWrite(LED_PIN, HIGH);
tone(BUZZER_PIN, 2200);
delay(80);
return;
}
digitalWrite(LED_PIN, HIGH);
// Чем ближе объект, тем меньше пауза между короткими сигналами.
int pauseMs = map((int)distance, 15, 150, 100, 900);
pauseMs = constrain(pauseMs, 100, 900);
tone(BUZZER_PIN, 2200, 50);
delay(pauseMs);
}
Не подключайте электромагнитный зуммер, мотор или реле напрямую к пину Arduino/ESP32: для нагрузки с заметным током нужен транзисторный ключ. Почему это важно, разобрано в .
Как сделать показания стабильнее
Один замер HC-SR04 может случайно дать неверный результат. Причины обычные: отражение пришло от края предмета, рядом проехал другой робот с таким же датчиком, человек слегка повернулся, или провод в макетке имеет плохой контакт. Для автоматики лучше фильтровать измерения.
Вариант 1. Среднее из нескольких измерений
Подходит, если помех мало, а объект неподвижен или движется медленно.
float readAverageDistanceCm(byte count = 5) {
float sum = 0;
byte valid = 0;
for (byte i = 0; i < count; i++) {
float value = readDistanceCm();
if (value > 0) {
sum += value;
valid++;
}
delay(60);
}
return valid ? sum / valid : -1.0;
}
Недостаток среднего: один очень плохой выброс заметно тянет результат вверх или вниз.
Вариант 2. Медиана из пяти измерений
Для HC-SR04 обычно лучше медиана: она отбрасывает одиночные скачки. Пример без библиотек:
float readMedianDistanceCm() {
const byte N = 5;
float values[N];
byte valid = 0;
for (byte i = 0; i < N; i++) {
float value = readDistanceCm();
if (value > 0) {
values[valid++] = value;
}
delay(60);
}
if (valid == 0) return -1.0;
for (byte i = 0; i < valid - 1; i++) {
for (byte j = i + 1; j < valid; j++) {
if (values[j] < values[i]) {
float temp = values[i];
values[i] = values[j];
values[j] = temp;
}
}
}
return values[valid / 2];
}
Медиана из пяти значений немного медленнее, зато хорошо переживает один-два случайных неверных импульса.
Несколько HC-SR04 в одном проекте
Два ультразвуковых датчика могут слышать не только своё эхо, но и сигнал соседа. Это называется перекрёстной помехой. Если запустить оба модуля одновременно, один из них может измерить расстояние до объекта, который «увидел» другой, или вообще получить случайную цифру.
Правило простое: запускайте датчики по очереди и выдерживайте минимум 60 мс после каждого измерения. Для двух датчиков это может выглядеть так:
Датчик 1: Trig → ждём Echo → пауза 60 мс
Датчик 2: Trig → ждём Echo → пауза 60 мс
ПовторяемТакже помогает механически разнести датчики, слегка направить их в разные стороны и поставить между ними перегородку из мягкого материала, если конструкция позволяет.
Почему HC-SR04 иногда не подходит
Ультразвук — хороший инструмент, но не универсальный. Рассмотрите другой датчик, если:
- нужно измерять расстояние меньше 2 см
- объект очень маленький, мягкий, тонкий или сильно наклонён
- нужно измерять через стекло, герметичный корпус или воду
- датчик будет работать на улице под дождём и пылью — обычный HC-SR04 не герметичен
- нужен узкий луч, высокая повторяемость или надёжность на чёрных/сложных предметах
- несколько датчиков должны опрашиваться очень быстро
- нужна низкая потребляемая мощность от батареи
В зависимости от задачи подойдут:
| Задача | Что рассмотреть вместо HC-SR04 |
|---|---|
| Компактное оптическое измерение | ToF-датчик VL53L0X / VL53L1X |
| Работа снаружи и измерение уровня | Герметичный ультразвуковой JSN-SR04T |
| Очень близкие расстояния | Инфракрасный ToF или аналоговый Sharp |
| Длинная дистанция и более серьёзная задача | Лидар или промышленный ультразвуковой датчик |
У каждого варианта есть собственные ограничения: ToF может по-разному реагировать на очень тёмные и отражающие поверхности, а герметичные ультразвуковые датчики часто имеют большую слепую зону. Выбор делают по реальной среде, а не только по максимальной дальности из карточки товара.
Частые ошибки и диагностика
Всегда 0 см или Нет эха
Проверьте:
- Питание: классический HC-SR04 ждёт 5 В, а не 3,3 В.
- Общую землю:
GNDмодуля иGNDконтроллера обязательно должны быть соединены. - Порядок проводов:
VCC,Trig,Echo,GND. - Правильность номеров пинов в коде.
- Не перепутаны ли
TrigиEcho. - Не застрял ли провод в соседнем отверстии макетки.
- Есть ли перед датчиком твёрдый объект на расстоянии примерно 20–100 см.
На ESP32 всё работало, а потом перестало
Первое, что нужно проверить, — подключён ли Echo через делитель. Прямые 5 В на GPIO могут повредить вход ESP32. Также проверьте питание модуля: с 3,3 В классический HC-SR04 часто работает нестабильно или не работает вовсе.
Значения прыгают
- Добавьте медианный фильтр или усреднение.
- Увеличьте интервал между запросами до 60–100 мс.
- Уберите датчик от вентилятора, струи воздуха и вибрирующей поверхности.
- Проверьте, что объект достаточно большой и расположен примерно перпендикулярно датчику.
- Укоротите провода и проверьте контакты.
- Если рядом несколько HC-SR04, запускайте их строго по очереди.
Датчик видит стену, но не видит ткань или руку под углом
Это нормальная физика. HC-SR04 ждёт, что отражённый звук вернётся именно к его приёмнику. Мягкая ткань поглощает часть энергии, а наклонная гладкая поверхность отражает звук в сторону — почти как зеркало отражает свет. Поверните датчик или объект, увеличьте площадь цели либо выберите другой принцип измерения.
Показания всегда примерно вдвое больше
В формуле забыли деление на два: Echo измеряет путь до объекта и обратно. Используйте:
cm = duration * 0.0343 / 2;или сокращённый вариант:
cm = duration / 58.0;Скетч периодически зависает
Добавьте тайм-аут в pulseIn():
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);Если Echo не приходит, pulseIn() без тайм-аута блокирует выполнение программы на заметное время. Это особенно неприятно в проектах с кнопками, дисплеем, Wi-Fi или управлением реле.
Практические идеи
- Робот, объезжающий препятствия. HC-SR04 смотрит вперёд; если расстояние меньше порога, робот останавливается и поворачивает.
- Уровень воды в баке. Датчик крепится над водой и измеряет расстояние до поверхности. Высота воды = высота бака − измеренное расстояние. Для влажной среды лучше использовать герметичный датчик.
- Бесконтактная кнопка. Рука подошла ближе 10 см — включаем свет, подаём команду или открываем крышку.
- Парковочный помощник. LED/зуммер меняяют режим, когда объект приближается.
- Контроль заполнения контейнера. Измеряем свободное расстояние от крышки до содержимого.
Что запомнить
- HC-SR04 измеряет время возврата ультразвукового эха и переводит его в расстояние.
- На
Trigподаётся импульс HIGH минимум 10 мкс,Echoвыдаёт импульс, длительность которого измеряет контроллер. - В сантиметрах:
Расстояние = время Echo / 58, потому что звук проходит путь туда и обратно. - Паспортный диапазон — 2–400 см, но реальная дальность зависит от предмета, угла, температуры и окружения.
- Arduino Uno/Nano можно соединять с HC-SR04 напрямую, поскольку оба используют 5-вольтовую логику.
- Для ESP32 классический HC-SR04 питают от 5 В,
Trigподают с GPIO напрямую, аEchoобязательно заводят через делитель до 3,3 В. - Между измерениями выдерживают хотя бы 60 мс, а для устойчивого проекта добавляют тайм-аут и фильтрацию.
Проверь себя
- Почему расстояние считают как
duration / 58, а неduration / 29? - Можно ли соединить
EchoHC-SR04 с GPIO ESP32 одним проводом? - Почему датчик иногда не видит мягкую ткань или гладкую поверхность под углом?
Показать ответы
- Импульс
Echoизмеряет время полного пути звука: от датчика до предмета и обратно. Поэтому деление на 58 уже учитывает обратный путь. - Нет. Классический HC-SR04 выдаёт около 5 В на
Echo, а GPIO ESP32 рассчитаны на 3,3 В. Нужен делитель напряжения или преобразователь уровня. - Ткань поглощает ультразвук, а наклонная гладкая поверхность отражает его в сторону. Поэтому сигнал возвращается слишком слабым или вообще не приходит к приёмнику.