Свой контроллер для Oculus Quest 2 на ESP32

Стандартные контроллеры популярных VR-гарнитур имеют сильно ограниченные возможности взаимодействия с виртуальным миром и некоторые задачи управления им практически не под силу, напр. имитация руля с коробкой передач. По схожей причине в мире игр уже давно существуют кастомные контроллеры и, пожалуй, наиболее известные из них — световой пистолет для NES и гитара Guitar Hero. У VR такого разнообразия нет, и отчасти из-за того, что производители не спешат предоставлять возможность подключения стороннего оборудования. Как это исправить и сделать свой контроллер для ходьбы — под катом.

Дисклаймер
Это Proof-of-Concept идеи о подключении микроконтроллера ESP32 к шлему, как Bluetooth-клавиатуры, и передачи срабатываний датчиков, как нажатий клавиш, в приложение, запущенное на нем (а не через SteamVR или Meta Horizon). Теоретически можно передавать данные от шлема на контроллер посредством оповещений для светодиодов для реализации обратной связи, но найти рабочий пример не вышло, как и исправить готовое. В итоге, с технической точки зрения, статья довольно слабая.


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

Передавать данные в шлем можно тремя способами: по Bluetooth, Wi-Fi и проводом через USB-порт. Теоретически самые большие задержки имеет Wi-Fi, минимальные USB-порт, а Bluetooth нечто среднее. Если рассматривать использование с точки зрения пользователя/игрока, то Bluetooth-устройство, требующее однократного сопряжения, кажется наиболее удобным.

У Bluetooth есть понятие профиля, которое по сути определяет тип устройства — наушники, клавиатура или что-то еще. Одно устройство может реализовать сразу несколько профилей, т.е. быть и клавиатурой и наушниками. Для передачи данных, есть специальный профиль RFCOMM, аналогичный UART, но, к сожалению в этом случае приложению на шлеме потребуется запрашивать разрешение на использование Bluetooth, что закрывает дорогу в магазин Meta Quest. Поэтому остаются варианты эмулировать геймпад или клавиатуру. Первый имеет больше возможностей по передаче данных, но может пересекаться с вводом от стандартных контроллеров. Ввод с клавиатуры же отдельный, обрабатывать её значительно проще, да и для ходьбы или дэнспада регистрация обычных нажатий достаточна, так что выбор пал на нее.

Знаете ли вы, что… каждая кнопка на стандартном контроллере имеет датчик, определяющий находится ли ваш палец над ней. Благодаря этим датчикам, в главном меню визуализируются положение пальцев, когда вы держите в руках контроллеры, скрывающих пальцы от камер своими кольцами.


Аппаратная часть


Какой взять микроконтроллер — легкий вопрос, если исходить из стоимости, поскольку ESP32, имеющий на борту как Bluetooth, так и Wi-Fi, значительно дешевле любой пары микроконтроллер + Bluetooth-модуль. Кроме того, ESP32 можно программировать в Arduino IDE, т.е. ко многим датчикам уже есть готовые библиотеки. Стоит иметь в виду, что ESP32 имеет несколько вариаций чипа, описанных в англоязычной Википедии. В данном случае подойдут самые дешевые варианты за примерно 200руб как на уже подустаревшем базовом ESP32, так и более современной версии ESP32-C3.

w9j_dkew8twlasu09lnuyd2v85m.jpeg
Мои no-name платы ESP32 с али

Особенности плат слева направо
1. EPS32 Super Mini на базе ESP32 C3. На 8-ой ноге есть светодиод, притянутый к 3.3В. Достаточна много брака, поэтому желательно смотреть отзывы. Иногда маркировка чипа бывает не на четыре, а три строки и в таком случае плата требует подключения внешней флеш-памяти, что делает её практически бесполезной. Главный минус следует из её размера — малое число портов. Информация о плате, включая распиновку, схему и примеры для Arduino IDE, на китайском доступна здесь.

