Разработка радиолокатора с использованием HC-SR04 и Arduino
С появлением Arduino, идея о системе ультразвукового зрения не покидают многих.
Оказывается, не только подводные лодки и и физики могут использовать ультразвуковые волны в своих корыстных (и не очень) целях. Если раньше вы могли только фантазировать и мечтать о подобном, то сейчас пора откопать ваш Arduino и ультразвуковой датчик расстояния и приняться за создание ультразвукового локатора своими руками! В статье подробно описана конструкция и особенности ультразвукового эхолокатора на Arduino. Отдельное внимание уделено визуализации измерений. Данный материал не является инструкцией по изготовлению подобного эхолокатора (исходников кода не прилагается), но полностью описывает алгоритм разработки механической части и программного обеспечения.
Необходимые компоненты
- Arduino Uno
- Сервомоторы SM-S4303R
- Источник питания 5 В DC
- Модуль HC-SR04 - ультразвуковой датчик расстояния
- Металлический конструктор - для механической части проекта
- Макетная плата и проводники
- Компьютер с USB кабелем для передачи о обработки данных
- Ну и всякая мелочевка...
В проекте использовались сервомоторы SM-S4303R, которые обеспечивают вращение ротора без ограничения угла поворота. Не самый популярный ход, но зато процесс разработки становится гораздо интереснее.
Видео завершенного эхолокатора с использованием ультразвукового датчика расстояния и Arduino приведено ниже:
Теоретическая база
Радар (radar (radio detection and ranging)) работает по принципу излучения и получения коротких импульсов электромагнитной радиации. Он отправляет радиоволну в заданном направлении в пространстве. Когда эта волна достигает объекта, она отражается от объекта и поступает обратно на радар, который отслеживает время, которое прошло с момента генерации импульса. Если знать, с какой скоростью электромагнитный импульс распространяется в той или иной окружающей среде (спойлер: в воздухе скорость составляет около 300,000 км или около 7,5 раз вокруг Земли за одну секунду), можно рассчитать расстояние до преграды, от которой он отразился. Это расстояние составит половину рассчитанного пути волны (так как импульс перемещается от радара к объекту и потом обратно на радар).
Сонар (sonar (sound navigation and ranging)) работает по тому же принципу, что и радар, но использует короткие звуковые импульсы (“pings”). В основном сонары используются на подводных кораблях и субмаринах. Дельфины и летающие мыши используют тот же принцим для обнаружения препятствий.
HC-SR04 - это дешевый ультразвуковой датчик расстояния, который работает по принципу, описанному выше. Он излучает короткие ультразвуковые импульсы и измеряет время, через которое импульс вернется обратно. В зависимости от времени и скорости звука (около 340 метров в секунду) можно рассчитать расстояние до объекта, от которого отразилась ультразвуковая волна.
После получения отраженного импульса, выход сенсора переключается с 0 В (low) на +5 В (high). Выход остается в режиме high, пока приемник (ресивер) не обнаружит первый отраженный сигнал. После этого происходит перезагрузка и устанавливается режим low. Таким образом, время, пока выход находится в состоянии high, равно времени распространени звуковой волны до преграды и обратно.
Давайте взглянем на чудесную улыбку готового радиолокатора. Синяя плата сверху - это ультразвуковой датчик расстояния. Левая часть - это ультразвуковой эмиттер (излучатель ультразвуковых волн), а правая часть - ресивер (приемник ультразвуковых волн).

В даташите нашего ультразвуковой сенсора указано, что угол излучаемой волны составляет около 30°, так что для того, чтобы обнаружить объекты на 360 градусов, нам надо обеспечить его вращение. Для этого нам понадобится вращающаяся платформа с серводвигателем в основании.
Сервы - это двигатели, которые управляются электрическими импульсами. Можно выделить два типа серводвигателей: те, которые вращаются без ограничений и те, у которых ротор перемещается с заранее предусмотренным "шагом". Управлять углом поворота последних можно с помощью подачи электрического импульса определенной длины. Если сервомотор получает на вход импульс, который интерпретируется как поворот на, угол, скажем, 90°, ротор выйдет в позицию 90° и остановится. Серводвигатели, которые вращаются без ограничений могут управляться по скорости вращения и направлению с помощью той же длины импульса.
В принципе, серводвигатель с управлением по углу поворота ротора - более практичный вариант для сканирующего радиолокатора. Вы можете обеспечить поворот выходного вала, например, на 5°, снять показания, передать информацию о расстоянии до объекта на ваш контроллер или персональный компьютер, сделать еще один поворот и так далее... В этом проекте используется серводвигатель с постоянным вращением ротора, которому нельзя передать данные для выхода в конкретное положение без дополнительной обвязки. Один из вариантов - подключить к валу серводвигателя потенциометр и контролировать показания с него. Сопротивление на выходе потенциометра можно преобразовать в угол поворота вала. Но в данном случае реализуется другой вариант: в этом случае контролируется скорость вращения вала двигателя и рассчитывается угол в зависимости от скорости. Конструктивное исполнения самого механизма радиолокатора показана на рисунке ниже:

