Мой вольный перевод статей в моем блоге.

Самые скучные времена в жизни рождают самые нескучные идеи: Жара, бескрайняя казахская степь и бесконечно разбитая казахская дорога. 2017 год. По радио прозвучала новость, в барах Англии начали ставить интерактивные писсуары. Без лишних слов лучше на видео посмотреть что это такое:

Urinal Games

Выглядело очень забавно. На видео игры показались слишком простыми. Поэтому сразу в голову полезли идеи в какие еще игры можно было бы сыграть на такой «игровой консоле». Сетевые игры самые захватывающие и интересные. Всегда интереснее соревноваться с живым игроком и чем‑нибудь помериться… Но во что можно сыграть при таком примитивном управлении? Лучше всего напрашивается аркадная игра типа пинг понга. А если учесть что в следующем году(2018) будет чемпионат мира по футболу, то можно стилизовать пинг‑понг под футбольные соревнования на мундиале. Забегая вперед выложу демо получившегося устройства и игры.

Но прежде надо было сделать устройство для регистрации положения струи в писсуаре. Так начиналась разработка бесконтактного motion сенсора Pinect. На сегодняшний день можно сказать Open Source проекта Pinect.

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

Чуть вперед-назад-сторону и красный крестик
Чуть вперед-назад-сторону и красный крестик

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

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

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

Еще полезный бонус такого подхода - можно играть с помощью карандашика.

MVP

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

Далее вычисляется сумма яркости всех пикселей в этих столбцах. Рассмотрено по шагам на видое:

Получается график сумм. ПО оси Х — номер столбца в зеленом прямоугольнике(слева‑ направо). Y — соответственно сумма. Теперь надо как‑то ловить изменения этого графика. Проще всего сделать это через вычитание. Просто запоминаем график перед началом игры, когда никакого движения нет и вычитаем из него все последующие.

График сумм по столбцам
График сумм по столбцам

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

Два почти равноправных пика
Два почти равноправных пика

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

площадь пиков в попугаях, для сравнения
площадь пиков в попугаях, для сравнения

Алгоритм давал хорошую точность и не смотря на то что был написан на Python, да еще и не оптимально, работал довольно шустро на слабом ПК. Осталось его реализовать в компактном и недорогом устройстве. Потому как полноценный ПК не поставишь в туалетную комнату.

Дизайн и компоновка

Игровую консоль надо было сделать максимально простой, дешевой, а также максимально тривиальной в эксплуатации. Вместо ПК, можно использовать Android планшет или смартфон. Его вычислительной мощности хватит и под распознавание струи и под аркадную игру. Камеру устройства можно было бы задейстовать под задачу нахождения струи, но так как экран будет под углом, то и камера получается тоже под углом, в таком случае она не всегда будет оптимально располагаться для качественной картинки, лучше задействовать копеечную 0,3Мpx USB(UVC) камеру с али экспресса. и расположить ее объектив строго вниз. Для более контрастной картинки, поставить дополнительное освещение в виде светодиода с линзой.

Расположение светодиода
Расположение светодиода

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

Обнаружение подходящего игрока на расстоянии
Обнаружение подходящего игрока на расстоянии

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

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

  • Планшет Huawei MediaPad T3 10 — на тот момент самый бюджетный безглюченный android аппарат с большим экраном (10 дюймов).

  • USB Камера 0,3Mpх, светодиод до 1Вт с линзой в качестве подстветки.

  • Сенсоры движения Инфракрасный PIR HC‑SR505 и доплеровский RCWL-0516.

  • Температурые датчик DS18B20 2 шт.

  • Обычный компьютерный 90мм вентилятор.

  • Плата управления для слаженной работы всей электроники с Arduino Mini на борту. Файлы scheme & pcb, формат DipTrace.

Суммарно стоимость выходила 20 000 рублей на 2018(при удачной покупке/изготовления компонентов).

Плата управления и ведомые устройства
Плата управления и ведомые устройства

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

Прямо напротив вентилятора на плате располагаются самые горячие модули платы, это:

  • Драйвер светодиода.

  • Повышающий преобразователь с 5 на 12В — не запаян на фото. Питание приставки должно было быть 5В, 5V вентиляторы достать проблематично, поэтому предполагалось использовать обычные 12В вентиляторы с повышающим преобразователем. Но обычные компьютерные 12В куллеры вполне хорошо заработали и от 5В.

  • Модуль зарядки Li‑ion аккумуляторов на TP4056. При такой эксплуатации зарядка через USB не вытягивала питание(от планшета питалась еще и USB камера) и планшет разряжался, поэтому решил просто напрямую заряжать батарею.

Плате управления надо сообщать планшету, что кто‑то приближается и надо готовиться запускать игру. Связь по Bluetooth и WiFi — лишние компопненты/монтаж/настройка и главное ненадежно. Поэтому сигнал подается через подключение камеры. В ждущем состоянии питание камеры отключено, как только игрок появляется на горизонте, плата управления включает питание камеры.

Под
Подключение камеры через плату управления

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

Иногда на планшете подключение камеры проходит не совсем гладко. При подключении камеры вылетает Exception или с камеры не идет изображение. Самое простое это переподключить камеру. Об этом тоже приходится сообщать нетипичным способом. На планшете стоит пьезо‑вибратор для уведомления пользователя о нотификации и звонках. Отключаем два его контакта и подключаем их к плате. Разумеется все делаем через оптическую развязку, дабы не поиметь земляную петлю. Дальше в случае зависания из программы подаем сигнал вибрации и плата управления сама переподключает камеру, со второго раза всегда работало как надо.

Корпус после печати
Корпус после печати

Корпус консоли спроектирован под 3D печать(скачать). Именно поэтому стенки сделано такие тонкие, а дно вообще неприличное тонкое. Иначе печать выйдет долгой и дорогой. Дешевое укрепление конструкции дает эпоксидная смола, просто заливаем дно детали на 5 миллиметро — конструкция не такая хлипкая.


Залитое эпоксидкой дно и экранирование доплеровского датчика движения
Залитое эпоксидкой дно и экранирование доплеровского датчика движения

Здесь видно смоляной пол для укрепления и железная пластиночка для ограничения видимости сенсора RCWL-0516. Этот доплеровский радио сенсор работает в две противоположные стороны относительно плоскости платы, поэтому чтобы сенсор не реагировал на вращение вентилятора(только видимость в желтом треугольнике), нужен такой ограничитель в виде железной пластиночки.

Отштукатуренный и покрашенный корпус
Отштукатуренный и покрашенный корпус

Штукатурка и покраска корпуса помимо красоты и заводского вида так же прибавляет немного жесткости.

Android

Под Android сделано несколько приложений.

  • PiBall — сама аркадная игра

  • PiLauncher — сервис который определяет положение струи и передает ее в игру

Два сервиса для удаленного управления устройством:

  • MClient — по факту почтовый клиент, получает в письмах команды/настройки и передает их остальным сервисам, отправляет статистику от остальных сервисов. Сейчас модно было бы телеграм бота сделать, но в 2018, телеграм был заблокирован. Самый простой и надежный способ управления на тот момент, без сервера, было через почтовые сообщения.

  • Admin‑DPC приложение, через которое можно обновлять сервисы и устанавливать дополнительные игры. Также можно менять разные настройки системы (WiFi для примера)

Получилось микросервисная архитектура, с четким разграничением функционала.

Посмотрим как работают и взаимодействую первые два сервиса. PiLauncher захватывает изображение с камеры с помощью библиотеки UVCCamera (вернее немного пропатченной).

Приложение PiLauncher
Приложение PiLauncher

Пользователем предустанавливается область в фиолетовом прямоугольнике, где будет работать алгоритм, на экране помечана красной маской на изображении с камеры (сама USB камера смотрит в писсуар). Дальше по алгоритму из MVP на питоне, мы сначала переводили изображение в серые тона (GrayScale), а потом сумировали пиксели по маске. Здесь можно оптимизировать алгоритм и избежать перевода в GrayScale, изображение из библиотеки поступает к нам в формате YUV

порядок байт в изображении
порядок байт в изображении

Здесь каждый нечетный байт (помечен как Y) — значение яркости(пусть и не совсем линейной, но тоже сгодится). Поэтому в алгоритме суммирования по столбцам можно просто брать каждый второй байт для суммы и сэкономить немного процессора.

порядок байт в изображении
отладочное окно приложения PiLauncher

На фото показано отладочное окно PiLauncher. Верхняя view показывает полученное изображение с камеры. Нижние графики, это первоначальный зафиксированный график суммы(желто‑зеленый), график текущей суммы (красный) и интеграл их разности(синий). В интеграле разности самый большой пик будет положение струи. Вычисленное положение в относительных координатах отображается на верхнем горизонтальном скролле. Дальше это положение нужно передать в игру.

Вернее сказать игра сама должна запросить эту информацию для себя. Игра может быть не одна. Поэтому проще что бы запущенная игра обращалась к сервису. Делать она это будет через AIDL интерфейс.

AIDL интерфейс
AIDL интерфейс

PiBall сделана на базе фреймворка LibGDX, по сети игра общается с помощью библиотеки kryonet, одно из устройств должно быть сервером, другое клиентом. Устанавливается это просто в настройках, на стартовом экране игры, выбирается последовательно Бразилия→Хорватия→Япония→Польша

последовательность нажатий, что бы попасть в сервисное меню
последовательность нажатий, что бы попасть в сервисное меню

Попадаем в настройки и дальше просто надо галочку установить

устанавливаем, будт ли наша консоль сервером или клиентом
устанавливаем, будт ли наша консоль сервером или клиентом

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

Все репозитории на GitHub:

Файлы проекта:

Комментарии (15)