Программирование ультразвукового датчика arduino

Ультразвуковой дальномер на Arduino

Так получилось, что в университете я изучаю C/C++. Для души пробую делать небольшие проекты на Python. Я много слышал про платформу Arduino, смотрел видео на YouTube, частенько посещал Arduino Project Hub и вот мне стало интересно самому поэкспериментировать, углубясь в разработку под микроконтроллеры. Купив стартовый набор с самой платой и горстью электронных компонентов и попробовав собрать проекты из обучающей брошюры, понял, что надо двигаться дальше. Продумав саму идею следующей самоделки, отправился на просторы Google и обнаружил, что не могу найти всего, что мне нужно на одном ресурсе. Безусловно, мне несложно было посетить несколько сайтитов и блогов с информацией, но я бы сильно сэкономил время, если бы нашел все в одном месте. Так и появилась эта статья-туториал.

Суть проекта

Мне хотелось сделать дальномер. Во-первых, из-за того, что у меня был ультразвуковой датчик и надо было научиться с ним взаимодействовать. Во-вторых, я хотел выводить всю информацию на OLED-дисплей. В статьях, которые я находил, либо рассказывалось про работу с дисплеем и датчиком по отдельности, либо они являлись частью совершенно другого проекта. Я собрал все необходимое тут и надеюсь, что это сможет как-то помочь другим.

  • Любая плата Arduino (у меня Uno);
  • Ультразвуковой дальномер HC-SR04;
  • OLED-дисплей на 0,96 дюймов;
  • Соединительные провода;
  • Макетная плата.
Читайте также:  Teco sg2 20hr d программирование

Работа с OLED-дисплеем

OLED-дисплей идеально подходит для DIY-устройств. Во-первых, мы имеем достаточно высокое разрешение экрана — 128×64 пикселя. Во-вторых, дисплей работает без модуля подсветки, что обеспечивает низкое потребление энергии. В-третьих, для подключения используется всего четыре разъема — два для питания и два для обмена информацией. Но несмотря на это, у OLED-дисплеев есть и минусы. Со временем пиксели могут тускнеть и перегорать.

Вот таким образом можно подключить дисплей:

Схема подключения

Есть несколько библиотек для работы с OLED-дисплеями, мне больше нравится OLED_I2C. Мне она кажется очень простой и максимально понятной. Следующим образом выведем классический «Hello, world!» на дисплей:

#include // Подключаем библиотеку OLED myOLED(A4, A5, A4); // Определяем пины extern uint8_t SmallFont[]; // Подключаем шрифт void setup() < myOLED.begin(); // Инициализируем дисплей >void loop() < myOLED.clrScr(); // Очищаем буфер дисплея myOLED.setFont(SmallFont); // Инициализируем шрифт myOLED.print("Hello, world!", CENTER, 0); // Выводим текст myOLED.printNumI(123, CENTER, 20); // Выводим целое число myOLED.update(); // Копируем буфер дисплея на дисплей >

Если функции без параметров понятны сразу и не вызывают вопросов, то с функциями вывода на дисплей могут быть вопросы. Давайте сразу с ними разберемся, их существует всего три вида:

  • print(st, x, y) — печать строки на дисплей.
    Параметры:
    st: строка для печати;
    x: координата верхнего левого угла первого символа по горизонтали;
    y: координата верхнего левого угла первого символа по вертикали.
    В качестве координат можно использовать как сами координаты, так и литералы LEFT, CENTER, RIGHT.
  • printNumI(num, x, y, [length, [filler]]) — печать целого числа на дисплей.
    Параметры:
    num: Число для вывода на экран (от -2147483648 до 2147483647);
    x: координата верхнего левого угла первой цифры/знака по горизонтали;
    y: координата верхнего левого угла первой цифры/знака по вертикали;
    length: минимальное количество цифр для отображения на экране;
    filler: Символ для заполнения, чтобы получить минимальную длину. По умолчанию “ “.
    В качестве координат можно использовать как сами координаты, так и литералы LEFT, CENTER, RIGHT.
  • printNumF(num, dec, x, y, [divider, [length, [filler]]]) — печать числа с плавающей точкой на дисплей.
    Параметры:
    num: Число для вывода на экран (от -2147483648 до 2147483647);
    dec: количество цифр после запятой (в дробной части) (допустимые значения 1-5);
    x: координата верхнего левого угла первой цифры/знака по горизонтали;
    y: координата верхнего левого угла первой цифры/знака по вертикали;
    divider: Одиночный символ для использования в качестве десятичной точки. По умолчанию ‘.’;
    length: минимальное количество цифр для отображения на экране;
    filler: Символ для заполнения, чтобы получить минимальную длину.
    По умолчанию “ “.В качестве координат можно использовать как сами координаты, так и литералы LEFT, CENTER, RIGHT.
Читайте также:  Массивы в языке программирования php

Работа с ультразвуковым дальномером

Ультразвуковой датчик расстояния работает по принципу эхолокации — посылает пучок ультразвука и получает его отражение с некоторой задержкой, с помощью которой и можно высчитать расстояние до объекта. Работает датчик от напряжения в 5V на расстоянии от 2 до 400 сантиметров.

