Концепция
Бывало ли у Вас такое, что выйдя из дома Вы не помните выключили ли утюг? Обсуждая с другом очередной такой случай, появилась шуточная идея сделать робота для дистанционной визуальной проверки домашних дел. Да и вообще хотелось, на коленке сделать “шпионского” робота управляемого по камере со смартфона. Эта идея вынашивалась нами давно, но руки дошли только сейчас. И мы сразу же отправились в ближайший бар для обсуждений. Собственно роботом это называть не совсем верно. Скорее это самоходная платформа с телеметрическим управлением через сеть Интернет. Но в статье будет использоваться термин “робот” просто потому что так привычней.
Технология WebRTC идеально нам подошла, так как довольно легко организовать передачу видео, аудио и data каналов между двумя peer’ами с минимальной задержкой сигнала. Да и опыта работы с этой технологией у нас не было, потому очень хотелось попробовать.
![](https://habrastorage.org/getpro/habr/upload_files/d8a/ead/0d6/d8aead0d6653cfc2da062578c90bc896.jpg)
Упрощенная схема всей системы приведена на рисунке. Пользователь - оператор и робот - Raspberry PI заходят каждый на свою веб-страницу, подключаются к сигнальному серверу, после чего между ними создается WebRTC сессия через которую и передается видео-поток с робота пользователю, и передаются управляющие сигналы роботу. Дальше, управляющие сигналы робот отправляет на свой localhost где уже другой сервис их обрабатывает и выводит на GPIO, для управления моторами. Кажется все просто. Вот что у нас получилось на данном этапе:
![](https://habrastorage.org/getpro/habr/upload_files/fc6/bee/e27/fc6beee276081a9ece476a0e5ba54266.jpg)
Далее разберемся со всем этим более детально.
Комплектующие
Насмотревшись фильмов про роботов, многим из нас не раз хотелось построить своего боевого товарища. Но строить двуного терминатора сложно и дорого, благо наши китайские друзья делятся с нами не только вирусами. Проект задумывался как домашний, потому при выборе комплектующих мы исходили из того что у нас уже было или возможности приобрести по минимальной цене.
Главный контроллер
![](https://habrastorage.org/getpro/habr/upload_files/4e7/3af/854/4e73af8548c36a4b5c43c097b22af373.jpg)
Так как у нас было две платы Raspberry Pi (3b и 4), и они нас вполне устраивали, то было решено использовать именно малинку со стандартной OS Raspbian. Применение данной платы дает возможность усовершенствования в будущем, использования OpenCV, подключение дополнительной периферии и т.д. И она достаточно распространенная чтобы можно было без проблем купить дешевый корпус и не боятся запачкать его в клей, или просверлить парочку монтажных отверстий.
Глаз (камера)
В качестве камеры можно в общем-то использовать любую вебку (что мы первое время и делали), но в процессе тестирования оказалось что лучше брать камеру с относительно высоким показателем FPS и светочувствительности. Потому практически сразу после первых тестов заменили старую вебку Logitech QuickCam Connect на относительно современную Logitech C270 приобретенную на доске бесплатных объявлений за 12$. Можно было использовать и Raspicam, но это обошлось бы несколько дороже.
Механика
![](https://habrastorage.org/getpro/habr/upload_files/351/c73/150/351c73150a27f8ffcd0a75edd55f1796.jpg)
Механическая основа робота — гусеничная платформа с дифференциальным приводом — классическая, в общем-то, для простых робототехнических экспериментов. Два независимых колеса вращающих гусеницы. Данное решение оказалось несколько ошибочным, так как такие конструкции не лишены следующих недостатков:
Часто слетают гусеницы при повороте на поверхностях с высоким коэффициентом трения, например на ковре.
Очень шумные редукторы на моторах
Идеальным решением была бы обычная платформа на колесах, управляемая по танковой схеме. Но гусеницы выглядят интересней.
Питание
![](https://habrastorage.org/getpro/habr/upload_files/29c/037/90a/29c03790a898c804013e431721925cea.jpg)
Для исключения возникновения помех и просадок напряжения цепи питания моторов и Raspberry Pi было решено разделить. Изначально драйвер моторов был запитан от телефонного аккумулятора на 3.7В с импульсным повышающим преобразователем напряжения типа DC-DC MT3608, но драйвер моторов не захотел с ним адекватно работать, и уходил в “зашкал”. Вероятно из-за импульсного характера напряжения. Потому было куплено два одинаковых аккумулятора от старого телефона Samsung. И они идеально вписались в батарейный отсек, будучи соединенными конструктивно скотчем и последовательно электрически. А малинка запитана от power-банка Xiaomi с быстрой зарядкой, так-же идеально подходящей под габариты платформы. Величины тока вполне хватает для питания Raspbery Pi4.
Драйвер моторов
Изначально был выбран драйвер L9110, но он часто выключался при питании от повышающего DC-DC преобразователя, потому код был исправлен и установлен L293N. Проблему это не решило, а модуль так и остался. Принципиальной разницы в работе модулей замечено не было.
Конструкционный монтаж
![](https://habrastorage.org/getpro/habr/upload_files/20f/834/f88/20f834f888de7f08395a92d93a51dddc.png)
Так как это лишь домашний прототип, то собирается все из "полиморфа", палок и супер-клея. Очень удобно было использовать советский металлический конструктор “Малыш” приобретенный на доске бесплатных объявлений за 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 дает возможность использовать интернет вместо традиционного радиоканала в управлении БпЛА типа различных коптеров из современными полетными контроллерами со стабилизацией и прочими плюшками, ограничивая радиус действия только покрытием сети и возможностями аккумулятора. И еще видео:
barbos6
Любопытно, какая задержка видео в результате получилась.
djarik Автор
70-90мс если через 3g. Но по факту вообще не заметно, в режиме использования. Ощущается как real-time