Last active
March 30, 2021 06:30
-
-
Save S60Team/4071557d13f3b92d428553148db5a80a to your computer and use it in GitHub Desktop.
Простой руль для ПК: Руль энкодер, Газ, Тормоз, Сцепление, КПП, Установка угла поворота руля - библиотека MHeironimus (ArduinoJoystickLibrary)
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/PaulStoffregen/Encoder | |
https://github.com/MHeironimus/ArduinoJoystickLibrary | |
КПП (5 пинов - 8 передач) основана на проекте: https://soo.gd/XRgt | |
3: X влево; 4: X вправо | |
5: X экстремально вправо | |
6: X вверх; 7: Y вниз. | |
Пины: 8,9,10,11,12, 14,15,16 - кнопки */ | |
#define Axe_Throttle A0 // Газ | |
#define Axe_Brake A1 // Тормоз | |
#define Axe_Clutch A2 // Сцепление | |
#define Axe_HBrake A3 // Ручной тормоз | |
#define BTN_CAL 2 // Кнопка калибровки | |
int8_t Btnz = 16; | |
// Значения кнопок (для коробки передач): | |
#define LEFT 0 | |
#define RIGHT 1 | |
#define RIGHTEXTREME 2 | |
#define UP 3 | |
#define DOWN 4 | |
// Подключаем энкодер: | |
//#define ENCODER_OPTIMIZE_INTERRUPTS | |
//#define ENCODER_USE_INTERRUPTS | |
#include <Encoder.h> | |
long encVal = 0; // Значения энкодера | |
Encoder myEnc(0, 1); // Пины энкодера | |
// Подключаем геймпад (джойстик): | |
// Библиотека поддерживает 128 кнопок, 2 крестовины, 7 осей (X,Y,Z,Rz,Rx,Ry,Throttle) | |
#include <Joystick.h> | |
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, | |
//JOYSTICK_TYPE_GAMEPAD, | |
//JOYSTICK_TYPE_MULTI_AXIS, | |
JOYSTICK_TYPE_JOYSTICK, | |
Btnz, 0, // Кол-во кнопок, кол-во крестовин | |
false, false, false, // X, Y, Z | |
true, true, false, // Rx, Ry, Rz | |
false, false, // Rudder(руль высоты), Throttle(Газ) | |
true, true, true); // Accelerator(Ускорение), brake(Тормоз), steering(Руль) | |
//const bool testAutoSendMode = true; | |
const bool testAutoSendMode = false; | |
// Переменные значений осей: | |
int16_t Axis0_ = 0, 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); // Встроенный светодиод ВЫКЛ | |
// Кнопка для сброса позиции энкодера/установки значения поворота руля: | |
pinMode(BTN_CAL, INPUT_PULLUP); | |
// Проверяем положение кнопки при включении USB: | |
if(digitalRead(BTN_CAL) == HIGH){ | |
digitalWrite(13, LOW); | |
racing_mode = false;} // Кнопка сброса ВЫКЛ. Режим симулятора | |
else{ | |
digitalWrite(13, HIGH); | |
racing_mode = true;} // Кнопка сброса ВКЛ. Гоночный режим | |
// Циклы для указания цифровых пинов как вход для обработки нажатия кнопок: | |
for (int8_t thisPin = 2; thisPin < 13; thisPin++) { // Leonardo: | |
pinMode(thisPin, INPUT_PULLUP); } // 3,4,5,6,7,8,9,10,11,12 | |
for (int8_t thisPin = 14; thisPin < 17; thisPin++) { | |
pinMode(thisPin, INPUT_PULLUP); // 14, 15, 16 | |
} | |
// Указываем границы осей: | |
Joystick.setSteeringRange(-32768,32767); | |
Joystick.setBrakeRange(-128,127); | |
Joystick.setAcceleratorRange(-128,127); | |
Joystick.setRyAxisRange(-128,127); | |
Joystick.setRxAxisRange(-128,127); | |
// Инициализация библиотеки джойстика: | |
if (testAutoSendMode){Joystick.begin();} | |
else{Joystick.begin(false);} | |
// Определяем, подключены ли педали и ручник к аналоговым входам: | |
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; } | |
} | |
// Запоминаем последние состояния кнопок: | |
int16_t lastButtonState[8] = {0,0,0,0,0,0,0,0}; | |
int16_t currentButtonState[8] = {0,0,0,0,0,0,0,0}; | |
int16_t input[5] = {0,0,0,0,0}; | |
int8_t gear = 0; //0 это нейтралка | |
// | |
void loop() { | |
// Сбрасываем значение осей: (на всякий случай) | |
Axis1_ = 0, Axis2_ = 0, Axis3_ = 0, Axis4_ = 0; | |
// Руль энкодер: | |
int16_t rotMax = 0; // обнуляем макс. значение поворота | |
int16_t rotMid = (rotMax>>1); // середина руля | |
if(racing_mode == false){ // Если не зажата кнопка сброса (пин 2): | |
// rotMax это Значение поворота, например: | |
// 4320=1080°, 3600=900°, 1440=360°, 1080=270°, 720=180° | |
rotMax = 3600; | |
rotMid = (rotMax>>1);} | |
// Если зажата кн. калибровки и кн. на пин 10: 600° | |
else if(racing_mode == true && digitalRead(10) == LOW){ | |
rotMax = 2400; | |
rotMid = (rotMax>>1);} | |
// Если зажата кн. калибровки и кн. на пин 11: 270° | |
else if(racing_mode == true && digitalRead(11) == LOW){ | |
rotMax = 1080; | |
rotMid = (rotMax>>1);} | |
// Если зажата кн. калибровки: 180° | |
else{ | |
rotMax = 720; | |
rotMid = (rotMax>>1);} | |
// Сброс позиции энкодера кнопкой на пине 2: | |
if(!digitalRead(BTN_CAL)){ myEnc.write(rotMid); } | |
encVal = myEnc.read() - rotMid; // Читаем показания энкодера | |
encVal = (encVal * 65535) / rotMax; // Вычисляем поворот | |
encVal = constrain(encVal, -32768, 32767); // Указываем границы значений | |
Joystick.setXAxis(encVal); // Записываем значения в ось. | |
// | |
// Педаль Газа: | |
if (throttle_present == true) { | |
Axis1_ = analogRead(Axe_Throttle); | |
Axis1_ = map(Axis1_,0,1023,-128,127); | |
Joystick.setAccelerator(Axis1_);} | |
else{Joystick.setAccelerator(0);} | |
// | |
// Педаль Тормоза: | |
if (brake_present == true) { | |
Axis2_ = analogRead(Axe_Brake); | |
Axis2_ = map(Axis2_,0,1023,-128,127); | |
Joystick.setBrake(Axis2_);} | |
else{Joystick.setBrake(0);} | |
// | |
// Педаль Сцепления: | |
if (clutch_present == true) { | |
Axis3_ = analogRead(Axe_Clutch); | |
Axis3_ = map(Axis3_,0,1023,-128,127); | |
Joystick.setRxAxis(Axis3_);} | |
else{Joystick.setRxAxis(0);} | |
// | |
// Ручной тормоз: | |
if (handbrake_present == true) { | |
Axis4_ = analogRead(Axe_HBrake); | |
Axis4_ = map(Axis4_,0,1023,-128,127); | |
Joystick.setRyAxis(Axis4_);} | |
else{Joystick.setRyAxis(0);} | |
// | |
// 8ми-ступенчатая коробка передач: | |
// Кнопки 1-5: Пины: 3,4,5,6,7 | |
for (int8_t index = 0; index < 5; index++) { | |
input[index] = !digitalRead(index+3); } // | |
// Сбрасываем передачу: | |
gear = 0; | |
if (input[UP]) { // палка вверх | |
if (input[LEFT]) { gear = 1; } // влево | |
else if (input[RIGHT]){ | |
if (input[RIGHTEXTREME]) { gear = 7; } // экстремально вправо | |
else { gear = 5; }} | |
else { gear = 3; } } // палка не влево и не вправо а просто торчит вверху | |
else if (input[DOWN]) { | |
if (input[LEFT]) { gear = 2; } | |
else if (input[RIGHT]) { | |
if (input[RIGHTEXTREME]) { gear = 8; } // экстремально вправо | |
else { gear = 6; }} | |
else { gear = 4; } }// палка не влево и не вправо а просто торчит внизу | |
// Соответственно 0 это нейтралка. | |
// Все кнопки в 0: | |
currentButtonState[0] = 0; | |
currentButtonState[1] = 0; | |
currentButtonState[2] = 0; | |
currentButtonState[3] = 0; | |
currentButtonState[4] = 0; | |
currentButtonState[5] = 0; | |
currentButtonState[6] = 0; | |
currentButtonState[7] = 0; | |
// Если передача, делаем номер кнопки передача-1 активной. Первая передача 0, вторая 1 и т.д: | |
if (gear != 0) {currentButtonState[gear-1] = 1;} | |
// Отправляем значения кнопок: | |
for (int8_t index = 0; index < 8; index++) { | |
if (currentButtonState[index] != lastButtonState[index]) { | |
Joystick.setButton(index, currentButtonState[index]); | |
lastButtonState[index] = currentButtonState[index];}} | |
// Кнопки: 9,10,11,12,13 (пины 8,9,10,11,12) | |
for (int8_t thisPind = 8; thisPind < 13; thisPind++) { | |
if(!digitalRead(thisPind)){ Joystick.pressButton(thisPind+1); } | |
else{ Joystick.releaseButton(thisPind+1); } } | |
// Кнопки: 13,14,15 (пины 14,15,16) | |
for (int8_t thisPindd = 14; thisPindd < 17; thisPindd++) { | |
if(!digitalRead(thisPindd)){ Joystick.pressButton(thisPindd); } | |
else{ Joystick.releaseButton(thisPindd); } } | |
// Отправляем значения в ПК: | |
if (testAutoSendMode == false){ | |
Joystick.sendState(); | |
delay(10); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment