Robotica educativa/Joystick

Indice del libro

Il tanto amato joystick. Chi afferma di non conoscerlo sicuramente sta mentendo. Nato nel mondo dei videogiochi ora è utilizzato in ogni ambito, fino a quello biomedicale, incluse operazioni delicatissime che non potrebbero essere svolte manualmente. Ecco perché è così importante.

Quest'immagine serve solo a ingolosire chi legge. Il joystick di Arduino è molto più piccolo, è pensato per essere manovrato da un singolo pollice, pertanto: perché accontentarsi di uno solo?

Procedendo per gradi è interessante ispezionare il suo circuito interno, così da capire come funziona e cosa si può ottenere da un dispositivo così semplice.

Dentro il joystick

modifica

Il joystick di Arduino non è diverso da quelli visti nelle sale giochi o scavando nei ricordi d'infanzia. Dispone di tre possibili comandi:

  • una movimentazione orizzontale;
  • una movimentazione verticale;
  • la pressione (associabile a un comando).

Va detto che la movimentazione non è semplicemente alto/basso, sinistra/destra, ma restituisce un valore proporzionale all'angolo con cui si sta premendo il joystick. Naturalmente, se la pressione è in diagonale, viene restituita sia la proiezione sull'asse delle ascisse, sia quella sull'asse delle ordinate della sua movimentazione.

 
Schema elettrico del joystick per Arduino

Infatti la movimentazione del joystick scivola (in orizzontale e in verticale) su due resistenze variabili da  , restituendo così una tensione compresa tra   e   la quale, connessa ai pin analogici, viene campionata a 10 bit, restituendo un numero compreso tra 0 e 1023 ( ), mentre – a riposo, se correttamente calibrato – dovrebbe restituire 511 ( ).

Pertanto, il joystick non rivela soltanto se la pressione è verso l'alto o verso il basso, ma anche di quanto. Analogamente questo accade per la movimentazione a sinistra e a destra.

La pressione del joystick chiude l'interruttore che si porta a livello basso.

Tutte queste premesse per dire che il controllo del joystick può avvenire senza l'ausilio di nessuna libreria.

Calibrazione

modifica

Alimentando il joystick con la tensione fornita da Arduino e prelevandone una porzione, grazie ai due potenziometri, il valore atteso per la situazione di riposo è 511. Tuttavia non è detto che sia sempre così. I componenti elettrici ed elettronici non sono perfetti, e le resistenze hanno un valore che dipende, oltre che dalle loro componenti intrinseche, anche dalla temperatura.

