Хотели бы вы иметь собственный танк с дистанционным управлением? В этой статье я расскажу об общих принципах танкостроения из доступных материалов.

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

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

Материалы и компоненты, которые я использовал:

  • Корпус игрушечного танка.
  • Модуль ESP-32-Cam — контроллер для Wi-Fi и камеры.
  • Arduino Nano — контроллер для датчиков и управления движением.
  • L298N — мотор-драйвер.
  • Комплект датчиков — ультразвуковой дальномер; барометр; акселерометр и гироскоп; термометр и гигрометр; Датчик Холла.
  • Две литиевые батареи, повышающий преобразователь, зарядная плата.
  • Android-смартфон с управляющим приложением.

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

Разделы статьи:

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

Разложение бака

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

Корпус и шасси

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

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

Для удобства доступа (и для красоты) я заменил верхнюю часть корпуса на откидной металлический люк, на котором находятся основные узлы танка. Под люком моторный отсек — два мотора + шестерни и аккумуляторный отсек с двумя аккумуляторами. Сама крышка вырезана из куска металла от автомагнитолы и покрашена в черный цвет, петля обычная — мебельная петля (наверное брутальное решение, но я именно такую ​​и хотел).

Корпус для ESP-32-Cam (белая коробка с антенной) представляет собой перевернутый корпус от инфракрасного датчика движения (БВ-201). Он достаточно вместительный и разделяется на две части, что позволяет легко что-то менять в нем.

Хорошее решение — получить готовую игрушечную модель, которая дает вам корпус, двигатели и шасси. Таким образом, вы можете быстро сделать прототип и легко изменить что-либо впоследствии. Имея опыт создания прототипа, вы уже знаете, чего хотите и как этого добиться.

Система электроснабжения (бортовая сеть)

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

Есть несколько способов добиться стабильного питания:

  • Создайте такие условия, чтобы нельзя было использовать больше энергии, чем может обеспечить устройство — например, программная защита или физическое ограничение.
  • Раздельное питание силовой части: двигатели и мощные потребители отдельно от интеллектуальной части: микроконтроллеры, датчики. Таким образом, при просадке напряжения в силовой части вы избежите просадки напряжения на вашем управлении — микроконтроллерах.
  • Обеспечение какой-либо краткосрочной защиты от провалов напряжения может помочь в большинстве случаев и легко реализуемо. Примером может служить конденсатор питания для микроконтроллера.

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

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

Аккумулятор танка состоит из пары литиевых аккумуляторов 18650 2000 мАч. Затем аккумулятор подключается к повышающему преобразователю DC-DC MT3608, который формирует стабильные 5,1В для бортовой сети. Запас 0,1В нужен для уменьшения влияния просадки напряжения на провода и диоды.

Все подключенное оборудование на танке питается от 5В, которое идет от стабилизатора. Те датчики, которым нужно 3,3В, питаются от стабилизатора на Arduino Nano из-за их малого потребления. Плата с ESP-32 имеет стабилизатор, который преобразует входные 5В в 3,3В, необходимые ESP.

Возле входа напряжения питания плат Arduino и ESP установлены электролитические конденсаторы с запирающим диодом. Эта небольшая емкость конденсатора обеспечивает питание микроконтроллеров во время кратковременных провалов напряжения при работающем двигателе или при разряде батарей. Без этого они бы замёрзли или перезагрузились. Эта мера продлила срок службы батареи танка примерно на 40%.

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

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

Микроконтроллеры

Для своего танка я решил разделить логику на две части. Один микроконтроллер будет обрабатывать данные с датчиков, двигать моторы и делать другие «простые вещи». Второй микроконтроллер будет управлять камерой и общаться с внешним миром через Wi-Fi.

  • ESP-32 в форм-факторе платы с камерой. Мне нужно было что-то дешевое и чтобы оно было с вайфаем и умело работать с камерой. Это лучший вариант, который я нашел.
  • Плата ATmega328p as Arduino Nano — идеальная плата по размеру, имеет много свободных контактов и все необходимые интерфейсы. Классический и надежный выбор для таких задач, как считывание показаний датчиков и управление двигателем.

