Как сделать лазерный дальномер на ардуино
Перейти к содержимому

Как сделать лазерный дальномер на ардуино

  • автор:

Самодельный фазовый лазерный дальномер

image

В статье я расскажу о том, как я делал лазерный дальномер и о принципе его работы. Сразу отмечу, что конструкция представляет собой макет, и ее нельзя использовать для практического применения. Делалась она только для того, чтобы убедится в том, что фазовый дальномер реально собрать самому.

Теория

Часто приходится встречать мнение, что с помощью лазера расстояние измеряют только путем прямого измерения времени «полета» лазерного импульса от лазера до отражающего объекта и обратно. На самом деле, этот метод (его называют импульсным или времяпролетным, TOF) применяют в основном в тех случаях, когда расстояния до нужного объекта достаточно велики (>100м). Так как скорость света очень велика, то за один импульс лазера достаточно сложно с большой точностью измерить время пролета света, и следовательно, расстояние. Свет проходит 1 метр примерно за 3.3 нс, так что точность измерения времени должна быть наносекундная, хотя точность измерения расстояния при этом все равно будет составлять десятки сантиметров. Для измерения временных интервалов с такой точностью используют ПЛИС и специализированные микросхемы.

image

Однако существуют и другие лазерные методы изменения расстояния, одним из них является фазовый. В этом методе, в отличие от предыдущего, лазер работает постоянно, но его излучение амплитудно модулируется сигналом определенной частоты (обычно это частоты меньше 500МГц). Отмечу, что длина волны лазера при этом остается неизменной (она находится в пределах 500 — 1100 нм).
Отраженное от объекта излучение принимается фотоприемником, и его фаза сравнивается с фазой опорного сигнала — от лазера. Наличие задержки при распространении волны создает сдвиг фаз, который и измеряется дальномером.
Расстояние определяется по формуле:

Где с — скорость света, f — частота модуляции лазера, фи — фазовый сдвиг.
Эта формула справедлива только в том случае, если расстояние до объекта меньше половины длины волны модулирующего сигнала, которая равна с / 2f.
Если частота модуляции равна 10МГц, то измеряемое расстояние может доходить до 15 метров, и при изменении расстояния от 0 до 15 метров разность фаз будет меняться от 0 до 360 градусов. Изменение сдвига фаз на 1 градус в таком случае соответствует перемещению объекта примерно на 4 см.
При превышении этого расстояния возникает неоднозначность — невозможно определить, сколько периодов волны укладывается в измеряемом расстоянии. Для разрешения неоднозначности частоту модуляции лазера переключают, после чего решают получившуюся систему уравнений.
Самый простой случай — использование двух частот, на низкой приблизительно определяют расстояние до объекта (но максимальное расстояние все равно ограничено), на высокой определяют расстояние с нужной точностью — при одинаковой точности измерения фазового сдвига, при использовании высокой частоты точность измерения расстояния будет заметно выше.

Так как существуют относительно простые способы измерять фазовый сдвиг с высокой точностью, то точность измерения расстояния в таких дальномерах может доходить до 0.5 мм. Именно фазовый принцип используется в дальномерах, требующих большой точности измерения — геодезических дальномерах, лазерных рулетках, сканирующих дальномерах, устанавливаемых на роботах.
Однако у метода есть и недостатки — мощность излучения постоянно работающего лазера заметно меньше, чем у импульсного лазера, что не позволяет использовать фазовые дальномеры для измерения больших расстояний. Кроме того, измерение фазы с нужной точностью может занимать определенное время, что ограничивает быстродействие прибора.

Наиболее важный процесс в таком дальномере — это измерение разности фаз сигналов, которая и определяет точность измерения расстояния. Существуют различные способы измерения разности фаз, как аналоговые, так и цифровые. Аналоговые значительно проще, цифровые дают большую точность. При этом цифровыми методами измерить разность фаз высокочастотных сигналов сложнее — временная задержка между сигналами измеряется наносекундами (эта задержка возникает также, как и в импульсном дальномере).

Для того, чтобы упростить задачу, используют гетеродинное преобразование сигналов — сигналы от фотоприемника и лазера по отдельности смешивают с сигналом близкой частоты, который формируется дополнительным генератором — гетеродином. Частоты модулирующего сигнала и гетеродина различаются на килогерцы или единицы мегагерц. Из полученных сигналов при помощи ФНЧ выделяют сигналы разностной частоты.

Пример структурной схемы дальномера с гетеродином. М — генератор сигнала модуляции лазера, Г — гетеродин.

Разность фаз сигналов в таком преобразовании не изменяется. После этого разность фаз полученных низкочастотных сигналов измерить цифровыми методами значительно проще — можно легко оцифровать сигналы низкоскоростным АЦП, или измерить задержку между сигналами (при понижении частоты она заметно увеличивается) при помощи счетчика. Оба метода достаточно просто реализовать на микроконтроллере.

