HC-SR04 – популярный ультразвуковой датчик расстояния. Может использоваться для измерения расстояния, определения препятствий для робота, как орган управления устройством и даже для построения карты помещения и наведения на подвижные объекты.
![]() |
В наборе GyverKIT | START | IOT | EXTRA |
---|---|---|---|---|
Дальномер | ✔ | ✔ |
Характеристики:
- Питание: 5V
- Рабочий ток: 15 мА
- Звуковая частота: 40 кГц
- Угол измерения: 15 градусов
- Диапазон измерения: 2 см.. 4 м
- Точность: ~1 мм при грамотной фильтрации
Принцип работы #
Датчик работает довольно интересно: подаём импульс с продолжительностью 10 мкс на пин Trig, модуль посылает ультразвуковой импульс, он отражается от препятствия и детектируется. Затем с пина Echo возвращается импульс по продолжительности соответствующий времени путешествия звуковой волны. Ардуина этот импульс должна измерить.
Подключение к Arduino #
Подключаем к питанию и любым цифровым пинам:
Программирование #
Связанные уроки:
// пины
#define HC_TRIG 3
#define HC_ECHO 2
// сделаем функцию для удобства
float getDist() {
// импульс 10 мкс
digitalWrite(HC_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(HC_TRIG, LOW);
// измеряем время ответного импульса
uint32_t us = pulseIn(HC_ECHO, HIGH);
// считаем расстояние и возвращаем
return (us / 58.2);
}
void setup() {
Serial.begin(115200); // для связи
pinMode(HC_TRIG, OUTPUT); // trig выход
pinMode(HC_ECHO, INPUT); // echo вход
}
void loop() {
float dist = getDist(); // получаем расстояние
Serial.println(dist); // выводим
delay(50);
}
Подвигаю рукой перед датчиком:
Отфильтруем данные при помощи простейшего экспоненциального фильтра:
// пины
#define HC_TRIG 3
#define HC_ECHO 2
float getDist() {
// импульс 10 мкс
digitalWrite(HC_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(HC_TRIG, LOW);
// измеряем время ответного импульса
uint32_t us = pulseIn(HC_ECHO, HIGH);
// считаем расстояние и возвращаем
return (us / 58.3);
}
void setup() {
Serial.begin(115200); // для связи
pinMode(HC_TRIG, OUTPUT); // trig выход
pinMode(HC_ECHO, INPUT); // echo вход
}
float distFilt = 0;
void loop() {
float dist = getDist(); // получаем расстояние
distFilt += (dist - distFilt) * 0.2; // фильтруем
Serial.println(distFilt); // выводим
delay(50);
}
Кстати, опрос датчика при помощи pulseIn()
, не так уж плох: погрешность измерения составляет всего 0.5 мкс:
что в пересчёте на расстояние даёт точность 0.17 мм! На деле точность получается в два раза выше, так как фактически мы измеряем сигнал два раза (путь до препятствия и обратно). Сам датчик шумит гораздо сильнее, поэтому миллиметровую точность получить абсолютно не проблема. Но есть проблема в другом: выполнение кода блокируется на время измерения, например на трёх метрах это будет 17 мс. Вроде и немного, но для некоторых задач это будет весьма критично.
Важный момент: чтобы датчик не ловил "эхо" от самого себя – его не рекомендуется опрашивать чаще 30 мс!
Коррекция скорости звука #
Скорость звука зависит от температуры: при +20°С это 343 м/с, а при -20°С – 318 м/с! А ведь это целых 318/343=7%, что на расстоянии в 1 метр даст погрешность 7 сантиметров. Много, гораздо больше возможных погрешностей в измерении. Давайте это исправим.
В диапазоне -50.. 50°С зависимость является линейной и аппроксимируется уравнением V = 0.609 * t + 330.75
:
Таким образом, для нахождения более точного расстояния с поправкой на температуру достаточно делить время импульса не на 58, а на.. кстати, откуда берётся 58? Для прохождения 1 м звуку понадобится 1 / 343 = 0.0029
с, или 2.915 мс. Мы получаем время туда и обратно, поэтому умножаем ещё на 2. В и для сантиметров – ещё на 10, и получаем 58.3
. Гораздо понятнее было бы умножать время импульса на скорость звука и делить пополам.
Для расчёта расстояния в миллиметрах с учётом температуры в °С получим формулу:
S = us * V / 2000
S = us * (0.609 * t + 330.75) / 2000
S = us * (t * 6 / 10 + 330) / 2000
Настолько высокая точность нам не нужна, поэтому можно избавиться от float
, чтобы код весил меньше (третье уравнение). Погрешность составит не более 1 мм на 1 метр. И финальный пример тогда:
// пины
#define HC_TRIG 3
#define HC_ECHO 2
int getMm(int t) {
// импульс 10 мкс
digitalWrite(HC_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(HC_TRIG, LOW);
// измеряем время ответного импульса
uint32_t us = pulseIn(HC_ECHO, HIGH);
// считаем расстояние и возвращаем
return (us * (t * 6 / 10 + 330) / 2000ul);
}
void setup() {
Serial.begin(115200); // для связи
pinMode(HC_TRIG, OUTPUT); // trig выход
pinMode(HC_ECHO, INPUT); // echo вход
}
void loop() {
int t = 24; // представим, что получили с датчика
int dist = getMm(t); // получаем расстояние в мм
Serial.println(dist); // выводим
delay(50);
}
Библиотеки #
С датчиком можно работать без библиотек, стандартными средствами Arduino. Но есть и библиотеки:
- HC-SR04 – можно установить по названию HC-SR04 из менеджера библиотек (автор Dirk Sarodnick)
- NewPing – можно установить по названию NewPing из менеджера библиотек
NewPing #
Данная библиотека умеет выдавать результат только в целых сантиметрах:
// пины
#define HC_TRIG 3
#define HC_ECHO 2
#include <NewPing.h>
// указываем пины и макс. расстояние в сантиметрах
NewPing sonar(HC_TRIG, HC_ECHO, 100);
void setup() {
Serial.begin(9600); // для связи
}
void loop() {
// получаем и выводим
Serial.println(sonar.ping_cm());
delay(50);
}
Полезные страницы #
- Набор GyverKIT – наш большой стартовый набор Arduino, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])
- Поддержать автора за работу над уроками