Есть несколько причин, по которым я выбрал две доски:

  • Я хотел максимальной отзывчивости от Wi-Fi соединения, поэтому любая дополнительная задача на ESP давала бы ему дополнительную нагрузку, и хоть он и двухъядерный, это могло привести к дополнительным задержкам, что не является позволенной роскошью.
  • Плата ESP-32 в форм-факторе модуля ESP-32-CAM, к сожалению, имеет очень мало свободных контактов, и часть из них зарезервирована для других нужд. Это означает, что вы не можете подключить все датчики сразу.
  • Некоторые библиотеки Arduino плохо работают с ESP.
  • Мне нравится эта идея разделения обязанностей.

Забавный баг с ESP-32

Перед прошивкой ESP-32 необходимо перевести его в загрузочный режим. Это делается путем замыкания контакта GPIO0 на GND. На баке есть переключатель (красный переключатель), который переводит ESP в режим прошивки или в обычный режим. Но я столкнулся с плохо документированной ошибкой/функцией. В нормальном, рабочем режиме на этом выводе формируется какой-то особый высокочастотный сигнал, нарушения которого приводят к различным глюкам всего ЭСП. Хоть контакт и имеет внутреннюю подтяжку к питанию, но это не помогало уменьшить наводки в проводе, ведущем к выключателю (около 7 см), из-за этого были периодические зависания платы. Отсоединив провод от штыря, проблемы исчезли. Я узнал, что это была редкая ошибка (вероятно, моя плата была неисправна). Замена платы мне помогла.

Среди макетных плат или микроконтроллеров постарайтесь выбрать что-то более популярное, чтобы при необходимости можно было найти решение большинства проблем.

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

Программное обеспечение (прошивка)

Я использовал фреймворк Arduino, поэтому вы получаете единую экосистему на Arduino и ESP. В этом проекте используется платформа espressif32 версии 3.2.1, т.к. более поздние версии нарушали алгоритм выделения памяти, что может привести к перезагрузке ESP.

Алгоритм работы танка

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

Защита от ошибок

Так как баги и сбои неизбежны, особенно во время отладки, мне пришлось сделать какой-то элегантный хак, который я назвал «защитой от ошибок».

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

У Arduino может очень быстро закончиться оперативная память. Это связано с двумя факторами: моими низкими навыками программирования и использованием библиотек. Решил поставить сторожевой таймер, который бы следил за платой и в случае чего перезагружал ее. К сожалению, у Arduino Nano такая нативная реализация загрузчика, что моя плата уходила бы в вечные перезагрузки (загрузочный цикл Arduino WDT). Это можно исправить, прошив другой загрузчик (типа optiboot), но это слишком скучное решение, поэтому я решил организовать сторожевой таймер с помощью ESP-32.

На ESP все гораздо скучнее, чем на Arduino, есть две защиты от ошибок:

  • Первая защита от переполнения оперативной памяти при интенсивной передаче данных с помощью встроенного сторожевого таймера на 4 секунды. В случае зависания плата перезапустится, а скорость перезагрузки позволяет даже не заметить обрыв Wi-Fi соединения (переподключение не требуется).
  • Второй — отключился детектор браунаута. Это сделано для того, чтобы в условиях напряжения 5В можно было работать дольше. Теперь в случае реального браунаута плата будет зависать, но это компенсируется программной защитой (подробнее ниже) и самое главное увеличенным временем автономной работы, т.к. у детектора немного завышен порог.

Защита двигателя от перегрузки

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

Алгоритм защиты двигателя от перегрузки реализован на Arduino, напряжение измеряется его внутренним АЦП. Вот как выглядит алгоритм:

  • Через некоторый интервал (5 мс) измеряется напряжение батареи.
  • Если напряжение ниже порогового, а в последнем измерении такого не было, просто запоминает этот факт.
  • Если напряжение ниже порогового, а в последнем измерении тоже было ниже, срабатывает защита и двигатели останавливаются.

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