Есть и другой способ измерения разности фаз — цифровое синхронное детектирование. Если частота модулирующего сигнала не сильно велика (меньше 15 МГц), то такой сигнал можно оцифровать высокоскоростным АЦП, синхронизированным с сигналом модуляции лазера. Из теоремы Котельникова следует, что частота дискретизации при этом должна быть в два раза выше частоты модуляции лазера. Однако, так как оцифровывается узкополосный сигнал (кроме частоты модуляции, других сигналов на входе АЦП нет), то можно использовать метод субдискретизации, благодаря которому частоту дискретизации АЦП можно заметно снизить — до единиц мегагерц. Понятно, что аналоговая часть дальномера при этом упрощается.
Более подробно (с всеми нужными формулами) этот метод рассматривается здесь (на английском) и здесь (на русском).
В первой статье указывается, что если частота дискретизации сигнала (fsp) связана с частотой модуляции (fo) следующим соотношением:

где p — целое число, то процесс вычисления фазы значительно упрощается.
Достаточно взять N выборок сигнала X[i], после чего разность фаз можно вычислить по следующим формулам:

Отмечу, что оба вышеуказанных метода часто применяются вместе — низкочастотные сигналы подаются напрямую на АЦП, высокочастотные переносятся в область более низких частот за счет гетеродинного преобразования, и также подаются на АЦП.

Именно второй вариант фазометра, с использованием частоты модуляции 10МГц я и решил реализовать в своем макете дальномера.

Практика

Структурная схема моего дальномера:

Фактически, вся конструкция состоит из 3 частей — отладочной платы с микроконтроллером, усилителя сигнала лазера с самим лазером, и фотоприемника с усилителем и фильтром.
В вышеописанной теории предполагалось, что излучение лазера модулируется синусоидальным сигналом. Сформировать такой сигнал частотой 10Мгц с использованием контроллера непросто, поэтому в своей конструкции я подаю на лазер меандр частотой 10МГц. После усиления сигнала с фотоприемника от полученного сигнала отсекаются лишние гармоники полосовым LC-фильтром, настроенным на частоту 10МГц, в результате чего на выходе фильтра возникает сигнал, очень близкий к синусоидальному.

laser1

Схема аналоговой части (усилителя лазера и приемной части):

Схема была взята из проекта лазерной связи Ronja, описание на русском. В этом проекте как раз реализована передача данных со скоростью 10Mbit, что соответствует выбранной частоте модуляции.
Как видно из схемы — усилитель мощности для лазера простейший, собран на микросхеме 74HC04 (содержит 6 инверторов). Включение микросхемы не совсем корректное, но оно работает. Ток через лазер ограничивается резисторами (тоже не самое лучшее решение). Напряжение питания 5В для усилителя берется с отладочной платы.
Для того, чтобы сигнал с усилителя не наводился на остальную часть схемы, корпус усилителя сделан металлическим, все провода экранированы.
Сам лазер (красного цвета) взят из пишущего DVD-привода, его мощность можно установить достаточно высокой, и он гарантированно будет работать на частоте 10МГц.

Приемник состоит из фотодиода и усилителя, собранного на полевом транзисторе и микросхеме-высокоскоростном усилителе. Так как с увеличением расстояния освещенность фотодиода сильно падает, то усиление должно быть достаточно большим (в этой схеме оно примерно равно 4000). Кроме того, с ростом частоты заметно падает сигнал на выходе фотодиода (сказывается его емкость). Отмечу, что усилитель в данной конструкции — важнейшая и наиболее капризная часть. Как оказалось, его усиления явно не хватает. Изначально я предполагал, что коэффициент усиления можно будет менять (чтобы ослаблять сигнал при его слишком большой величине), используемая схема позволяет это делать, меняя напряжение на втором затворе транзистора. Однако оказалось, что при изменении усиления достаточно сильно изменяется вносимый усилителем сдвиг фаз, что ухудшает точность измерения расстояния, так что пришлось установить коэффициент усиления на максимум, подавая на затвор транзистора напряжение 3В с батарейки.
Приемнику для работы требуется напряжение 12В, так что для его питания приходится использовать отдельный блок питания.
Усилитель очень чувствителен к внешним наводкам, так что он тоже должен быть экранированным. Я взял готовый корпус от нерабочего оптического датчика, и разместил усилитель в нем (белая полоска — фольга для дополнительного экранирования фотодиода):

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

LC-фильтр, используемый в дальномере — взят от приемника. Так как фильтр отсекает постоянную составляющую сигнала, а АЦП отрицательные сигналы не воспринимает, то ее приходится добавлять при помощи резисторного делителя R15, R16. Постоянное напряжение, подаваемое на делитель, берется c отладочной платы (VCC).

Отладочная плата — STM32F4-DISCOVERY. Ее выбрал потому, что для формирования двух достаточно различающихся частот нужен генератор достаточно высокой частоты (PLL STM32F4 может давать частоты больше 100МГц).
В формуле, связывающей частоту модуляции и дискретизации, коэффициент «p» я принял равным 6, так что при частоте модуляции 10МГц частота дискретизации должна быть 1.6МГц.