Красный диск прикреплен к оси, которая обеспечивает вращение ультразвукового датчика расстояния. К диску прикреплена пружина от шариковой ручки. Пружина вращается вместе с диском. Пружина подключена к общей земле. Две тонкие металлические пластины установлены в конечных точках вращения. Каждая пластина одному из двух контактов на Arduino, которые поддерживают работу прерываний. Количество и номера контактов с прерываниями зависят от модели Arduino, которая используется. На Arduino Uno это два пина: пины 2 и 3). Пины на Arduino подключены к контакту + 5 Вольт через подтягивающие резисторы. В результате, фольга и пружина выполняют роль кнопки-переключателя. Когда контакт не замкнут - пружина не прижата к фольге - на контакте Arduino 5 В. Когда появляется контакт, соответствующий пин зазенляется и напряжение на нем падает до 0 В. С использованием attachInterrupt, можно указать функцию, которая будет выполняться, каждый раз при изменении питания на контакте от 5 В до 0 В. В пределах данной конкретной функции прерывания, указана определенная длительность управляющего импульса и сбрасывается счетчик вращения. Счетчик отслеживает микросекунды с момента последней смены направления вращения. То есть, зная скорость вращения, мы можем рассчитать текущее положение.
Для того, чтобы обеспечить стабильное вращение в обоих направлениях, реализован алгоритм калибровки скорости, который отрабатывает каждый раз, когда Arduino перезагружается. Скорость вращения ротора по часовой стрелке указана на уровне программы, скорость вращения в противоположном направлении подстраивается (под скоростью подразумевается длина инмульсов, которые обеспечивают вращение по и против часовой стрелки). Основная задача калибровки - определить длину импульса, которая гарантирует одинаковую скорость вращения в обоих направлениях. При калибровке, Arduino подает команду вращаться вперед и в противоположном направлении на протяжении 20 секунд. На протяжении этого времени, засекается продолжительность вращения и рассчитывается средний период. После 20 секунд калибровки, вращение по и против часовой стрелки сравниваются и подбирается необходимая скорость вращения против часовой стрелки. После этого проводится вторая итерация калибровки - еще 20 секунд отработки указанного алгоритма. Новые итерации будут повторяться, пока разница между периодами не составит меньше 1/10 секунды. Обычно для этого необходимо 3-4 итерации.
Обмен данными с компьютером
Есть очень простой метод обмена данными между Arduono и персональным компьютером через USB кабель. Подключение реализуется по серийному порт, который дает возможность передавать и принимать данные. В нашем случае Arduino передает данные на персональный компьютер, на котором запущена программа для визуализации показаний радиолокации.
Основная часть программы для визуализации данных с сонара написана на языке программирования Scala. На Java написана небольшая часть кода, которая отвечает за обмен данными с Arduino. За основу был взят вот этот пример this code example с официального сайта Arduino. В программе добавлен кольцевой буфер (ссылка на API) для хранения данных, которые получены с Arduino без риска переполнения буфера. В скетче Arduino используется функция serialEvent для обработки поступающих данных. Этот метод гораздо удобнее, чем использовать серийный порт для небольшого пакета данных на каждой итерации цикла loop.
Программа запускает и останавливает работу эхолокатора, посылая строки “CONT” и “STOP” на плату Arduino. Как только Arduino получает строку “CONT”, отсылается управляющий сигнал на серву для начала вращения. Когда серводвигатель работает, Arduino подает команды на ультразвуковой датчик расстояния, который излучает ультразвуковые волны и рассчитывает время до приема отраженной волны. Для снятия показаний с ультразвукового датчика расстояния, использовалась отличная библиотека NewPing library. Процесс измерений можно увидеть на осциллограмме на видео в начале статьи. Для этого обратите внимание на уровни напряжений high и low на выходе сенсора. Каждый раз, когда Arduino получает значение расстояния, контроллер проверяет время, которое прошло с момента последнего изменения направления вращения ротора Arduino двигателя и конвертирует это время в угол поворота. Этот угол характеризует угол поворота эхолокатора в полярной системе координат. После этого угол и расстояние отсылаются на персональный компьютер по серийному порту. Программа на ПК считывает полученную пару данных и помещает их в массив, где также фиксируется текущее время. Благодаря этому можно мы можем в определить и время, когда было произведено измерение. На основании времени, в программе реализован эффект затухания, который характерен для старых аналоговых мониторов на радарах.
Скриншот разработанной программы для эхолокации приведен ниже. Красной линией указывается текущее направление. Старые данные постепенно затухают.

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

