Я большой поклонник «Формулы-1», и поскольку гонки в Саудовской Аравии и Бахрейне на тот момент сезона не были включены в календарь, ожидание следующего уикенда казалось слишком долгим. Поэтому вместо того, чтобы ждать с нетерпением, я решил собрать свой собственный контроллер в виде гоночного руля, чтобы сделать впечатления от «Формулы-1» максимально домашними.

Основным компонентом контроллера является Raspberry Pi 5, который считывает данные с различных переключателей и датчиков и отображает информацию на 5-дюймовом ЖК-экране. Контроллер хорошо работает с гоночными играми, поскольку управление поворотами влево и вправо осуществляется с помощью акселерометра и гироскопа MPU-6050. Он также включает виброотдачу для большей интерактивности.

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

В следующих разделах пошагово объясняется, как собрать контроллер.

Инструменты и материалы, использованные в этом проекте, перечислены ниже:

  • Raspberry Pi 5 (16 ГБ ОЗУ);

  • 5-дюймовый HDMI ЖК-дисплей (сенсорный контроллер XPT2046 — Waveshare);

  • Arduino Pro Micro;

  • вибромотор Keystudio;

  • ноутбук для программирования;

  • паяльник;

  • припой;

  • термоусадочная трубка;

  • 3D-принтер (Creality K2 Pro);

  • 3D-филамент;

  • двусторонняя клейкая лента;

  • соединительные провода;

  • проволока для обмотки 0,25 мм;

  • металлические вставки;

  • гайки и шайбы;

  • бокорезы;

  • отвёртка.

Шаг 1: Разработка корпуса контроллера и 3D-печать

Дизайн корпуса контроллера основан на рулевом колесе Mercedes F1. Я использовал фотографию рулевого колеса, импортировал её в Autodesk Inventor и обвёл профиль корпуса. Затем я масштабировал дизайн так, чтобы ЖК-экран аккуратно помещался в него.

Корпус был разработан таким образом, чтобы все компоненты точно вписывались в свои места, и это исключало необходимость в дополнительных опорах. Для аккуратной прокладки проводов были также добавлены канавки для каждого электронного компонента. После завершения работы над основным корпусом была разработана верхняя пластина, а текст был добавлен с помощью программы для нарезки 3D-принтеров Creality.

Вся электроника и проводка размещены внутри корпуса, а верхняя пластина надёжно закрывает компоненты. Raspberry Pi подключён напрямую к ЖК-экрану через контактные разъёмы, а экран крепится с помощью стоек на заднюю пластину. Эта задняя пластина прикрепляется к задней части рулевого колеса, поэтому центральное отверстие остаётся открытым как с передней, так и с задней стороны.

Следующим компонентом, разработанным в Inventor, стал кронштейн для крепления потенциометров. Три потенциометра расположены в нижней части рулевого колеса, и кронштейн был разработан для их надёжной фиксации.

После этого я придумал специальные ручки. Они надеваются на валы потенциометров.

Финальной 3D-моделью выступает рамка экрана, которая облегает ЖК-экран, обеспечивая аккуратный внешний вид.

После завершения всех разработок детали были напечатаны на 3D-принтере Creality K2 Pro. Все компоненты были изготовлены из PLA-пластика, при этом основной корпус — из PLA-пластика, имитирующего углеродное волокно, а задняя панель — из PLA-пластика, имитирующего дерево.

Шаг 2: Добавление электроники: Тактильные и тумблерные переключатели

Электронные компоненты включают шесть тактильных переключателей, два тумблерных, акселерометр/гироскоп, вибромотор и три потенциометра.

В этом разделе основное внимание уделяется добавленным тактильным и тумблерным переключателям. Все восемь подключены непосредственно к контактам GPIO Raspberry Pi.

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

Использовались следующие контакты GPIO:

левый синий: 20, левый белый: 13, жёлтый: 12, левый тумблер: 19, правый синий: 5, правый белый: 6, красный: 26, правый тумблер: 16.

Каждый переключатель был подключён следующим образом: одна сторона переключателя — к контакту GPIO, а другая — к земле (GND). Встроенные подтягивающие резисторы Raspberry Pi были включены, поэтому внешние не потребовались.

Изначально я использовал стандартные перемычки, но их толщина затрудняла аккуратную прокладку внутри корпуса. Затем я перешёл на обмоточный провод сечением 0,25 мм², что сделало проводку гораздо более компактной и удобной. Провода были припаяны к переключателям и изолированы термоусадочной трубкой.

Шаг 3: Добавление электроники: Потенциометры

