Skip to content

Instantly share code, notes, and snippets.

@S60Team
Last active March 30, 2021 06:29
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/8dbf742d80aa9aa5834351c107bc78fc to your computer and use it in GitHub Desktop.
Save S60Team/8dbf742d80aa9aa5834351c107bc78fc to your computer and use it in GitHub Desktop.
Простой руль для ПК: Руль энкодер, Газ, Тормоз, Сцепление, Установка угла поворота руля, матрица кнопок 4 на 4 - библиотека NicoHood (HID)
/* Простой руль для ПК:
Основан на: https://is.gd/gyverwheel и https://is.gd/udubon
Изменён: Гендель Владимир aka S60Team
Скачай и поставь библиотеки:
https://github.com/PaulStoffregen/Encoder
https://github.com/NicoHood/HID
https://github.com/Chris--A/Keypad
*/
// Подключаем геймпад (джойстик):
// Библиотека поддерживает 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 // Кнопка калибровки
//
// Подключаем энкодер (360):
#include <Encoder.h>
long encVal; // Значения энкодера
Encoder myEnc(0, 1); // Пины энкодера
//
// Матрица кнопок (4x4): https://is.gd/k4pgga
#include <Keypad.h>
#define ROWS 4
#define COLS 4
byte buttons[ROWS][COLS] = {
{15,14,13,12},
{11,10,9,8},
{7,6,5,4},
{3,2,1,0}
};
byte rowPins[ROWS] = {10,9,8,7}; // Строки 4,3,2,1
byte colPins[COLS] = {6,5,4,3}; // Столбцы 4,3,2,1
Keypad buttbx = Keypad(makeKeymap(buttons), rowPins, colPins, ROWS, COLS);
//
// Переменные значений осей:
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); // Встроенный светодиод ВЫКЛ
pinMode(BTN_CAL, INPUT_PULLUP); // Кнопка сброса позиции энкодера
if(digitalRead(BTN_CAL) == HIGH){
digitalWrite(13, LOW);
racing_mode = false;} // Кнопка сброса ВЫКЛ. Режим симулятора
else{
digitalWrite(13, HIGH);
racing_mode = true;} // Кнопка сброса ВКЛ. Гоночный режим
//
// Циклы для указания цифровых пинов как вход для обработки нажатия кнопок:
pinMode(11, INPUT_PULLUP); // 11,12
pinMode(12, INPUT_PULLUP);
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):
int16_t rotMax = 0; // обнуляем макс. значение поворота
int16_t rotMid = (rotMax>>1); // середина руля
if(racing_mode == false){ // Если не зажата кнопка сброса (пин 2):
// rotMax это Значение поворота, вычисляется по (ppr*4*угол поворота)/360
// 4320=1080°, 3600=900°, 1440=360°, 1080=270°, 720=180°
rotMax = 3600;
rotMid = (rotMax>>1);}
// Если зажата кн. калибровки и кн. на пин 9: 600°
else if(racing_mode == true && digitalRead(9) == LOW){
rotMax = 2400;
rotMid = (rotMax>>1);}
// Если зажата кн. калибровки и кн. на пин 10: 270°
else if(racing_mode == true && digitalRead(10) == 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); // Указываем границы значений
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);}
//
// Матрица кнопок 4на4: https://is.gd/k4pgga
if (buttbx.getKeys()){
for (int i = 0; i < LIST_MAX; i++) {
if ( buttbx.key[i].stateChanged ) {
switch (buttbx.key[i].kstate) {
// IDLE, PRESSED, HOLD, или RELEASED
case PRESSED:
Gamepad.press(buttbx.key[i].kchar);
break;
case RELEASED:
Gamepad.release(buttbx.key[i].kchar);
break; } } }
}
// Leonardo: Пины: 11,12
if(!digitalRead(11)){ Gamepad.press(17); }
else{ Gamepad.release(17); }
if(!digitalRead(12)){ Gamepad.press(18); }
else{ Gamepad.release(18); }
//
// Пины: 14, 15, 16 (ещё кнопки!)
if(!digitalRead(14)){ Gamepad.press(19); }
else{ Gamepad.release(19); }
if(!digitalRead(15)){ Gamepad.press(20); }
else{ Gamepad.release(20); }
if(!digitalRead(16)){ Gamepad.press(21); }
else{ Gamepad.release(21); }
//
// Отправляем значения в ПК:
Gamepad.write();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment