Всем привет, меня зовут Антон, и как вы могли уже догадаться из названия, решил я рассказать о своих попытках вкатиться в робототехнику, а в частности о своем дроне из 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, которая в свою очередь отвечает за коммуникацию с приложением и контроль позиции, используя данные с камеры. Кому интересно посмотреть код Та часть логики что на ESP32 Та что на Raspberry Pi Приложение под андроид Если заметите говнокод, сильно не бомбите, я был скорее занят попытками заставить это работать, пробуя и отбрасывая разные варианты реализации. Может как-нибудь займусь и причешу :) Также я снял видео об этом: Буду очень признателен если посмотрите, поставите лукас и напишите в коментах: “Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик!” Спасибо за внимание!