Потенциометры были добавлены для имитации поворотных переключателей, используемых на рулевых колёсах болидов «Формулы-1». Обычно они применяются для выбора элементов из большого списка опций. Например, поворотный переключатель стратегии на рулевом колесе Mercedes F1 имеет опции от 1 до 16, которые используются для выбора предустановленных настроек двигателя в различных сценариях гонки.

В этом проекте использовались три потенциометра на 10 кОм. Считывание аналоговых сигналов оказалось не таким простым, поскольку Raspberry Pi не имеет встроенной возможности аналогового ввода. Для решения этой проблемы я использовал Arduino Pro Micro для считывания трёх аналоговых сигналов, а затем передавал данные на Raspberry Pi по протоколу UART.

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

Потенциометры питались от 5 В, а выходы ползунков были подключены к аналоговым входам Arduino A0, A1 и A2.

Важным моментом было преобразование выходного сигнала Arduino TX из логического уровня 5 В в логический уровень 3,3 В, необходимый для Raspberry Pi. Это удалось реализовать с помощью простого делителя напряжения, состоящего из резисторов 2 кОм и 3,3 кОм.

Шаг 4: Добавление электроники: датчик движения MPU-6050

Датчики отлично работают для определения ориентации рулевого колеса, и это делает игровой процесс в гонках намного реалистичнее, позволяя физически поворачивать руль вместо нажатия кнопок для поворота влево или вправо. Устройство использует акселерометр и гироскоп для определения наклона и вращения. Акселерометр измеряет наклон, который я использовал для поворотов влево и вправо. Устройство передаёт эти измерения по протоколу I2C, который подключается непосредственно к контактам SDA и SCL Raspberry Pi. Я использовал GPIO 2 (SDA) и GPIO 3 (SCL).

Шаг 5: Добавление электроники: Вибромотор

Вибромотор добавляет тактильную обратную связь к рулевому колесу и делает управление более похожим на управление настоящим контроллером. Этот модуль можно использовать непосредственно с контакта GPIO Raspberry Pi. Клеммы платы — G, V и S, где G — заземление, V — напряжение питания (я использовал 5 В постоянного тока от Raspberry Pi), а S — сигнал, который я подключил к контакту GPIO и который включит мотор, когда напряжение на GPIO достигнет 3,3 В постоянного тока.

Шаг 6: Добавление электроники: Raspberry Pi и ЖК-дисплей

Дисплей делает контроллер полностью портативным, поэтому вы можете использовать его где угодно. Также здорово, что это сенсорный экран, поэтому вам не нужно удалённо подключаться к Raspberry Pi или использовать мышь для открытия приложений. Вот ссылка на ЖК-дисплей, который я использовал.

Он подключается напрямую к клеммной колодке Raspberry Pi. ЖК-экран подключается к контактам Pi с 1 по 26, что немного неудобно, если вы хотите использовать эти контакты. На самом деле ЖК-дисплей использует только 5 контактов Pi, а остальные — в качестве дополнительной поддержки. Мне пришлось задействовать некоторые контакты, но у ЖК-дисплея есть клеммная колодка, которая подключена ко всем тем, которые сопряжены с Raspberry Pi. Я припаял провода напрямую к клеммной колодке, но не рекомендую этого делать. Лучше всего было бы припаять к этим контактам контактную планку, чтобы можно было подключить перемычки. Эти планки очень маленькие, и провода легко обрываются при перемещении ЖК-экрана.

ЖК-экран поставляется с HDMI-разъёмом, который подключается к HDMI-портам дисплея и Raspberry Pi. Дисплей сразу заработал на моём Pi 5, но сенсорный экран поначалу не откликался. Мне пришлось настроить некоторые параметры в Pi, прежде чем он заработал. Ссылка выше поможет в этом.

Для связи и программирования Pi я использовал удалённые соединения через VNC. Просто введите IP-адрес Pi, и вы сможете удалённо подключиться к дисплею Pi.

Шаг 7: Схемы подключения

В этом разделе показаны схемы, которые использовались для подключения всех компонентов к Pi. Все буквы G обозначают заземление, и заземление Arduino и Raspberry Pi должно быть соединено. Соединения уже упоминались и были указаны в предыдущих разделах, а прикреплённые изображения просто передают более наглядное представление всех соединений.

Шаг 8: Программное обеспечение

Программирование Raspberry Pi осуществлялось с использованием Python, а Arduino — с C++. В этом разделе объясняется, что было сделано, а также приводится весь использованный код.

С помощью этого контроллера можно играть во множество игр, но мне больше всего понравилась SuperTuxKart — классные гонки. Я скачал и установил игру на Raspberry Pi и запрограммировал Pi так, чтобы игра распознавала контроллер как джойстик. Когда я открываю программу на Python, она сразу же запускает SuperTuxKart и настраивает все мои компоненты для использования в игре. Важно, чтобы ней при настройке управления контроллер распознавался как джойстик.

