Как превратить игрушечного робота-доставщика в ровер с беспроводным управлением через мобильное приложение

—

от автора

Привет, Хабр!

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

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

Игрушка на Яндекс Маркете

Игрушка на Яндекс Маркете

Робот-доставщик

Модель выполнена в виде настоящего ровера 3 от Яндекса в масштабе 1/64. Инерционный механизм делает из него небольшую игрушку, работающую по принципу детских машинок, которые были, вероятнее всего, у каждого в прекрасные времена более голубого неба и самой зеленой травы.

Работа инерционного механизма

Работа инерционного механизма

Также внутри робота расположены светодиоды для подсветки его «глаз» и периметра контейнера, который, к слову, открывается. Работает все великолепие на 3 батарейках типа LR44.

Подсветка ровера

Подсветка ровера

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

А может сделать его управляемым?

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

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

В итоге решил делать следующее:

  1. Управление ровером должно быть реализовано с помощью мобильного приложения на iOS, которое я напишу на Flutter (про мой первый опыт работы с этим фреймворком можно прочитать в статье про Smart Connect)

  2. Беспроводная передача данных будет производиться с помощью BLE, потому что ранее я имел с ним дело (можете ознакомиться со статьями про SmartLight и SmartPulse) и я считаю его идеальным под подобные проекты (имхо)

  3. Ровер должен ездить вперед, назад, поворачивать влево и вправо, а также включать подсветку по кнопке в мобильном приложении

Далее я решил разобрать робота, чтобы понять, каким объемом пространства внутри него я могу располагать.

Внутри игрушки

Внутри игрушки

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

Что по начинке?

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

Схема направления движения колес при повороте ровера

Схема направления движения колес при повороте ровера

Для управления моторчиками нужен драйвер. Естественно, так как мы имеем дело с небольшим корпусом игрушки, то все платы надо было подобрать так же миниатюрные. Сказано — сделано, и драйвер L298N mini уже был у меня. На него сразу можно было припаять два моторчика, чему я был несказанно рад.

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

А что будет всем этим управлять? Для работы с BLE существует крайне удачная линейка ESP32 контроллеров с различными модификациями. Так как в этом проекте мы ограничиваемся сравнительно небольшим пространством для монтажа плат внутрь устройства, я выбрал ESP32-C3 SuperMini, которая по своим размерам не больше зарядной платы аккумулятора.

Разобранный ровер и все то, что в него предстоит засунуть

Разобранный ровер и все то, что в него предстоит засунуть

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

Схема подключения электронных компонентов

Схема подключения электронных компонентов

Прошивка робота

Перейдем к прошивке ровера, полная версия которой лежит у меня в репозитории на GitHub (всегда рад гостям).

По сути все, что нам нужно для реализации передачи данных на ровер, это поднять BLE-сервер и определить сервис и характеристику, в которую мы будем отправлять значения для включения и выключения моторчиков. Я писал код в Arduino IDE с использованием библиотек BLEDevice.h, BLEUtils.h и BLEServer.h

Инициализируем работу с BLE посредством следующего кода:

BLEDevice::init("Yandex Delivery Robot"); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService* pMoveService = pServer->createService(BLEUUID((uint16_t)0x170D)); pMoveCharacteristic = pMoveService->createCharacteristic(BLEUUID((uint16_t)0x2A60), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE); pMoveCharacteristic->setCallbacks(new MoveCharacteristicCallbacks()); pMoveService->start(); BLEAdvertising* pAdvertising = pServer->getAdvertising(); pAdvertising->addServiceUUID(pMoveService->getUUID()); pAdvertising->setScanResponse(false); pAdvertising->setMinPreferred(0x06); pAdvertising->setMinPreferred(0x12); BLEDevice::startAdvertising();

Здесь мы определяем наименование устройства, а также присваиваем UUID нашему сервису и характеристике pMoveCharacteristic

Запись в характеристики производится с помощью MoveCharacteristicCallbacks, в которой я реализовал switch-case конструкцию. Внизу прикреплен урезанный фрагмент.