Звуковые сигналы

Звуковые оповещения — классная штука, они дают мне знать, если что-то случилось с танком или он готов к работе.

Всего у меня четыре звуковых сигнала:

  • «Уведомление» — самое громкое. Это для того, чтобы пугать людей на улицах (чтобы случайно не наступили на танк). Этот сигнал можно вызвать вручную из управляющего приложения.
  • «Внимание» — что-то произошло, но не критично, например, двигатели остановились из-за низкого напряжения.
  • «Ошибка» — что-то сломалось так, что бак больше не может функционировать без вмешательства или перезагрузки.
  • «Хорошо» — значит, все в порядке. В настоящее время используется как индикатор того, что танк готов к работе.

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

Терминал управления (приложение)

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

Функции приложения состоят из:

  • Основной экран, на котором расположены кнопки управления движением танка, кнопки навигации по окнам приложений, верхняя панель с данными датчиков и дополнительной информацией.
  • Верхняя панель содержит данные от тех же датчиков: скорость, расстояние до ближайшего препятствия (ультразвук), наклон танка, напряжение и уровень заряда батареи. Также есть индикатор качества связи, последней команды движения, которая была отправлена ​​танку и FPS камеры.
  • Окно журнала, в котором Arduino, ESP и само приложение могут записывать всевозможные события — удобно для отладки.
  • Кнопка включения оружия акустического подавления — звуковой сигнал.
  • Окно настроек — можно настроить танк, видеокамеру и приложение.
  • Окно телеметрии — вывод данных со всех датчиков.

Алгоритм работы приложения:

  • Искать танк в сети Wi-Fi, если нашли — установить с ним связь.
  • Прием и отображение видео. При необходимости качество видео регулируется автоматически.
  • Получение данных с датчиков.
  • Получение данных в бортовой журнал (журнал).
  • Если есть команды управления — отправить их танку.
  • В случае сбоя соединения будет предпринята попытка восстановить соединение.

Управление движением танка

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

На моем тихоходном танке хватило 8 направлений движения: влево, вправо, вперед, назад и по диагонали, чтобы развернуть танк на ходу. Каждой стороне движения (включая остановку) соответствует число от 0 до 8.

Как только состояние кнопок управления меняется, на танк по HTTP GET-запросу отправляется число, указывающее сторону движения. Каждые полсекунды танку повторно посылается команда движения. В случае движения танк ожидает повторной подачи каждой команды не позднее одной секунды, если команды нет, то он останавливается. Команда «СТОП» повторяется всего три раза (даже если не доходит, танк остановится сам).

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

Коммуникации

Внешняя связь

Вы можете использовать различные протоколы связи для управления автомобилем. Это может быть классический радиоканал, Wi-Fi или Bluetooth. У каждого есть свои плюсы и минусы. Я использовал Wi-Fi, поэтому напишу об этом.

Причины, по которым я выбрал Wi-Fi:

  • Мне нужно было передать данные, возможно в будущем довольно большие объемы.
  • Я хотел контроль (с видеотрансляцией) в радиусе около 30 метров на улице.
  • Wi-Fi позволяет управлять со смартфона.
  • Мне нравится сама технология.

Есть два режима подключения к резервуару:

  • «Напрямую» — танк становится точкой Wi-Fi, к нему подключается терминал управления (смартфон).
  • «Повторитель» — отдельная плата ESP8266 с внешней антенной, разворачивает точку Wi-Fi. К нему подключаются бак и терминал управления.

Мод повторителя нужен для увеличения дальности связи, что достигается несколькими вещами:

  • Внешняя антенна-репитер — эта антенна имеет лучшие характеристики, чем та, что в смартфоне.
  • Физически разместив ретранслятор где-то между смартфоном и танком.

Повторитель снижает влияние слабых возможностей Wi-Fi смартфона. Увеличивает дальность связи примерно в 1,5–2 раза, чем прямое соединение.