Для формирования частоты 10МГц используется таймер TIM2, работающий в режиме формирования ШИМ сигнала. При системной частоте 160МГц его период — 16 «тиков».
АЦП получает запросы на запуск от таймера TIM8. Для формирования частоты 1.6МГц его период — 100 «тиков». Все данные от АЦП при помощи DMA сохраняются в массив, размер которого должен быть равен двойке в N степени. Оба таймера, АЦП и DMA запускаются один раз при включении и больше уже не отключаются. Таким образом, так как таймеры тактируются от одного источника, а одному периоду измеряемого сигнала соответствуют четыре выборки данных, получается, что в массив всегда попадет целое число периодов сигнала.
Так как останавливать DMA не желательно (это упрощает управление захватом данных), при заполнении первой половины массива генерируется прерывание. Обнаружив, что половина массива заполнена, контроллер копирует ее содержимое в другой массив (в целях упрощения программы вторая половина основного массива при этом не используется). После этого полученные данные обрабатываются — вычисляется средняя амплитуда и фаза сигнала, проводится пересчет фазового сдвига в расстояние.
Полученные величины выводятся на ЖК индикатор от кассового аппарата, также подключенный к отладочной плате.

Дальномер должен знать где находится начало отсчета. Для его калибровки при включении на «нулевом» расстоянии от дальномера устанавливается объект, после чего на отладочной плате нужно нажать кнопку, при этом измеренное значение дальности записывается в память, после чего это значение будет вычитаться из измеренной дальномером дальности.

Как я уже отмечал выше, реализовать автоматическое управление усилением не удалось. При этом изменение амплитуды принятого сигнала приводит к изменению фазовых сдвигов в усилителе, и следовательно, к дополнительным ошибкам.
Поэтому мне пришлось регулировать освещенность фотодиода при помощи механической заслонки, поворачиваемой сервоприводом — при слишком большой освещенности заслонка перекрывает световой поток. ШИМ сигнал для управления приводом формируется таймером TIM3.

Про оптику. Без нее дальномер невозможен. Ее конструкция хорошо видна на фотографиях ниже. Лазер находится внутри пластиковой трубки, установленной вертикально. В нее вставлена небольшая втулка с зеркальной призмой. Втулку можно поворачивать, поднимать и опускать, перемещая таким образом луч лазера. Так как я догадывался, что усиления не хватит, то для приема сигнала использовал крупную линзу Френеля.
Так так лазер, линза и фотодиод установлены соосно, то на близких расстояниях лазер закрывает от фотодиода собственный луч. Для компенсации этого эффекта я установил вторую линзу (лупа с оправой), хотя полностью эффект не устраняется, поэтому максимальный сигнал наблюдается на расстоянии примерно 50-70 см от лазера.

А вот и фотографии получившейся конструкции:

На индикаторе первое число — амплитуда в единицах АЦП, второе число — расстояние в сантиметрах от края доски.

Видео работы дальномера:

Дальность работы у получившегося дальномера вышла достаточно небольшая: 1,5-2 м в зависимости от коэффициента отражения объекта.
Для того, чтобы увеличить дальность, можно использовать специальный отражатель, на который нужно будет направлять луч лазера.
Для экспериментов я сделал линзовый отражатель, состоящий из линзы, в фокусе которой расположена матовая бумага. Такая конструкция отражает свет в ту же точку, откуда он был выпущен, правда, диаметр луча при этом увеличивается.
Фотография отражателя:

Использование отражателя:

Как видно, расстояние до отражателя — 6.4 метра (в реальности было примерно 6.3). Сигнал при этом возрастает настолько, что его приходится ослаблять, направляя луч лазера на край отражателя.

Точность получившегося дальномера — 1-2 сантиметра, что соответствует точности измерения сдвига фаз — 0,2-0,5 градуса. При этом, для достижения такой точности, данные приходится слишком долго усреднять — на одно измерение уходит 0.5 сек. Возможно, это связано с использованием PLL для формирования сигналов — у него довольно большой джиттер. Хотя я считаю, что для самодельного макета, аналоговая часть которого сделана довольно коряво, в котором присутствуют достаточно длинные провода, даже такая точность — довольно неплохо.
Отмечу, что я не смог найти в Интернете ни одного существующего проекта фазового дальномера (хотя бы со схемой конструкции), что и послужило причиной написать эту статью.

UPD: Моя статья про реверс-инжиниринг лазерной рулетки, которая тоже использует фазовый метод измерения расстояния: habr.com/ru/articles/327642

  • лазерный дальномер
  • stm32
  • stm32f4discovery
  • Программирование микроконтроллеров
  • DIY или Сделай сам
  • Электроника для начинающих

Как сделать лазерный дальномер на ардуино