Для запуска кода на Python я использовал Geany.

Полная рабочая программа на Python прилагается, а далее поясняется основная часть:

1. В начале кода импортируются несколько библиотек Python:

  • gpiozero используется для чтения физических кнопок, подключённых к контактам GPIO Raspberry Pi.

  • evdev используется для создания виртуальных устройств ввода, таких как джойстик и клавиатура.

  • mpu6050 применяется для чтения данных о наклоне с датчика MPU-6050.

  • threading позволяет непрерывно считывать данные с датчика движения, пока кнопки продолжают работать.

  • subprocess нужен для автоматического запуска SuperTuxKart из скрипта.

2. Настройка датчика движения MPU-6050

  • sensor = mpu6050(0x68)

  • MPU-6050 подключается к Raspberry Pi по I2C. Его адрес по умолчанию — 0x68.

  • Эти настройки затем используются для настройки рулевого управления:

  • MAX_AY определяет, какой уровень движения датчика соответствует полному повороту руля.

  • DEADBAND создаёт небольшую нейтральную зону вокруг центра, поэтому даже малейшие вибрации не влияют на рулевое управление.

  • SMOOTHING уменьшает дрожание и делает рулевое управление более плавным.

  • STEERING_DIRECTION используется для изменения направления рулевого управления, если левая и правая стороны поменяны местами.

3. Создание виртуального джойстика

Функция joystick_capabilities создаёт виртуальное устройство джойстика.

Именно это позволяет SuperTuxKart воспринимать самодельный руль как настоящий игровой контроллер.

4. Создание виртуальной клавиатуры для меню

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

Функция keyboard_capabilities делает это:

  • Левая белая кнопка → перемещение по меню влево

  • Правая белая кнопка → перемещение по меню вправо

  • Правая синяя кнопка → Enter/Select

  • Левая кнопка переключения → Escape/Back

5. Назначение физических кнопок

Каждая физическая кнопка подключена к контакту GPIO Raspberry Pi:

  • btn_red = Button(26, pull_up=True)

  • btn_yellow = Button(12, pull_up=True)

  • btn_left_white = Button(13, pull_up=True)

  • btn_right_white = Button(6, pull_up=True)

  • btn_left_blue = Button(20, pull_up=True)

  • btn_right_blue = Button(5, pull_up=True)

  • btn_left_toggle = Button(19, pull_up=True)

  • btn_right_toggle = Button(16, pull_up=True)

Назначения кнопок:

  • Красная кнопка = GPIO 26 = Ускорение;

  • Жёлтая кнопка = GPIO 12 = Тормоз / задний ход;

  • Левая белая = GPIO 13 = Меню влево; Правая белая = GPIO 6 = Меню вправо;

  • Левая синяя = GPIO 20 = нитро;

  • Правая синяя = GPIO 5 = Enter / select;

  • Левый переключатель = GPIO 19 = Escape / назад;

  • Правый переключатель = GPIO 16 = Ускорение стрельбы.

6. Сопоставление MPU-6050 с аналоговым рулевым управлением

  • def steering_loop(): Здесь программа считывает значение ускорения по оси Y с MPU-6050.

  • def map_ay(ay): Значение датчика сглаживается, затем преобразуется в значение по оси X джойстика.

Это преобразует показания датчика в диапазон джойстика:

  • -32768 → полностью влево

  • 0 → центр

  • 32767 → полностью вправо

7. Запуск цикла управления в фоновом режиме

threading.Thread(target=steering_loop, daemon=True).start()

Это позволяет непрерывно считывать данные с MPU-6050, в то время как остальная часть программы продолжает реагировать на нажатия кнопок. Без многопоточности программа либо считывала бы данные с датчика, либо с кнопок, но не одновременно.

8. Автоматический запуск игры

game = subprocess.Popen(["supertuxkart"])

Это автоматически запускает SuperTuxKart при выполнении скрипта управления контроллером. То есть, мне нужно запустить только один файл Python, и игра стартует с уже активным контроллером.

Полная программа прилагается ниже.

Вибромотор и потенциометры в этой игре не используются, но их можно настроить для другого симулятора «Формулы-1». Arduino применяется для непрерывной передачи аналоговых значений потенциометров, программа на C++ также прилагается. Программа проста: она просто считывает аналоговые напряжения с трёх потенциометров и непрерывно передаёт данные через UART с вывода TX Arduino на вывод RX Raspberry Pi.

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