Способы улучшения связи по 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 МГц. Из-за меньшего диапазона рабочих частот меньше вероятность перекрытия вашего сигнала с чем-то другим — меньше помех.
  • Для того чтобы Wi-Fi устройства не мешали друг другу, они работают на разных каналах (частотах). Если ваше устройство работает в месте, где много других 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

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

Протоколы передачи данных

Данные передаются в виде строк. Часть из них упакована в формат JSON, а часть передается как есть. Обмен данными между резервуаром и терминалом управления происходит по трем протоколам: HTTP, WebSocket (WS), Server-Sent Events (SSE).

  • HTTP — только клиент может начать сеанс связи, сервер не может сначала обратиться к клиенту. Он передает данные от датчиков, команды управления и настройки.
  • WebSocket — позволяет отправлять данные в двух направлениях от сервера к клиенту и наоборот. Он используется в качестве начального «пинга» для установления режима связи и передачи данных из ESP и Arduino в лог.
  • SSE — работает по принципу клиент-серверной подписки, но работает только в одну сторону, от сервера к клиенту. Передает на терминал некоторые данные с датчиков, которые быстро обновляются.

Основной используемый протокол — HTTP. WebSocket и SSE я выбрал, чтобы набраться опыта. Итак, варианты использования немного надуманные, без них можно было бы легко обойтись. Кроме того, собственный асинхронный веб-сервер работает довольно быстро.

Выбор WS и SSE основан на двух факторах:

  • Они позволяют отправлять данные с сервера клиенту напрямую. При использовании HTTP клиент должен будет опрашивать сервер.
  • Теоретически они работают быстрее, чем HTTP, из-за меньшей избыточности данных и ненужных сеансов связи.

Скорость обновления данных на ESP-32

ESP-32 имеет определенное ограничение на объем данных, которые он может обрабатывать, примерно 15 пакетов в секунду. Если этот предел превышен, данные удаляются с записью «ОШИБКА: слишком много сообщений в очереди» в UART. Обратите внимание, что количество подключений в секунду здесь имеет большее значение, чем объем данных.

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

  • WebSocket — ограничение количества подключений аналогично HTTP-серверу. Нет никаких преимуществ, кроме прямой передачи с сервера на клиент.
  • SSE — позволяет немного увеличить лимит передачи на 3–5 пакетов в секунду.
  • Оба протокола менее стабильны, чем HTTP-сервер. Например, иногда ESP-32, могут перезагружаться или зависать при интенсивном трафике через них, как напоминание: «не заморачивайтесь с обходом лимитов». Если не переусердствовать, то можно использовать.

Скорость отклика всех трех протоколов одинакова, нельзя сказать, что HTTP медленнее WS или SSE при передаче одних и тех же данных. Это означает, что окончательная реализация важнее, чем выбор любого из этих протоколов для управления или чего-либо еще, что требует малой задержки.

Передать данные с датчиков

Датчики делятся на две группы:

  • Медленные датчики — обновляются с определенным интервалом и передаются от Arduino к ESP. Терминал управления (приложение) периодически запрашивает эти данные. Частота обновления один раз в две секунды. Передача через HTTP GET-запросы.
  • Быстрые датчики — обновляются с определенным интервалом (быстрее, чем медленные датчики) и передаются Arduino на ESP, после чего сразу отправляются на управляющий терминал. Скорость обновления составляет 2,5 раза в секунду. Передача через SSE.

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

Внутреннее общение. Ардуино — ЕСП

Плата Arduino и ESP-32-Cam используют для связи протокол UART. Сначала я сделал собственное решение для передачи данных, но когда данных стало слишком много, я понял, что гораздо лучше использовать готовое решение. Это решение — замечательная библиотека SerialTrasfer, она берет на себя грязную работу по передаче данных.

Скорость UART для передачи данных установлена ​​на 76800 бод/с. На этой скорости меньше всего ошибок передачи из-за тактовой частоты 16 МГц микроконтроллеров Arduino и 320 МГц ESP. Это решение позволяет в значительной степени гарантировать доставку правильных данных между ESP и Arduino без необходимости их проверки и, возможно, дублирования.