Загрузка и конфигурирование микросхемы CH341 с ПЗУ 24C01Как подключить пьезоизлучатель (пьезопищалку) к ArduinoКак отключить создание файла plot.log в AutoCADКак отключить ввод пароля при входе в Windows 10Как установить среду разработки Quartus IIЧто такое ШИМ и как она используется в ArduinoКак разобрать ноутбук Sony Vaio SVT1111M1RSКак запрограммировать Arduino Pro Mini с помощью программатораКак подключить к Arduino преобразователь логического уровня сигналаЧтение и запись флеш-памяти с помощью Arduino на примере микросхемы 25L8005WPF: Как использовать свойство объекта в качестве параметра конвертера IValueConverter.ConverterParameter

Полезные советы

Print Friendly, PDF & Email

Заметка совершенно не по теме блога, но всё же напишу. Я люблю русский язык, и мне больно смотреть на то, как люди в последние годы становятся всё менее грамотными и всё проще относятся к наследию наших предков – великому русскому языку. В частности, многие совершенно безобразно путают, как правильно писать ТСЯ и ТЬСЯ в глаголах. Они помнят, что когда-то в школе им рассказывали, что в некоторых случаях ТЬСЯ пишется с мягким знаком, и теперь вставляют его везде, где нужно и не нужно. Из-за этого порой получаются слова, которых и вовсе не существует в русском языке (например, «перемещаеться»). Но давайте ближе к делу. Очень легко запомнить, в каком случае в глаголе следует писать «тся», а в каком «ться». Существует такое простое мнемоническое правило. Задаём вопрос к глаголу – «что делает?» или «что делать?». Если подходит первый вариант – «что делает?» – значит, «тся» пишется без мягкого знака (обратите внимание: в вопросе также нет мягкого знака). Если подходит форма вопроса «что делать?» (с мягким знаком), значит и в глаголе пишем мягкий знак: «ться». Рассмотрим пример.

Дальномер своими руками на Arduino

Ультразвуковой дальномер с дисплеем на базе платформы Arduino.

  • Используется дисплей на драйвере TM74HC59, что позволяет выводить расстояние с десятичной точкой
  • Для определения расстояния используется дешёвый модуль ультразвукового дальномера
  • Показания с дальномера фильтруются двумя фильтрами, благодаря чему достигнута точность ~1 мм
  • Отдельный переключатель позволяет сдвигать начало отсчёта на противоположный конец корпуса
  • Работает от 3х батареек формата АА

ВИДЕО

КОМПОНЕНТЫ

Каталоги ссылок на Алиэкспресс на этом сайте:

  • Всё для пайки: паяльники, приспособления
  • Платы Ардуино, модули и датчики
  • Модули и датчики для умного дома
  • Дешёвые инструменты
  • Аккумуляторы, платы защиты, зарядники
  • Мультиметры
  • Блоки питания, преобразователи

Стараюсь оставлять ссылки только на проверенные крупные магазины, из которых заказываю сам. Также по первые ссылки ведут по возможности на минимальное количество магазинов, чтобы минимально платить за доставку. Если какие-то ссылки не работают, можно поискать аналогичную железку в каталоге Ардуино модулей . Также проект можно попробовать собрать из компонентов моего набора GyverKIT .

  • Arduino Nano купить в РФ, aliexpress, aliexpress, искать
  • Дисплей https://ali.ski/Xxo85https://ali.ski/0P7fL
  • Сонар https://ali.ski/X5RYzRhttps://ali.ski/oMN83a
  • Батарейный отсек АА aliexpress, aliexpress, искать
  • Корпус aliexpress, aliexpress, искать
  • Выключатели https://ali.ski/O7OmLc
  • Монтажный провод aliexpress, aliexpress, искать
  • Всё для пайки https://alexgyver.ru/all-for-soldering/

Самодельный лидар на Arduino и VL53L0X TOF-дальномере

В этом проекте мы сделаем свой лидар. По характеристикам он конечно немного не дотягивает до коммерчески выпускаемых лидаров, но вполне подойдёт для небольшого простого робота, чтобы он мог обнаруживать и избегать препятствия на своём пути или более-менее точно строить карту помещения.

Я объясню вам, что такое лидар, принципы его работы и один из вариантов, как его можно сделать на Arduino и времяпролётном (TOF) инфракрасном датчике расстояния.

Корпус лидара можно сделать по-разному, но для данного проекта разработал я выбрал один из самых простых и удобных вариантов его изготовления — напечатал на 3D-принтере. Корпус сделан так, чтобы верхняя часть, в которой установлен дальномер, мог вращаться на 360 градусов без остановки. Чтобы верхняя часть не болталась и могла легко вращаться, в основании большого размера установлен подшипник.

Лидар (LIDAR, Light Detection and Ranging — «обнаружение и определение дальности с помощью света») — технология получения и обработки информации об удалённых объектах с помощью активных оптических систем, использующих явления поглощения и рассеяния света в оптически прозрачных средах. Лидар как прибор представляет собой, как минимум, активный дальномер оптического диапазона. Есть несколько типов лидаров, один из них – это сканирующие лидары, с помощью которых формируют двумерную или трёхмерную картину окружающего пространства. В данном случае с помощью нашего лидара можно получать информацию о расстояниях в двумерном пространстве, т.е. на плоскости.