2. Плата на базе ESP32-D0WD-v3 с памятью, распаянной рядом на внешней флешке, и отдельной UART-USB-микросхемой СР341G. Также есть порт для зарядки аккумулятора и встроенный светодиод на 22 ноге. Чтобы заливать прошивку может потребоваться подключить электролитический конденсатор на 10uF между землей G и контактом EN. Мой фаворит.

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

Питать платы можно как от USB, так и от LiPo-аккумулятора. В описании плат обычно есть допустимый диапазон напряжений, скорее всего 3.3–6В, но лучше уточнить по схеме, зачастую имеющуюся в описании у продавца, наличие стабилизатора, напр. AMS1117, на 3.3В. Питание надо подавать на 5В ножку.

Как начать работать с ESP32 в Arduino IDE
1. Установить Arduino IDE. Для Windows 7 надо ставить 1.8.х.

2. Открыть File > Preferences и для поля Additional Board Manager URLs указать raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json. Закрыть настройки кнопкой OK, открыть Tools > Boards Manager…, вбить в поиске esp32 и установить esp32 by Espressif Systems. Если все сделано правильно, то в Boards появится пункт ESP32 Arduino.

3. В Boards перечислено много плат, но можно выбирать Dev Module по чипу, напр. ESP32C3 Dev Module.

4. После подключения платы по USB, в зависимости от версии Windows и платы может потребоваться установка драйвера. Для Windows 7 и плат, использующих программный USB и определяющихся как один/два «USB Serial/JTAG порт», драйвер можно взять тут. В Windows 10/11 драйвера установятся сами.

5. Иногда, даже после установки драйверов, Arduino IDE не может загрузить прошивку, т.к. закрыт COM-порт. В этом случае можно перегрузить плату, нажав RST на ней. Или, если есть кнопка BOOT, то удерживать её при подключении платы к USB.

Однако с ESP32 не все так гладко. Во первых сборка и загрузка скетча в Arduino IDE будет занимать более 30сек, т.к. по сути собирается целая операционка FreeRTOS, а кеширования скомпилированных ранее модулей в IDE нет. Решением может быть использование платного плагина к Visual Studio. А во вторых многие датчики рассчитаны на питание 5В, в то время как ESP32 питается от 3.3В, и потому по линиям данных рекомендуется ставить преобразователи TTL-уровней, чтобы не сжечь порты у ESP32. В некоторых мануалах это может опускаться, т.к. для попробовать и так работает. В продаже есть датчики рассчитанные на 3.3В, но они обычно значительно дороже.

Для прототипа контроллера я выбрал ESP32 C3 Super Mini. Еще потребовалось пара кнопок, провода и два резистора на 10КОм. Кнопки подключил к 0 и 1 портам по стандартной схеме с подтяжкой к земле. Чтобы кнопки было удобнее нажимать ногами, я приклеил к ним кусочки пластика. При нажатии отправляются буквы A и C, а при отпускании B и D.

k28vajde0dgey5bak1ujnnewkkw.jpeg
Итоговый прототип, в котором обе ноги обрабатывает один контроллер.

Приложение для шлема


Тестовое приложение я сделал на Godot. Это не самый популярный движок, но он прост, прекрасно подходит для прототипов, в том числе и VR, да и в отличии от Unreal и Unity, не требует для установки десятков гигабайт на диске и может запускаться под Windows 7.

Как сделать приложение для Oculus Quest в Godot
1. Установить последнюю версию Godot. На момент публикации это 4.2.2.

2. Создать новый проект с Mobile-рендером.

3. Зайти в «Project > Project Settings…». В разделах «XR > OpenXR» и «XR > Shaders» поставить галочки Enabled. Перезагрузить проект.

4. Перейти в AssetLib и установить Godot OpenXR Vendors plugin.

5. Добавить к проекту скрипт, включающий OpenXR-рендер, с содержимым

extends Node3D