Учитывая разные напряжения логических уровней ESP-32 (3,3 В) и Arduino (5 В), UART между ними подключается через переключатель уровней.

Принцип передачи данных по UART:

  • Данные передаются парами: «Тип данных» и «Полезные данные», причем последний может отсутствовать, так как иногда достаточно просто наличия факта передачи, например сигнала о необходимости обновления сторожевой таймер.
  • Всего 8 типов данных: «Показания датчика», «Команда управления», «Тип сигнала», «Wathdog», «Сообщение журнала», «Быстрые показания датчика», «Настройки Arduino», «Чтение настроек Arduino».
  • На стороне отправки подготавливается сообщение с типом данных в начале, за которым следуют полезные данные, если они необходимы.
  • Получатель получает сообщение и в зависимости от типа сообщения может быть: какое-то действие или распаковка данных.

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

Можно использовать не только UART, например SPI, или I2C, или другой протокол передачи данных. Я выбрал UART из-за его хорошей документации, простоты работы с ним и того, что он все равно понадобится — для отладки.

Датчики

На баке есть ряд датчиков:

  • Модульный термометр и гигрометр DHT-11. Не очень точный, но дешевый и простой в работе. Я думаю, что на баке (с телеметрией) должен быть классический датчик — термометр.
  • Датчик Холла A3144 в качестве тахометра. На ведущей звездочке левой гусеницы установлен небольшой неодимовый магнит, а рядом с ним на корпусе размещен датчик Холла. Датчик считывает каждый магнит, который проходит над ним, и вычисляет количество оборотов ведущей звездочки. Зная диаметр звездочки, можно точно узнать, какое расстояние прошел танк и с какой скоростью. Точность этой импровизации заставляет желать лучшего, но работает она круто.
  • Барометр БМП-280. Позволяет получить атмосферное давление и на его основе высоту над уровнем моря. Датчик имеет множество режимов работы на все случаи жизни, но немного сложен в настройке.
  • Модуль акселерометра и гироскопа MPU-6050. Хороший, быстрый датчик для измерения ориентации в пространстве. Использует для работы сложную математику, но это компенсируется множеством доступных библиотек.
  • Ультразвуковой дальномер УС-025 (аналог HC-SR04). Используется для отображения расстояния до ближайшего препятствия перед танком.

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

Забавный баг с шиной I2C на Arduino Nano

Некоторые датчики (МПУ-6050, БМП-280) подключаются по I2C. Иногда из-за этой шины может зависать микроконтроллер Arduino Nano. Я наблюдал с помощью осциллографа, что там происходит в автобусе, и вместо примерно плоских прямоугольных форм я видел ужасные искаженные фронты сигналов, больше похожие на треугольники или даже случайные шумы. Проверял на нескольких платах и ​​без бака, но результат был тот же. Я так и не понял, что было причиной этого. Может быть, это было из-за дешевых деталей Arduino или, может быть, что-то еще. Помогла сильная подтяжка шины к питанию через 1,3кОм.

Камера, прием видео

Модуль ESP-32-Cam имеет 2-мегапиксельную видеокамеру OV2640. Камера может запечатлеть окружающий мир в удивительном диапазоне разрешений от 96х96 до 1600х1200. На танке использую три разрешения: HVGA — 480х320; VGA — 640x480; СВГА — 800x600. Выбор этих разрешений обусловлен: быстрым формированием и передачей кадра такого размера, что дает стабильные 25 FPS. Разрешение выше этого слишком велико для стабильной частоты кадров, а низкое разрешение приводит к слишком большой потере качества изображения.

В основе кода ESP для работы с камерой лежит стандартный пример CameraWebServer. Для камеры есть отдельный HTTP-сервер, который при подключении к нему отдает клиенту бесконечный поток JPEG-картинок с камеры — получаем MJPEG-поток.