VL53L0X – это миниатюрный высокоточный лазерный дальномер, обеспечивающий измерение расстояния до 2 м. Для измерения расстояния используется метод измерения времени (TOF, Time-of-Flight). TOF-дальномеры ещё называют время пролётными дальномерами. В датчике установлен миниатюрный лазер и фоточувствительная матрица диодов. Лазер короткими импульсами испускает свет, который отражаясь от препятствий попадает обратно и регистрируется на фоточувствительной матрице. Датчик измеряет время, за которое свет прошёл путь от излучателя до препятствия и обратно до датчика и на основе этого вычисляет расстояние до препятствия.

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

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

Существует несколько способов, как определять текущий угол поворота.

Очень часто используется следующий метод. Используя коллекторный мотор, маленький магнит и датчик холла, можно раскрутить мотор до нужной скорости и затем по датчику холла определять момент, когда при вращении магнит окажется возле датчика холла.

В момент, когда магнит приблизился к датчику холла, в программе переменной «угол» присваивается значение 0. Мотор постоянно вращает датчик, периодически производятся измерения расстояний до препятствий и текущий угол поворота датчика.

Текущий угол поворота вычислить не сложно. В программе можно получить информацию о том, сколько тактов прошло с момента включения микроконтроллера. Если, к примеру, Arduino работает на частоте 16Мгц, в секунду таких тактов будет 16 миллионов, т.е. каждый такт это 1/16 000 000 секунды. Этого более чем достаточно для точного измерения времени при реализации такого лидара. Можно использовать и не системный таймер-счётчик, считающий такты микроконтроллера, принцип будет такой же.

После каждого измерения расстояния вычисляется, сколько тактов прошло с последнего измерения (прошло = текущее – предыдущее). Скорость вращения постоянна и известна (за сколько тактов таймер-счётчика делается один оборот), время, прошедшее с последнего измерения тоже. На основе этих данных и вычисляется текущий угол поворота.

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

В данном лидаре используется другой способ. Он очень прост в реализации и в некоторых случаях очень удобен. Для его реализации нужен шаговый мотор, маленький магнит и датчик холла.

Шаговый мотор в отличие от коллекторного вращается не постоянно, а проворачивается на небольшой фиксированный угол (который ещё называют «шаг», от сюда и название «шаговый мотор»), после чего вал мотора удерживается в текущем положении до тех пор, пока драйверу мотора не поступит команда опять провернуть вал в нужную сторону.

Магнит и датчик холла используется аналогично первому методу – когда магнит приблизился к датчику холла, в программе переменной «угол» присваивается значение 0. После каждой команды провернуть вал в ту или иную сторону, значение некоторой переменной изменяется в большую или в меньшую сторону (в зависимости от направления поворота), на некоторое значение.

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

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

В loop цикле программы сначала делается два шага, производится измерение расстояния и затем к переменной «угол» прибавляется 2.4 (градуса). 2.4 градуса на два шага это с шага используемого шагового мотора и придаточного числа редуктора.

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

После того, как мотор провернёт вал, он будет оставаться в этом положении столько, сколько нужно и в коде можно сколь угодно долго делать что-то до следующей команды драйверу мотора провернуть вал. В случае использования коллекторного мотора, он ждать не будет и продолжит вращать датчик.

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

Если нам нужно измерять расстояния только в определённом направлении, допустим в направлении 0° или 45°, мы может провернуть датчик на нужный угол и затем производить измерения расстояния в этом направлении столь угодно долго.

Если нужно сканировать некоторый сектор, допустим в пределах 200-250°, можно не постоянно вращать на 360градусов, а поворачивать датчик сначала влево, затем вправо в нужных нам пределах.

Используемые компоненты

Список деталей:

1 х Arduino NANO
1 х Модуль с датчиком VL53L0X
1 х Повышающий преобразователь
1 х Шаговый мотор
1 х Драйвер шагового мотора на микросхеме A4988
1 х Скользящие контакты (slip ring) на 6 проводов. Диаметр 12.5мм, длина 15мм или меньше
1 х 6710ZZ подшипник
1 х Датчик Холла 49E
1 х Макетная плата
1 х 100 мкФ электролитический конденсатор
1 х 5 мм х 1 мм неодимовый магнит

Так же понадобиться резистор на 10К, немного M3 винтов, гаек, вставных гаек (резьбовые вставки, insert nuts), «пасик» и напечатанный на 3D-принтере корпус, припой и паяльник.

3D-файлы для печати можно скачать по следующей ссылке . Для печати использовался PLA пластик. Вместо стального подшипника можно использовать напечатанный (стальные шарики продаются пакетами, к примеру, как запасные для линейных направляющих). Модель для печати можно начертить самостоятельно или попробовать поискать на сайте Thingiverse , Cults и т.д., к примеру введя в поиск «parametric bearing». Вместо подшипника можно распечатать просто пластиковое кольцо, например, из PLA, PETG, нейлона или пэт. Если используемый пластик будет недостаточно скользить или переживаете, что со временем из-за трения протрёт, сверху и снизу можно наклеить липкую ленту или кольцо из какого-нибудь материала (плёнки для ламинации, плёнки для лазерной печати, упаковки для фломастеров, тонкостенной коробочки и т.д.).

