Dopo l’ultimo ultimatum del primogenito (basta beep e lucine), ho passato le ultime due notti serate in un piccolo progettino con Arduino: usare un potenziometro per muovere uno sprite sullo schermo del mac. La cosa è stata sommariamente interessante, perché mi ha permesso di capire un po’ di cose di quello che succede nel mondo reale, che è un po’ diverso da quello plug&play. Non descriverò nel dettaglio il progetto, sia perché è molto semplice, sia perché è ancora work in progress, sia perché non ne ho voglia, ma racconterò solo due o tre scogli incontrati nel viaggio. Sarà interessantissimo.

Il codice (sbagliato) di arduino

Il primo codice (errato) che avevo scritto su arduino era pressapoco così:


void loop() {

int sensorValue = analogRead(A0);
esco=sensorValue;

Serial.println(esco);
oldesco=esco;

}

Il valore del potenziometro (collegato alla porta analogica A0) veniva letto, infilato nella variabile esco e spedito all’uscita seriale. Il valore andava da 0 a 1000 e qualcosa. Lato python il dato veniva preso in un loop infinito da un:

premuto=ser.readline()

Dove ser è un ser = serial.Serial('/dev/tty.usbmodemfa121', baudrate=9600, bytesize=8, stopbits=1,timeout=0, parity="N").

Pieno di entusiasmo ho fatto partire il codice da tutte e due le parti. Da una parte su Arduino veniva letto il potenziometro, il valore veniva spedito in una riga al mac che lo leggeva e che lo interpretava: se era minore di un certo valore, spostava lo sprite a sinistra. Se era maggiore di un certo valore lo spostava a destra (per questo ho utilizzato la libreria pygame).
La cosa in effetti funzionicchiava. Il valore veniva effettivamente inviato. Quello che non funzionava è che la lettura si incantava spesso su un valore, e che ruotando il potenziometro l’aggiornamento arrivava dopo molto tempo e di nuovo si incantava. In più, spesso e volentieri, la riga arrivava sporca a python che si irritava e si chiudeva perché si aspettava un numero e gli era arrivati due numeri attaccati, o niente o un accapo. Il mondo reale è sempre deludente.

Dopo aver controllato che fossero a 9600 baud e 8N1 da tutte e due le parti, non sapendo né leggere né scrivere, ho pensato che il problema fosse che stavo inviando una linea di testo e non un valore. Se leggevo dal potenziometro 1000, per esempio, mandavo ben cinque caratteri (le cifre più l’accapo), in un flusso continuo di scarico.

Sarebbe stato più intelligente mandare un solo carattere, ovvero un solo byte con dentro il valore. Si poteva fare? Si poteva fare, usando, su Arduino Serial.write(esco), istruzione che manda, appunto un byte, in forma di carattere. Però i byte hanno un valore che va da 0 a 255, mentre la mia lettura va da 0 a 1000 e rotti. Come fare? Usare due byte?

La soluzione che ho scelto è più semplice, ovvero normalizzare il valore letto dal potenziometro riducendolo al range 0-255, in proporzione. Un po’ spannometricamente ho fatto così;

esco=sensorValue/4.01;
Serial.write(esco);

Non so se sia il metodo giusto, ma ha funzionato, che è comunque un segnale positivo. Lato python il codice è cambiato con un:

premuto=ser.read(1)
premo=ord(premuto)

Ovvero leggi un byte dalla porta seriale aperta. Solo un byte non tutta la riga. Poi convertilo da carattere a valore.

Dopo questi radicali cambiamenti di codice ho fatto ripartire i programmi lati Arduino e lato python e questa volta ha continuato a non funzionare niente. Come prima.
Era circa l’una di notte e alle mie spalle primogenito stava leggendo un manuale di sopravvivenza agli zombies.

Cosa diavolo non funzionava? E soprattutto: è più saggio spegnere tutto e andare a dormire e ripensarci domani o continuare a brancolare nel codice con le palpebre già a mezz’asta? Voi conoscete meglio di me la risposta. Non si può andare a dormire quando il codice non funziona. Il karma non vuole. Ho continuato a fare prove.

Alla fine mi sono detto, ma non è che Arduino è troppo veloce? Non è che fa un numero altissimo di letture e le manda tutte in uscita seriale dove si mettono in coda saturando il buffer? Mentre mi domandavo queste cose guardavo la lucina tx che lampeggiava come una pazza. Così ho detto, proviamo a mandare i dati in seriale solo quando il potenziometro è effettivamente mosso. Se è fermo, la lettura viene fatta, ma non viene mandato niente al buffer seriale, così non viene intasato. Proviamo, mi sono detto.

void loop() {
int sensorValue = analogRead(A0);
esco=sensorValue/4.01;
if (esco != oldesco)
{
Serial.write(esco);
oldesco=esco;
}
}

Bingo. O quasi. In questa versione, spostando la rotella a destra o a sinistra, Arduino mandava i dati di lettura senza saturare il buffer. Su mac l’astronavicella si spostava a destra e sinistra. Avessi avuto una birra, l’avrei stappata. Però. Però se spostavo tutta la manovella a destra o sinistra, Arduino mandava tutte le letture intermedie di tutti i valori rilevati, e la cosa prendeva un sacco di tempo. Bisognava rendere tutto più reattivo, e il metodo che ho trovato è stato quello di dare intervalli di lettura a campione:

if (esco>oldesco+10 || esco < oldesco -10)

Così la lettura viene inviata solo quando la variazione è di un range di almeno 10. Vengono inviati meno dati e l’astronavicella è più reattiva. E noi sappiamo quanto è importante avere una navicella bella reattiva, no?

spacespace

Annunci