Получение кадров не является сложной задачей, ведь MJPEG-поток — это бесконечная передача JPEG-изображений, достаточно поймать специальные маркеры (байты). Маркер всегда начинается с байта 0xFF, за которым следует байт, обозначающий тип маркера. Маркеры могут обозначать разные вещи, но нас интересуют два типа маркеров: начало кадра — 0xD8 и конец кадра — 0xD9.

Unity не может самостоятельно поддерживать потоковую передачу MJPEG. Поскольку я использовал Unity, я решил использовать их метод UnityWebRequest и их стандартный механизм многопоточности — Coroutine.

Принцип приема изображения прост:

  • Я сделал свою реализацию обработчика (DownloadHandler), который просто подтягивает событие каждый раз, передавая туда кучу байтов (JPEG) в момент прихода кадра.
  • Далее кадр попадает в метод (LoadImage), который пытается преобразовать байты JPEG в текстуру (Texture2D).
  • Если метод работает успешно, текстура растягивается поверх объекта в сцене. Он визуализируется, и мы можем видеть его на экране.

Обнаружение поврежденного кадра JPEG в Unity

Метод LoadImage может не загрузить текстуру, так как он получает поврежденный кадр. Хотя он должен возвращать false, но по какой-то причине всегда возвращает true. Но я воспользовался тем, что когда не может загрузить текстуру, выдает вместо нее белую текстуру с красным знаком вопроса, она размером ровно 8 на 8 пикселей. И я не использую этот размер в своем аквариуме, поэтому простая проверка размера текстуры на выходе дает мне знать, что пришла поврежденная текстура и позволяет избежать сна эпилептика — внезапно появляющейся белой текстуры, которая будет мигать между нормальными кадрами. Кстати, умные веб-браузеры знают, как в данном случае визуализировать эту часть кадра, а я нет, поэтому приходится использовать этот элегантный лайфхак.

ESP-32 Частота кадров камеры

Сама камера достаточно быстрая и честно выдает заявленные производителем 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, но не передаст больше, чем вы сможете принять. Поэтому необходимо очень внимательно отнестись к организации общения.

Автонастройка видео

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

  • Зная количество кадров, которые приходят в секунду можно узнать FPS.
  • Как только FPS падает ниже определенного порога, понижаем качество картинки (качество JPEG), если качество снижать некуда, то понижаем разрешение.
  • Если FPS выше определенного порога, все происходит точно так же, только качество и разрешение увеличиваются.

Приводы

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

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

Для управления моторами на танке я использовал драйвер L298N. Можно было бы использовать более новые и более производительные драйверы. Но мне нравится пользоваться таким старьем, которое имеет брутальный вид и большой, а главное теплый радиатор после работы — придает дух танку и идеально вписывается в его «построенный из того, что было на столе» дизайн.

Принцип управления двигателем:

  • Команда «Стоп» — машинисту подается сигнал на остановку двигателей.
  • Команда «Движение» — водитель раскручивает оба мотора вперед или назад.
  • Команда «Поворот» — двигатель на стороне поворота вращается назад, а второй двигатель вперед. Этим достигается быстрый поворот на месте.
  • Команда «Движение с поворотом» — мотор пути, противоположного повороту, работает на 100%, а мотор со стороны поворота снижает обороты, например, на 70%. В результате получается плавный поворот в сторону тормозящей гусеницы.

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

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

Фото и видео презентация

Выводы

Весь исходный код прошивки Arduino, ESP-32 и приложения Unity я выложил в репозиторий на GitHub, не удивляйтесь, если найдете интересные решения. Моя цель — показать вам сам принцип, лучший способ — разобраться в нем самому и сделать что-то свое на основе полученных знаний.

Написание этой статьи помогло мне выложить весь опыт, который у меня был при создании танка. И помнить решения всех тех багов и недочетов, которые возникали в процессе, которых можно избежать, и сосредоточиться на поиске собственных уникальных багов, чтобы поделиться ими с сообществом. Я очень надеюсь, что смогу вдохновить кого-то на создание такой классной вещи.