Повышающий стабилизатор нужен для шагового мотора. Такие моторы обычно потребляют максимум сотни миллиампер. Стабилизатор желательно взять с запасом, допустим на 1А или больше. Выходное напряжение питания у стабилизатора, 12В или более. Выбирая стабилизатор, так же учитывайте, что они не должен быть слишком большой, иначе его нельзя будет поместить внутри корпуса.

Схема

Схема проста, часть деталей запаивается на макетной плате.

Через скользящие контакты от Arduino к датчику VL53L03X подключаются контакты +5В, земля и две линии интерфейса I2C (SCL и SDA). К датчику Холла подключается земля, +5В и вывод D8 от Arduino. Также между +5В и D8 устанавливается резистор на 10кОм.

На повышающего преобразователя подаётся 5В. На плате построечным резистором устанавливается выходное напряжение примерно 12В. Эти 12В с выхода стабилизатора подключаются к выводам «питание мотора» модуля драйвера моторов. Так же по линии 12В устанавливается электролитический конденсатор, который нужен что бы драйвер мотора работал без сбоев (на плате его может не быть совсем, а даже когда запаян керамический или танталовый конденсатор, его ёмкости обычно недостаточно). 5В подключается к выводам «питание логики» драйвера моторов. Не перепутайте, где выводы «питание логики» и «питание мотора», иначе драйвер может выйти из строя.

Платы бывают разные, иногда плюс питания для мотора обозначается, допустим надписью VMOT, а плюс питания логики обозначаться как VCC. Выводов GND на плате может быть один или несколько, в данном случае это не имеет значения.

Выводы STEP, DIR и EN от драйвера моторов подключаются к Arduino, а выводы RESET и SLEEP соединяются между собой.

На платах с драйвером моторов A4988 обычно запаян подстроечный резистор, им настраивается ограничение по току для шагового мотора. Ограничение тока для шаговых моторов очень желательно настроить. Если ограничить ток слишком сильно, мотор под нагрузкой или не сможет вообще проворачивать вал или будут пропуски шагов. Если задать слишком большой ток и источник питания способен будет его обеспечить, мотор будет греться или его обмотки просто сгорят. Так же это абсолютно ненужная нагрузка на источник питания. При питании от аккумулятора это приведёт к тому, что он будет быстрей разряжаться. При питании от USB (блока питания, порт компьютера или ноутбука и т.д.) в лучшем случае будет просто лишняя нагрузка, в худшем, когда блок питания или порт не рассчитан на такой ток и нет защиты, это даже может привести к выходу из строя блока питания или порта.

Вот и все. В качестве источника питания используется USB-кабель, подключенный к Arduino NANO.

Печать корпуса и сборка

Загрузите файлы STL, по ссылке выше (после списка деталей) и распечатайте детали корпуса. Настройте слайсер, в зависимости от особенностей вашего принтера и типа пластика, которым будете печатать. В данном случае детали напечатаны PLA пластиком, основные настройки были следующими — 2 периметра, высота слоя 0.3 мм, заполнение 20%. Когда детали корпуса будут готовы, можно приступить к сборке.

Возьмите скользящие контакты и поместите его в верхнюю часть корпуса. Убедитесь, что вращающаяся часть кольца находится на верхней стороне корпуса, чтобы она вращалась одновременно с диском. Теперь установите шаговый мотор, который фиксируется к корпусу двумя 3M винтами и гайкам. Крышка готова:

Теперь установим большой подшипник в верхней части корпуса:

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

Теперь пропускаем провода от скользящих контактов через отверстие вращающегося диска:

После чего берём датчик и припаиваем к нему 4 провода (+5V, GND, SCL и SDA) от скользящих контактов:

С помощью двух болтов М3 закрепляем модуль дальномера на корпусе вращающегося диска:

Если у вас модуль с другим расстоянием между крепёжными отверстиями, модуль можно закрепить только одним болтом. Если крепёжных отверстий совсем нет, модуль можно приклеить (двустороння липкая лента, термоклеем с помощью клеевого пистолета и т.д.).

Когда датчик будет закреплён, вращающийся диск надевается на подшипник:

На вращающуюся крышку приклеивается неодимовый магнит, а в верхнюю крышку вставляется датчик холла:

Магнит служит для того, чтобы на него на него срабатывал датчик Холла и в этот момент в коде происходит установка переменной «угол» в некоторое значение. Если магнит по размерам позволяет наклеить его по центру под датчиком, это будет самый лучший вариант, т.к. при срабатывании переменной «угол» нужно будет присвоить значение 0. Если нет, магнит можно наклеить возле датчика. Тогда переменной «угол» нужно будет присвоить не 0, а соответствующее значение (на какой угол относительно магнита повёрнут датчик). Если магнит находится с противоположной стороны, нужно присвоить 180. Если угол составляет 20 градусам (на фото выше угол немного больше):