Для получения данных с датчика необходимо:

  • Подать на выход Trig импульс длительностью 10 микросекунд;
  • Трансмиттер отправит 8 импульсов с частотой 40 кГц;
  • Когда импульсы отразятся от препятствия и будут приняты ресивером, то на выходе Echo образуется входной сигнал;
  • С помощью формулы данные преобразуются в расстояние. Чтоб получить расстояние в сантиметрах, нам необходимо разделить ширину импульса на 58, для получения расстояния в дюймах — на 148.

Подключить датчик к плате можно следующим образом:

Схема подключения

Финальный проект

Теперь, когда мы разобрались с работой с каждого элемента по отдельности, можно перейти к основному проекту дальномера.

Подключим все элементы к плате следующим образом:

Схема проекта

#include OLED myOLED(A4, A5, A4); extern uint8_t SmallFont[]; // Инициализируем пины int echoPin = 2; int trigPin = 3; void setup() < myOLED.begin(); // Определяем ввод и вывод pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); >void loop() < int duration, cm, inch; // Генерация короткого импульса длительностью 2 микросекунды digitalWrite(trigPin, LOW); delayMicroseconds(2); // В течении 10 микросекунд датчик посылает сигналы в 40 кГц digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Получаем время задержки с выхода Echo duration = pulseIn(echoPin, HIGH); // Находим расстояние в сантиметрах и дюймах cm = duration / 58; inch = duration / 148; // Выводим информацию на дисплей myOLED.clrScr(); myOLED.setFont(SmallFont); myOLED.print("Centimeters:", CENTER, 10); myOLED.printNumI(cm, CENTER, 20); myOLED.print("Inches:", CENTER, 40); myOLED.printNumI(inch, CENTER, 50); myOLED.update(); >

Финальный проект в работе выглядит следующим образом:

Что дальше?

Проект дальномера готов и прекрасно работает, но несмотря на все, он не является идеальным законченным решением. Можно поработать над улучшениями, и сделать следующие:

  • Перенести все на монтажную плату и избавиться от макетки. Тогда получится цельное устройства без торчащих проводов;
  • Перейти на Arduino Nano ради более компактного размера;
  • Добавить автономное питание для работы без кабеля;
  • Изготовить корпус.

Источник

Ультразвуковой дальномер HC-SR04: подключение, схема и примеры работы

Ультразвуковой дальномер рассчитан на определение расстояния до объектов в радиусе четырёх метров.

Работа модуля основана на принципе эхолокации. Модуль посылает ультразвуковой сигнал и принимает его отражение от объекта. Измерив время между отправкой и получением импульса, не сложно вычислить расстояние до препятствия.

Подключение ультразвукового дальномера к Arduino

Модуль подключается четырьмя проводами. Контакты VCC и GND служат для подключения питания, а Trig и Echo — для отправки и приема сигналов дальномера. Подключим их к пинам 10 и 11 соответственно.

Напряжение питания дальномера 5 В. Модуль работает и с платами, напряжение которых 3,3 В — в этом случае подключайте его к пинам группы с P8 по P13. Установите джампер выбора питания V2 на Troyka Shield в положение V2+5V. Пин микроконтроллера, соединённый с пином Echo должен быть толерантен к 5 В. Приведённая схема подходит для подключения дальномера к Iskra JS.

Пример работы

Рассмотрим как работает дальномер.

Для того чтобы инициализировать отправку сигнала дальномером, необходимо подать высокий сигнал длительностью 10 μs на пин Trig .

После получения высокого сигнала длительностью 10 μs на пин Trig , модуль генерирует пучок из восьми сигналов частотой 40 кГц и устанавливает высокий уровень на пине Echo .

Зная продолжительность высокого сигнала на пине Echo можем вычислить расстояние, умножив время, которое потратил звуковой импульс, прежде чем вернулся к модулю, на скорость распространения звука в воздухе (340 м/с).

Функция pulseIn позволяет узнать длительность импульса в μs . Запишем результат работы этой функции в переменную duration.

Теперь вычислим расстояние переведя скорость из м/с в см/мкс:

distance = duration * 340 м/с = duration * 0.034 м/мкс

Преобразуем десятичную дробь в обыкновенную

distance = duration * 1/29 = duration / 29

Принимая во внимание то, что звук преодолел расстояние до объекта и обратно, поделим полученный результат на 2

Оформим в код всё вышесказанное и выведем результат в Serial Monitor

// Укажем, что к каким пинам подключено int trigPin = 10; int echoPin = 11; void setup() { Serial.begin (9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); } void loop() { int duration, distance; // для большей точности установим значение LOW на пине Trig digitalWrite(trigPin, LOW); delayMicroseconds(2); // Теперь установим высокий уровень на пине Trig digitalWrite(trigPin, HIGH); // Подождем 10 μs delayMicroseconds(10); digitalWrite(trigPin, LOW); // Узнаем длительность высокого сигнала на пине Echo duration = pulseIn(echoPin, HIGH); // Рассчитаем расстояние distance = duration / 58; // Выведем значение в Serial Monitor Serial.print(distance); Serial.println(" cm"); delay(100); }

Работа с библиотекой

Количество строк кода можно существенно уменьшить, используя библиотеку для работы с дальномером.

#include #define TRIGGER_PIN 10 #define ECHO_PIN 11 #define MAX_DISTANCE 400 NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); void setup() { Serial.begin(9600); } void loop() { delay(50); Serial.print("Ping: "); Serial.print(sonar.ping_cm()); Serial.println("cm"); }

Работа с Iskra JS

var sonic = require('@amperka/ultrasonic') .connect({trigPin: P10, echoPin: P11}); sonic.ping(function(err, value) { if (err) { console.log('An error occurred:', err); } else { console.log('The distance is:', value, 'millimeters'); } }, 'mm');

Источник

Arduino и датчик расстояния HC-SR04

HC-SR04 – ультразвуковой датчик расстояния. Характеристики:

  • Питание: 5V
  • Рабочий ток: 15 мА
  • Звуковая частота: 40 кГц
  • Угол измерения: 15 градусов
  • Диапазон измерения: 2 см.. 4 м
  • Точность: ~1 мм при грамотной фильтрации

Датчик работает довольно интересно: подаём импульс с продолжительностью 10 мкс на пин Trig, модуль посылает ультразвуковой импульс, он отражается от препятствия и детектируется. Затем с пина Echo возвращается импульс по продолжительности соответствующий времени путешествия звуковой волны. Ардуина этот импульс должна измерить.

Подключение

Подключаем к питанию и любым цифровым пинам:

Библиотеки

С датчиком можно работать без библиотек, стандартными средствами Arduino. Но есть и библиотеки:

  • HC-SR04 – можно установить по названию HC-SR04 из менеджера библиотек (автор Dirk Sarodnick)
  • NewPing – можно установить по названию NewPing из менеджера библиотек

Примеры

Небольшой момент: чтобы датчик не ловил “эхо” от самого себя – его не рекомендуется опрашивать чаще 30 мс!

Для опроса используем встроенные Arduino-функции

// пины #define HC_TRIG 3 #define HC_ECHO 2 void setup() < Serial.begin(9600); // для связи pinMode(HC_TRIG, OUTPUT); // trig выход pinMode(HC_ECHO, INPUT); // echo вход >void loop() < float dist = getDist(); // получаем расстояние Serial.println(dist); // выводим delay(50); >// сделаем функцию для удобства float getDist() < // импульс 10 мкс digitalWrite(HC_TRIG, HIGH); delayMicroseconds(10); digitalWrite(HC_TRIG, LOW); // измеряем время ответного импульса uint32_t us = pulseIn(HC_ECHO, HIGH); // считаем расстояние и возвращаем return (us / 58.2); >

Подвигаю рукой перед датчиком:

Отфильтруем данные при помощи простейшего экспоненциального фильтра

// пины #define HC_TRIG 3 #define HC_ECHO 2 void setup() < Serial.begin(9600); // для связи 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); >// сделаем функцию для удобства float getDist() < // импульс 10 мкс digitalWrite(HC_TRIG, HIGH); delayMicroseconds(10); digitalWrite(HC_TRIG, LOW); // измеряем время ответного импульса uint32_t us = pulseIn(HC_ECHO, HIGH); // считаем расстояние и возвращаем return (us / 58.3); >

Данная библиотека умеет выдавать результат только в целых сантиметрах

// пины #define HC_TRIG 3 #define HC_ECHO 2 #include // указываем пины и макс. расстояние в сантиметрах NewPing sonar(HC_TRIG, HC_ECHO, 100); void setup() < Serial.begin(9600); // для связи >void loop() < // получаем и выводим Serial.println(sonar.ping_cm()); delay(50); >

Кстати, опрос датчика при помощи pulseIn() , не так плох, как про него пишут на форумах: погрешность измерения составляет всего 0.5 мкс:

что в пересчёте на расстояние даёт точность 0.17 мм! На деле точность получается в два раза выше, так как фактически мы измеряем сигнал два раза (путь до препятствия и обратно). Сам датчик шумит гораздо сильнее, поэтому миллиметровую точность получить абсолютно не проблема. Но есть проблема в другом: выполнение кода блокируется на время измерения, например на трёх метрах это будет 17 мс. Вроде и немного, но для некоторых задач это будет весьма критично.

Ещё один момент: скорость звука зависит от температуры: при +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 void setup() < Serial.begin(9600); // для связи pinMode(HC_TRIG, OUTPUT); // trig выход pinMode(HC_ECHO, INPUT); // echo вход >void loop() < int t = 24; // представим, что получили с датчика int dist = getMm(t); // получаем расстояние в мм Serial.println(dist); // выводим delay(50); >// сделаем функцию для удобства 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); >

Отфильтровать – и будет супер!

Домашнее задание

  • Попробовать другие библиотеки для HC-SR04
  • Попробовать разные фильтры из урока на финальном примере

Источник

Оцените статью