Хотели бы свой дистанционно управляемый танк? В этой статье я расскажу про общие принципы танкостроения из доступных материалов.
Я опишу процесс создания танка с камерой который управляется со смартфона по Wi-Fi. В ходе статьи я буду так же описывать и альтернативные решения, чтобы вы имея теоретическую базу могли создать что-то свое.
Эта статья рассчитана на людей, которые не имеют большого опыта в электронике, но очень хотят попробовать. Некоторые мои решения нельзя назвать правильными, из-за моей неопытности или просто потому, что мне так захотелось. Главная идея, которую я хочу донести – это то, что бы вы не повторяли как я, а делали свое уникальное на основе прочитанного здесь. Я буду показывать на примере своего танка, но изложенные тут принципы можно применять при создании другой подобной дистанционно управляемой техники.
Материалы и компоненты, которые я использовал:
Корпус от игрушечного танка.
Модуль ESP-32-Cam – контроллер для Wi-Fi и камера.
Arduino Nano – контроллер для датчиков и управления движением.
L298N – драйвер для двигателя.
Набор датчиков – ультразвуковой дальномер; барометр; акселерометр и гироскоп; термометр и гигрометр; датчик Холла.
Два литиевых аккумулятора, повышающий преобразователь, зарядная плата.
Android смартфон с управляющим приложением.
Статья получилась довольно большая, но она поделена на разделы, которые соответствуют каждой части устройства или функциональному предназначению. В этих частях вначале будет теория, потом мой опыт и какие-то рекомендации. В конце статьи фото и видео демонстрация.
Разделы статьи:
Корпус и шасси.
Система электропитания.
Микроконтроллеры.
Программное обеспечение (прошивка).
Коммуникации.
Датчики.
Исполнительные механизмы.
Часть своих мыслей я буду прятать под спойлер. Там я буду описывать то, без чего я считаю можно обойтись, но любознательные могут почитать.
Любая техника состоит из множества компонентов, необходимо разложить то, что вы собираетесь делать на составные части каждая из которых выполняет определенную функцию. Тогда вы будете легко ориентироваться в структуре вашего устройства, понимать, что за что отвечает и с меньшими затратами исправлять ошибки в процессе отладки. Ниже пример разложения моего танка на компоненты.
Корпус и шасси
От выбранного корпуса зависит что и как вы сможете разместить, а от шасси зависит проходимость и быстроходность. Например, если вы хотите весело гонять на улице вам стоит выбрать шасси с большим клиренсом и желательно с какой никакой, но системой подвески, если же ваша техника будет ездить исключительно по ровным полам вашего дома и без преодоления таких сложных противотанковых препятствий как махровые ковры, то вы можете не заморачиваться – подойдет любое шасси.
Скорее всего вы будете создавать такое устройство, в котором будут использоваться редукторы (набор шестеренок, которые меняют обороты на усилие и наоборот) учитывайте, что они могут довольно сильно шуметь. Моторы часто продаются в паре с редукторами и найти мотор подходящих вам характеристик для достижения необходимой динамики не сложно.
Старайтесь все что вы размещаете на корпусе закреплять при помощи надежных, но разборных соединений – что-то вроде болта с гайкой. Это убережет вас от случайных поломок и даст вам необходимую гибкость для полета вашей фантазии в размещении элементов.
В своем танке я взял корпус от игрушечного танка, отфрезеровав внутри все что было лишним, для увеличения полезного объема. Все не нужные отверстия залил термоклеем (на улице это полезно – меньше набивается всякой пыли и воды). Редуктор оставил родным, но один из двигателей пришлось заменить так как оказалось он не имел совместимости со случайно слетевшей фрезой.
Для удобства доступа (и для красоты) я сделал верхнюю часть корпуса в виде откидной металлической крышки, на которой размещаются основные блоки танка. Под крышкой находится моторное отделение – два мотора + редукторы и батарейный отсек с двумя аккумуляторами. Сама крышка вырезана из куска метала от автомагнитолы и покрашена в черный цвет, петля обычная – мебельная (возможно брутальное решение, но я так и хотел).
Корпус для ESP-32-Cam (белая коробка с антенной) – это перевернутый корпус от инфракрасного датчика движения (BV-201). Он достаточно просторный и разделяется на две части что позволяет легко в нем что-то менять.
При креплении всех плат я использовал нейлоновые стойки M3 – если у вас не какая-то «дикая машина», которая требует большой крепкости я рекомендую использовать именно нейлоновые стойки, а не металлические, так как их легко подрезать/подпилить, и они являются диэлектриком, что иногда может быть полезно.
Учитывая неадекватные цены на готовые шасси/корпуса для самоделок, самым дешевым решением будет взять уже готовую игрушечную модель, при покупке которой вы получите: корпус, двигатели и шасси. Так вы сможете быстро сделать прототип и в последствии легко что-либо поменять. Имея опыт построения прототипа, вы будете уже знать чего хотите и как этого достичь.
Система электропитания (бортовая сеть)
От этой системы зависит надежность вашей техники и продолжительность ее автономной работы.
В зависимости от сценария использования (температура, напряжение, ток, безопасность) вашего устройства вам может понадобится различные типы аккумуляторов. В интернете довольно много информации по аккумуляторам поэтому я не буду на них заострять внимание. Скорее всего это будут литиевые аккумуляторы: Li-Ion или Li-Po.
При подборе аккумуляторов необходимо определится с потребностями вашей машины – номинальное напряжение и максимальный ток потребителей: двигатели, микроконтроллеры, датчики и другое. К максимальному току прибавьте, хотя бы 30% запаса на случай модернизации или ошибки при расчетах.
Зная ток вашей нагрузки, вы можете определится с формфактором и количеством аккумуляторов (не забывайте, что есть аккумуляторы повышенной токоотдачи).
Сформировать нужное бортовое напряжение вы можете комбинацией нескольких аккумуляторов (учитывайте, что по мере разряда аккумуляторы будут снижать напряжение) или же подключить между аккумуляторами и нагрузкой DC-DC преобразователь – который повысит или понизит напряжение до необходимого уровня и будет его удерживать на всем рабочем диапазоне аккумуляторов.
Маленькие советы по бортовой сети
Не стоит подключать аккумуляторы методом «запаивания намертво», лучше соединить их при помощи разъемов или батарейных отсеков, так вы получите возможность легкой замены и обслуживания аккумуляторов и на время хранения сможете доставать аккумуляторы – для безопасности (Li-ion загораются так же эффективно, как и отдают энергию).
Учитывайте, что на платах с микроконтроллерами могут быть встроены стабилизаторы. Иногда есть смысл подключить плату в обход стабилизатора – самим обеспечив стабильное питание, а иногда через стабилизатор – возможно упростив схему, но учитывайте, что встроенные стабилизаторы могут иметь не самые лучшие характеристики.
По возможности изолируйте электрические контакты, для защиты от короткого замыкания. Замыкание на неизолированном контакте это самый простой и неприятный способ уничтожить то, что вы делаете.
Для защиты аккумуляторов и остальных компонентов желательно использовать плату контроллера батареи (BMS) – она подключается в разрыв между батареей и нагрузкой обеспечивая защиту от короткого замыкания (КЗ) и ограничивая диапазон напряжений защищая от аварийных ситуаций. Не забывайте обращать внимание на максимальный ток, который может пропустить через себя BMS до отключения нагрузки. Так же эти платы могут иметь возможность зарядки батареи.
Вы должны обеспечить стабильное питание всего устройства в любых, даже самых худших условиях. Когда все включено на максимум, напряжение не должно проседать то того уровня, при котором будут глюки или перезагрузки.
Достичь стабильности электропитания можно несколькими способами:
Создать такие условия, при которых будет невозможно использовать энергии больше, чем устройство способно себе предоставить – например программной защитой или физическим ограничением.
Разделить питание для силовой части – моторы и мощные потребители отдельно от интеллектуальной части – микроконтроллеры, датчики. Таким образом при просадке напряжения в силовой части, например из-за заклинившего мотора вы убережетесь от просадки напряжения для вашего управления – микроконтроллеров.
Обеспечить какую-то кратковременную защиту от просадки напряжения, это может помочь в большинстве случаев и легко в реализации. Примером может быть конденсатор по питанию для микроконтроллера.
Главная идея в том, что просадка напряжения не так страшна для исполнительных механизмов типа моторов или манипуляторов, как для микроконтроллеров, поскольку это значит потерю управления над всей машиной, со всеми последствиями...
Потребление тока моего танка составляет примерно такие значения:
Компонент | Ток, мА |
ESP-32-Cam | 350 |
Arduino Nano | 25 |
Датчики | 25 |
Двигатели x2 | 600-1200 mA; >2A в режиме заклинивание |
Сумма: | 1600 |
Из значений выше видно, что самым большим потребителем являются двигатели, у которых к тому же неравномерный расход энергии в зависимости, от местности по которой едет танк.
Танковая батарея состоит из пары дешевых литиевых аккумуляторов Westinghouse INR18650 2000мА*ч, 20А. Дальше батарея подключается к повышающему DC-DC преобразователю MT3608, который формирует стабильные 5.1В для бортовой сети. Запас 0.1В нужен для уменьшения влияния просадки напряжения на проводах и диодах.
Аккумуляторы подключаются параллельно к плате зарядки. Хотя она может выполнять роль BMS, я подключил плату в обход, потому что она рассчитана всего лишь на ток в 1А, то есть будет отключатся при рабочем режиме танка.
На входе DC-DC преобразователя стоит конденсатор, который немного уменьшает эффект резких просадок напряжения от работы двигателей в момент переходных процессов или заклинивания. Рядом установлен светодиод, который является индикатором роботы танка – очень полезная штука, чтобы всегда видеть, что устройство включено.
Все подключаемое оборудование на танке питается от 5В которые выходят от стабилизатора. Те датчики, которым требуется 3.3В, ввиду их малого потребления питаются от стабилизатора на Arduino Nano. На плате с ESP-32 имеется стабилизатор, который преобразует входные 5В в необходимые для ESP 3.3В.
Возле входа питающего напряжения на платах Arduino и ESP, стоят электролитические конденсаторы с запирающим их диодом. Из-за диодов снижается напряжение питания, например для ESP пришлось использовать диод Шоттки (из-за его малого падения напряжения). Но зато эта небольшая емкость конденсаторов обеспечивает питание микроконтроллеров в кратковременных просадках питания при работе двигателей или по мере того, как разряжаются аккумуляторы. Без этого они бы зависли намертво или перезагружались. Данная мера позволила расширить время автономной работы танка примерно на 40%.
На двигателях стоят керамические конденсаторы 0.1 мкФ, они гасят искру на щетках и устраняют помехи в цепи питания. Блокировочные конденсаторы также стоят возле входа по питанию на каждой плате микроконтроллеров, для защиты от помех.
Разводка бортовой сети
При монтаже я использовал по одному контакту для минуса и для плюса. Из этих двух точек я делал разводку уже по всем местам, где требовалось питание. Делая так же, вы с меньшей вероятностью запутаетесь и будет меньше «земляных петель». Точки плюса и минуса лучше разнести подальше друг от друга для безопасности, например у меня можно эффектно уничтожить танк удачным попаданием металлической отвертки на контакты (а вот и недостаток обхода BMS – нет защиты от КЗ).
Мое решение не идеальное, лучше было бы использовать раздельное питание, при котором силовая часть запитывалась бы отдельно и не влияла на работу микроконтроллеров. К тому же микроконтроллеры и большинство датчиков можно запитать напряжением 3.3В, уменьшив потери энергии на стабилизаторах, но мне просто захотелось что бы было единое бортовое 5В питание.
Рекомендую внимательно отнестись к организации бортовой сети, ведь случайные глюки не нравятся никому, и вы можете потратить уйму времени на отлов бага, которого можно было избежать, потратив немного больше усилий при проектировании.
Микроконтроллеры
Интеллектуальная часть вашей техники для обработки данных и управлением всеми остальными частями устройства. Не имея большого опыта брать голый микроконтроллер и городить вокруг него обвязку не имеет смысла – вы наберетесь опыта, но потратите много времени.
Если хотите поскорее увидеть готовый результат, гораздо более эффективно будет взять платы разработчика (dev board) с уже распаянными микроконтроллерами и дополнительными компонентами, вроде разъемов и программаторов. На таких платах могут быть установлены различные микроконтроллеры, на самом деле их очень много и в интернете по ним достаточно информации, могу лишь посоветовать начинающим смотреть в сторону плат с ESP-32, ESP-8266 и Arduino. Существует много других плат с классными микроконтроллерами, имеющие намного лучшие характеристики за те же деньги, но порог вхождения там будет выше, поскольку там не такое большое сообщество, меньше инструкций, документации, библиотек или попросту более сложное программирование.
Если же вам не хватает возможностей «обычных» микроконтроллеров или вы хотите сделать что-то более ресурсоемкое попробуйте поискать среди мини-компьютеров – Raspberry Pi и его аналоги.
Для своего танка я решил разделить логику на две части. Одна плата будет заниматься обработкой данных с датчиков, дергать моторами и заниматься другими «простыми делами» например моргать светодиодом или пищать в пищалку, то есть такой себе драйвер для доступа к остальным устройствам. Вторая плата будет заниматься обработкой камеры и коммуникациями с внешним миром.
Я выбрал две платы: в качестве драйвера – Arduino Nano, и ESP-32-CAM в роли коммуникационного центра с возможностью смотреть через камеру. Таким образом на танке получилось два бортовых микроконтроллера:
ESP-32 в формфакторе платы с камерой – мне нужно было что то дешевое и что бы оно было с Wi-Fi и могло работать с камерой, лучшего по соотношению цена/возможности я не нашел.
ATmega328 в виде платы Arduino Nano – это идеальная плата по размеру и у нее множество свободных пинов и все необходимые интерфейсы. Классический и надежный выбор для таких задач как снять показания датчиков и подергать моторами.
Можно было сделать все на одной плате, но есть несколько причин почему я выбрал две платы:
Я хотел максимальной отзывчивости от Wi-Fi связи, поэтому любая лишняя задача на ESP дополнительно бы нагружала ее, и хоть она и двуядерная это могло бы привести к дополнительным задержкам, а это не позволительная роскошь.
Плата с ESP-32 в формфакторе модуля ESP-32-CAM, к сожалению, имеет по жадному очень мало свободных пинов, причем часть из них зарезервирована для других нужд. Это значит, что все датчики не подключить, можно использовать было что-то типа сдвиговых регистров, но мне хотелось попроще.
Некоторые из Arduino библиотек без обработки напильником плохо работают на ESP.
Просто так захотелось, что бы было две платы. Мне нравится такая идея разделения обязанностей.
Вместо Arduino можно взять плату с ESP-8266 и отключить на ней Wi-Fi. Она бы тоже отлично подошла, даже лучше поскольку в наличии больше вычислительной мощности и оперативной памяти.
Забавный баг с ESP-32
Перед прошивкой ESP-32 необходимо ее перевести в boot режим. Делается это замыканием контакта GPIO0 на GND. На танке есть переключатель (красный рычажок), который переводит ESP в режим прошивки или в рабочий режим. Но я столкнулся с плохо документированным багом/фичей. В обычном, рабочем режиме, на этом контакте генерируется какой-то специальный высокочастотный сигнал, нарушения которого приводит к различным глюкам всей ESP. Хотя контакт имеет внутреннюю подтяжку к питанию, это не спасало от помех на мой провод к переключателю (около 7 см), из-за этого постоянно были случайные зависания. При отключении провода от контакта, проблемы исчезали. Я выяснил, что это редкий баг (но бывает), замена платы мне помогла.
Среди аналогов плат разработчиков или микроконтроллеров по возможности старайтесь выбирать что-то более популярное, так вы сможете в случае необходимости найти решения большинства проблем.
Попробуйте хотя бы примерно представить какое количество вычислительных ресурсов вам необходимо, не имея опыта представить это довольно тяжело, но можно поискать в интернете похожие проекты и взять нечто подобное. Микроконтроллер подбирается под задачу, а не наоборот, избыточность не всегда хороша, как минимум это будет большее энергопотребление, а в некоторых случаях что-то реализовать может быть проще на более простом и «тупом камне».
Программное обеспечение (прошивка)
Тут я опишу общие моменты по коду которые у меня возникали, некоторые подробности я упущу, они будут описаны в частях ниже.
Попробуйте VS Code и PlatformIO
Если вы пишите код в Arduino IDE, рекомендую попробовать VS Code с расширением PlatformIO. Я сам ее использую так как, это дает возможность пользоваться такими плюшками «нормальных» IDE как автоподстановка, удобную работу с вкладками и несколькими проектами, более быстрая компиляция, преимуществ на самом деле больше, я описал лишь те, что главные для меня. В родной Arduino IDE было очень неудобно каждый раз переключатся между проектами и настраивать их заново. Сначала вы, потратите немного времени на изучение новой среды, но потом будете делать все намного быстрее и экономия времени будет вашим вознаграждением.
Я использовал Arduino фреймворк, таким образом получается единая экосистема на Arduino и ESP, хотя последняя обладает собственным фреймворком с прекрасной документацией.
В этом проекте используется платформа espressif32 версии 3.2.1, потому что в версиях выше поломали алгоритм выделения памяти, и за чего ESP может перезагружаться. Это касается только моего случая поскольку у меня используется несколько протоколов типа HTTP, SSE, Websocket и частая передача данных, в других сценариях все нормально работает.
Маленькие советы по коду
Старайтесь хранить константы особенно строковые в Flash памяти (память, где хранится прошивка). Если для Arduino с ее прекрасными 2 КБ ОЗУ не вызывает сомнений зачем так делать, то в случае с ESP-32 может показаться что там много оперативной памяти, но всякие веб-серверы и буферы данных, убедят вас в обратном. Может оказаться так что у вас будут случайные зависания из-за нехватки ОЗУ (такие баги довольно тяжело отслеживать). Что бы избежать этого вы можете пользоваться различными способами хранения констант в Flash памяти, характерными для вашей платформы – например для Arduino это макрос F()
или модификатор PROGMEM
, а ESP по умолчанию переменные обозначенные как const
хранит в Flash памяти.
Библиотеки тоже могут вас обмануть – например вы можете найти какую-то «легкую» библиотеку, а потом выяснится, что она работает хуже, чем та, что казалась громоздкой на вид, но написанная более квалифицированными людьми. Не надо относится с недоверием ко всем библиотекам, просто будьте более бдительными при использовании чужого кода.
Так же не стоит забывать про правильное объявление типов переменных, не зачем занимать 4 байта (int) если вам нужно всего 255 значений (один байт). Для хранения различных состояний неплохо подходят перечисления (Enum
), так как это всего лишь цифры, но уровень абстракции позволяет с ними комфортно работать. Иногда может показаться что эта экономия лишняя, но поверьте недостаток памяти вы встретите тогда, когда будете меньше всего этого ожидать.
Алгоритм работы танка
Это рабочие циклы в общих чертах. Мои алгоритмы нельзя назвать точным описанием того, что происходит на самом деле, для этого лучше смотреть код, я описываю лишь саму суть происходящего.
Защита от сбоев
Так как багов и зависаний не избежать, особенно в процессе отладки, пришлось сделать несколько элегантных костылей и назвать это «защитой от сбоев».
Следящие собаки (Watchdog). Есть такая штука как Watchdog, это аппаратный таймер, который все время считает в обратную сторону, и если дошел до нуля, то перезагружает микроконтроллер. В нормальном режиме работы, микроконтроллер должен периодически сбрасывать Watchdog приводя его время в изначальное состояние. Если вдруг микроконтроллер задумался и не успел сбросить, собака (Watchdog) дёрнет за рубильник перезагрузки – просто и эффективно.
На Arduino может резко закончится ОЗУ. Связано это с двумя факторами: радиус кривизны моих рук и использование библиотек. Мне не хотелось городить свои велосипеды (переписывать библиотеки), да и зависания были эпизодическими. Учитывая, что Arduino перезагружается быстро (пара сек), а если убрать мой код, в который специально вложены задержки, то еще быстрее. Я решил поставить собаку (таймер), которая бы следила бы за платой и в случае чего перезагружала бы плату. К сожалению, в Arduino Nano так реализован родной загрузчик что моя плата ушла бы в вечные перезагрузки (Arduino WDT bootloop). Можно это исправить, загрузив другой загрузчик (например optiboot), но это слишком скучное решение поэтому я решил организовать собаку при помощи ESP-32.
На ESP все гораздо скучнее чем на Arduino, там две защиты от сбоев. Первая для защиты от нехватки ОЗУ при интенсивной передаче данных – обычный watchdog на 4 секунды. В случае зависания плата будет перезагружена, а скорость готовности к работе после включения позволяет даже не заметить обрыва связи по Wi-Fi (не требуется переподключение).
Вторая – защита от низкого питания (brownout detector) была выключена. Сделано это для того, чтобы в условиях 5В напряжения минус падение напряжения на диоде, была возможность поработать подольше. Теперь в случае реального зависания из-за нехватки питания, плата зависнет намертво или может что-то забаговатся, но это компенсируется программной защитой от перегрузки двигателей (подробнее ниже) и самое главное – увеличенным сроком работы от батареи, поскольку детектор имеет немного завышенный порог срабатывания.
Защита от перегрузки двигателей
Не смотря на название эта программная защита не защищает двигатели, а защищает бортовую сеть от просадки напряжения до критического уровня. Поскольку двигатели являться самими большими потребителями энергии на танке, то я сделал защиту, которая при напряжении ниже определенного уровня – останавливает двигатели (уменьшая тем самым потребления тока), это спасает от большинства перезагрузок или зависаний по питанию. При желании эту защиту можно отключить, но тогда есть риск намертво зависнуть и потерять управление.
Алгоритм реализован на Arduino, напряжение измеряется ее внутренним АЦП, он имеет следующий вид:
С некоторой периодичностью (5 мс) замеряется напряжение на батареи.
Если напряжение ниже порога, и в прошлое измерение не было такого, то просто запоминается этот факт.
Если напряжение ниже порога, и в прошлом измерении тоже было ниже, то срабатывает защита – двигатели останавливаются. На терминал управления отправляется сообщение от том, что была сработана защита, пищалка издает характерный звуковой сигнал.
Я пробовал смягчить эффект просадки напряжения от переходных процессов (в момент смены стороны движения), путем плавной раскрутки двигателей, но это не дало ощутимого эффекта (возможно на больших двигателях это дало бы лучший результат), плюс потерялась динамика управления поскольку добавилась задержка во времени пока раскрутятся движки.
Звуковые сигналы
Звуковые оповещения – классная штука, позволяют мне знать, что с танком что-то произошло или же он готов к работе. Поскольку для генерации звукового сигнала требуется аппаратный таймер, то если танк движется – один из двигателей перестает получать ШИМ сигнал. Для устранения нежелательного движения перед тем, как пикнуть танк останавливается.
Всего у меня 4 звуковых сигнала:
«Оповещение» – самый громкий, для разгона зевак по улице (что б не задавили танк), этот сигнал можно вызывать вручную с терминала управления.
«Предупреждение» – просто что-то произошло, но не критично, например остановка двигателей из-за низкого напряжения.
«Ошибка» – что-то сломалось так, что танк уже не может функционировать, без вмешательства или перезагрузки.
«Хорошо» – значит, что все отлично, на данный момент используется как индикатор того, что танк готов к работе.
Все сигналы состоят из набора четырех частей. Каждая часть хранит частоту и длительность звучания, специальная функция переключает частоты во время звучания сигнала. Такая система оповещений простая в реализации и позволяет легко масштабироваться.
Аппаратная реализация пищалки
В железе пищалка представляет собой обычный зуммер (пьезоизлучатель) подключений к Arduino через биполярный транзистор (базу не помешало бы подключить через резистор). Переключатель нужен для отключения звуковых сигналов – бесшумный режим.
Управляющий терминал
Это приложение, которое обеспечивает: управление движением, просмотр данных с датчиков, проведение диагностики и настройки танка. Приложение было сделано при помощи игрового движка Unity. Данное решение я могу обосновать как «just for fun». Выбор Unity обладает определенной избыточностью и костыльностью решений (из-за того, что движок не предназначен для такого).
Функционал приложения состоит из:
Главный экран, на котором расположены кнопки управления движением танка, кнопки навигации по окнам приложения, верхней панели с данными датчиков и вспомогательной информации.
Верхняя панель содержит данные с основных датчиков: скорость, расстояние до ближайшего препятствия (ультразвук), наклон танка, напряжение и уровень заряда батареи. Так же там есть уровень связи с повторителем, индикатор качества связи, последняя команда движения, которая была отправлена на танк и количество полученных кадров с камеры за секунду.
Окно журнала (лог), куда Arduino, ESP и само приложение умеет записывать всякие события – удобно при отладке.
Кнопка запуска акустического оружия подавления – звуковой сигнал оповещения.
Окно настроек – можно подрегулировать масштаб видео, перезапустить стрим, вкл/выкл защиту от перегрузки, автоматическую настройку видео, а также настроить качество, разрешение и усиление видеокамеры.
Окно телеметрии – вывод данных со всех датчиков и качество связи.
Алгоритм работы приложения:
Поиск танка в Wi-Fi сети, если найден – установление с ним связи.
Прием и отображение видео. При необходимости качество видео автоматически регулируется.
Прием данных с датчиков.
Прием данных в журнал (лог).
Если есть команды управления – отправка их на танк.
В случае обрыва связи, будет предпринята попытка заново установить связь.
Установление связи терминала с танком. Есть три режима соединения с танком:
«Напрямую» – танк становится точкой Wi-Fi, к нему подключается терминал управления (смартфон).
«Повторитель» – отдельная плата ESP8266 с внешней антенной, разворачивает точку Wi-Fi. К ней подключаются танк и терминал управления.
«Нет соединения» – ничего не происходит.
При поиске танка, терминал периодически посылает сигналы через WebSocket на два IP адреса: адрес танка при режиме «Напрямую» и адрес при режиме «Повторитель», если с какого-то адреса приходит ответ, значит танк найден и выставляется соответствующий режим.
Почему WebSocket для поисковых сигналов?
Потому что по HTTP запросу если нет ответа срабатывает исключение по таймауту (особенность Unity), которое нельзя обработать, это ни на что не влияет, но при отладке меня бесит. Если же отравлять стандартный Ping, это будет работать, но в Android нет. Там Ping сходит с ума, и может возвращать ответ и даже значения задержки (абсолютно случайное) даже если такой сети не существует, а телефон отключен от всех возможных интерфейсов. На компьютере такой проблемы нету – видимо какой-то баг на Android. Поэтому здесь я применил такой элегантный хак через WebSocket.
После установления режима связи, соединение периодически проверяется отправкой HTTP запроса, если есть ответ значит все хорошо, если нету, то все соединения прерываются и начинается процесс поиска танка заново.
Определитель качества связи
Как только танк вышел на рабочий режим («Напрямую» или «Повторитель»), на терминале запускается Ping который периодически отправляет сигналы на танк и возвращает задержку. Тут записывается минимальная и максимальная задержка. Так же сохраняется значения последних 15 отправленных Ping, по ним высчитывается средняя задержка и соотношения отправленных к принятым.
На главном экране приложения есть индикатор (цветной квадрат), возле которого выводятся краткие данные по качеству связи и меняется цвет индикатора: Зеленый – Хорошо; Желтый – Потери; Красный – Нет соединения. Эта нехитрая система позволяет быстро оценить состояние канала связи.
Управление движением танка
Изначально у меня была идея сделать управление танком при помощи двух виртуальных джойстиков. От этой идеи было решено отказаться так как двигатели весьма маломощные, и вместе с редуктором не позволяют развивать большие скорости, то есть попросту нету диапазона регулирования скоростей – максимальная скорость мала. Но я уверен, что, если бы танк мог бы развивать внушительные скорости, то это было бы круто – можно было бы плавно развивать скорость и выделываться дрифтом на танке.
На моей же тихоходной танкетке оказалось достаточно 8 направлений движения: влево, вправо, вперед, назад и по диагоналям для поворота танка на ходу. Каждой стороне движения (включая стоп) соответствует цифра от 0 до 8.
Как только изменяется состояние кнопок управления, на танк посредством HTTP GET запроса отправляется цифра, обозначающая сторону движения. Каждые полсекунды команда движения повторно отправляется на танк. В случае движения танк ожидает что каждая команда будет повторно отправлена не позже, чем через одну секунду, если же команды нету, то он останавливается. Команда «СТОП» повторяется всего три раза (если даже не дойдет, танк остановится сам).
Таким образом для движения танка необходима постоянное подтверждение команд с терминала, в случае их отсутствия танк автоматически прекращает движение. Эта избыточность позволяет достичь гарантии доставки команд движения и избежать забавной ситуации, когда танк движется, а вы не можете его остановить, потому что оборвалась связь.
Коммуникации
Внешняя связь
Вы можете использовать различные протоколы связи для управления своей техникой. Это может быть классический радиоканал, Wi-Fi или Bluetooth. У каждого есть свои плюсы и минусы, я же использовал Wi-Fi поэтому буду писать про него.
Причины почему я выбрал Wi-Fi:
Мне нужно было передавать данные, возможно в будущем довольно большие объемы.
Хотел управление (с передачей видео) в радиусе примерно 30 метров на улице.
Хотелось управление со смартфона.
Сама по себе технология мне нравится.
Учитывая, что на смартфоне не так и много радиоинтерфейсов, обычно это: NFC, GSM, Bluetooth и Wi-Fi, то только последний обладает нужными характеристиками. Bluetooth тоже неплохое решение если не надо передавать что-то вроде потокового видео.
Wi-Fi на танке работает в двух режимах «Напрямую» и «Повторитель». В режиме «Повторитель» танк и смартфон подключаются к другому микроконтроллеру (ESP8266), который выполняет роль Wi-Fi роутера. Сделано это для того, чтобы увеличить дальность связи, которая достигается несколькими вещами:
Внешней антенной повторителя – эта антенна обладает лучшими качествами чем та, что в смартфоне.
Физическим размещением повторителя где-то между смартфоном и танком.
По большому счету повторитель нужен для того, чтобы уменьшить влияние слабых Wi-Fi возможностей смартфона. Повторитель увеличивает радиус дальности связи примерно в 1.5-2 раза чем подключение напрямую. Добавление дополнительного элемента в цепочке передачи данных также увеличивает задержку примерно на 10-15 мс.
Почему Wi-Fi точка создается не на смартфоне?
Таким образом я могу контролировать настройки Wi-Fi. На смартфоне, к сожалению, нельзя подробно настроить точку, при этом у разных производителей, свое виденье настроек по умолчанию, из-за этого нет гарантии одинаковой работоспособности на разных смартфонах. Но есть и плюсы в решении развернуть точку на телефоне, например легкость доступа из сети Wi-Fi, в мобильную сеть (Интернет), то есть танком можно управлять через удаленный веб сайт (я так делал в одной из версий своего танка).
Методы улучшения Wi-Fi связи:
ESP-32 работает в Wi-Fi сети на диапазоне 2.4 ГГц, значит все что на этих частотах и не наш полезный сигнал, является нам помехой. Об этом надо помнить, например в некоторых, очень зашумленных местах ваше устройство будет работать гораздо хуже, чем могло бы.
Внешняя антенна вместо интегрированной. Для стабильной и далекой связи, родная антенна обладает не лучшими характеристиками. Я использовал внешнюю антенну от старого роутера на 5 дБ (родная 2 дБ).
ESP-32 поддерживает три стандарта Wi-Fi: 802.11b; 802.11g и 802.11n, каждый стандарт обладает своей скоростью передачи данных, и условиях при которых они передаются, например чувствительностью уровня сигнала. Зная свои потребности в необходимой скорости, вы можете поменять стандарт на более «простой», выиграв при этом в чувствительности. Например, я использую на своем танке 802.11b, который обеспечивает всего 11 Мбит/с (для передачи данных и видео достаточно), но увеличивает чувствительность приема.
Если вы используете стандарт Wi-Fi: 802.11n, имеет смысл уменьшить ширину полосы пропускания с 40 МГц до 20 МГц. Уменьшение ширины также уменьшает теоретическую максимальную скорость со 150 до 75 Мбит/с (вряд ли такие скорости понадобятся и микроконтроллер будет с ними справляться). Из-за меньшего рабочего диапазона частот, уменьшается вероятность наложения вашего сигнала с каким-либо еще – меньше помех. На стандартах Wi-Fi: 802.11b/g, такой фичи еще не было, поэтому там нет смысла напрягаться.
Wi-Fi на ESP-32 использует диапазон частот от 2400 МГц по 2484 МГц. Для того что бы устройства не мешали друг другу они работают на разных каналах (частотах). Если ваше устройство работает в месте, где много других Wi-Fi сетей, возможно имеет смысл перейти на другой канал, чтобы избежать взаимных помех. На танке я выбрал 11 канал как самый менее популярный.
По умолчанию на ESP-32 включен режим энергосбережения (сна) для Wi-Fi. Это прекрасное решение для каких-то IoT штучек, но плохое для устройств, где нужен максимальный отклик. Из-за этого режима, Wi-Fi как бы иногда «отдыхает», видно это по большим случайным задержкам. Отключить легко –
WiFi.setSleep(false)
. Выключение этого режима, дает ровный стабильный отклик по сети, при условии отсутствия других проблем.Если вы используете одновременно Bluetooth и Wi-Fi, то надо помнить, что ESP-32 обладает одним радиомодулем. Хоть эти две технологии и работают в одном частотном диапазоне 2.4 ГГц, но все же их реальные рабочие частоты разнесены на десятки МГц. Поэтому при одновременной работе на этих двух технологиях ESP будет переключаться с одной связи на другую, вызывая задержки.
Принцип разворачивания Wi-Fi на танке:
Вначале танк ищет, Wi-Fi точку повторителя, если она есть, он успешно к ней подключается.
Если при каких-то обстоятельствах соединение с повторителем разорвется, танк попробует снова с первого пункта.
Если повторитель не найден, танк разворачивает свою точку Wi-Fi.
Для любителей далекой связи
ESP-32 поддерживает Long Range мод, это протокол разработанный Espressif Systems, который позволяет сделать связь еще дальше, обладает увеличенной чувствительностью даже по сравнению с 802.11b. Разработчики говорят про связь на 1 км, и даже больше с применением направленных антенн. Но данный мод поддерживается только платами ESP-32.
Забавный аппаратный баг антенны ESP-32
Встроенная антенна может быть плохо согласована. Это проверить очень легко – попробуйте пинговать ESP или смотрите видео с нее, если в этот момент к антенне приложить палец и связь улучшается (меньше задержки или больший FPS), значит антенна низкого качества. Как я понял такое встречается не часто и всему виной моя любовь к дешевым комплектующим. В сети есть решения вроде наклеить кусочек антистатического пакета или что-то подобное, но на деле эти решения не очень эффективные. В попытках с этим разобраться я потратил много часов и поменял антенну на внешнюю, я даже обклеил корпус ESP фольгой, хотя это больше, чтобы уберечь ее от случайных помех на улице, а еще это красиво.
Итого – танк имеет настроенный для его вида трафика Wi-Fi и два режима работы. Первый «напрямую» – для быстрого разворачивания, с меньшим радиусом работы и минимальной задержкой. И второй режим с повторителем, который хоть и добавляет задержку, позволяет работать танку на дальних дистанциях и в условиях сильно зашумленного эфира.
Протоколы передачи данных
Обмен данных между танком и терминалом управления происходит через три протокола: HTTP, WebSocket (WS), Server-Sent Events (SSE).
HTTP – начать сеанс связи может только клиент, сервер не может обратится сам первый к клиенту. По нему передаются данные с датчиков, команды управления и конфигурации.
WebSocket – позволяет передавать данные в две стороны от сервера клиенту и наоборот. Используется в качестве начального «ping» для установления режима связи и для передачи данных с ESP и Arduino в журнал.
SSE – работает по принципу подписки клиента на сервер, но работает только в одну сторону, от сервера к клиенту. Передает на терминал некоторые данные с датчиков, которые быстро обновляются.
В качестве основного протокола используется HTTP. WebSocket и SSE я выбрал для «поиграться». Поэтому сценарии использования немного надуманы, можно было бы легко обойтись и без них. К тому же родной асинхронный веб сервер довольно быстро работает.
Выбор WS и SSE обусловлен двумя факторами:
Позволяют передавать данные от сервера к клиенту напрямую. В HTTP, пришлось бы клиенту опрашивать сервер или городить свой велосипед.
В теории работают быстрее HTTP, за счет меньшей избыточности данных и лишних сеансов установления связи.
Скорость обновления данных
На ESP-32 есть определенный лимит количества данных, которые она может обработать – примерно 15 пакетов/с. В случае превышения этого предела, данные отбрасываются с записью в UART «ERROR: Too many messages queued». Заметьте тут больше влияет количество соединений за секунду, чем объем данных.
Так как я хотел передачу побыстрее, я решил попробовать обойти это через WS и SSE. Трафик у меня почти всегда однородный, поэтому тестировалось все в одинаковых условиях. Вот какие результаты у меня получились:
WebSocket – в лимит упирается аналогично HTTP серверу. Преимуществ кроме как передачи от сервера к клиенту напрямую не будет.
SSE – позволяет немного увеличить лимит передачи на 3-5 пакетов/с.
Оба протокола работают менее стабильно чем HTTP сервер. Например иногда, ESP-32, может перезагрузится или зависнуть, когда через них идет интенсивный трафик, как напоминание того, что «нечего обходить лимиты». Если не выделываться, то пользоваться можно.
Скорость отклика у всех трех протоколов одинаковая, нельзя сказать, что HTTP, медленнее чем WS или SSE при передаче таких же данных. Это значит, что для управления или чего-то другого что требует низкой задержки, более важна конечная реализация, чем выбор какого-то из этих протоколов.
Возможное решение лимита пакетов
Скорее всего лимит пакетов возможно увеличить путем редактирования конфигурации проекта (там есть размер буфера, и лимит очереди сообщений). Но для связки Arduino фреймворка и ESP-32 используются предварительно скомпилированный код ESP-IDF. Поэтому внести туда изменения очень сложно.
Принцип передачи данных
Данные передаются в виде строк. Часть из них в таком виде как есть, другая упаковывается в JSON.
На ESP-32 поднят асинхронный HTTP сервер. Он общается посредством HTTP GET запросов. Терминал передает команды управления запросом, в параметре которого находится цифра, которая соответствует стороне движения танка. Настройки камеры или Arduino передаются похожим образом. Данные с датчиков терминал опрашивает периодически, получая в ответе от ESP последние принятые показания в JSON формате.
WebSocket – передает терминалу служебные сообщения для журнала (лог) и подтверждения того что настройки Arduino были приняты.
SSE – используется для одной цели: передачи на терминал данных быстро обновляемых сенсоров сразу же как только они были приняты от Arduino.
Передача данных с датчиков
Датчики разделены на две группы:
Медленные датчики – обновляються с определённым интервалом и передаются от Arduino к ESP. Терминал управления (приложение) периодически запрашивает эти данные. Частота обновления раз в две секунды. Передача через HTTP GET запросы.
Быстрые датчики – обновляются с определенным интервалом (быстрее чем, медленные датчики) и передаются Arduino к ESP, после этого сразу же отправляться на терминал управления. Частота обновления 2.5 раза в секунду. Передача через SSE.
Разделение датчиков на медленные и быстрые, позволяет передавать определенные данные, которые должны быть немедленно или как можно чаще доставлены, отделяя их от тех которые могут подождать. Отправляя такими двумя кусками «быстрых» и «медленных» данных, уменьшается общее количество пакетов и время на отправку/прием и обработку этих данных, чем если их отправлять по отдельности.
Внутренняя связь. Arduino – ESP
Для связи между платами Arduino и ESP-32-Cam используется протокол UART. Сначала я делал свой велосипед для передачи данных, но, когда этих данных стало много я понял, что намного лучше использовать готовое решение.
Таким решением стала прекрасная библиотека SerialTrasfer, она берет на себя «грязную» работу по передаче данных»: организации правильной передачи пакетов, подсчета контрольных сум и позволяет передавать простые типы данных и структуры, как раз то, что мне и нужно, поскольку я храню данные с датчиков в структуре.
Хотя у SerialTrasfer заявлена поддержка программного UART'а (Software Serial), у меня не заработало. Из-за этого и учитывая интенсивный трафик, я оставил аппаратный UART на Arduino для передачи данных. Поэтому для перепрошивки Arduino, ее надо вытянуть из танка или отключить ESP (мешает прием данных по UART).
ESP-32 имеет на борту несколько аппаратных UART, которые к тому же в отличии от Arduino могут легко переконфигурироватся на другие выводы. UART_0 остался для отладки и прошивки, а UART_1 для связи с Arduino.
Скорость UART для передачи данных установлена в 76800 бод/с. На такой скорости возникает меньше всего ошибок при передаче из-за тактовой частоты микроконтроллеров 16 МГц у Arduino и 320 МГц на ESP. Такое решение позволяет с большой степенью гарантировать доставку корректных данных между ESP и Arduino, отказавшись от их проверки и возможного дублирования.
Из-за разной архитектуры микроконтроллеров Arduino Nano (ATmega328) – 8 бит и ESP-32 – 32 бит, необходимо использовать выравнивание данных в памяти, чтобы они (перечисления, структуры) были корректно приняты на обоих платформах. Я использую для этого атрибут «__attribute__((__packed__))».
Учитывая разные напряжения логичных уровней ESP-32 (3.3В) и Arduino (5В), UART между ними подключен через конвертер.
Принцип передачи данных по UART:
Данные передаются парами: «Тип данных» и «Полезные данные», причем последние могут отсутствовать, ведь иногда достаточно лишь наличие самого факта передачи, например сигнал о том, что надо обновить wathdog таймер.
Всего 8 типов данных: «Показания датчиков», «Команда управления», «Тип звукового сигнала», «Wathdog», «Сообщение в журнал (лог)», «Показания быстрых датчиков», «Настройки Arduino», «Считать настройки Arduino».
На отправляющей стороне готовится сообщение вначале которого стоит тип данных, за ним данные, если они нужны.
Приемная сторона принимает сообщение и в зависимости от типа сообщения, может быть: какое-то действие или распаковка «посылки» в виде полезных данных.
Такая простая система передачи данных легко масштабируется, позволяя передавать различные виды данных и вносит небольшую избыточность поскольку типы данных всего лишь перечисления (Enum) то есть обычные цифры.
Можно использовать не только UART, а например SPI, или I2C, или другой протокол передачи данных на произвольных выводах. Я же выбрал UART по причине его хорошей документации, легкости работы с ним, и то, что он все равно нужен был бы – для отладки.
Датчики
Датчиков существует огромное количество на все случаи жизни, они нужны для измерения всех существующих и несуществующих физических величин. Это «глаза и уши» вашего устройства. С помощью них ваше устройство может воспринимать реальность и на основе этого с ней взаимодействовать.
Про работу с датчиками в сети есть довольно много информации. Опишу лишь то, что я считаю важным при выборе датчика:
Диапазон, точность измерений.
Вид выдачи информации: цифровой или аналоговый. В зависимости от «крутости» датчика он может сразу выдавать готовый (цифровой) результат по какому-то протоколу. Если ж датчик попроще, то он выдает в сыром (аналоговом) виде, что требует дополнительной обработки на приемной стороне и требует наличие свободного АЦП.
Если датчик цифровой, то его рабочий протокол (интерфейс). Ведь при прочих равных некоторые интерфейсы гораздо проще реализовать чем, другие.
На танке установлен ряд датчиков:
Модуль DHT-11 термометр и гигрометр. Не очень точный, зато дешевый и с ним легко работать. Я считаю, что на танке (с телеметрией) обязан быть классический датчик – термометр.
Датчик Холла A3144, в роли тахометра. На ведущей звездочке левой гусеницы установлен маленький неодимовый магнит, напротив нее со стороны корпуса установлен датчик Холла. Датчик реагирует на каждый проход магнита над ним и таким образом считывает количество оборотов ведущей звездочки. Зная диаметр звезды, можно узнать на сколько именно продвинулся танк и с какой скоростью. Точность этой импровизации, оставляет желать лучшего, но зато прикольно работает.
Барометр BMP-280. Позволяет получать атмосферное давление и на основе этого высоту над уровнем моря. Датчик имеет множество режимов работы на все случаи жизни, но немного сложный в настройке.
Модуль акселерометр и гироскоп MPU-6050. Хороший, быстрый датчик для измерения ориентации в пространстве, использует сложную математику для работы, но это компенсируется наличием библиотек.
Ультразвуковой дальномер US-025 (аналог HC-SR04). Используется для вывода расстояния до ближайшего препятствия спереди танка.
Забавный баг с шиной I2C
Некоторые датчики (MPU-6050, BMP-280) подключаются по I2C. Иногда из-за этой шины микроконтроллер Arduino Nano может зависать намертво. Я смотрел осциллографом что там творится на шине, увидел вместо примерно ровных прямоугольных форм, ужасные искаженные фронты сигналов, которые больше напоминали треугольники или даже случайный шум, надо было очень постараться что бы понять, что там что. Я проверил на нескольких платах и без танка, результат был тот же. Я так и не понял из-за чего это возникает. Возможно мои китайские подделки Arduino, возможно что-то другое. Помогла сильная подтяжка шины к питанию через 1.3 кОм.
Показания с датчиков могут обрабатываться прямо на Arduino или ESP, а для тяжелых расчетов обработка на уровне приложения и на основе этого отправка команд управления на танк. В данный момент датчики не несут какой-то практической цели и установлены для обучения и как основа для дальнейших танковых модернизаций, а также придают танку вид «серьезного» устройства.
Камера, прием видео
На модуле ESP-32-Cam установлена 2Мп видеокамера OV2640. Камера может захватывать окружающий мир в потрясающем диапазоне разрешений от 96x96 до 1600x1200. На танке я же использую три разрешения: HVGA – 480x320; VGA – 640x480; SVGA – 800x600. Выбор этих разрешений обусловлен: быстрым формированием и передачей такого размера кадра, что дает стабильные 25 FPS, разрешения выше уже слишком большое для стабильного фреймрейта, а ниже – слишком теряется качество картинки.
В основу кода (тот, что на ESP) для работы с камерой взят стандартный пример «CameraWebServer». Для камеры поднят отдельный HTTP сервер, который при подключении к нему отдает клиенту бесконечный поток картинок в формате JPEG с камеры – получается MJPEG стрим. Сервер камеры (не путать с сервером для передачи данных) может работать одновременно только с одним клиентом, но я видел в сети примеры работы и с большим количеством клиентов, мне такое не нужно поэтому я не заморачивался.
Прием кадров не сложная задача ведь поток MJPEG, это бесконечная передача JPEG изображений, достаточно вылавливать специальные маркеры (байты). Маркер всегда начинается с байта 0xFF, за ним следует байт, который обозначает тип маркера. Маркеры могут обозначать разное, но нас интересуют два типа маркеров начало кадра – 0xD8 и конец кадра – 0xD9.
Unity с коробки не умеет поддерживать MJPEG поток. Поискав по сети, я нашел примеры кода, часть из них не работала, или была устаревшей, или имели утечки памяти, платные решения я не рассматривал. Потыкав все возможное что я нашел, я понял, что ничего адекватного для моей задачи нету. Решено было городить свой велосипед. Так как я делал все в Unity я решил использовать их метод UnityWebRequest и стандартный механизм «многопоточной» работы с ними через сопрограммы (Coroutine).
Принцип приема изображения простой:
Я сделал свою реализацию обработчика (DownloadHandler), который просто дергает каждый раз событие передавая туда кучу байт (JPEG) в тот момент, когда пришел кадр.
Дальше кадр попадает в метод (LoadImage), который пытается преобразовать JPEG байты в текстуру (Texture2D).
Если у метода получилось, то текстура натягивается на объект на сцене, то есть отрисовывается и мы ее видим на экране.
Детектирование битого кадра
Из-за приема битого кадра метод LoadImage может не загрузить текстуру. И хотя он должен в этом случае возвращать false, на деле он почему-то всегда возвращает true. Но я воспользовался тем, что, когда он не может загрузить текстуру он выдает вместо нее белую текстуру с красным вопросительным знаком, она размером ровно 8 на 8 пикселей. А я такой размер в работе танка не использую, поэтому простая проверка на размер текстуры на выходе дает понять, что пришла битая текстура и избежать мечты эпилептика – внезапно появляющейся белой текстуры, которая, по сути, будет мигать в реальных условиях. Кстати, хитрые Web-браузеры умеют в таком случае отрисовывать ту часть кадра что успешно пришла, но я так не умею поэтому обхожусь таким элегантным хаком.
Кадровая частота
Сама по себе камера довольно быстрая и честно выдает заявленные производителем 25 кадров в SVGA разрешении, но есть нюансы:
Необходимо наличие PSRAM – это внешняя ОЗУ, в ней могут хранится кадры. Без нее нельзя будет выбрать более высокий размер разрешения и кадровых буферов. Большинство плат ESP-32-Cam уже имеют такую память.
Частота XCLK сигнала – я не знаю точно, за что именно отвечает этот параметр. Как я понял тактирующий сигнал для каких внутренних нужд камеры. Если я правильно понял из документации, то он может быть в диапазоне от 6 до 24 МГц. Но в интернете советуют выставлять его 10 или 20 МГц. У себя я поставил 20 МГц. С данным параметром надо быть аккуратным, камера может не корректно работать с некоторыми разрешениями.
Количество кадровых буферов – позволяет увеличить FPS, тот который камера снимает. Для увеличения числа данных буферов как раз таки и требуется наличие PSRAM. По идее каждый буфер кратно увеличивает FPS. Я использую 2 буфера.
Качество JPEG – степень сжатия изображения, может быть в диапазоне от 0 до 63, но на практике при значениях ниже 10, кадр будет обрезаться из-за его большого размера при передаче по сети. Я же в основном регулирую в диапазоне от 16 до 63 качество. Этот параметр позволяет значительно увеличить FPS при плохом соединении, ценой квадратных артефактов на изображении.
Даже при хорошо настроенной камере, на приемной стороне вы можете увидеть ужасающе низкий FPS, это происходит, потому что из-за сетевых задержек кадры просто не успевают смениваться с нужной частотой. От состояния канала связи очень сильно зависит FPS, даже больше, чем от правильной настройки камеры. Потому что пока вы можете принимать по сети 5 кадров, то камера хоть 60 их наснимает больше вам не передаст. Поэтому надо очень внимательно отнестись к организации связи.
Настройки видео
У видео есть много настроек, некоторые из них я сделал что б можно было регулировать прямо из приложения:
Разрешение – три на выбор HVGA, VGA, SVGA.
Качество – уровень сжатия JPEG.
Усиление (Gain ceiling) – позволяет усилить сигнал с камеры для лучшей видимости в условиях недостаточной освещенности, взамен дарит кучу шума в кадре.
Автонастройка видео
Возможность передавать качественный видео сигнал, а главное стабильный фреймрейт падает по мере ухудшения сигнала. Что б не крутить каждый раз руками настройки камеры я сделал функцию, которая сама крутит настройки вместо меня. Принцип работы простой:
Зная количество кадров, которые приходят за секунду можно узнать FPS.
Как только FPS падает ниже определенного порога, снижаем качество картинки (JPEG quality), если понижать качество уже некуда, то понижаем разрешение.
Если FPS выше определённого порога, то все происходит точно так же только качество и разрешение повышаются.
Работает хоть и не всегда хорошо, но достаточно эффективно. Можно улучшить эту систему. Например, более точно определять момент «плохого видеосигнала» и расширить диапазон разрешений.
В моем случае стоит самая бюджетная версия камеры, для тех, кто будет делать что-то подобное с видом от первого лица (FPV), рекомендую купить версию камеры с линзой в 120 градусов обзора, потому что обычная с ее 66 градусами весьма печальна – банально не видно, что находится рядом.
Исполнительные механизмы
Это то, что делает ваше устройство живым, например на моем танке это два мотора, которые приводят его в движение. Так же это мог бы быть какой-то лазер и сервоприводы для его наведения.
Зачастую исполнительные механизмы потребляют значительную часть бортовой энергии. Поскольку микроконтроллер может пропускать через себя лишь маленький ток, управлять такими устройствами надо через специальные «переходники» – драйверы.
Драйвер — это плата, к которой подключается микроконтроллер, исполнительный механизм и питание. Суть в том, что микроконтроллер посылает только сигналы управления в духе «сделай то или это», а драйвер сам разбирается как надо правильно привести в действие исполнительный механизм. Можно и самим генерировать необходимый сигнал с микроконтроллера, но тогда придётся сделать всю обвязку из электронных компонентов и реализовать алгоритм управления. Куда эффективнее и быстрее использовать готовое специализированное устройство – драйвер.
Для танка я использовал драйвер L298N. Можно было бы использовать более новые и эффективные драйвера. Но мне нравится использовать такое старье, которое имеет брутальный вид и большой, а главное теплый радиатор после работы – это придает дух танку и отлично вписывается в его дизайн «собрано с того, что было на столе».
Всего есть 9 команд управления:
«Движение»: вперед, назад.
«Поворот»: влево, вправо.
«Движение с поворотом»: вперед и влево, вперед и вправо, назад и влево, назад и вправо.
«Стоп».
Учитывая, что на танке установлены немного не одинаковые двигатели, то для прямолинейного движения у них выставлены разные максимумы ШИМ сигналов (максимальные скорости вращения двигателей).
Принцип управления двигателями такой:
Команда «Стоп» – драйверу посылается сигнал остановить двигатели.
Команда «Движение» – драйвер крутит оба двигателя вперед или назад.
Команда «Поворот» – двигатель со стороны поворота вращается назад, а второй двигатель вперед. Таким образом достигается быстрый разворот на месте.
Команда «Движение с поворотом» – двигатель гусеницы противоположный повороту работает на 100%, а двигатель со стороны поворота понижает обороты, например 70%. Получается плавный поворот в сторону тормозящей гусеницы.
Можно применять более агрессивную тактику тормоза, например реверсивное движение или блокировку мотора, но учитывая маленькую массу моего танка и почти полное отсутствие инерции, это избыточно. К тому же редуктор сопротивляется самопроизвольному движению, а еще такой тормоз кратковременно потребляет очень много энергии.
Для поворота можно заглушить (остановить) двигатель гусеницы со стороны, на которую идет поворот. Таким образом можно добиться красивого поворота на месте по радиусу вокруг гусеницы-тормоза.
Как видите нету ничего сложного в управлении исполнительным механизмом. Необходимо лишь подобрать драйвер, который будет подходить под ваши задачи, в зависимости от потребления тока и типа устройства, которым вы хотите управлять.
Фото и видео презентация
Бонус – прототип и первая версия танка
Итоги
Весь исходный код прошивок Arduino, ESP-32 и Unity приложения я выложил в репозитории на GitHub, не удивляйтесь если найдете «интересные решения». Моя цель показать вам сам принцип, лучше всего это разобраться самому и на основе полученных знаний сделать что-то свое.
Написание этой статьи помогло мне разложить по полочкам весь тот опыт что я получил при создании танка. И запомнить решения всех тех костылей, багов и недоработок, которые возникли в процессе, и которых вы сможете избежать что бы найти свои уникальные проблемы и поделится ними с сообществом. Я очень надеюсь, что я смогу кого-то вдохновить на создание подобной прикольной штуки.