Добавить в избранное

Ультразвуковой дальномер HC-SR04 с Arduino: измерение расстояния

Чтение ≈ 4 мин

HC-SR04 — самый популярный ультразвуковой датчик расстояния для Arduino: схема подключения, pulseIn и пересчёт в сантиметры, фильтрация показаний, радар на серво и ограничения датчика.

Как работает ультразвуковой дальномер

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 см — ближе эхо сливается с импульсом.
Поделиться
Понравился материал?

Комментарии

Добавить комментарий