Skip to content

Instantly share code, notes, and snippets.

@S60Team
Last active March 30, 2021 06:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save S60Team/4071557d13f3b92d428553148db5a80a to your computer and use it in GitHub Desktop.
Save S60Team/4071557d13f3b92d428553148db5a80a to your computer and use it in GitHub Desktop.
Простой руль для ПК: Руль энкодер, Газ, Тормоз, Сцепление, КПП, Установка угла поворота руля - библиотека MHeironimus (ArduinoJoystickLibrary)
/* Простой руль для ПК:
Основан на: 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