func _ready():
	OS.request_permissions()		
	var xr_interface = XRServer.find_interface("OpenXR")
	if xr_interface and xr_interface.is_initialized():
		get_viewport().use_xr = true

6. Создание приложения для различных платформ в Godot называется экспортом и каждая платформа, будь то Windows или Android, требует установки шаблона экспорта. Чтобы установить шаблоны надо в редакторе зайти в «Editor > Manage Export Templates…» и нажать кнопку Download and Install, которая скачает и установит шаблоны для текущей версии Godot.

7. Для сборки VR-приложения для Android также требуется установить шаблон сборки, что делается через вызов «Project > Install Android Build Template». А также надо установить Android SDK и в «Editor > Editor Settings > Export > Android» указать Android SDK Path. На той же вкладке надо указать где установлена Java.

8. Для экспорта приложения под Android, надо зайти в «Project > Export… > Add …» и добавить Android и изменить следующие настройки: включить Use gradle build, XRMode задать как OpenXR, включить Enablle Meta Plugin и в самом конце снять флажки у Quest 3 Support и Quest Pro Support. После этого можно собирать apk кнопкой Export Project…

9. Чтобы после каждой сборки не закидывать apk на шлем самостоятельно, достаточно подключить шлем к компьютеру кабелем. В этом случае станет доступна кнопка «Remote Debug > Oculus Quest 2» в правом верхнем углу редактора Godot.

10. Чтобы не держать шлем на кабеле, поскольку это не всегда удобно, можно перевести adb в режим работы по сети. Для этого надо подключить шлем кабелем, набрать в консоли «adb devices», чтобы убедиться что шлем определился. Потом выполнить «adb tcpip 6007», отключить кабель от шлема и выполнить «adb connect :6007». Можно использовать и другой порт, но в этом случае надо в Godot указать его в «Editor > Editor Setting… > Debug > Remote Port». При этом можно сразу видеть результат вызова print в консоли, если выполнить «adb logcat -s godot».

11. В проекте на сцене не забыть добавить XROrigin3D и дочерние узлы XRCamera3D и два XRController3D.

В тестовом проекте я реализовал следующую логику: при поднятии ноги полсекунды или пока нога не будет опущена игрок, а точнее базовая точка, перемещается вперед. Обычно, когда надо, чтобы игрок мог упираться в препятствия, его перемещают не путем изменения позиции, а толкают его капсулу-коллайдер. Однако, если привязать коллайдер к базовой точке, то непонятно что делать, когда игрок перемещается в реальном мире, отходит от базовой точки и выходит из коллайдера. Поэтому я просто закрепил на камере коллайдер-сферу, которая при регистрации столкновения переносит базовую точку и, следовательно саму камеру, назад. Хотя это в VR воспринимается не очень, но свою задачу «запрещения игроку проходить сквозь стены» решает. Наверняка есть способы лучше.

70lnjylmb097yifm0ck2ti3k_tk.jpeg
Демо-приложение

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

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

Вместо послесловия


Meta, как и другие производители VR-гарнитур, ограничилась комплектом «шлем и два контроллера», что по сути представляет собой минимальный набор для игр в VR Однако, с моей точки зрения, бритва Оккама в этот раз отрезала лишнее — трекинг ног. Безногие аватары в Meta-вселенной выглядят нелепо, а уже о потерянных возможностях в играх и думать грустно. Казалось бы добавить сандали на лентах-липучках, как у шлема, с акселерометрами и тензометрическими датчиками для отслеживания распределения веса (и более точного восстановления позы), хотя бы как дополнительный аксессуар, не так уж и сложно, но — нет. С другой стороны рост производительности процессоров и развитие машинного обучения, видимо приведет к full-body трекингу всего одной камерой мобильного телефона, т. к. зачаточные версии на основе ML-Kit есть уже сейчас, и потому делать что-то специальное для ног многим кажется бесперспективным.

© Habrahabr.ru