Концепция
Бывало ли у Вас такое, что выйдя из дома Вы не помните выключили ли утюг? Обсуждая с другом очередной такой случай, появилась шуточная идея сделать робота для дистанционной визуальной проверки домашних дел. Да и вообще хотелось, на коленке сделать шпионского робота управляемого по камере со смартфона. Эта идея вынашивалась нами давно, но руки дошли только сейчас.И мы сразу же отправились в ближайший бар для обсуждений. Собственно роботом это называть не совсем верно. Скорее это самоходная платформа с телеметрическим управлением через сеть Интернет. Но в статье будет использоваться термин робот просто потому что так привычней.
Технология WebRTC идеально нам подошла, так как довольно легко организовать передачу видео, аудио и data каналов между двумя peerами с минимальной задержкой сигнала. Да и опыта работы с этой технологией у нас не было, потому очень хотелось попробовать.
Упрощенная схема всей системы приведена на рисунке. Пользователь - оператор и робот - Raspberry PI заходят каждый на свою веб-страницу, подключаются к сигнальному серверу, после чего между ними создается WebRTC сессия через которую и передается видео-поток с робота пользователю, и передаются управляющие сигналы роботу. Дальше, управляющие сигналы робот отправляет на свой localhost где уже другой сервис их обрабатывает и выводит на GPIO, для управления моторами. Кажется все просто. Вот что у нас получилось на данном этапе:
Далее разберемся со всем этим более детально.
Комплектующие
Насмотревшись фильмов про роботов, многим из нас не раз хотелось построить своего боевого товарища. Но строить двуного терминатора сложно и дорого, благо наши китайские друзья делятся с нами не только вирусами. Проект задумывался как домашний, потому при выборе комплектующих мы исходили из того что у нас уже было или возможности приобрести по минимальной цене.
Главный контроллер
Так как у нас было две платы Raspberry Pi (3b и 4), и они нас вполне устраивали, то было решено использовать именно малинку со стандартной OS Raspbian. Применение данной платы дает возможность усовершенствования в будущем, использования OpenCV, подключение дополнительной периферии и т.д. И она достаточно распространенная чтобы можно было без проблем купить дешевый корпус и не боятся запачкать его в клей, или просверлить парочку монтажных отверстий.
Глаз (камера)
В качестве камеры можно в общем-то использовать любую вебку (что мы первое время и делали), но в процессе тестирования оказалось что лучше брать камеру с относительно высоким показателем FPS и светочувствительности. Потому практически сразу после первых тестов заменили старую вебку Logitech QuickCam Connect на относительно современную Logitech C270 приобретенную на доске бесплатных объявлений за 12$. Можно было использовать и Raspicam, но это обошлось бы несколько дороже.
Механика
Механическая основа робота гусеничная платформа с дифференциальным приводом классическая, в общем-то, для простых робототехнических экспериментов. Два независимых колеса вращающих гусеницы. Данное решение оказалось несколько ошибочным, так как такие конструкции не лишены следующих недостатков:
-
Часто слетают гусеницы при повороте на поверхностях с высоким коэффициентом трения, например на ковре.
-
Очень шумные редукторы на моторах
Идеальным решением была бы обычная платформа на колесах, управляемая по танковой схеме. Но гусеницы выглядят интересней.
Питание
Для исключения возникновения помех и просадок напряжения цепи питания моторов и Raspberry Pi было решено разделить. Изначально драйвер моторов был запитан от телефонного аккумулятора на 3.7В с импульсным повышающим преобразователем напряжения типа DC-DC MT3608, но драйвер моторов не захотел с ним адекватно работать, и уходил в зашкал. Вероятно из-за импульсного характера напряжения. Потому было куплено два одинаковых аккумулятора от старого телефона Samsung. И они идеально вписались в батарейный отсек, будучи соединенными конструктивно скотчем и последовательно электрически. А малинка запитана от power-банка Xiaomi с быстрой зарядкой, так-же идеально подходящей под габариты платформы. Величины тока вполне хватает для питания Raspbery Pi4.
Драйвер моторов
Изначально был выбран драйвер L9110, но он часто выключался при питании от повышающего DC-DC преобразователя, потому код был исправлен и установлен L293N. Проблему это не решило, а модуль так и остался. Принципиальной разницы в работе модулей замечено не было.
Конструкционный монтаж
Так как это лишь домашний прототип, то собирается все из "полиморфа", палок и супер-клея. Очень удобно было использовать советский металлический конструктор Малыш приобретенный на доске бесплатных объявлений за 1$. Power-банк на самом дне, для сохранения низкого центра тяжести. Прижат пластиной из конструктора, на которую пластиковыми болтами закреплены две скобы к которым уже и крепится корпус Raspberry Pi. Камера прикручена в задней части по причине того что так комфортнее управление. Проще понимать габариты когда видишь края гусениц, а объектив на камере не широкоформатный. Чудесным образом размер пластины из конструктора совпал с габаритным размером задней части платформы, что дало возможность спрятать под пластину скрученный длинный провод. Мелкие детали крепятся на супер-клей. А драйвер моторов - на двухсторонний скотч прямо к power-банку.
Программная часть
Так как это прототип, то качество кода, да и всего проекта в целом соответственное. Есть некритические ошибки. Реализован проект на языках JavaScript и Python. Репозитории проекта с комментированным кодом доступен по ссылке. Весь код тут приводить не буду, постараюсь описать только основные моменты.
Сигнальный сервер
Представлен примитивным NodeJS сервером. Он выполняет две функции:
-
Отдает нужные страницы для платформы и на устройство оператора, который управляет роботом.
-
Собственно сигнальная функция, т.е. обслуживает подключения по веб-сокету.
При подключении к серверу платформа регистрируется под под своим уникальным идентификатором. Этот самый идентификатор должен ввести у себя в интерфейсе оператор. И сообщения отправляемые со страницы оператора доставляются на страницу платформы и наоборот. Таким образом реализована абстракция типа комнаты, для возможности одновременного функционирования нескольких платформ.С кодом сигнального сервера можно ознакомится по ссылке.
Для общения с сигнальным сервером из клиентской части реализован класс SignalEmitter. Принимает в конструктор объект с настройками. id - идентификатор платформы , isControl - переменная указывающая на то платформа это или оператор. signalServer - uri сигнального сервера. Развернут он у нас на старом десятилетнем ноутбуке.
const se = new SignalEmitter({id: searchParams.get('id'),isControl: false,signalServer: config.signalServer});
WebRTC
Для соединения по протоколу был реализован класс RTC. В конструктор принимает два параметра - объект настроек options и экземпляр класса SignalEmitter, который был описан выше. isControl - переменная указывающая на то платформа это или страница оператора. platformSocket - uri localhost'а с портом на который отправляется управляющий сигнал для гусениц.
const webrtc = new RTC({isControl: false,platformSocket: config.platformSocket}, se);
Интерфейс клиентской части
Для прототипирования интерфейса использовался Vue.js, так как достаточно простой и позволяет быстро реализовать идею. Все что касается интерфейса находится в директории /public. Как выглядит прототип интерфейса и его функционал опубликовал в видео:
Selenium
Чтобы не запускать вручную каждый раз браузер, мы решили использовать Selenium WebDriver + geckodriver в headless режиме. Код императивный и очень простой, находится в файле robot-signal-server/selenium/index.js. Здесь мы подключаем конфигурационный файл, устанавливаем нужные флаги браузеру и открываем соответствующую страницу. О назначении каждого с флагов можно догадаться интуитивно, ну или же воспользоваться поисковиком. Можно добавить выполнение скрипта в /etc/network/if-up.d/ что бы он запускался автоматически при подключении к сети.
Управление драйвером двигателей
Эта часть написана на Python. Ее функция - принять управляющий сигнал по websocket со страницы платформы, преобразовать сигнал и вывести соответствующие значения на выводы GPIO. Так как схема управления у нас танковая, то контракт сигнала у нас такой: [0+-1, 0+-1] в формате JSON. Т.е. два значения, для левой и правой гусеницы, которые изменяются в пределах от -1 до +1 с шагом 0.01. Что соответствует движению назад и вперед, и дает возможность весьма точно регулировать скорость движения с помощью широтно-импульсной модуляции. (см. GItHub репозиторий)
Вывод
Как видно, сложного ничего нет. Применение данной схемы в production-варианте реализации возможно и для роботов-промоутеров или для мобильной, самоходной системы слежения да и вообще ограничивается только фантазией. Посещение музеев и выставок так же можно было бы сделать дистанционным, что особенно полезно во времена пандемии. Сидите Вы у себя в кресле и изучаете Собор Святого Петра в Риме или музей Васа в Стокгольме.
А повсеместное распространение скоростного 3/4/5G дает возможность использовать интернет вместо традиционного радиоканала в управлении БпЛА типа различных коптеров из современными полетными контроллерами со стабилизацией и прочими плюшками, ограничивая радиус действия только покрытием сети и возможностями аккумулятора. И еще видео: