Last active
April 12, 2021 06:10
-
-
Save S60Team/819715b891fd1a562d7a92a1865ddf41 to your computer and use it in GitHub Desktop.
Простой руль для ПК: Руль энкодер, Газ, Тормоз, Сцепление, Установка угла поворота руля - библиотека NicoHood (HID)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Простой руль для ПК: | |
Основан на: https://is.gd/gyverwheel и https://is.gd/udubon | |
Изменён: Гендель Владимир aka S60Team | |
Скачай и поставь библиотеки: | |
https://github.com/S60Team/Rotary2 | |
https://github.com/NicoHood/HID | |
Пины: 3,4,5,6,7,8,9,10,11,12, 14,15,16 - кнопки. | |
*/ | |
// Если у вас Arduino Pro Micro (0 для Arduino Leonardo): | |
#define ProMicro 1 | |
// Если ось идёт вправо а руль крутится влево, | |
// меняем направление (0 или 1): | |
#define Direction 1 | |
// Подключаем геймпад (джойстик): | |
// Библиотека поддерживает 32 кнопки, 1 крестовину, 6 осей (X,Y,Z,Rz,Rx,Ry) | |
#include "HID-Project.h" | |
// Указываем Оси: | |
#define Axe_Throttle A0 // Газ | |
#define Axe_Brake A1 // Тормоз | |
#define Axe_Clutch A2 // Сцепление | |
#define Axe_HBrake A3 // Ручной тормоз | |
#define BTN_CAL 2 // Кнопка сброса | |
// Подключаем энкодер: | |
/* Настройки переехали в файл библиотеки Rotary2.h | |
Тут только подсказки: | |
#define DWF // Включить быструю версию DigitalWrite. | |
#define ENABLE_PULLUPS // Включить встроенный резистор подтяжки. | |
#define ENCODER2 // Включить другой тип энкодера. | |
#define HALF_STEP // Включить другой шаг энкодера. | |
*/ | |
#include <Rotary2.h> | |
#define outA 0 // пин 0 (PD2) | |
#define outB 1 // пин 1 (PD3) | |
Rotary2 rotary = Rotary2(outA, outB); | |
volatile int16_t counter = 0; | |
int16_t encVal = 0; | |
// Переменные значений осей: | |
int16_t Axis1_ = 0, Axis2_ = 0, Axis3_ = 0, Axis4_ = 0; | |
// Переменные ВКЛ определения осей: | |
bool handbrake_present = true, throttle_present = true; | |
bool brake_present = true, clutch_present = true; | |
// Переменная режима угла поворота руля: | |
bool racing_mode = false; | |
void setup() { | |
pinMode(13, OUTPUT); // Встроенный светодиод | |
digitalWrite(13, LOW); // Встроенный светодиод ВЫКЛ | |
//CHANGE для срабатывания прерывания если пин меняет значение: | |
attachInterrupt(digitalPinToInterrupt(outA),rotate,CHANGE); | |
attachInterrupt(digitalPinToInterrupt(outB),rotate,CHANGE); | |
pinMode(BTN_CAL, INPUT_PULLUP); // Кнопка сброса позиции энкодера | |
// Проверяем положение кнопки при включении USB: | |
// (по-умолчанию режим выключен - 900°) | |
// при зажатой кнопке (при подсоединении к ПК): ВКЛ (270°) | |
if(digitalRead(BTN_CAL) == HIGH){ | |
digitalWrite(13, LOW); | |
racing_mode = false;} // Кнопка сброса ВЫКЛ. Режим симулятора | |
else{ | |
digitalWrite(13, HIGH); | |
racing_mode = true;} // Кнопка сброса ВКЛ. Гоночный режим | |
// Циклы для указания цифровых пинов как вход для обработки нажатия кнопок: | |
for (int thisPin = 3; thisPin < 13; thisPin++) { // Leonardo: | |
pinMode(thisPin, INPUT_PULLUP); } // 3,4,5,6,7,8,9,10,11,12 | |
for (int thisPin = 14; thisPin < 17; thisPin++) { | |
pinMode(thisPin, INPUT_PULLUP); // 14, 15, 16 | |
} | |
// Инициализация джойстика: | |
Gamepad.begin(); | |
// Определяем, подключены ли педали и ручник к аналоговым входам: | |
int16_t ap1 = analogRead(Axe_Throttle), | |
ap2 = analogRead(Axe_Brake), | |
ap3 = analogRead(Axe_Clutch), | |
ap4 = analogRead(Axe_HBrake); | |
delay(10); | |
if(abs(ap1-analogRead(Axe_Throttle)) > 10){ throttle_present = false; } | |
if(abs(ap2-analogRead(Axe_Brake)) > 10){ brake_present = false; } | |
if(abs(ap3-analogRead(Axe_Clutch)) > 10){ clutch_present = false; } | |
if(abs(ap4-analogRead(Axe_HBrake)) > 10){ handbrake_present = false; } | |
} | |
// | |
void loop() { | |
// Сбрасываем значение осей: (на всякий случай) | |
Axis1_ = 0, Axis2_ = 0, Axis3_ = 0, Axis4_ = 0; | |
// Руль энкодер (360ppr/1140ppr): | |
// Сброс позиции энкодера кнопкой на пине 2: | |
if(!digitalRead(BTN_CAL)){ counter = 0;Gamepad.xAxis(0); } | |
encVal = counter; | |
// Если не зажата кнопка сброса (пин 2): 900° | |
if(racing_mode == false){ | |
encVal = constrain(encVal,-450,450); | |
encVal = map(encVal,-450,450,-32768,32767);} | |
// Если зажата кнопка сброса: 270° | |
else { | |
encVal = constrain(encVal,-135,135); | |
encVal = map(encVal,-135,135,-32768,32767);} | |
Gamepad.xAxis(encVal); // Записываем значения в ось. | |
// Педаль Газа: | |
if (throttle_present == true) { | |
Axis1_ = analogRead(Axe_Throttle); | |
Axis1_ = map(Axis1_,0,1023,-32768,32767); | |
Gamepad.rxAxis(Axis1_);} | |
else{Gamepad.rxAxis(0);} | |
// Педаль Тормоза: | |
if (brake_present == true) { | |
Axis2_ = analogRead(Axe_Brake); | |
Axis2_ = map(Axis2_,0,1023,-128,127); | |
Gamepad.zAxis(Axis2_);} | |
else{Gamepad.zAxis(0);} | |
// Педаль Сцепления: | |
if (clutch_present == true) { | |
Axis3_ = analogRead(Axe_Clutch); | |
Axis3_ = map(Axis3_,0,1023,-128,127); | |
Gamepad.rzAxis(Axis3_);} | |
else{Gamepad.rzAxis(0);} | |
// Ручной тормоз: | |
if (handbrake_present == true) { | |
Axis4_ = analogRead(Axe_HBrake); | |
Axis4_ = map(Axis4_,0,1023,-32768,32767); | |
Gamepad.ryAxis(Axis4_);} | |
else{Gamepad.ryAxis(0);} | |
// Перебираем оставшиеся пины и задаём их как кнопки: | |
#if (ProMicro == 0) | |
// Leonardo: | |
// Пины: 3,4,5,6, 7,8,9,10, 11,12 | |
for (int thisPind = 3; thisPind < 13; thisPind++) { | |
if(!digitalRead(thisPind)){ Gamepad.press(thisPind - 2); } | |
else{ Gamepad.release(thisPind - 2); } } | |
#else | |
// Pro Micro: | |
// Пины: 3,4,5,6, 7,8,9,10 | |
for (int thisPind = 3; thisPind < 11; thisPind++) { | |
if(!digitalRead(thisPind)){ Gamepad.press(thisPind - 2); } | |
else{ Gamepad.release(thisPind - 2); } } | |
#endif | |
// Пины: 14, 15, 16 (ещё кнопки!) | |
for (int thisPindd = 14; thisPindd < 17; thisPindd++) { | |
if(!digitalRead(thisPindd)){ Gamepad.press(thisPindd - 3); } | |
else{ Gamepad.release(thisPindd - 3); } } | |
// Отправляем значения в ПК: | |
Gamepad.write(); | |
delay(10); | |
} | |
// Функция для считывания показаний энкодера: | |
void rotate() { | |
unsigned char result = rotary.process(); | |
#if (Direction == 0) | |
if (result == DIR_CW){counter++;} | |
else if (result == DIR_CCW){counter--;} | |
#else | |
if (result == DIR_CW){counter--;} | |
else if (result == DIR_CCW){counter++;} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment