Ciao a tutti,
sto realizzando un volante DIY per giocare a Euro Truck Simulator usando un Arduino Leonardo come joystick HID e un potenziometro lineare da 10k per rilevare l’angolo di sterzata.
Situazione attuale
L’analogRead(A0) funziona perfettamente.
Nel Serial Monitor ottengo valori da 0 a 1023, stabili e lineari lungo tutta la rotazione del potenziometro.
- Il cablaggio è corretto (5V – A0 – GND).
- Non ci sono disturbi o oscillazioni.
Problema
Quando passo il valore del potenziometro alla libreria Joystick.h, su Windows (joy.cpl) e in ETS2 l’asse non è lineare, oppure viene usata solo una parte del range, nonostante il valore RAW sia corretto.
Ho provato diverse mappature:
- 0 → 255
- 0 → 1023
- 0 → 65535
Il Serial Monitor mostra sempre valori corretti, ma in joy.cpl il movimento dell’asse non è fluido o non utilizza tutto il range.
Codice attuale
/*
* =====================================================
* CONTROLLER RACING USB DIY - ARDUINO LEONARDO
* Versione FIXATA & STABILE (2025)
* =====================================================
*/
#include <Joystick.h>
// ===== CONFIG =====
#define INVERTI_STERZO true
#define INVERTI_ACCELERATORE false
#define INVERTI_FRENO false
// Curva sterzo: 0=lineare, 1=leggera, 2=forte
#define CURVA_STERZO 0
// Deadzone centro
#define DEADZONE_STERZO 10
// ===== PIN =====
#define PIN_STERZO A0
#define PIN_ACCELERATORE A1
#define PIN_FRENO A2
#define USA_ACCELERATORE false
#define USA_FRENO false
// ===== PULSANTI =====
#define USA_PULSANTE_1 true
#define USA_PULSANTE_2 false
#define USA_PULSANTE_3 false
#define USA_PULSANTE_4 false
#define USA_PULSANTE_5 false
#define USA_MICROSWITCH_1 false
#define USA_MICROSWITCH_2 false
const byte PIN_PULSANTI[7] = {A3, A4, A5, A6, A7, A8, A9};
const bool PULSANTI_ATTIVI[7] = {
USA_PULSANTE_1,
USA_PULSANTE_2,
USA_PULSANTE_3,
USA_PULSANTE_4,
USA_PULSANTE_5,
USA_MICROSWITCH_1,
USA_MICROSWITCH_2
};
#define NUM_PULSANTI 7
bool statoPrec[NUM_PULSANTI];
unsigned long ultimoDebounce[NUM_PULSANTI];
#define TEMPO_DEBOUNCE 50
// ===== CALIBRAZIONE =====
int sterzoMin = 1023, sterzoMax = 0;
int accMin = 1023, accMax = 0;
int frenoMin = 1023, frenoMax = 0;
bool calibrazioneCompletata = false;
unsigned long tempoInizio;
// ===== JOYSTICK OBJECT =====
Joystick_ Joystick(
JOYSTICK_DEFAULT_REPORT_ID,
JOYSTICK_TYPE_JOYSTICK,
NUM_PULSANTI,
0,
true,
USA_ACCELERATORE,
USA_FRENO,
false, false, false,
false, false, false, false, false
);
// =========================================================
// SETUP
// =========================================================
void setup() {
Serial.begin(115200);
// Pulsanti
for (int i = 0; i < NUM_PULSANTI; i++) {
if (PULSANTI_ATTIVI[i]) pinMode(PIN_PULSANTI[i], INPUT_PULLUP);
statoPrec[i] = HIGH;
ultimoDebounce[i] = 0;
}
Joystick.setXAxisRange(0, 1023);
#if USA_ACCELERATORE
Joystick.setYAxisRange(0, 1023);
#endif
#if USA_FRENO
Joystick.setZAxisRange(0, 1023);
#endif
Joystick.begin();
Serial.println("=== CALIBRAZIONE 10 SECONDI ===");
Serial.println("Muovi lo sterzo COMPLETAMENTE a dx e sx");
tempoInizio = millis();
}
// =========================================================
// LOOP
// =========================================================
void loop() {
int sterzoRaw = analogRead(PIN_STERZO);
int accRaw = analogRead(PIN_ACCELERATORE);
int frenoRaw = analogRead(PIN_FRENO);
// ===== CALIBRAZIONE =====
if (!calibrazioneCompletata) {
unsigned long t = millis() - tempoInizio;
if (t < 10000) {
if (sterzoRaw < sterzoMin) sterzoMin = sterzoRaw;
if (sterzoRaw > sterzoMax) sterzoMax = sterzoRaw;
#if USA_ACCELERATORE
if (accRaw < accMin) accMin = accRaw;
if (accRaw > accMax) accMax = accRaw;
#endif
#if USA_FRENO
if (frenoRaw < frenoMin) frenoMin = frenoRaw;
if (frenoRaw > frenoMax) frenoMax = frenoRaw;
#endif
if (t % 1000 < 50) {
Serial.print("Calibrazione... ");
Serial.print(10 - t / 1000);
Serial.println("s");
}
} else {
calibrazioneCompletata = true;
Serial.println("\n=== CALIBRAZIONE COMPLETATA ===");
Serial.print("Sterzo min/max: "); Serial.print(sterzoMin); Serial.print(" / "); Serial.println(sterzoMax);
#if USA_ACCELERATORE
Serial.print("Acceleratore min/max: "); Serial.print(accMin); Serial.print(" / "); Serial.println(accMax);
#endif
#if USA_FRENO
Serial.print("Freno min/max: "); Serial.print(frenoMin); Serial.print(" / "); Serial.println(frenoMax);
#endif
Serial.println("Chiudi Serial Monitor.");
}
}
// ===== MAPPATURA ASSI =====
int sterzoMapped = 512;
if (calibrazioneCompletata) {
int centro = (sterzoMin + sterzoMax) / 2;
if (abs(sterzoRaw - centro) > DEADZONE_STERZO) {
sterzoMapped = map(sterzoRaw, sterzoMin, sterzoMax, 0, 1023);
} else {
sterzoMapped = 512;
}
// Curva
if (CURVA_STERZO > 0) {
float n = (sterzoMapped - 512) / 512.0;
if (CURVA_STERZO == 1) n = n*n * (n>0 ? 1:-1);
if (CURVA_STERZO == 2) n = n*n*n;
sterzoMapped = (int)(n * 512 + 512);
}
if (INVERTI_STERZO) sterzoMapped = 1023 - sterzoMapped;
sterzoMapped = constrain(sterzoMapped, 0, 1023);
}
Joystick.setXAxis(sterzoMapped);
// ===== PULSANTI =====
for (int i = 0; i < NUM_PULSANTI; i++) {
if (!PULSANTI_ATTIVI[i]) {
Joystick.setButton(i, 0);
continue;
}
int lettura = digitalRead(PIN_PULSANTI[i]);
if (lettura != statoPrec[i]) ultimoDebounce[i] = millis();
if ((millis() - ultimoDebounce[i]) > TEMPO_DEBOUNCE) {
Joystick.setButton(i, (lettura == LOW));
}
statoPrec[i] = lettura;
}
delay(10);
}
Obiettivo
Vorrei capire perché il valore in joy.cpl non è lineare anche se il valore RAW è corretto, e come impostare correttamente:
- il range dell’asse X,
- la risoluzione più adatta (8/10/16 bit),
- eventuali parametri della libreria Joystick,
- eventuali errori nel mio codice o approccio.
Qualsiasi aiuto o esempio funzionante sarebbe molto apprezzato.
Grazie in anticipo!