Тогда переменной «угол» нужно присвоить 20 и т.д.

На макетную плату по схеме, приведенной ранее, запаиваем конденсатор, драйвер мотора, 10K резистор, датчик Холла, провода от Arduino и стабилизатора питания:

Всё припаяно, теперь закрепляем (двусторонней липкой лентой, клеем, термоклеем и т.д.) Arduino Nano внутри корпуса и наш лидар почти готов:

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

Скетч для Arduino

#include Adafruit_VL53L0X sensor = Adafruit_VL53L0X(); //Outputs/inputs #define dirPin 3 //Pin for direction of the stepper driver #define stepPin 4 //Pin for steps of the stepper driver #define Enable 5 //Pin for enable the stepper driver //Variables int Value = 1200; //Delay value between steps float angle = 0; //Start angle /* ----------------Step angle calculation---------------- We need 1.5 rotations for 360�. (pully ratio 1.5 : 1) Each 200 steps the motor will make a rotation. We move 2 steps and the we make a measurement. This equals to 360�/(200steps * 1.5) * 2 = 2.4angle/loop -> ----------------Step angle calculation----------------*/ float angle_step = 2.4; //So place that value here float maxdist = 400; //I've set the maximum distance around the sensor to only 400mm. Change to any other value. bool loop_starts = false; byte last_PIN_state; void setup() < // Declare pins as output: pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); pinMode(Enable, OUTPUT); digitalWrite(Enable, LOW); //Place enable to low so the driver is enabeled digitalWrite(dirPin, HIGH); //Place dirPin to HIGH so we spin CW Serial.begin(9600); //Start serial port sensor.begin(); PCICR |= (1  PCIE0); //enable PCMSK0 scan so we can use interrupts PCMSK0 |= (1  PCINT0); //Set pin "D8" trigger an interrupt on "any" state change. > void loop() < if (loop_starts) //We reset angle when the magnet is detected on D8 < angle = 0; loop_starts = false; > digitalWrite(stepPin, HIGH); //Make one step delayMicroseconds(Value); //Small delay digitalWrite(stepPin, LOW); //Make another step delayMicroseconds(Value); //Add another delay VL53L0X_RangingMeasurementData_t measure; sensor.rangingTest(&measure, false); // pass in 'true' to get debug data printout! if (measure.RangeStatus != 4) < int r = measure.RangeMilliMeter; if (r > maxdist) //Limit the dsitance to maximum set distance above r = maxdist; Serial.print(angle); //Print the values to serial port Serial.print(","); Serial.print(r); Serial.println(","); angle = angle + angle_step; //Increase angle value by the angle/loop value set above (in this case 2.4� each loop) > else < //phase failures have incorrect data //Serial.println(" out of range "); > > //This is the magnet detection interruption routine //---------------------------------------------- ISR(PCINT0_vect) < if (PINB & B00000001) //We make an AND with the pin state register, We verify if pin 8 is HIGH. < if (last_PIN_state == 0) < last_PIN_state = 1; > > else if (last_PIN_state == 1) //Now verify if pin 8 is LOW. -> Magnet was detected < last_PIN_state = 0; loop_starts = true; //If yes, we set loop_starts to true so we reset the angle value > >//End of ISR 

Откройте Arduino IDE и скопируйте в него скетч. Если при загрузке скетча в плату появится сообщение, что отсутствует библиотека «Adafruit_VL53L0X.h»:

