Problema software potenziometri per Gaming Steering Wheel DIY

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.

:white_check_mark: 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.

:cross_mark: 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.

:wrench: 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);
}

:bullseye: 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!

@lollopera09

Buonasera e benvenuto nella sezione Italiana del forum,

cortesemente, come prima cosa, leggi attentamente il REGOLAMENTO di detta sezione, (... e, per evitare future possibili discussioni/incomprensioni, prestando molta attenzione al punto 15), dopo di che, come da suddetto regolamento (punto 16.7), fai la tua presentazione NELL'APPOSITA DISCUSSIONE (... quello che vedi in blu è un link, fai click su di esso per raggiungere la discussione) spiegando bene quali esperienze hai in elettronica e programmazione, affinché noi possiamo conoscere la tua esperienza ed esprimerci con termini adeguati.

Grazie,

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposita discussione, nel rispetto del succitato regolamento nessuno ti risponderà (eventuali risposte o tuoi ulteriori post, verrebbero temporaneamente nascosti), quindi ti consiglio di farla al più presto. ;)