Черная точка - это наш ультразвуковой датчик расстояния, зеленая площадь - эго угол обзора при различных углах поворота привода. Синяя звездочка - это объект, который мы никогда не сможем увидеть, так как он во всех случаях находится дальше чем красный треугольник или розовый квадрат.
Подобную проблему можно решить с помощью видеокамеры. При использовании видеокамеры с Arduino вы можете воспользоваться функцией распределения точки (ФРТ) (point spread function). Камеры не идеальны. Всегда есть определенный уровень шума, который зависит от расстояния до объекта. ФРТ - это способ описать эти шумы. Представьте, что вы делаете фотография маленькой черной точки на белом фоне. На рисунке ниже слева показана маленькая черная точка на белом фоне. Справа - фото той же точки, которое сделано камерой с большим уровнем шумов.

Обратите внимание, что очертания точки слева очень четкие. Если же фотография делается плохой камерой, точка будет выглядеть как показано справа. Во-первых, ее размеры кажутся больше, а границы размыты. Можно провести аналогию, что ФРТ - это изображение очень маленькой (меньше чем один пиксель) точки. Используя самую крутую камеру, вы никогда получите изображение, идентичное оригиналу. То есть, шумы будут всегда. Если мы знаем spread function нашей камеры, можно корректировать изображение с помощью метода обратной свертки. Это позволяет получить более четкое изображения после его обработки. Кстати, именно эта методика использовалась первые три года на Hubble Space Telescope’s. Измеряя ФРТ телескопа, астрономы могли корректировать изображения на Земле (через три года были внесены некоторые коррективы в работу телескопа и необходимость в подобной обработке отпала).
К сожалению, подобная методика совершенно неприменима в случае использования ультразвукового датчика расстояния, так как есть концепт под названием суперпозиция. Представьте себе, что вы сделали фотографию двух точек вместо одной.

На фотографии будут две точки. Обе будут немного размыты, но друг от друга они совершенно не зависят. То есть, фотография по сути является фотографией одной точки плюс фотографией второй точки. Другими словами, совмещенное изображение фотографий двух точек называется линейной суперпозицией двух отдельных фотографий.
Если мы теперь взглянем на ультразвуковой датчик расстояния, то поймем, что процесс формирования изображения не может быть описан принципом суперпозиции. Пример выше показал, что "фотографии" голубой звездочки, розового треугольника и розового квадрата не подлежат принципам суперпозиции фотографии трех отдельных объектов. Вместо этого датчик расстояния обнаруживает ближайший объект и игнорирует все остальные. Такую систему невозможно описать с помощью ФРТ и восстановить объекты, которых не хватает, с помощью пост-обработки не получится. То есть, использовать наш ультразвуковой датчик, Arduino и предложенный софт в качестве полноценного 3D сканера в медицине, мы не сможем.
А каким же образом реализуются такие сканеры, ведь они работают по тому же принципу и могут обеспечить формирования полную 2D и 3D модель человеческого тела с точным указанием расположения внутренних органов? Разница в принципе работы сенсора. Медицинский ультразвуковой датчик расстояния посылает короткие ультразвуковые импульсы и ждет их возврата. Но, в отличие от нашего датчика, он не контролирует промежуток времени, через который вернулся первый отраженный сигнал, а фиксирует все отраженные сигналы через на протяжении некоторого периода времени. Каждый принятый импульс является отраженной от определенного органа ультразвуковой волной. Таким образом сканер может построить 3D поверхность всего человеяеского тела. Вторая особенность промышленных 3D сканеров: ультразвуковая волна имеет максимально узкую направленность. То есть, вместо 30° покрытия, эти сенсоры генерируют сфокусированную волну.
Так что улучшать предложенный сонар на Arduino есть куда. Во-первых, не стоит использовать серву с управлением по скорости. Конструкция будет гораздо проще, а следовательно - точнее, если использовать серводвигатель с управлением по углу поворота выходного вала. Во вторых, есть смысл задумать о чем-то вроде фокусирующей линзы на ультразвуковой датчик расстояния. Если волна будет более узкой, вы сможете отследить объекты, сигнал от которых был подавлен другими, находящимися в широком поле зрения нашего сенсора. Кроме того, даташит на наш датчик говорит, что минимальное расстояние до объекта, которое контролируется, составляет 2 сантиметра. Над этим тоже можно подумать.
Ну и конечно же, можно просто использовать другую модель ультразвукового датчика расстояния. Но это уже совсем другой проект и другая история...
Надеемся, эта статья дала вам некоторую теоретическую и практическую базу для разработки собственного ультразвукового сканера на Arduino, а представленные результаты и рекомендации позволят избежать некоторых проблем и в вашем проекте будут учтены все раскрытые недостатки базовой конструкции.
Оставляйте Ваши комментарии, вопросы и делитесь личным опытом ниже. В дискуссии часто рождаются новые идеи и проекты!