Её нужно будет установить. Для этого в меню «Инструменты» выберете пункт «Управлять библиотеками. » и в появившемся окне найдите «Adafruit_VL53L0X» (что бы сократить список, можно ввести в поле поиска «VL53»:

Для VL53L0X кроме библиотеки от Adafruit есть и от Pololu. Подключается она аналогичным образом, но код нужно немного изменить:

#include #include VL53L0X sensor; // Uncomment this line to use long range mode. This // increases the sensitivity of the sensor and extends its // potential range, but increases the likelihood of getting // an inaccurate reading because of reflections from objects // other than the intended target. It works best in dark // conditions. #define LONG_RANGE // Uncomment ONE of these two lines to get // - higher speed at the cost of lower accuracy OR // - higher accuracy at the cost of lower speed #define HIGH_SPEED //#define HIGH_ACCURACY //Outputs/inputs #define dirPin 3 //Pin for direction of the stepper driver #define stepPin 4 //Pin for steps of the stepper driver #define Enable 5 //Pin for enable the stepper driver //Variables int Value = 1200; //Delay value between steps float angle = 0; //Start angle /* ----------------Step angle calculation---------------- We need 1.5 rotations for 360º. (pully ratio 1.5 : 1) Each 200 steps the motor will make a rotation. We move 2 steps and the we make a measurement. This equals to 360º/(200steps * 1.5) * 2 = 2.4angle/loop -> ----------------Step angle calculation----------------*/ float angle_step = 2.4; //So place that value here float maxdist = 400; //I've set the maximum distance around the sensor to only 400mm. Change to any other value. bool loop_starts = false; byte last_PIN_state; void setup() < Serial.begin(115200); Wire.begin(); // Declare pins as output: pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); pinMode(Enable, OUTPUT); digitalWrite(Enable, LOW); //Place enable to low so the driver is enabeled digitalWrite(dirPin, HIGH); //Place dirPin to HIGH so we spin CW sensor.setTimeout(500); if (!sensor.init()) < Serial.println("Failed to detect and initialize sensor!"); while (1) <> > #if defined LONG_RANGE // lower the return signal rate limit (default is 0.25 MCPS) sensor.setSignalRateLimit(0.1); // increase laser pulse periods (defaults are 14 and 10 PCLKs) sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18); sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14); #endif #if defined HIGH_SPEED // reduce timing budget to 20 ms (default is about 33 ms) sensor.setMeasurementTimingBudget(20000); #elif defined HIGH_ACCURACY // increase timing budget to 200 ms sensor.setMeasurementTimingBudget(200000); #endif PCICR |= (1  PCIE0); //enable PCMSK0 scan so we can use interrupts PCMSK0 |= (1  PCINT0); //Set pin "D8" trigger an interrupt on "any" state change. //See interrupt vector below the void loop > void loop() < if (loop_starts) //We reset angle when the magnet is detected on D8 < angle = 0; loop_starts = false; > digitalWrite(stepPin, HIGH); //Make one step delayMicroseconds(Value); //Small delay digitalWrite(stepPin, LOW); //Make another step delayMicroseconds(Value); //Add another delay int r = sensor.readRangeSingleMillimeters(); //Get distance from sensor if (r > maxdist) //Limit the dsitance to maximum set distance above < r = maxdist; > Serial.print(angle); //Print the values to serial port Serial.print(","); Serial.print(r); Serial.println(","); angle = angle + angle_step; //Increase angle value by the angle/loop value set above (in this case 2.4º each loop) > //This is the magnet detection interruption routine //---------------------------------------------- ISR(PCINT0_vect) < if (PINB & B00000001) //We make an AND with the pin state register, We verify if pin 8 is HIGH. < if (last_PIN_state == 0) < last_PIN_state = 1; > > else if (last_PIN_state == 1) //Now verify if pin 8 is LOW. -> Magnet was detected < last_PIN_state = 0; loop_starts = true; //If yes, we set loop_starts to true so we reset the angle value > >//End of ISR 

В коде для обоих библиотек, в самом начале цикла loop мы проверяем, не сработал ли датчик Холла (в прерывании для этого переменной loop_starts устанавливается значение true) и, если сработал, устанавливаем переменной angle значение 0. Если у вас магнит находится не центру под датчиком, присвойте этой переменной соответствующее число.

Далее в коде отправляем команду драйверу мотора провернуть вал на один шаг, небольшая пауза с помощью delayMicroseconds, затем опять проворачиваем вал на один шаг и опять пауза.

После этого вызываем функцию измерения расстояния и проверяем, считал ли датчик корректные данные. При получении корректных данных от датчика, полученные данные о расстоянии присваиваются переменной r. Затем происходит проверка, выходит ли измеренное расстояние за установленные границы (переменная maxdist) и, если выходит, переменной r присваивается значение maxdist.

В конце цикла в последовательный порт выводятся полученные данные и к текущему значению переменной angle прибавляется значение переменной angle_step (в данном коде это 2.4, т.е. 2.4 градуса). Если у вас шаговый мотор с другим шагом, будете использовать режим микрошага, измените размеры шкивов или будете делать не два, а один, три или ещё сколько-то шагов, не забудьте пересчитать на какой угол будет вращаться датчик и присвоить переменной angle_step соответствующее значение.

Скетч для компьютера

Для визуализации используется приложение Processing, скачать его можно по следующей ссылке . Запустив среду Processing можно переключить языка интерфейса на русский. Для этого в меню нажмите «File», затем » Preferences…» и в открывшемся окне можно будет переключить язык:

Если при запуске появится сообщение, что не найдено Android SDK:

можно проигнорировать это сообщение и просто закрыть окно, нажав на крестик. Только при когда отобразиться окно программы, нужно будет переключить среду Processing из режима работы «Android» в режим «Java». Для этого слева вверху нажмите на «Android»:

И в появившемся меню выберете пункт «Java»:

После чего среда автоматически перезапустится:

Создайте новый скетч (файл -> создать) и скопируйте в него скетч:

Одно из отличий Processing от Arduino IDE заключается в том, как выбирается последовательный порт. В Processing порт выбирается не в меню, а в коде по индексу массива. При запуске скетча, внизу окна выводится список портов:

Найдите в списке порт, к которому подключена Arduino и в строчке:

myPort = new Serial(this, Serial.list()[0], 115200);

при необходимости поменяйте индекс. Если к примеру текущий порт «COM4», замените в коде ноль на единицу:

myPort = new Serial(this, Serial.list()[1], 115200);

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *