Я сделаю свою «умную» колонку… «with blackjack and hookers!»
Привет всем. В данной статье я расскажу историю как мы с двоюродным братом сделали свою «умную» колонку.
На самом деле никакая она неумная, грубая и не особо полезная, но зато весёлая и с характером.
За мной сама идея, программирование, железо (подбор и настройка).
От брата 3D-модель, 3D-печать, железо (подбор и электромонтаж).
Статья по-большей части описывает то, что делал я, лишь немного касаясь 3D-модели.
«Ты на самом деле хочешь дружить с роботом?»
Будучи большим фанатом известного мультсериала «Футурама», однажды (где-то в 2018 году) мне захотелось заиметь самодельную голову робота Бендера Родригеса. В голове, в том числе крутились дурацкие варианты сделать её из какой-нибудь кастрюли. В силу своей глупости идея была забыта и заброшена ровно до того момента пока у одного хорошего человека, моего брата, товарища xbost’а не появился 3D-принтер (весна 2019 года). И тут эта идея снова ожила…
Обсудив эту идею за пивом, принялись за работу. Брат начал делать 3D-модель, а я искать, что из электронного хлама в ящике стола можно задействовать в проекте.
К тому моменту, у меня уже несколько лет валялась без дела плата Intel Galileo Gen2. И было желание задействовать её в этом проекте. Изначально никаких «умных» функций не планировалась, просто запихнуть её в корпус вместе с динамиком и светодиодами, вытащить кнопочку, при нажатии на которую воспроизводились бы цитаты из серий и светились диоды.
В то же время вокруг буйным цветом расцветали (и продолжают расцветать сейчас) умные колонки с голосовыми ассистентами. Они вежливы (Алиса правда хамовата), достаточно много всего умеют и не работают без Интернета. И по мне достаточно скучны.
Это привело к мысли, что на основе Бендера с его вредным, эгоистичным и вообще отрицательным характером можно сделать для себя отличную «умную» колонку. Этакий арт-проект, протест против умных колонок. И обязательно работающую оффлайн, даже ценой производительности.
Первые попытки
Почитав о системах распознавания речи с возможностью оффлайн-распознавания, а также узнав, что ещё один хороший человек, коллега с прошлой работы, в то время писавший диплом, использует CMU Sphinx, выбор был остановлен на нём.
В силу своей природной… хм… невнимательности, я упустил существование более подходящей для моей задачи версии – pocketsphinx, и начал с «большого» CMU Sphinx на Java.
Создал простенькие JSGF-грамматику и программу на Яве. Взял несколько наиболее известных цитат для проигрывания(“with blackjack and hookers”, “bite my shiny metal ass”, “kill all humans” и т.п.). Пробовал изначально на достаточно мощном компьютере(MacBook Pro 13-го года), был доволен результатом производительности, но понимал, что на Галилео меня ждёт нечто другое. Но дело оказалось совсем плохо.
Вообще Галилео уже давно заброшен Интелом. Стандартный Линукс, шедший с ним мне в принципе особенно не нравился. Поэтому попробовал с последней доступной для него сборкой Дебиан.
Туда с проблемами(подробности уже честно не вспомню) был поставлен JRE. В качестве устройства ввода/вывода аудио была использована USB-гарнитура. И… Результат был крайне печален в плане производительности. Сейчас опять же не вспомню, возможно неправильную акустическую модель использовал на ней, но на реакции уходило 30-60 секунд. Плюс брат начал разрабатывать 3D-модель, и сказал, что габариты Галилео большеваты. Плюс отсутствие встроенного Wi-Fi. В общем Галилео опять отправилась в стол.
Решено было попробовать на гораздо более популярной Малинке, и выбор пал на слабую, но самую компактную версию Raspberry Pi Zero W. А также, прокачав внимательность, узнал о pocketsphinx (отличная статья для старта), перешёл на него, и переписал программу на Питоне.
При переходе на Малину, с подачи xbost’а, родилось название для проекта – Pinder (Raspberry Pi + Bender). Да, я прекрасно помню историю с Pidora в русскоязычном сегменте, но в данном случае намеренно выбрал такое лулзовое для русского уха название.
И так предыстория завершена, можно переходить непосредственно к описанию Пиндера.
Внутренняя железная часть
Перечень использованных компонентов:
- Raspberry Pi Zero W – собственно основа всего.
- UPS-Lite for Raspberry Pi Zero Маленький ИБП для Малинки. Его штатный выключатель был выпаян, и к его контактам был припаян микропереключатель (см. далее по списку).
- RGB адресная светодиодная лента на WS2812B, 60 светодиодов на 1 метр Для подсветки и анимации «зубов»(18 штук) и глаз(2 штуки).
- USB-аудиокарта В принципе подойдёт любая, работающая в Линуксе. Подключается через OTG-кабель в единственный доступный для этого порт на Малине Зеро.
- Усилитель и один динамик от таких колонок В общем тут колхозный вариант был использован. Колонки были раздербанены, взят один динамик, усилитель вытащен из корпуса. Можно было купить отдельный усилитель и динамик, но для меня самым быстрым вариантом было тогда купить эти колонки и разобрать на части.
- Микрофон HBC10A Но во время разработки поначалу использовался микрофон от телефонной гарнитуры Philips.
- Микропереключатель с лапкой KLS7-KW10 Замыкается/размыкается при вставлении/вынимании «антенны» Бендера. Включает/выключает питание от UPS к Малине.
- 3,5мм разъём и гнездо jack. Для подключения микрофона к аудиокарте (микрофон находится наверху Бендера, в антенне).
В общем внутри всё достаточно колхозно.
Схема подключений очень простая:
Глаза сидят на отдельном пине от зубов и запараллелены между собой. Если бы делал сейчас, то включил бы глаза на одну ленту вместе с зубами, но что уже сделано, то сделано.
3D-модель, корпус
Здесь я не смогу рассказать многого, так как эта часть работы полностью брата.
3D-модель и небольшая инструкция доступны здесь.
Зубы и глаза напечатаны фотополимерной смолой на Anycubic Photon. Все остальные части PLA на Creality Ender 3.
Если будут какие-то вопросы по 3D-модели и печати можно задать мне, я их передам, либо попробовать напрямую спросить у xbost’а на thingiverse (но не уверен будет ли он на них отвечать).
Краткая схема сборки:
Фото
Фото в процессе сборки и полностью собранном виде:
Программная часть 1
В качестве ОС используется штатный Raspbian (теперь Raspberry Pi OS).
За распознавание, как уже писалось выше, отвечает pocketsphinx. В качестве аудиоподсистемы используется Alsa (Pulseaudio выпилен).
При разработке никакими лучшими практиками не руководствовался, поэтому код «попахивает».
Поддерживается два языка: английский и русский. Для каждого языка своя JSGF-грамматика, набор аудио-сэмплов(сэмплов в репозитории нет, по соображениям авторских прав) и синтез речи. Русский дорабатывался(и дорабатывается) с некоторым опозданием.
Основной целью была просто возможность отвечать фановыми фразами из серий. Задаешь ему вопросы типа “Как дела?”, “Где ты родился?”, “Что думаешь о Сири?”. Ищется и воспроизводится ответ из сэмплов (в случае отсутствия сэмпла используется синтез речи, но об этом чуть позже).
Изначально скорость ответов на Малине была не очень шустрой (4-6 секунд до ответа):
Покопавшись у себя в коде, были найдены и уничтожены необязательные паузы. То же самое касалось и сэмплов (были пустые места вплоть до 1 секунды в начале файлов). А также прочитана информация о параметрах оптимизации pocketsphinx. Получилось уже получше:
Далее начал добавлять кое-какие полезные функции. Первой стала проигрывание музыки с локальной ФС или интернет-радио с помощью MPD. При этом докричаться до Бендера при проигрывании музыки на приличной громкости сложновато:
После достаточно долгого перерыва, живя на даче, была добавлена первая функция “умного дома”- управление освещением в своём углу через ModBusTCP. Вот только Бендера недостаточно иногда просто попросить включить свет, нужно обязательно сказать «пожалуйста». Работает достаточно шустро:
Программная часть 2
Потом однажды захотелось добавить читалку RSS-новостей. Это уже было невозможно без синтеза речи, но при этом хотелось, чтобы синтезатор звучал как, или хотя бы похоже на голос Бендера. Такой синтез речи на Малине Зеро представляется малореальным и поэтому в этом моменте пришлось сдаться и задействовать онлайн-сервис.
Почитав информацию и попробовав разные варианты остановился на Microsoft Azure Custom Speech.
При создании пользовательского голоса на выбор есть три варианта:
- Statistical Parametric – стандартное качество, нужно небольшое количество(для английского языка) сэмплов для обучения.
- Concatenative – высокое качество, нужно 6000 сэмплов для обучения.
- Neural премиум-качество. По факту недоступно(доступно из США, при написании челобитной в Майкрософт зачем тебе это нужно и выкладывании 100 000$).
Более подробно по технологиям синтеза речи можно почитать например на Википедии.
У меня не было большого количества сэмплов, поэтому сначала поигрался со Statistical Parametric. Результат был неплох, голос конечно не был похож(такой тип синтеза для сильной похожести и не предназначен), но интонации передавал сносно. В итоге на основе набора данных созданного с помощью этой модели я создал оффлайновую модель для CMU Flite, используемую в случае отсутствия связи с MS Azure.
Но всё же хотелось большей похожести и я решился попробовать собрать 6000 сэмплов для Concatenative модели, использующей отрывки из сэмплов настоящего голоса. Очень помог некий хороший человек, выложивший на YouTube 7 видео The Best of Bender. Надёргав оттуда сэмплов, приплюсовав к ним те что уже были и натравив на них майкрософтовский же Text-to-Speech (здесь у меня набор тулзов вспомогательных), получил что-то около 2000 транскрибированных сэмплов. Было принято решение просто скопировать это всё три раза под разными именами, чтобы получить 6000.
В итоге всё это было залито на обучение модели, и результат получился следующим:
Да конечно не идеально, но меня результат трудов устроил.
В итоге синтез речи используется не только для чтения новостей, но и в случае отсутствия оригинального сэмпла. Сначала ищется сэмпл. Если его нет, проверяется связь с порталом MS Azure, если есть – синтезируется с помощью него. Если же связи с Azure нет – используется локальная модель Flite(а для русского языка роботизированный голос eSpeak).
В сумме периодическими волнами и рывками разработка шла с весны 2019-го по весну 2020-го, в свободное время(хорошо видно по коммитам на гитхабе). Далее уже даже не волнами, просто отдельными всплесками.
Будущее
Как таковых планов развития проекта нет. Если появляется желание и вдохновение, то добавляю что-нибудь. Так конечно напрашивается сделать режим просто болталки на нейронке, обученной на фразах Бендера. Ещё возможно добавить режим bluetooth-колонки(и чтобы зубы загорались синим в этом режиме) и приложение для смартфона, для активации схемы патриотизма.
Но для начала надо изобрести удлинитель пальца.
Заключение
Исходный код ПО и 3D-модель выложены под открытыми лицензиями, так что если у кого-то есть желание сделать своего Бендера, добавить свои функции и улучшить – буду рад.
На этом статья подошла к концу. Спасибо, что прочитали!
Беспроводная колонка своими руками
Стараюсь оставлять ссылки только на проверенные крупные магазины, из которых заказываю сам. Также по первые ссылки ведут по возможности на минимальное количество магазинов, чтобы минимально платить за доставку. Если какие-то ссылки не работают, можно поискать аналогичную железку в каталоге Ардуино модулей . Также проект можно попробовать собрать из компонентов моего набора GyverKIT .
- Подборка Bluetooth и усилителей на сайте
https://alexgyver.ru/sound/ - Bluetooth модуль https://ali.ski/Q7tWS
- Усилитель из видео (TDA7297) https://ali.ski/906ys
- Усилок + приёмник https://ali.ski/ji80L1
- Модуль питания 3.3V – 5 ШТУК (как в видео) https://ali.ski/M88B-
- Индикатор заряда (3S 12.6V) https://ali.ski/m0Ve6j
- Преобразователь с изол. землёй
- https://www.chipdip.ru/product/b1205s-1wr2 (чип дип, 1 штука)
- aliexpress
- https://www.chipdip.ru/product0/41486 (чип дип, 1 штука)
- https://ali.ski/1IiOn
Умный дисплей — своими руками
Последние пару недель вижу рекламу «умных дисплеев» или чего-то в этом духе. Суть их в том, что это «умная колонка», оснащённая экраном. Ценник по минимуму — что-то от 12000 руб.
Чуть больше года назад я присматривался к подобным девайсам, но только стоили они тогда ещё дороже. И пораскинув мозгами я нашёл гораздо менее затратный вариант сделать такое же «умное» устройство, но с более широкими возможностями. Попользовавшись своей «разработкой» пару месяцев я отчитался о результатах статьёй на helpix.ru , но как вижу, исходя из текущих тенденций, нелишним будет поделиться информацией и с вами, друзья-пикабушники.
«Умные колонки», которые горячо рекламируют Яндекс, Амазон и масса других производителей, может действительно настолько умные, что нам и не снилось, но обладают одним гигантским минусом: кроме звуков от них более ничего не дождёшься. Есть, конечно, прикол в том, чтобы разговаривать с «умной колонкой», получать ответы на вопросы, управлять устройствами «умного дома», но всё это больше похоже на скоропроходящее развлечение. Да и неудобно на слух получать большие объёмы информации. Например, метеопрогноз на неделю.
Примерно год назад появился ещё один класс устройств: «умные экраны/дисплеи». Их не так активно рекламируют (не известно по какой причине), но они, являясь гибридом «умной колонки» и планшета, позволяют получать и визуальную информацию. Среди производителей таких экранов отметились Amazon, Google, Lenovo. Но как отмечают в обзорах, в итоге получается недопланшет и недоколонка. Операционная система с урезанными функциями, «заточенная» под «умные» функции не даёт такой широты возможностей как даже «голый» Android на планшете, да и звук тоже не фонтан. А цены у более-менее приличных моделей начинаются от 200 баксов…
И вот тут меня взяла непонятка: не самые дорогие планшеты стоят вполовину от этих «умных дисплеев». А подержанные — и того дешевле. Почему нужно платить такие безумные деньги, если можно взять простой планшет и установив несколько программ и виджетов установить его на кухне, подключив к розетке?
В интернете нахожу в продаже за 500 (!) рублей 7-дюймовый планшет с полудохлым аккумулятором на 6-м «андроиде». «Ирбисом» зовут. В ломбарде за те же самые 500 рублей купил компактные, но с приличными характеристиками колонки с питанием от USB. И за три сотни докупаю к этой парочке сетевой адаптер с двумя выходами USB — не так много у меня на кухне свободных розеток.
Без прощальных слёз с полочки снимается старый радиоприёмник и отправляется в дальний угол кладовки. И на это место встаёт планшет. Подключаем его к домашнему WiFi и.
Но теперь звук должен быть гораздо лучше. Вопрос — откуда его теперь получать? Можно, конечно, от эфирных радиостанций, но есть вариант и получше: интернет-радио. На телевизор в комнате я установил программу PC-radio, и имею возможность выбирать из почти трёх тысяч радиостанций со всего мира. Устанавливаем её и на планшет. На рабочий стол выводим виджет. Программа имеет бесплатную и платную версии. В платной качество звука лучше.
По правде говоря, всю эту историю с планшетом и колонками инициировал этот самый приёмник «благодаря» отстойному звуку и неудобному управлению. И прожил-то он на этой полочке три года только по причине наличия крупных ярких часов и интересного дизайна.
Первая задача решена. Теперь попробуем превратить планшет в «умный дисплей».
Устанавливаем «Яндекс с Алисой», ярлык «Алисы» выводим на рабочий стол. Ну, здравствуй, «Алиса». Какая у нас там погода на завтра?
Погоду «Алиса» оттарабанивает чётко. Вот только в отличие от «умных» колонок и дисплеев не висит постоянно в памяти, ловя каждое ваше слово, поэтому приходится вызывать её через ярлык с экрана. Также «Алиса», как оказалось, не поддерживает команды типа напомнить о чём-либо когда-либо. Эта возможность присутствует только в «умных» гаджетах. А вот поставить таймер — это пожалуйста.
А вот как-то раз я во время рекламной паузы поскакал на кухню быстренько сделать бутерброды. И не успел уложиться до окончания рекламы! А я так ждал ту информацию, которая должна была прозвучать после неё…
И вот только после этого случая меня озарило: телевизор-то я смотрю через интернет. Так что же мне мешает поставить программу телепрограммы на планшет? И теперь на планшете есть программа ТВ+, позволяющая смотреть эфирные телепередачи через WiFi.
Кстати, ТВ+ на моём телевизоре Xiaomi Mi 4S позволяет смотреть телепередачи в HD качестве, и картинка гораздо лучше чем при приёме через антенну. На дисплее 4К это особенно заметно. Впрочем, на 7 дюймах планшета HD как-то не требуется.
Само собой на планшете можно смотреть ролики с ютьюба. Видеорецепты, например. Можно из браузера смотреть, а можно и отдельную программу поставить.
Хочу предупредить, что планшеты-старички будут тормозить и тупить. Мой планшет меня порой своей медлительностью подбешивает. Так что, чем новее — тем лучше, а минимальной границей я считаю планшеты на 6-м «андроиде». Диагонали 7 дюймов вполне достаточно, Но если захотите поболее — кто ж протестовать-то будет?
Теоретически, можно ещё транслировать на планшет слайд-шоу из фотографий. Можно в качестве заставки какие-нибудь релаксирующие видео крутить. На второй рабочий стол поставить виджет календаря. Нужны напоминания, которые «Алиса» отказывается делать? Поставьте программу «Запоминатор» — и ввод голосом напоминаний вам будет доступен. А, да! Если «умные» лампочки или розетки работают в экосистеме с передачей данных через WiFi, то можно будет установить на планшет общую управляющую программу. На смартфонах же такое прокатывает.
Но мне пока хватает «живых обоев» с аквариумом и часов на рабочем столе: поскольку питается планшет от сети, экран можно не гасить и пользоваться этим преимуществом.
В общем — вот вам поле для экспериментов, и будьте умными, не ведитесь сразу на «умные» гаджеты.
И по прошествии полутора лет эксплуатации такой сборки дополню: весь функционал, описанный выше, работает. Критичных сбоев в работе не обнаружено. Электропитание подаётся на планшет 24/7 — батарея до сих пор не вспучилась, перегрев на корпусе не ощущается.
Но версию андроида однозначно надо брать поновее. На планшет тоже не стоит слишком скупиться. Я-то брал самую дешёвку только потому, что не знал — выйдет ли что-то из этой затеи толковое. По моему мнению — вышло.
Поддержать
111 постов 2K подписчиков
Подписаться Добавить пост
1 год назадСудя по результу, никакой умной колонкой там не пахнет. Стоит говенный старый планшет, на который установили пару приложений, а рассказа на простыню. Умные гаджеты на то и умные, что не из говна и палок, а заточены под конкретный функционал и нет необходимости ни с чем ебаться при их использовании. Для души, так сказать.
раскрыть ветку
1 год назадРезюмируя, ТС обнаружил, что на планшет можно установить нужные приложения и подключить колонки? Или я что-то упускаю?
раскрыть ветку
1 год назадУмной колонки так и не получилось, а получился планшет с программами. Без поддержки постоянного управления голосом смысла в этом крайне мало.
раскрыть ветку
1 год назадярлык «Алисы» выводим на рабочий стол
Что-то не ясно — требуется ли нажимать на ярлык Алисы
Сейчас ТВ на андроиде многие и от планшета в теории вовсе можно отказаться.
Пост потенциально полезный но ИМХО сумбурный.
Проще развернуть HASIO, в нем автоматизации больше и Алиса интегрируется
раскрыть ветку
1 год назад
Почему-то возникла ассоциация — Парень он неплохой, только ссытся и глухой.
раскрыть ветку
Похожие посты
5 месяцев назадСам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера
К сожалению, в наше время многие старые, но весьма неплохие по характеристикам гаджеты отправляются напрямую в помойку, и их владельцы не подозревают, что им можно найти применение. Сервер, мультимедийная-станция, да даже просто как TV-приставка — люди в упор не замечают сфер, где старенький планшет мог бы быть полезен. Но как быть, если посвящаешь жизнь портативным гаджетам, кодингу и копанию в железе? Правильно: сделать довольно мощную игровую консоль из старого планшета самому! Сегодня вам расскажу, как я сделал свою портативную приставку из планшета с нерабочим тачскрином, Raspberry Pi Pico и 8 кнопок! За рабочим результатом прячется несколько дней работы: поиск UART на плате, разработка контроллера геймпада на базе RPi Pico, написание приложения-сервиса, которое слушает события и отправляет их в подсистему ввода Linux в обход Android. Интересно? Тогда жду вас под катом!
❯ Мотивация
Прошло уже практически 10 лет с того момента, как у меня появилась моя первая портативная консоль. Несмотря на то, что я был заядлым ПК-игроком, я уже успел посмотреть на PS3 и PSP, но денег на их покупку у меня особо не было, да и к тому времени уже был в наличии Android-планшет. Но к моему 13-летию в 2014 году, когда я ходил и выбирал себе будущий девайс на день рождения, отец и мама решили подарить мне мою первую портативную консоль. Изначально, я уговаривал её купить мне целых два девайса, но бюджет был ограничен 4.000 рублей, а я хотел взять смартфон Fly IQ239 и консоль JXD S601 одновременно:
Однако, увидев здоровую 7-дюймовую консоль в магазине TREC (думаю, жители южной части РФ помнят такой), мама уговорила меня взять именно её, мотивируя это «ну и чего ты будешь тыкаться в этот мелкий экран? Возьми большую». После покупки гаджета, я был доволен: играл какие-то игрушки с ретро-платформ, устанавливал игры на Android, сидел в ВК через Kate Mobile. Что еще нужно было школяру? Однако, планшет прожил у меня недолго: с очередного лага я психанул и ударил по нему кулачком, унеся на тот свет и дисплей и тачскрин. Так консолька и пролежала в подвале около 8 лет. Впрочем, мне продолжали импонировать подобные устройства и в прошлом году я купил и написал про несколько подобных девайсов.
Несколько месяцев назад, мой читатель Кирилл Севостьянов с Хабра прислал мне HTC HD2 в качестве донора и планшет Prestigio PMP7170B3G, который был рабочим, но… у него отказал тачскрин. Я всё думал, чего бы с ним сделать и решил реализовать игровую консольку своими руками из подручных средств. Идея крутилась в голове довольно давно, но реализовал я её только сейчас.
❯ Что нам нужно сделать?
Итак, что должно быть у портативной консоли? Чипсет, дисплей, звук, ОС — это всё нам уже предоставляет планшет. Нам остаётся лишь сделать свой геймпад. Давайте подумаем, что нам будет нужно для того, чтобы его сделать и передавать от него события на планшет:
- Контроллер для геймпада: тут нам подойдет практически любой микроконтроллер, который работает от 3.3в. Выбор большой: Arduino Pro Mini 3.3v, ESP32, RPi Pico. Я остановился на последнем: недавно я взял себе две штучки «пощупать» их — и они мне очень понравились!
- Физический интерфейс: с планшетом нужно как-то общаться. У нас есть три варианта: USB (не факт, что поддержка преобразователей включена в ядре), UART и SPI/I2C на пятачках тачскрина (потребуют написания драйвера т. к. в android-устройствах нет прямого доступа к SPI/I2C из userland’а). Я остановился на UART: его легко найти на большинстве китайских планшетов, а если не получилось — то на помощь может прийти схема платы.
- Программная реализация: как это будет работать? Я решил реализовать геймпад в виде сервиса на Android, который слушает состояния кнопок с UART и «инжектит» события напрямую в драйвер ввода. Таким образом, поддержка нашего геймпада появляется даже в самой системе — можно управлять менюшкой или приложениями как с клавиатуры!
С планом определились, пора начать с программной части: сначала нам обязательно понадобится ROOT-доступ. Его получение на разных девайсах отличается — на prestigio уже был порт CWM и я просто поставил SuperSU. Без ROOT доступа мы не сможем использовать UART!
Теперь нам нужно найти пятачки UART на плате. Разведен он не везде, но в случае устройств на MediaTek — почти всегда, ещё и пятачки подписаны. На моём планшете он нашёлся сразу: был между двух металлических экранов и соответствовал 4-ому каналу UART. Получить к нему доступ можно в /dev/ttyMT3. Я использую ESP32 в качестве UART преобразователя: подпаиваемся к RX/TX, запускаем putty и заходим в adb shell. Определяем бодрейт (скорость) нашего UART порта — на MediaTek он обычно равен 921600, на других чипсетах — 115200. Пытаемся что-то вывести и хоба — мы уже можем «поболтать» с планшетом!
❯ Приложение-сервис
Итак, у нас уже есть доступ к UART и мы можем общаться с планшетом из внешнего мира. Но получить события с кнопок пол дела, нужно их ещё и послать в систему. Для этого есть целых три способа:
- InputManager.injectInputEvent — именно этим методом пользуется команда input, которую вы можете использовать через adb. Но увы, он работает только при наличие разрешения INJECT_EVENTS, который доступен только системным приложениям — находятся они в /system/app и подписаны тем же сертификатом, что и остальная прошивка.
- Модуль uinput дает возможность создать виртуальное устройство ввода и посылать события из userland’а — т. е. из прикладного приложения. У моего планшета было устройство /dev/uinput, но lsmod показывал, что сам модуль не загружен. Так что отметаем — он есть не везде.
- Прямой инжект событий в character устройство — весьма грязный хак, который позволяет инжектить события, не притворяясь системным приложением, но имеет некоторые ограничения. Именно его я и выбрал и о ограничениях ниже.
Сначала нам нужно узнать, какие кнопки поддерживают загруженные устройства ввода в системе. Для этого используем команду getevent -li. Там есть разные устройства ввода, в том числе и тачскрин (если вам нужно симулировать нажатия на экран), мне же подошёл драйвер физических кнопок mtk-kpd. Он занимается обработкой кнопок громкости, включения и т. п. Тут важно обратить внимание на то, что если попытаться послать кнопку, которое устройство не реализует (например пробел), то ничего не произойдет:
Инжект событий я писал на C, т. к. это требовало прямой записи input_event, а в Java прокинул его через Jni. Концепция простая: открываем устройство /dev/input/event2 и посылаем в него события ввода и синхронизации (это обязательно!), которые затем Android читает и обрабатывает:
#include
#include
#include
#include
#include
#include
#include
int uinput;
extern «C» JNIEXPORT void JNICALL Java_com_monobogdan_inputservicebridge_InputNative_init(JNIEnv *env, jclass clazz)
uinput = open(«/dev/input/event2», O_WRONLY);
__android_log_print(ANDROID_LOG_DEBUG , «Test», uinput >= 0 ? «Open event OK» : «Failed to open event»); >
void emit(int fd, int type, int code, int val)
struct input_event ie; ie.type = type;
ie.code = code; ie.value = val;
ie.time.tv _sec = 0;
ie.time.tv _usec = 0;
write(fd, &ie, sizeof(ie)); >
extern «C» JNIEXPORT void JNICALL Java_com_monobogdan_inputservicebridge_InputNative_sendKeyEvent(JNIEnv *env, jclass clazz, jint key_code, jboolean pressed)
__android_log_print(ANDROID_LOG_DEBUG , «Test», «Send»);
emit(uinput, EV_KEY, key_code, (bool)pressed ? 1 : 0);
emit(uinput, EV_SYN, SYN_REPORT, 0);
>
Основной обработкой занимается сервис, который я реализовал в отдельном потоке: он слушает события с UART и посылает соответствующие изменения состояния через sendKeyEvent. На вход приходят простые сообщения вида:
U L где U/D — нажато, не нажато, а L — однобайтовый идентификатор кнопки. В случае L — это влево, R — вправо и т. п. Вся доступная раскладка хранится в словаре. Причём само чтение из UART реализовано костылем с чтением «чужого» stdout, т. к. android-приложения не умеют сами по себе работать с root правами. В теории, это могло дать неприятный оверхед, но на практике никакого серьезного инпут лага это не создает. Не забываем сделать устройство event записываемым — ставим ему права 777:
package com.monobogdan.inputservicebridge;
public class InputListener extends Service
private static final int tty = 3;
private InputManager iManager;
private Map keyMap;
private Method injectMethod;
private Process runAsRoot(String cmd)
try
return Runtime.getRuntime().exec(new String[] < "su", "-c", cmd >);
>
catch (IOException e)
e.printStackTrace();
return null;
>
>
@override
public void onCreate()
super.onCreate();
// According to linux key map (input-event-codes.h)
keyMap = new HashMap<>();
keyMap.put(‘U’, 103);
keyMap.put(‘D’, 108);
keyMap.put(‘L’, 105);
keyMap.put(‘R’, 106);
keyMap.put(‘E’, 115);
keyMap.put(‘B’, 158);
keyMap.put(‘A’, 232);
keyMap.put(‘C’, 212);
InputNative.init();
try
runAsRoot(«chmod 777 /dev/input/event2»).waitFor();
> catch (InterruptedException e)
throw new RuntimeException(e);
>
Executors.newSingleThreadExecutor().execute(new Runnable()
@override
public void run()
Process proc = runAsRoot(«cat /dev/ttyMT» + tty);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while(true)
try
String line = reader.readLine();
if(line != null && line.length() > 0)
Log.i(«Hi», «run: » + line);
boolean pressing = line.charAt(0) == ‘D’;
int keyCode = keyMap.get(line.charAt(2));
Log.i(«TAG», «run: » + keyCode);
InputNative.sendKeyEvent(keyCode, pressing);
>
>
catch(IOException e)
e.printStackTrace();
>
/*try
Thread.sleep(1000 / 30);
> catch (InterruptedException e)
e.printStackTrace();
>*/
>
>
>);
>
@override
public IBinder onBind(Intent intent)
return null;
>
>
Таким образом, если мы отправляем с ПК «D L» — система считает, что мы зажали стрелку влево, а U L — считает что мы отпустили. Но если mtk-kpd поддерживает стрелки и еще некоторые действия без каких либо проблем, то enter в список обрабатываемых кнопок не входит: придется мудрить! И тут нам приходит на помощь механизм трансляции кодов кнопок в действия: они хранятся в специальных файлах .kl в /system/usr/keylayout/. Я назначил DPAD_CENTER на… кнопку регулировки громкости звука! Ну, а почему бы и нет. 🙂 Таким образом можно переназначить уже имеющиеся кнопки громкости на, например, start/select.
❯ Геймпад
После того, как сервис был готов и отлажен, нужно было реализовать хардварную часть проекта — сам геймпад. В качестве контроллера я, как уже говорил, выбрал Raspberry Pi Pico на базе МК RP2040 — бодреньком контроллере с двумя ARM Cortex-M0 ядрами. Стоит копейки, а в отличии от ESP’шек, его SDK не такое перегруженное и выглядит более приближенным к bare-metal.
На данный момент, я решил развести все кнопки на бредборде — макетной плате без пайки, т. к. макеток для пайки у меня под рукой не было. Сделал примитивный геймпад:
Развел на соответствующие GPIO:
И написал примитивную прошивку, которая отслеживает состояние кнопок. В прошивке точно так же есть словарь, задающий ассоциацию между физическими пинами и «виртуальными» кнопками. При нажатии или отжатии кнопки, программа изменяет стейт и отсылает новое состояние планшету.
Собираем всё вместе и тестируем. Хоба, всё работает, мы можем перемещаться по менюшке используя наш геймпад!
А почему бы не попробовать поиграть в какую-нибудь игру? Ну мы же консоль вроде делаем: берём эмулятор NES, биндим кнопки в настройках и наслаждаемся игрой в Марио!
❯ Заключение
Реализация этого проекта заняла у меня не так уж и много времени: всего около 3-х дней работы по вечерам. Вероятно кто-то спросит: «а чего ты просто Bluetooth геймпад не купил?». Так это не прикольно ведь. Гораздо приятнее играть в девайс, к которому ты приложил руку сам. Более того, не у всех старых планшетов есть BT. Обошёлся на данной стадии проект недорого: планшет мне подарили бесплатно (точно также у вас дома может лежать подобный), RPi Pico — 350 рублей, кнопки по 10 рублей/штучка.
В целом, я сам по себе обожаю копаться в различных железках и их софтварной части (вспомнить хотя-бы статью про перекомпиляциюu-boot из вендорских исходников для нонейм консоли), а созидать что-то свое вообще вызывает какие-то нереальные всплески эндорфина — оно и понятно! 🙂
Однако несмотря на то, что мы уже имеем рабочий «прототип», проект далёк от завершения: я намерен довести его до конца и окончательно перевоплотить старый планшет в автономную игровую консоль (и рассказать об этом во второй части статьи). Для этого мне понадобится распечатать корпус и кнопки на 3D-принтере. К сожалению, у меня в городе ни у кого особо нет 3D-принтеров, поэтому начну копить на Ender 3, а от вас, читателей, с удовольствием почитаю мнение в комментариях и советы касательно выбора принтера!
Статья подготовлена при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, чтобы не пропускать еженедельные статьи про моддинг различных гаджетов!
Умный дисплей — своими руками
Последние пару недель вижу рекламу «умных дисплеев» или чего-то в этом духе. Суть их в том, что это «умная колонка», оснащённая экраном. Ценник по минимуму — что-то от 12000 руб.
Чуть больше года назад я присматривался к подобным девайсам, но только стоили они тогда ещё дороже. И пораскинув мозгами я нашёл гораздо менее затратный вариант сделать такое же «умное» устройство, но с более широкими возможностями. Попользовавшись своей «разработкой» пару месяцев я отчитался о результатах статьёй на helpix.ru , но как вижу, исходя из текущих тенденций, нелишним будет поделиться информацией и с вами, друзья-пикабушники.
«Умные колонки», которые горячо рекламируют Яндекс, Амазон и масса других производителей, может действительно настолько умные, что нам и не снилось, но обладают одним гигантским минусом: кроме звуков от них более ничего не дождёшься. Есть, конечно, прикол в том, чтобы разговаривать с «умной колонкой», получать ответы на вопросы, управлять устройствами «умного дома», но всё это больше похоже на скоропроходящее развлечение. Да и неудобно на слух получать большие объёмы информации. Например, метеопрогноз на неделю.
Примерно год назад появился ещё один класс устройств: «умные экраны/дисплеи». Их не так активно рекламируют (не известно по какой причине), но они, являясь гибридом «умной колонки» и планшета, позволяют получать и визуальную информацию. Среди производителей таких экранов отметились Amazon, Google, Lenovo. Но как отмечают в обзорах, в итоге получается недопланшет и недоколонка. Операционная система с урезанными функциями, «заточенная» под «умные» функции не даёт такой широты возможностей как даже «голый» Android на планшете, да и звук тоже не фонтан. А цены у более-менее приличных моделей начинаются от 200 баксов…
И вот тут меня взяла непонятка: не самые дорогие планшеты стоят вполовину от этих «умных дисплеев». А подержанные — и того дешевле. Почему нужно платить такие безумные деньги, если можно взять простой планшет и установив несколько программ и виджетов установить его на кухне, подключив к розетке?
В интернете нахожу в продаже за 500 (!) рублей 7-дюймовый планшет с полудохлым аккумулятором на 6-м «андроиде». «Ирбисом» зовут. В ломбарде за те же самые 500 рублей купил компактные, но с приличными характеристиками колонки с питанием от USB. И за три сотни докупаю к этой парочке сетевой адаптер с двумя выходами USB — не так много у меня на кухне свободных розеток.
Без прощальных слёз с полочки снимается старый радиоприёмник и отправляется в дальний угол кладовки. И на это место встаёт планшет. Подключаем его к домашнему WiFi и.
Но теперь звук должен быть гораздо лучше. Вопрос — откуда его теперь получать? Можно, конечно, от эфирных радиостанций, но есть вариант и получше: интернет-радио. На телевизор в комнате я установил программу PC-radio, и имею возможность выбирать из почти трёх тысяч радиостанций со всего мира. Устанавливаем её и на планшет. На рабочий стол выводим виджет. Программа имеет бесплатную и платную версии. В платной качество звука лучше.
По правде говоря, всю эту историю с планшетом и колонками инициировал этот самый приёмник «благодаря» отстойному звуку и неудобному управлению. И прожил-то он на этой полочке три года только по причине наличия крупных ярких часов и интересного дизайна.
Первая задача решена. Теперь попробуем превратить планшет в «умный дисплей».
Устанавливаем «Яндекс с Алисой», ярлык «Алисы» выводим на рабочий стол. Ну, здравствуй, «Алиса». Какая у нас там погода на завтра?
Погоду «Алиса» оттарабанивает чётко. Вот только в отличие от «умных» колонок и дисплеев не висит постоянно в памяти, ловя каждое ваше слово, поэтому приходится вызывать её через ярлык с экрана. Также «Алиса», как оказалось, не поддерживает команды типа напомнить о чём-либо когда-либо. Эта возможность присутствует только в «умных» гаджетах. А вот поставить таймер — это пожалуйста.
А вот как-то раз я во время рекламной паузы поскакал на кухню быстренько сделать бутерброды. И не успел уложиться до окончания рекламы! А я так ждал ту информацию, которая должна была прозвучать после неё…
И вот только после этого случая меня озарило: телевизор-то я смотрю через интернет. Так что же мне мешает поставить программу телепрограммы на планшет? И теперь на планшете есть программа ТВ+, позволяющая смотреть эфирные телепередачи через WiFi.
Кстати, ТВ+ на моём телевизоре Xiaomi Mi 4S позволяет смотреть телепередачи в HD качестве, и картинка гораздо лучше чем при приёме через антенну. На дисплее 4К это особенно заметно. Впрочем, на 7 дюймах планшета HD как-то не требуется.
Само собой на планшете можно смотреть ролики с ютьюба. Видеорецепты, например. Можно из браузера смотреть, а можно и отдельную программу поставить.
Хочу предупредить, что планшеты-старички будут тормозить и тупить. Мой планшет меня порой своей медлительностью подбешивает. Так что, чем новее — тем лучше, а минимальной границей я считаю планшеты на 6-м «андроиде». Диагонали 7 дюймов вполне достаточно, Но если захотите поболее — кто ж протестовать-то будет?
Теоретически, можно ещё транслировать на планшет слайд-шоу из фотографий. Можно в качестве заставки какие-нибудь релаксирующие видео крутить. На второй рабочий стол поставить виджет календаря. Нужны напоминания, которые «Алиса» отказывается делать? Поставьте программу «Запоминатор» — и ввод голосом напоминаний вам будет доступен. А, да! Если «умные» лампочки или розетки работают в экосистеме с передачей данных через WiFi, то можно будет установить на планшет общую управляющую программу. На смартфонах же такое прокатывает.
Но мне пока хватает «живых обоев» с аквариумом и часов на рабочем столе: поскольку питается планшет от сети, экран можно не гасить и пользоваться этим преимуществом.
В общем — вот вам поле для экспериментов, и будьте умными, не ведитесь сразу на «умные» гаджеты.
И по прошествии полутора лет эксплуатации такой сборки дополню: весь функционал, описанный выше, работает. Критичных сбоев в работе не обнаружено. Электропитание подаётся на планшет 24/7 — батарея до сих пор не вспучилась, перегрев на корпусе не ощущается.
Но версию андроида однозначно надо брать поновее. На планшет тоже не стоит слишком скупиться. Я-то брал самую дешёвку только потому, что не знал — выйдет ли что-то из этой затеи толковое. По моему мнению — вышло.
Поддержать
111 постов 2K подписчиков
Подписаться Добавить пост
1 год назадЛишний абзац убери
раскрыть ветку (1)
1 год назадУбрал. Спасибо за подсказку.
1 год назад
Два раза одно и тоже написал ты
раскрыть ветку (1)
1 год назад
1 год назадНу, руками запускать такое себе.
Проще нативный браузер держать, там оно активируется самораскрыть ветку (1)
1 год назадТкнуть в иконку на рабочем столе планшета — не вот уж большая проблема.
Я считаю — лучше я буду управлять «помощником», а не он мной.
1 год назад
Если уж управление умным домом,то на планшет надо mqtt сервер ставить.Чтоб по mqtt управлять.
раскрыть ветку (1)
1 год назадДа, нужно. Тем, кто будет управлять через планшет IoT.
У меня ни умных розеток, ни умных лампочек пока не предвидится. А пылесосом и со смартфона управлять не в напряг.
1 год назад
Судя по результу, никакой умной колонкой там не пахнет. Стоит говенный старый планшет, на который установили пару приложений, а рассказа на простыню. Умные гаджеты на то и умные, что не из говна и палок, а заточены под конкретный функционал и нет необходимости ни с чем ебаться при их использовании. Для души, так сказать.
раскрыть ветку (1)
1 год назадГовённый, старый — да. И я объяснил почему он именно такой. Читай внимательнее.
И рекомендую самому попробовать те «умные» гаджеты, которые на фабрике собраны. После этого уже сравнивать их функционал с «говном и палками».
И да, от умной колонки не дождаться таких возможностей, которые даёт мой вариант. Не могёт-с. 😀
показать ответы
1 год назадярлык «Алисы» выводим на рабочий стол
Что-то не ясно — требуется ли нажимать на ярлык Алисы
Сейчас ТВ на андроиде многие и от планшета в теории вовсе можно отказаться.
Пост потенциально полезный но ИМХО сумбурный.
Проще развернуть HASIO, в нем автоматизации больше и Алиса интегрируется
раскрыть ветку (1)
1 год назадДа, «Алису» запускаю принудительно, через ярлык. А в целом, от «Алисы» я не в восторге.
Но хочу предостеречь от прямого сравнения планшета и смартфона с телевизором. В телевизорах андроид мощно так урезан по функционалу.
показать ответы
1 год назадПовторение- мать учения!
После третьего раза мы точно знаем, что:»Но теперь звук должен быть гораздо лучше. Вопрос — откуда его теперь получать? Можно, конечно, от эфирных радиостанций, но есть вариант и получше: интернет-радио. На телевизор в комнате я установил программу PC-radio, и имею возможность выбирать из почти трёх тысяч радиостанций со всего мира. Устанавливаем её и на планшет. На рабочий стол выводим виджет. Программа имеет бесплатную и платную версии. В платной качество звука лучше.»
раскрыть ветку (1)
1 год назадПовтори ещё раз.
Может после этого повтора будет понятно что за претензия.
показать ответы
1 год назадТы из говна и палок собрал конструкцию, которая даже тебя самого не устраивает. И ты ещё удивляешься на реакцию?
Ок. Ты молодец! Собрал мега девайс! Запускай его в производство! Станешь миллионером!
Так лучше?раскрыть ветку (1)
1 год назадНо ты и до такого даже не додумался.
И с чего ты взял, что я удивляюсь на реакцию?1 год назад
Умной колонки так и не получилось, а получился планшет с программами. Без поддержки постоянного управления голосом смысла в этом крайне мало.
раскрыть ветку (1)
1 год назадУ меня и не было цели сделать умную колонку.
Я хотел сделать умный планшет. И под мои задачи проект работает.Единственно, я не мог предположить какая будет производительность у такого дешёвого планшета при работе с Алисой, но в целом для меня Алиса не особо-то и нужна.
В остальном — музыку играет, видео показывает, в инет выходит. Больше от него я ничего не требую.
показать ответы
1 год назадДа просто просто поразительно, как можно разъелозить такую элементарщину. Думаю, в этой жизни тебя ждет еще много удивительного. Дерзай!
раскрыть ветку (1)
1 год назадЯ каждый день столько удивительного наблюдаю в разных сферах моих профессиональных навыков, что попросил бы не желать мне излишнего.
И вот мне удивительно в вашем ответе: типа 90% людей вокруг нас прекрасно знают о том, что можно сделать так же как я описал? И 70% из них уже так сделали?
Мы с вами, похоже, живём в разных мирах.
98% моих клиентов даже не подозревают о том, что есть свободное вещание интернет-ТВ, которое можно смотреть не покупая дополнительные «пакеты» от провайдера. Что для просмотра телепрограмм достаточно только подключения к интернету.
1 год назад
Мда. Я понял ваше мнение и отношение к данному вопросу. Не вижу смысла продолжать разговор
раскрыть ветку (1)
1 год назадЯ считаю, это хорошо, когда у читателя не остаётся вопросов относительно темы статьи. И, конечно, нет смысла продолжать обсуждение если всё понятно.
Забегайте в комментарии, если будет возможность. У меня это не последняя статья, обсудим новые по мере поступления. 🙂1 год назад
Тут уже спор о вкусе фломастеров. На этот случай станцию можно подключить как блютуз колонку и слушать что душе угодно.
раскрыть ветку (1)
1 год назадТак нахер я буду платить деньги за станцию, если я могу купить просто блютуз-колонку!? Уж на неё-то я без проблембуду транслировать музыку из своей коллекции, и не париться о контенте. Но — только музыку.
Ещё раз объясняю суть: «умный дисплей» (и колонка) завязан исключительно на софт и контент производителя и «партнёров». Будешь жрать то что дадут. На планшет ты можешь установить любые программы, которые позволят реализовать в разы больше всяких возможностей.
показать ответы
1 год назадПожалуй не соглашусь. У самого Яндекс станция которая подключена к телевизору, все гораздо удобнее чем у вас, в по функционалу не хуже.
раскрыть ветку (1)
1 год назадЯндекс-станция + телевизор — это примерно похоже, но несопоставимо с моим вариантом и свободой выбора, который он даёт.
Яндекс-станция не даст вам слушать ту радиостанцию, которая выдаёт в эфир музыку, которая вам нравится. Она будет подбирать вам музыку по своему «алгоритму». А мне этот «алгортим» нифига не нравится. Ну невозможно этой санции объясгить что не хочу я слушать «Нирвану» или «перчиков». Каждые полчаса приходится командовать заново.
А интернет-радиостанции — я подобрал 3 штуки, и если не нравится их текущий плейлист — переключился на другую. Вы просто не пробовали так делать. А я — на себе попробовал. И утверждаю, что навязываемый «умными колонками» репертуар — отстой.
показать ответы
1 год назадРезюмируя, ТС обнаружил, что на планшет можно установить нужные приложения и подключить колонки? Или я что-то упускаю?
раскрыть ветку (1)
1 год назадНет, всё правильно.
Только отдельные охочие до денег бренды хотят слупить с людей деньги за вот такую фигню. И — нехилые деньги.
А можно всё сделать гораздо дешевле и с большим функционалом.
(Извини, что приходится снова и вкратце объяснять суть статьи. По-видимому, с длинными текстами у тебя не ладится)показать ответы
1 год назад
Не забывайте про удобство пользования, ограничения для детей и т.д.
раскрыть ветку (1)
1 год назадНикакого удобства пользования колонками я не обнаружил. Пользовал их — туфта полная.
А с детьми — вообще проблем не вижу. Что тут может быть не так?
показать ответы
1 год назад
Почему-то возникла ассоциация — Парень он неплохой, только ссытся и глухой.
раскрыть ветку (1)
1 год назадСудя по твоим постам и комментариям, ты внезапно в зеркало посмотрелся. Вот и навеяло.
показать ответы
Похожие посты
5 месяцев назадСам себе игровая консоль: превращаем планшет с нерабочим тачскрином в игровой девайс из 8 кнопок и микроконтроллера
К сожалению, в наше время многие старые, но весьма неплохие по характеристикам гаджеты отправляются напрямую в помойку, и их владельцы не подозревают, что им можно найти применение. Сервер, мультимедийная-станция, да даже просто как TV-приставка — люди в упор не замечают сфер, где старенький планшет мог бы быть полезен. Но как быть, если посвящаешь жизнь портативным гаджетам, кодингу и копанию в железе? Правильно: сделать довольно мощную игровую консоль из старого планшета самому! Сегодня вам расскажу, как я сделал свою портативную приставку из планшета с нерабочим тачскрином, Raspberry Pi Pico и 8 кнопок! За рабочим результатом прячется несколько дней работы: поиск UART на плате, разработка контроллера геймпада на базе RPi Pico, написание приложения-сервиса, которое слушает события и отправляет их в подсистему ввода Linux в обход Android. Интересно? Тогда жду вас под катом!
❯ Мотивация
Прошло уже практически 10 лет с того момента, как у меня появилась моя первая портативная консоль. Несмотря на то, что я был заядлым ПК-игроком, я уже успел посмотреть на PS3 и PSP, но денег на их покупку у меня особо не было, да и к тому времени уже был в наличии Android-планшет. Но к моему 13-летию в 2014 году, когда я ходил и выбирал себе будущий девайс на день рождения, отец и мама решили подарить мне мою первую портативную консоль. Изначально, я уговаривал её купить мне целых два девайса, но бюджет был ограничен 4.000 рублей, а я хотел взять смартфон Fly IQ239 и консоль JXD S601 одновременно:
Однако, увидев здоровую 7-дюймовую консоль в магазине TREC (думаю, жители южной части РФ помнят такой), мама уговорила меня взять именно её, мотивируя это «ну и чего ты будешь тыкаться в этот мелкий экран? Возьми большую». После покупки гаджета, я был доволен: играл какие-то игрушки с ретро-платформ, устанавливал игры на Android, сидел в ВК через Kate Mobile. Что еще нужно было школяру? Однако, планшет прожил у меня недолго: с очередного лага я психанул и ударил по нему кулачком, унеся на тот свет и дисплей и тачскрин. Так консолька и пролежала в подвале около 8 лет. Впрочем, мне продолжали импонировать подобные устройства и в прошлом году я купил и написал про несколько подобных девайсов.
Несколько месяцев назад, мой читатель Кирилл Севостьянов с Хабра прислал мне HTC HD2 в качестве донора и планшет Prestigio PMP7170B3G, который был рабочим, но… у него отказал тачскрин. Я всё думал, чего бы с ним сделать и решил реализовать игровую консольку своими руками из подручных средств. Идея крутилась в голове довольно давно, но реализовал я её только сейчас.
❯ Что нам нужно сделать?
Итак, что должно быть у портативной консоли? Чипсет, дисплей, звук, ОС — это всё нам уже предоставляет планшет. Нам остаётся лишь сделать свой геймпад. Давайте подумаем, что нам будет нужно для того, чтобы его сделать и передавать от него события на планшет:
- Контроллер для геймпада: тут нам подойдет практически любой микроконтроллер, который работает от 3.3в. Выбор большой: Arduino Pro Mini 3.3v, ESP32, RPi Pico. Я остановился на последнем: недавно я взял себе две штучки «пощупать» их — и они мне очень понравились!
- Физический интерфейс: с планшетом нужно как-то общаться. У нас есть три варианта: USB (не факт, что поддержка преобразователей включена в ядре), UART и SPI/I2C на пятачках тачскрина (потребуют написания драйвера т. к. в android-устройствах нет прямого доступа к SPI/I2C из userland’а). Я остановился на UART: его легко найти на большинстве китайских планшетов, а если не получилось — то на помощь может прийти схема платы.
- Программная реализация: как это будет работать? Я решил реализовать геймпад в виде сервиса на Android, который слушает состояния кнопок с UART и «инжектит» события напрямую в драйвер ввода. Таким образом, поддержка нашего геймпада появляется даже в самой системе — можно управлять менюшкой или приложениями как с клавиатуры!
С планом определились, пора начать с программной части: сначала нам обязательно понадобится ROOT-доступ. Его получение на разных девайсах отличается — на prestigio уже был порт CWM и я просто поставил SuperSU. Без ROOT доступа мы не сможем использовать UART!
Теперь нам нужно найти пятачки UART на плате. Разведен он не везде, но в случае устройств на MediaTek — почти всегда, ещё и пятачки подписаны. На моём планшете он нашёлся сразу: был между двух металлических экранов и соответствовал 4-ому каналу UART. Получить к нему доступ можно в /dev/ttyMT3. Я использую ESP32 в качестве UART преобразователя: подпаиваемся к RX/TX, запускаем putty и заходим в adb shell. Определяем бодрейт (скорость) нашего UART порта — на MediaTek он обычно равен 921600, на других чипсетах — 115200. Пытаемся что-то вывести и хоба — мы уже можем «поболтать» с планшетом!
❯ Приложение-сервис
Итак, у нас уже есть доступ к UART и мы можем общаться с планшетом из внешнего мира. Но получить события с кнопок пол дела, нужно их ещё и послать в систему. Для этого есть целых три способа:
- InputManager.injectInputEvent — именно этим методом пользуется команда input, которую вы можете использовать через adb. Но увы, он работает только при наличие разрешения INJECT_EVENTS, который доступен только системным приложениям — находятся они в /system/app и подписаны тем же сертификатом, что и остальная прошивка.
- Модуль uinput дает возможность создать виртуальное устройство ввода и посылать события из userland’а — т. е. из прикладного приложения. У моего планшета было устройство /dev/uinput, но lsmod показывал, что сам модуль не загружен. Так что отметаем — он есть не везде.
- Прямой инжект событий в character устройство — весьма грязный хак, который позволяет инжектить события, не притворяясь системным приложением, но имеет некоторые ограничения. Именно его я и выбрал и о ограничениях ниже.
Сначала нам нужно узнать, какие кнопки поддерживают загруженные устройства ввода в системе. Для этого используем команду getevent -li. Там есть разные устройства ввода, в том числе и тачскрин (если вам нужно симулировать нажатия на экран), мне же подошёл драйвер физических кнопок mtk-kpd. Он занимается обработкой кнопок громкости, включения и т. п. Тут важно обратить внимание на то, что если попытаться послать кнопку, которое устройство не реализует (например пробел), то ничего не произойдет:
Инжект событий я писал на C, т. к. это требовало прямой записи input_event, а в Java прокинул его через Jni. Концепция простая: открываем устройство /dev/input/event2 и посылаем в него события ввода и синхронизации (это обязательно!), которые затем Android читает и обрабатывает:
#include
#include
#include
#include
#include
#include
#include
int uinput;
extern «C» JNIEXPORT void JNICALL Java_com_monobogdan_inputservicebridge_InputNative_init(JNIEnv *env, jclass clazz)
uinput = open(«/dev/input/event2», O_WRONLY);
__android_log_print(ANDROID_LOG_DEBUG , «Test», uinput >= 0 ? «Open event OK» : «Failed to open event»); >
void emit(int fd, int type, int code, int val)
struct input_event ie; ie.type = type;
ie.code = code; ie.value = val;
ie.time.tv _sec = 0;
ie.time.tv _usec = 0;
write(fd, &ie, sizeof(ie)); >
extern «C» JNIEXPORT void JNICALL Java_com_monobogdan_inputservicebridge_InputNative_sendKeyEvent(JNIEnv *env, jclass clazz, jint key_code, jboolean pressed)
__android_log_print(ANDROID_LOG_DEBUG , «Test», «Send»);
emit(uinput, EV_KEY, key_code, (bool)pressed ? 1 : 0);
emit(uinput, EV_SYN, SYN_REPORT, 0);
>
Основной обработкой занимается сервис, который я реализовал в отдельном потоке: он слушает события с UART и посылает соответствующие изменения состояния через sendKeyEvent. На вход приходят простые сообщения вида:
U L где U/D — нажато, не нажато, а L — однобайтовый идентификатор кнопки. В случае L — это влево, R — вправо и т. п. Вся доступная раскладка хранится в словаре. Причём само чтение из UART реализовано костылем с чтением «чужого» stdout, т. к. android-приложения не умеют сами по себе работать с root правами. В теории, это могло дать неприятный оверхед, но на практике никакого серьезного инпут лага это не создает. Не забываем сделать устройство event записываемым — ставим ему права 777:
package com.monobogdan.inputservicebridge;
public class InputListener extends Service
private static final int tty = 3;
private InputManager iManager;
private Map keyMap;
private Method injectMethod;
private Process runAsRoot(String cmd)
try
return Runtime.getRuntime().exec(new String[] < "su", "-c", cmd >);
>
catch (IOException e)
e.printStackTrace();
return null;
>
>
@override
public void onCreate()
super.onCreate();
// According to linux key map (input-event-codes.h)
keyMap = new HashMap<>();
keyMap.put(‘U’, 103);
keyMap.put(‘D’, 108);
keyMap.put(‘L’, 105);
keyMap.put(‘R’, 106);
keyMap.put(‘E’, 115);
keyMap.put(‘B’, 158);
keyMap.put(‘A’, 232);
keyMap.put(‘C’, 212);
InputNative.init();
try
runAsRoot(«chmod 777 /dev/input/event2»).waitFor();
> catch (InterruptedException e)
throw new RuntimeException(e);
>
Executors.newSingleThreadExecutor().execute(new Runnable()
@override
public void run()
Process proc = runAsRoot(«cat /dev/ttyMT» + tty);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while(true)
try
String line = reader.readLine();
if(line != null && line.length() > 0)
Log.i(«Hi», «run: » + line);
boolean pressing = line.charAt(0) == ‘D’;
int keyCode = keyMap.get(line.charAt(2));
Log.i(«TAG», «run: » + keyCode);
InputNative.sendKeyEvent(keyCode, pressing);
>
>
catch(IOException e)
e.printStackTrace();
>
/*try
Thread.sleep(1000 / 30);
> catch (InterruptedException e)
e.printStackTrace();
>*/
>
>
>);
>
@override
public IBinder onBind(Intent intent)
return null;
>
>
Таким образом, если мы отправляем с ПК «D L» — система считает, что мы зажали стрелку влево, а U L — считает что мы отпустили. Но если mtk-kpd поддерживает стрелки и еще некоторые действия без каких либо проблем, то enter в список обрабатываемых кнопок не входит: придется мудрить! И тут нам приходит на помощь механизм трансляции кодов кнопок в действия: они хранятся в специальных файлах .kl в /system/usr/keylayout/. Я назначил DPAD_CENTER на… кнопку регулировки громкости звука! Ну, а почему бы и нет. 🙂 Таким образом можно переназначить уже имеющиеся кнопки громкости на, например, start/select.
❯ Геймпад
После того, как сервис был готов и отлажен, нужно было реализовать хардварную часть проекта — сам геймпад. В качестве контроллера я, как уже говорил, выбрал Raspberry Pi Pico на базе МК RP2040 — бодреньком контроллере с двумя ARM Cortex-M0 ядрами. Стоит копейки, а в отличии от ESP’шек, его SDK не такое перегруженное и выглядит более приближенным к bare-metal.
На данный момент, я решил развести все кнопки на бредборде — макетной плате без пайки, т. к. макеток для пайки у меня под рукой не было. Сделал примитивный геймпад:
Развел на соответствующие GPIO:
И написал примитивную прошивку, которая отслеживает состояние кнопок. В прошивке точно так же есть словарь, задающий ассоциацию между физическими пинами и «виртуальными» кнопками. При нажатии или отжатии кнопки, программа изменяет стейт и отсылает новое состояние планшету.
Собираем всё вместе и тестируем. Хоба, всё работает, мы можем перемещаться по менюшке используя наш геймпад!
А почему бы не попробовать поиграть в какую-нибудь игру? Ну мы же консоль вроде делаем: берём эмулятор NES, биндим кнопки в настройках и наслаждаемся игрой в Марио!
❯ Заключение
Реализация этого проекта заняла у меня не так уж и много времени: всего около 3-х дней работы по вечерам. Вероятно кто-то спросит: «а чего ты просто Bluetooth геймпад не купил?». Так это не прикольно ведь. Гораздо приятнее играть в девайс, к которому ты приложил руку сам. Более того, не у всех старых планшетов есть BT. Обошёлся на данной стадии проект недорого: планшет мне подарили бесплатно (точно также у вас дома может лежать подобный), RPi Pico — 350 рублей, кнопки по 10 рублей/штучка.
В целом, я сам по себе обожаю копаться в различных железках и их софтварной части (вспомнить хотя-бы статью про перекомпиляциюu-boot из вендорских исходников для нонейм консоли), а созидать что-то свое вообще вызывает какие-то нереальные всплески эндорфина — оно и понятно! 🙂
Однако несмотря на то, что мы уже имеем рабочий «прототип», проект далёк от завершения: я намерен довести его до конца и окончательно перевоплотить старый планшет в автономную игровую консоль (и рассказать об этом во второй части статьи). Для этого мне понадобится распечатать корпус и кнопки на 3D-принтере. К сожалению, у меня в городе ни у кого особо нет 3D-принтеров, поэтому начну копить на Ender 3, а от вас, читателей, с удовольствием почитаю мнение в комментариях и советы касательно выбора принтера!
Статья подготовлена при поддержке TimeWeb Cloud. Подписывайтесь на меня и @Timeweb.Cloud, чтобы не пропускать еженедельные статьи про моддинг различных гаджетов!