Se si desidera semplicemente sapere se il movimento è verso l'alto, il basso, a sinistra o a destra, quello che segue non è rilevante. Tuttavia, se si desidera utilizzare il joystick come strumento di lavoro è bene conoscere almeno tre parametri:

  • valore minimo (quando è completamente in basso o a sinistra);
  • valore a riposo (senza interazioni con l'utente);
  • valore massimo (quando è completamente in alto o a destra).

Nota bene

Come anticipato, questa operazione va eseguita inizialmente, soprattutto se si desidera acquisire, oltre alla direzione dettata dall'orientamento del joystick, anche il suo valore.

A titolo di esempio, se si vuole pilotare un motore e, tramite il joystick, definire oltre al verso di rotazione (avanti/indietro) la sua velocità è bene procedere a una taratura iniziale.

Questa va fatta per ogni componente, poiché ogni joystick restituirà dati differenti.

Come visibile dallo schema elettrico le tensioni   e   dipendono da due diverse resistenze. Per quanto il costruttore abbia fatto tutto il possibile affinché queste siano identiche, è risaputo che non esistono due oggetti identici in natura.

La calibrazione avviene con un codice che deve semplicemente mostrare i valori   e   nel monitor seriale. Nel codice che segue viene testato anche il funzionamento del pulsante.

// Terminali a cui va connesso il joystick
#define VRx A0
#define VRy A1
#define SW   2

// Dati restituiti dal joystick
int x, y, pulsante;
 
void setup() {
    Serial.begin(9600);
    pinMode(pulsante, INPUT);
}
 
void loop() {
    // Legge i dati del joystick
    x = analogRead(VRx);
    y = analogRead(VRy);
    pulsante = digitalRead(SW);
 
    // Li mostra nel monitor seriale
    Serial.print("VRx: ");
    Serial.print(x);
    Serial.print(" | VRy: ");
    Serial.print(y);
    Serial.print(" | Button: ");
    Serial.println(pulsante);
 
    // Attende 100 ms
    delay(100);
}

È fondamentale acquisire i dati minimi, massimi e a riposo. In tabella viene riportato un esempio:

Elemento Valore

minimo

Valore

a riposo

Valore

massimo

  0 523 1023
  0 498 1023

Si noti che, tipicamente, i valori a riposo difficilmente coincideranno con 511. Una volta acquisiti questi dati si è pronti per calibrare il joystick.

Ora che si dispone di questi dati è possibile correggere i dati x e y con i dati ottenuti durante la calibrazione.

Di seguito il codice per l'acquisizione dei dati del joystick ricalibrati con i dati ottenuti.

// Valori ottenuti in sede di calibrazione
#define xMin 0
#define xMid 523
#define xMax 1023
#define yMin 0
#define yMid 498
#define yMax 1023

// Terminali a cui va connesso il joystick
#define VRx A0
#define VRy A1
#define SW   2

// Dati restituiti dal joystick
int x, y, pulsante;

// Dati restituiti dal joystick e corretti
int x1, y1;

void setup() {
    Serial.begin(9600);
    pinMode(pulsante, INPUT);
}

void loop() {
    int x = analogRead(VRx);
    int y = analogRead(VRy);

    // Rettifica i dati forniti dal joystick
    joystick();

    // Li mostra nel monitor seriale
    Serial.print("VRx: ");
    Serial.print(x1);
    Serial.print(" | VRy: ");
    Serial.print(y1);
    Serial.print(" | Button: ");
    Serial.println(pulsante);

    // Attende 100 ms
    delay(100);
}

// Dai dati grezzi x, y del joystick restituisce i dati calibrati x1 e y1
void joystick() {
    if (x < xMid)
        x1 = map(x, xMin, xMid, 0, 511);
    else
        x1 = map(x, xMid, xMax, 512, 1023);
    
    if (y < yMid)
        y1 = map(y, yMin, yMid, 0, 511);
    else
        y1 = map(y, yMid, yMax, 512, 1023);
}

Si noti che nella funzione joystic() si è utilizzata la funzione map. Per chi non l'avesse mai usata , essa – data una variabile compresa tra un valore minimo e massimo – restituisce una sua rimappatura rispetto a due altri termini (anch'essi minimo e massimo).

Matematicamente, si scrive:

 

Attenzione

La funzione map() utilizza e restituisce numeri interi.

In questo caso è quello che si vuole, ma frazioni come  ,  ,   saranno tutte restituite come 1 dalla funzione map(), nonostante i loro valori reali siano differenti.

Pertanto, se il progetto richiede calcoli precisi (come valori con una o più cifre decimali), è bene evitare map() e implementare la funzione manualmente come descritto nell'equazione precedente.

Schema circuitale

modifica

Di seguito come collegare il joystick ad Arduino:

 

Sin qui tutto bene. Ora si ha a disposizione un joystick (perfettamente calibrato) e connesso ad Arduino. Naturalmente, si può controllare qualsiasi dispositivo. Di più: nulla vieta di inserire più di un joystick. Arduino Uno, avendo sei ingressi analogici ne può ospitare fino a tre.

Espansioni suggerite

modifica
  • La cosa più semplice è inserire quattro led che mostrano la direzione in cui è orientato il joystick (volendo un quinto potrebbe mostrare se il joystick è premuto o meno). Senza modificare il circuito, se le uscite sono analogiche la pressione del joystick può essere resa visibile con l'intensità luminosa dei led stessi.
  • I led possono essere sostituiti con motori. Utilizzando fili un po' più lunghi si può comandare un robot. Questo, naturalmente, può anche essere telecomandato se si utilizza un sistema di trasmissione e ricezione.
  • Con matrici di led (es. 8x8) è possibile realizzare semplici videogiochi come snake.