class MoveCharacteristicCallbacks : public BLECharacteristicCallbacks {     void onWrite(BLECharacteristic* pCharacteristic) {         std::string value = pCharacteristic->getValue();         if (value.length() > 0) {             switch (value[0]) {                 case 0x01: // Поворот ровера влево                     ledcWrite(CHANNEL_IN1, 255);                      ledcWrite(CHANNEL_IN2, 0);                     ledcWrite(CHANNEL_IN3, 255);                     ledcWrite(CHANNEL_IN4, 0);                     break;                 case 0x02: // Поворот ровера вправо                     ledcWrite(CHANNEL_IN1, 0);                     ledcWrite(CHANNEL_IN2, 255);                      ledcWrite(CHANNEL_IN3, 0);                     ledcWrite(CHANNEL_IN4, 255);                     break;             }         }     } }

Мобильное приложение

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

Логика работы кода мобильного приложения также как и в случае с кодом прошивки построена на switch-case конструкции. Я решил расположить на странице управления ровером кнопки в виде стрелок направления (вперед, назад, влево, вправо) и кнопку включения/выключения подсветки в виде горящей лампочки. Когда пользователь нажимает на любую из кнопок направления, в BLE-характеристику подключенного устройства записывается соответствующее значение (к примеру, для поворота ровера влево — 0x01, для правого поворота — 0x02 и тд.).

Positioned(   bottom: 160,   left: 80,   child: controlButton(Icons.arrow_back, 0x01, "Left"), ), Positioned(   bottom: 160,   right: 80,   child: controlButton(Icons.arrow_forward, 0x02, "Right"), )

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

onPointerDown: (_) => sendCommand(command), onPointerUp: (_) => sendCommand(0)

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

Positioned(   bottom: 40,   right: 20,   child: FloatingActionButton(     onPressed: () {       setState(() {         toggleState = !toggleState;         sendCommand(toggleState ? 3 : 6);       });     },     child: Icon(       toggleState ? Icons.lightbulb_outline : Icons.lightbulb,       color: Color.fromRGBO(255, 53, 63, 1),     ),     backgroundColor: Colors.white,   ), )

Чтобы работать с BLE, я подключил flutter_blue: ^0.8.0 , а сам процесс подключения к устройству построен на определении рассылки от конкретного BLE-сервера по его названию. Запись значений производится по UUID сервиса и характеристики ровера.

List<BluetoothService> services = await widget.device.discoverServices(); var targetService = services.firstWhere((service) =>     service.uuid == Guid('0000170D-0000-1000-8000-00805f9b34fb')); var targetCharacteristic = targetService.characteristics.firstWhere(     (characteristic) =>         characteristic.uuid ==         Guid('00002A60-0000-1000-8000-00805f9b34fb')); await targetCharacteristic.write(value);

После того, как я протестировал работоспособность приложения с микроконтроллером, мне захотелось как-то «довести до ума», чтобы как минимум приложение выглядело чуть более симпатично. На странице управления ровером были только четыре кнопки управления моторами и одна кнопка для подсветки. Это выглядело скучновато, поэтому мне захотелось добавить динамики. Решил изобразить в Adobe Illustrator модельки с направлением ровера.

Изображения направления ровера

Изображения направления ровера

Реализовал обновление картинок по нажатию на соответствующие кнопки управления ровером также через switch по отправляемому с кнопки значению.

setState(() {   switch (command) {     case 0x01:       currentImage = 'assets/Влево.png';       break;     case 0x02:       currentImage = 'assets/Вправо.png';       break;     case 0x05:       currentImage = 'assets/Вперед.png';       break;     case 0x04:       currentImage = 'assets/Назад.png';       break;     default:       break;   } });

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

Иконка мобильного приложения

Иконка мобильного приложения

Собираем приложение в Xcode, устанавливаем его на мобильное устройство (в моем случае это iPhone 12 Pro Max) и запускаем для тестирования работоспособности. В итоге мобильное приложение получило следующий внешний вид:

Работа и внешний вид мобильного приложения

Работа и внешний вид мобильного приложения

Пайка, флюс, два колеса

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

Колеса ровера до подключения моторов и после

Колеса ровера до подключения моторов и после

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

Разобранный ровер со срезанными креплениями

Разобранный ровер со срезанными креплениями

Чтобы получить возможность зарядки аккумулятора без разбора всего робота (потому что это садизм), я отпилил батарейный блок. В этом месте я расположу зарядную плату аккумулятора так, чтобы порт USB Type-C выходил на крышку бывшего батарейного блока. В таком случае для зарядки ровера нужно будет только снять эту крышку и подключить кабель к зарядной плате. Также я выпилил места под моторы, потому что места оказалось недостаточно, а мне не хотелось, чтобы их работе что-либо мешало.

Модифицированное днище ровера

Модифицированное днище ровера

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

Пайка электронных компонентов ровера

Пайка электронных компонентов ровера

В итоге не без проблем, но у меня получилось разместить все компоненты внутри ровера. Зарядка устройства производится со стороны нижней части корпуса. Это напоминает мне подключение Magic Mouse, но только я это сделал за неимением других вариантов, а не потому что не люблю людей. Можно было бы расположить зарядную плату как-то иначе, но я не хотел портить внешний вид ровера (днище не считается, потому что его не видно).

Процесс зарядки ровера от сети

Процесс зарядки ровера от сети

Поехали!

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

В качестве демонстрации управления ровером я записал небольшое видео:


Большое спасибо всем, кто прочитал эту статью!

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

Если у вас есть идеи или предложения, можете написать в комментариях, какие еще игрушки или вещи можно было бы модифицировать, и рано или поздно я сделаю это)


ссылка на оригинал статьи https://habr.com/ru/articles/809953/


Комментарии

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

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