Всем привет, меня зовут Антон, и как вы могли уже догадаться из названия, решил я рассказать о своих попытках вкатиться в робототехнику, а в частности о своем дроне из Raspberry Pi и ESP32. В конце статьи я приложил видео со схожим содержанием, кому больше заходит текст, читайте дальше.
Предыстория
На начало этой истории я работал веб-разработчиком (react, typescript и тд), немного щупал плюсы, из навыков работы с электроникой - мог спаять порванные наушники.
На зп я не жаловался, но периодически меня посещали мысли о том, что мой код не производит никакого эффекта на реальный мир.
Хоть и существуют софтверные проекты, которые на этот мир влияют, для себя я решил это исправить наиболее прямолинейно, занявшись робототехникой. (само собой влияние глобальное и чисто физическое это разные вещи, но физическое все же лучше, чем ничего)
В общем я почитал какие-то книжки, статьи, посмотрел видосы по этой теме, купил паяльные принадлежности и 3д принтер, чтобы не думать из какого мусора сделать и как приспособить те или иные детали. Тем более что 3д принтеры сейчас вполне доступны.
Первый робот
Мой первый робот выглядел вот так
Я задизайнил детали в Blender’e и распечатал. В качестве мозгов использовал Raspberry Pi и пауэр бэнк в качестве источника питания. Спаял контроллер моторчиков (если его можно так назвать) из реле и транзисторов, перепутав у них коллектор и эмиттер, из-за чего моторчики едва двигались (но двигались тем не менее). Когда в итоге выяснил в чем проблема и перепаял транзисторы другой стороной, то все заработало. Роботом эту штуку сложно назвать, тк она просто управляется удаленно. Тем не менее я был доволен, поверил в себя и решил повысить градус сложности, сделав тоже самое, но чтоб летало.
Кстати, если занимаетесь чем-то подобным, не делайте тех же ошибок и не используйте художественные 3д-редакторы для дизайна механических частей, а лучше потратьте пару дней на освоение какого-нибудь параметрического 3д-редактора, поскольку он гораздо лучше подойдет для вещей с четкими размерами и формами.
Второй робот
После некоторого погружения в тему было принято решение использовать традиционные для коптеров бесщеточные моторчики, контроллеры моторчиков и литиево-полимерный аккумулятор способный отдавать большой ток. В качестве мозгов я решил использовать все ту же Raspberry Pi. После того как я выяснил как контролировать моторчики с Raspberry Pi, я принялся за дизайн рамы. Делал я это абсолютно по наитию, думая что если дроны самых безобразных форм летают, то требования к раме не такие высокие.
Также я купил плату с гироскопом, акселерометром, барометром и магнитометром на i2c шине. До того, как я узнал, что такое PID контроллер, я сделал что-то похожее на то, как работает его P - компонент: просто увеличивал или уменьшал скорость моторчиков пропорционально тому, как дрон отклоняется от горизонта.
В начале мне казалось, что там нет ничего сложного, но после кучи неудачных попыток я был абсолютно без понятия как вообще это делать правильно, ведь там столько всего, что может работать не так, как надо. Да и в отличии от написания только-лишь софта, любой косяк может привести к физическим повреждениям. К тому же эту штуку сложно тестировать в маленькой съемной квартире. Было бы у меня большое просторное помещение, я бы мог соорудить конструкцию, ограничивающую движение дрона.
Но вместо этого приходилось использовать шнурки и вручную пытаться предотвратить аварию одной рукой, а другой контролировать дрон с ПК, что в свою очередь дополнительно ограничивало мои возможности по перемещению. В итоге я решил написать мобильное приложение под андроид, где я бы мог менять параметры, следить за показаниями сенсоров, и контролировать дрон аналогово-подобными элементами управления.
Изначально я сосредоточился на контроле удержания горизонта, но никак не мог его нормально протестировать, вручную управляя высотой, и на тот момент мне стоило начать именно с нее. Первая мысль была использовать показания барометра, но они были недостаточно точными, чтобы использовать их для контроля небольшой высоты в помещении (ну или я его неправильно использовал), так что я купил ультразвуковой датчик расстояния. У него странный способ взаимодействия, он поднимает напряжение на одном из пинов в процессе замера, нужно считать время пока он его не опустит, и умножить это время на скорость звука, чтобы выяснить расстояние.
Без нагрузки Raspberry Pi справлялась с этим, но будучи загруженной другими задачами, пропускала этот момент, и показания были мягко говоря неточными. Так что мне пришлось использовать Atmega168p, только для того чтобы считать это время и отдавать показания в удобном цифровом виде через SPI. Даже пришлось прочитать книжку “Make: AVR Programming”, где очень доступно для нубов объясняется как программировать эти штуки. Давно хотел научиться программировать микроконтроллеры и тут такая возможность.
Чтобы тестировать свою реализацию контроля высоты и не думать о других степенях свободы, я купил велосипедные тормозные тросики и распечатал направляющие, чтобы ограничить движение дрона только вверх и вниз.
Все работало, правда появилась проблема, заключающаяся в том, что работающие пропеллеры мешали ультразвуковому сенсору определять расстояние больше 40см, в итоге пришлось заменить его на лазерный сенсор, у которого нормальный цифровой интерфейс, так что и в вышеупомянутом микроконтроллере необходимость отпала.
Теперь у меня был контроль высоты, но я все еще не мог добиться стабильного удержания горизонта, хоть и реализовал PID контроллер для этого. Предполагаемые причины следующие:
Я использовал дешевые пропеллеры (даже пытался их печатать) и не отбалансировал их. А это перегружает сенсоры вибрациями, снижая их точность. Решил я эту проблему выводя разницу между самым большим и маленьким из 100 последних значений гироскопа, чтобы понять насколько сильно вибрирует пропеллер при работе. А затем клеил кусочки изоленты на лопасти пропеллера и смотрел, как изменится это значение. Если увеличилось, пробовал другую лопасть, в общем подбирал место, где это значение было бы минимальным. Само собой проверял я это на неподвижном дроне на малых оборотах.
У Raspberry Pi всего 2 канала для генерации PWM, а управлять нужно 4-мя моторчиками, а программно генерируемый PWM, который я изначально использовал, возможно недостаточно точен да и в холостую загружает процессор. Тут я уже забросил надежду использовать одну лишь Raspberry Pi в качестве мозгов. И начал смотреть в сторону ESP32. Сначала попробовал контролировать моторчики через нее, подключенную по SPI к Raspberry Pi, а потом и вовсе перенес всю логику контроля полета на ESP32. Выбрал я ее из-за дешевизны, доступности и наличия кучи интерфейсов. Как ею пользоваться я узнал из книжки “Kolban's book on ESP32”, не такая захватывающая с художественной точки зрения, как книжка по AVR микроконтроллерам, но тоже ничего.
Недостаточно жесткая рама. Все таки каким то требованиям она должна удовлетворять. И если ее делать из частей, то нужно убедиться что в местах соединений нет люфта.
Я использовал дополняющий (complementary в англ источниках) фильтр для определения угла наклона с неоптимальным соотношением коэффициентов. Оптимальные 0.999 - для угла, измеренного интегрированием значений гироскопа, и 0.001 для угла, измеренного акселерометром.
Не учел что pitch превращается в roll и наоборот если наклоненный дрон крутится по оси z (если гироскоп определяет угловую скорость по этой оси)
При очень медленных колебаниях угла наклона возможно нужно увеличить коэффициент P, причем в разы, а не уменьшать, как рекомендуют некоторые источники, не вдаваясь в характер колебаний.
В процессе разработки меня начала напрягать борода из проводов между модулями, да и вообще то, как они расположены. И я решил вложить немного времени в навык создания своих печатных плат. Давно хотел это попробовать, но не решался, тк думал что для этого нужны дорогие специфичные инструменты, да еще и с химикатами нужно возиться.
В итоге я посмотрел какие-то туториалы по KiCAD, чтобы научиться делать дизайн платы. Купил с рук принтер за 3000р, утюг без дырок меньше чем за 500р, а самым дорогим инструментом оказался сверлильный станок за 6000р. А необходимые химикаты оказались не такими опасными и от прикосновения к ним ничего не случится.
С четвертой попытки я таки сделал эту плату. Самый сложный шаг оказался - нанести паяльную маску. Что конкретно эта плата делает, так это соединяет ESP32 с сенсорами по i2c, и с Raspberry Pi по SPI, также распределяет необходимое питание по компонентам.
Во время тестовых полетов красивые графики в приложении, отображающие данные с сенсоров, оказалось, сложно анализировать, пытаясь при этом уберечь дрон от разрушения. Так что я добавил возможность записывать данные с сенсоров и написал скрипт который помогает покадрово анализировать их вместе с видеозаписью полета.
Сделал бы я это раньше, потратил бы гораздо меньше времени на обнаружение проблемы с ультразвуковым сенсором, о которой говорил ранее.
В какой то момент у меня уже был относительно стабильный контроль высоты, направления и горизонта, но я не мог избавиться от произвольных перемещений в горизонтальной плоскости. Кстати, если кто-то знает можно ли избавиться от этих перемещений, используя только акселерометр, гироскоп и магнитометр, пожалуйста, напишите в комментах.
После некоторого ресерча, я выяснил что некоторые дроны используют GPS для удержания позиции. И я попытался это реализовать. Проблема была в том, что это работает только на улице, но и на улице я не добился удовлетворительных результатов, тк из-за плохой погоды мне не удалось сделать много попыток, я забил на GPS и попытался решить проблему с помощью компьютерного зрения.
Я установил камеру снизу дрона и попытался удерживать синюю метку на полу с помощью OpenCV. После нескольких попыток и модификаций вот что получилось.
Наконец-то он висит в одной точке без ручного вмешательства и без каких-либо веревок. Это и была моя промежуточная цель, которой я наконец то добился, собственно поэтому и решил сейчас задокументировать и опубликовать свой прогресс на данный момент.
Еще я добавил передачу видео из дрона в приложение, чтобы было проще экспериментировать с компьютерным зрением и пробовать разные подходы для удержания позиции без конкретной синей метки и для реализации прочего функционала.
В данный момент дрон выглядит следующим образом:
ESP32 отвечает за контроль высоты, направления, и горизонта. Он берет данные с датчиков ориентации и лазерного сенсора расстояния снизу. Он отдает команды контроллерам моторчиков и принимает команды от Raspberry Pi, которая в свою очередь отвечает за коммуникацию с приложением и контроль позиции, используя данные с камеры.
Кому интересно посмотреть код
Если заметите говнокод, сильно не бомбите, я был скорее занят попытками заставить это работать, пробуя и отбрасывая разные варианты реализации. Может как-нибудь займусь и причешу :)
Также я снял видео об этом:
Буду очень признателен если посмотрите, поставите лукас и напишите в коментах: “Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик!”
Спасибо за внимание!
Комментарии (36)
freylis
18.04.2022 14:17+1Очень много усилий потрачено ради достижения цели, вы молодец.
Какой следующий шаг? следопыт, который будет следовать за вами во время покатушек на байке? :)
tohntobshi Автор
18.04.2022 15:35довести до ума удержание позиции, чтобы оно динамически выбирало опорные точки, ну и скорее всего да, дальше можно пилить фичи, типа преследования, избегания препятствий и тд)
DmitryOlkhovoi
18.04.2022 14:59+1супер) только правда можно было взять привычные компоненты или даже современный полетник и накатать свою прошивку раз так хочется сделать самому)
tohntobshi Автор
18.04.2022 15:41+2но ведь в существующих контроллерах полета есть один фатальный недостаток ) да и я это делал больше ради процесса и скила, который мне пригодится при создании чего-то менее типичного, чем квадрокоптер)
FGV
18.04.2022 16:23хм:
float seconds_elapsed = u_seconds_elapsed / 1000000.f;
так понимаю шаг считывания информации с датчиков, да и работы всей системы управления не фиксирован? Так обычно не делают, ибо все коэф. цифровых фильтров плавать будут, да и вся система управления с плавающим шагом тоже ни к чему хорошему не приведет.
tohntobshi Автор
18.04.2022 16:57В моем интуитивном представлении, чем быстрее пройдет итерация тем лучше, например точнее сынтегрируется угловая скорость гироскопа в угол. А с фиксированным временем итерации мне бы пришлось взять какой-то запас времени, например на случай, если произойдет коммуникация с другим модулем или еще какие-то нерегулярные для основного цикла действия. Но я подумаю над тем что вы говорите
FGV
18.04.2022 17:18+2…чем быстрее пройдет итерация тем лучше…
Подберите минимальновозможный фиксированный шаг, и с ним работайте.
Для есп32 и мпу9250 у меня вышло 2мс (только акс. и гироскоп).
А с фиксированным временем итерации мне бы пришлось взять какой-то запас времени, например на случай, если произойдет коммуникация с другим модулем или еще какие-то нерегулярные для основного цикла действия.
Автопилот - система жесткого реального времени, тут никаких если, весь обмен с датчиками и исполнительными механизмами, а так же вычисления - должны быть жестко расписаны во времени.
blind_oracle
18.04.2022 17:42Да, вместо того чтобы биться об уже решённые проблемы - лучше почитать код Betaflight/Inav/Arducopter и посмотреть как сделано там.
В Бете точно фиксированный цикл, в Айнав недавно вроде бы сделали некий плавающий, но он по моему работает в режиме 'быстрее Х герц если возможно, но не медленнее'
lgorSL
18.04.2022 17:40Кстати, если занимаетесь чем-то подобным, не делайте тех же ошибок и не
используйте художественные 3д-редакторы для дизайна механических частей,
а лучше потратьте пару дней на освоение какого-нибудь параметрического
3д-редактора, поскольку он гораздо лучше подойдет для вещей с четкими
размерами и формами.Какие есть бесплатные альтернативы?
В блендере делаю модели для 3д печати, сталкиваюсь с некоторыми недостатками, но пока ничего принципиально усложняющего работу не было. Если активно использовать модификаторы, то, как мне кажется, можно и в нём достаточно "параметрическую" модель собрать. И ещё есть привязка вершин к координатной сетке и к другим вершинам, для квадратных моделей с точностью размеров никаких проблем нет.tohntobshi Автор
18.04.2022 18:21я FreeCAD заюзал, он конечно сырой и тоже для своего рода мазохистов, но мне было гораздо легче в нем по быстрому что-то набросать и распечатать, что в блендере бы стало для меня эпопеей
xhd
18.04.2022 18:02Я примерно догадываюсь, почему ESP32 для сенсоров, но выбор Raspberry, как основной платформы... как-то не совсем понятно. ESP, по моему опыту, вполне справляются с расчетами.
tohntobshi Автор
18.04.2022 18:05Контроль удержания позиции у меня сделан с помощью камеры, да и в дальнейшем планирую добавлять другие фичи, опирающиеся на компьютерное зрение. Конечная цель - автономный дрон, а не радиоуправляемый, и esp будет для этого недостаточно
xhd
18.04.2022 19:47-1ESP с OpenCV неплохо стыкуются, модули ESP32 с камерой встроенной есть, можно воткнуть несколько штук, плюс их можно легко состыковывать и масштабировать. А Raspberry большая, тяжёлая и дорогая - по цене одной RpI4/8 можно взять штук сорок ESP32 cam.
Другое дело, если малина уже есть, другой не планируется и коммерческие перспективы не интересны.
VAE-STV
18.04.2022 18:07А можете пояснить, в чем конкретно была проблема с УЗ датчиками? Делаю похожий проект, только на RPi zero w и RP2040. С учетом фильтрации выбросов расстояние измеряется ~ до 3 метров, с небольшой погрешностью.
tohntobshi Автор
18.04.2022 18:14когда пропеллеры не крутились, то у меня тоже до 3х метров определялось расстояние, но когда они работали, у меня сенсор переставал видеть(слышать) дальше 40см, из-за турбулентности под дроном скорее всего, а может из-за помех в питании, но я чет не стал разбираться, и поменял его на лазерный в итоге и все нормально стало
VAE-STV
18.04.2022 19:27Меня в лидаре смутила более короткая дистанция, т.к. коптер мной тоже задумывался автономным - хотелось выжать максимум из доступного. С отсутствием слышимости, связанного с винтами, не столкнулся - возможно, из-за другого расположения датчиков (у меня их 6 штук, по одному с каждой стороны), а может быть просто больше повезло. О такой возможности я изначально даже не задумывался, поэтому меня это удивило при прочтении статьи. Надеюсь будет продолжение, т.к. интересно сравнить ваши решения с моими. Например, я проблему с удержанием позиции решил как раз с помощью УЗ датчиков и GPS, а камера используется для распознавания кустов и деревьев от которых стоит держаться подальше.
tohntobshi Автор
18.04.2022 23:15Я использую vl53l1x и у него вроде как дальность 4м, то есть такая же как и у УЗ сенсора. Вообще на большой высоте я думаю барометр использовать. А по поводу GPS, я его тоже планирую использовать, когда он доступен (на открытом пространстве то есть), а для остальных ситуаций использовать камеру для удержания позиции. А какая у вас модель GPS модуля, кстати? (у меня ublox neo m8n, я вот не знаю достаточная ли у него частота обновления и точность для этой цели)
VAE-STV
19.04.2022 09:46У меня используется neo 6m. Частоты обновления хватает, а вот точность временами оставляет желать лучшего, зависит от того сколько спутников видит. Для полета от точке к точке обычно достаточно, а для удержания позиции дополнительно опираюсь на показания с УЗ датчиков. В условиях города и внутри помещений такой способ дает не плохие результаты, а вот на природе, где от УЗ информация не поступает и позиционирование выполняется только по GPS - "рысканье" гораздо выше, доходит вплоть до полетов кругами, с радиусом около метра, вокруг заданной точки. Пока оставил так, в будущем буду думать как улучшить это поведение. Возможно модуль придется поменять на какой-либо другой. Сейчас основная задача перенести всю работу с датчиками и двигателями на RP2040.
YDR
18.04.2022 20:05по-новичковски и пока не оптимально, но лучше эти велосипеды пройти самому. Очень хорошо, что довел до рабочего состояния. Если все еще интересно, то можно уже переписать правильно.
Под капотом у ESP32-arduino - ESP-IDF и FreeRTOS. FreeRTOS можно использовать прямо из ардуино.
alexvalchuk
19.04.2022 16:38Молодец. Очень четко видно, что проделана огромная работа. Сам уже год, как подсел на похожий сценарий. Правда меня больше интересуют тема дронов самолетного типа.
SkysurfAU
20.04.2022 09:47Очень интересный материал, спасибо.
У нас есть стартап, находящийся в ранней стадии разработки системы спасения дронов с использованием AI. Было бы интересно с Вами пообщаться - может быть есть поле для сотрудничества.
Как с Вами можно связаться?
Владимир
iliasam
20.04.2022 10:48Есть вот такие jоптические датчики движения: https://shop.pimoroni.com/products/pmw3901-optical-flow-sensor-breakout?variant=27869870358611
Их можно использовать для стабилизации дрона в горизонтальной плоскости.
Blackjaguar1982
20.04.2022 16:52Я тут дилетант, но почему не взять больше гироскопов и усреднять их значения для стабилизации положения дрона?
Если дрон не получает команду, то в какое положение он возвращается/поддерживает?
Испытания на местности уже проводились? Как планируете решать проблему сдувания дрона ветром? Что будет для дрона опорной точкой, если GPS мотает дрон по радиус 1м? В какой-то момент дрон просто удрейфует в дальние дали, если будете опираться только на GPS.
На винты подумайте защиту лопастей. Китайцы кажется сетку какую-то используют.
Не нагнетаю, просто вот такие вопросы появились.
FGV
21.04.2022 07:12…но почему не взять больше гироскопов и усреднять их значения…
а смысл? усреднение ошибки от одинаковых источников на выходе даст ту же ошибку.
Что будет для дрона опорной точкой, если GPS мотает дрон по радиус 1м? В какой-то момент дрон просто удрейфует в дальние дали, если будете опираться только на GPS.
При работающем GPS - не удрейфует, т.к. мотается именно позиция получаемая от GPS приемника.
Blackjaguar1982
21.04.2022 08:52Если дрон при этом не пытается следовать за позицией, то да - вы правы и ничего не будет.
Alex_ME
А вы пробовали добавить фильтрацию данных гироскопа до подачи на вход ПИД-регулятора? Существующие популярные прошивки полетных контроллеров квадрокоптров (betaflight, inav итп) используют различные фильтры и их комбинации:
Low-pass filter/Фильтр низких частот: отсекает выскоеи частоты шума
Notch filter/Полосовой фильтр
Dynamic notch: notch фильтр, частота которого выбирается автоматически как частота наиболее "громкой" гармоники шума
RPM-filter: фильтр из betaflight, который с помощью протокола bidirectional DSHOT получает от регуляторов двигателей их текущие обороты и применяет динамический notch фильтр на частоте, соответствующей скорости вращения двигателей
Matrix filter: фильтр из inav, по-сути dynamic notch, который применяет notch фильтр каждой оси для всех остальных (yaw, pitch, roll), что позволяет учитывать взаимное влияние шумов по разным осям
Фильтр Калмана (в inav называется unicorn filter)
Помимо этого, есть отдельно фильтр (вроде low-pass) по D-компоненте ПИД-регулятора.
tohntobshi Автор
в MPU-9250 (сенсор который я использую тут) есть несколько режимов low-pass фильтра для гироскопа и акселерометра, я выбрал режим 3 для обоих (даже добавил в свою приложуху возможность на ходу переключать эти режимы), так что они фильтруются в какой-то степени. Затем использовал complementary filter, объединяя интегрированные показания гироскопа (нешумные, но подверженные накоплению погрешностей) и акселерометра (шумные, но точные) в соотношении 999 к 1 (тоже добавил в приложуху возможность это на ходу менять). И только потом уже этот угол контролируется PID контроллером. Но тем не менее этого недостаточно, если пропеллеры сильно вибрируют, я прямо заметил колоссальную разницу невооруженным глазом до и после того, как отбалансировал их.
Alex_ME
Понятно, спасибо.
Насколько я знаю, у гоночных/фристайл квадрокотперов пропеллеры не балансируют (это осталось в прошлом), а требования к шумам там довольно высокие, потому что фильтры увеличивают задержку.
К сожалению, я не знаю, как там реализован режим стабилизации, я использовал только т.н. acro mode, т.е. стабилизация только угловых скоростей по гироскопу. И я бы не сказал, что он нешумный, как раз на гироскоп вешают программные фильтры, помимо встроенного в сенсор. Кстати о сенсорах, почему-то (вроде, наименее шумный и менее подверженный помехам) самым лучшим сенсором для квадов считается MPU-6000.
tohntobshi Автор
дорогие пропеллеры не балансируют) я использовал самые дешевые убогие, чтоб не жалко было сломать во время тестовых запусков, поэтому пришлось