Arduino/bash e porta seriale: differenze tra le versioni

Da PNLUG.
(creazione della pagina)
 
(continuazione)
 
(Una versione intermedia di uno stesso utente non è mostrata)
Riga 1: Riga 1:
 +
{{TOC|align=right}}
 +
<div style=tex-align:justify>
 
Usiamo [http://www.processing.org| Processing]?
 
Usiamo [http://www.processing.org| Processing]?
  
 
No grazie, '''stiamo imparando'''.
 
No grazie, '''stiamo imparando'''.
 
  
 
Arduino è un dispositivo semplice, cerchiamo di usarlo con strumenti di base.<br/>
 
Arduino è un dispositivo semplice, cerchiamo di usarlo con strumenti di base.<br/>
Dunque la bash.
+
Dunque la bash. [http://it.wikipedia.org/wiki/Bash| Bash] è il '''linguaggio di terminale nativo su Linux'''. Prescelto da Torvalds fin dalla primissima versione del '91.
  
D'altronde, ci dobbiamo fare input output.<br/>
+
=Premessa: configurare la porta seriale=
Se voglio scrivere qualcosa e comunicarlo ad arduino, è un ouput.<br/>
+
Non sempre, quando vogliamo interagire con arduino attraverso la porta seriale, troviamo il sistema autoconfigurato correttamente. I parametri di connessione, infatti, sono spesso gestiti dai programmi di alto livello all'insaputa dell'utente finale e vengono alterati in un modo non adatto all'uso da terminale. Per non dilungarci oltre misura questo aspetto, suggeriamo di impostare la porta seriale con questo comando, testato su arduino uno:
 +
  * stty -F /dev/arduino 1:0:1cb2:80:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
 +
 
 +
=Input ed output=
 +
D'accordo. Ora chiediamoci: cosa ci dobbiamo fare, con il terminale?<br/>
 +
Semplice. Ci dobbiamo fare ''input/output''.<br/>
 +
Allora, se voglio scrivere qualcosa e comunicarlo ad arduino, è un ouput.<br/>
 
L'output, in bash è gestito dal comando ''echo''.
 
L'output, in bash è gestito dal comando ''echo''.
 
Per esempio:
 
Per esempio:
Riga 16: Riga 23:
  
 
L'input, in bash, è gestito dal comando ''cat'', oppure dal comando ''head''.
 
L'input, in bash, è gestito dal comando ''cat'', oppure dal comando ''head''.
 +
  * cat </dev/arduino # legge dalla porta seriale di arduino.
 +
  * head -n3 </dev/arduino # legge le prime 3 righe provenienti dalla porta seriale di arduino.
 +
 +
=L'ordine delle operazioni: prima leggere e poi scrivere.=
 +
Adesso dobbiamo istruire arduino a gestire la porta seriale.<br>
 +
Prima di cominciare, ci serve uno sketch per testare il sistema.<br/>
 +
[http://arduino.cc/en/Serial/Read| Questa] è una soluzione minimale. Oppure possiamo usare [[Arduino/leggere_una_stringa_numerica| quest'altro]] sketch, su cui stiamo lavorando.
 +
 +
Scriviamo dunque:
 +
  * echo 30 >/dev/arduino
 +
  * cat /dev/arduino
 +
 +
''Sorpresa''. Non esce nulla. Anzi il terminale si blocca e siamo costretti a uscirne con la combinazione di tasti Ctrl-c.
 +
 +
Per forza!!! Stiamo lavorando con un dispositivo fisico '''esterno''', mica con i soliti dispositivi virtuali a cui siamo abituati. Se avessimo provato a scrivere:
 +
  * echo 30 >/tmp/prova.txt
 +
  * cat </tmp/prova.txt
 +
 +
Il risultato sarebbe molto più soddisfacente. E non si sarebbe incastrato nulla.
 +
 +
Qual è la differenza? Il contatto con la realtà. Se spediamo un echo verso arduino, la nostra stringa viene correttamente acquisita e processata, generando una risposta, che viene generata immediatamente.<br/>
 +
''Qualche istante dopo'', eseguiamo il cat... Acciderba, '''troppo tardi!''' La risposta si è già perduta.<br/>
 +
 +
Davvero, comunicare con Arduino è infinitamente educativo. Soprattutto per noi insegnanti.<br/>
 +
Dovremmo sempre comportarci così:<br/>
 +
'''Prima disporci all'ascolto, e solo dopo interrogare'''.
 +
 +
Infatti, per comunicare con arduino bisogna rovesciare l'ordine delle operazioni. Proviamo così:
 +
 +
  * head -n1 </dev/arduino & # il simbolo & permette di eseguire il comando in batch, lasciando libero il terminale per i comandi successivi.
 +
  * echo >/dev/arduino      # Come si diceva: prima leggere e poi scrivere!!!
 +
 +
Davvero. È tutta un'altra cosa.
 +
 +
=Controllo e prontezza dell'input/output: il comando exec=
 +
Proviamo ora a includere una chiamata di input/output in uno script, oppure (che è lo stesso) a eseguire i due comandi precedenti in un'unica riga di bash:
 +
  * head -n1 </dev/arduino & echo 30 >/dev/arduino
 +
 +
Questa volta i risultati saranno instabili e deludenti. Solo qualche volte si otterrà una risposta corretta, ma il più delle volte si osserverà una completa mancanza di reazione o verranno ricevute risposte incomplete e scorrette.<br/>
 +
In precedenza, infatti, digitando manualmente due istruzioni in successione, la distanza temporale tra i comandi copriva le latenze di comunicazione del sistema, inspirandoci una soddisfazione illusoria.<br/>
 +
Anche in questo caso, si crea una occasione per riflettere sulle differenze tra la comunicazione virtuale e la comunicazione reale.
 +
 +
Le operazioni di input/ouput tra due sistemi reali, infatti, sono più complesse di quanto non si possa immaginare a priori. In particolare, non si esauriscono meramente allo scambio dei dati, ma richiedono una procedura di sincornizzazione mutua che introduce delle latenze piuttosto fastidiose (nel mio sistema sono spesso superiori ai due secondi).<br/>
 +
In queste condizioni, ovviamente, non sarebbe possibile gestire un dialogo dinamico attraverso la porta seriale.
 +
 +
In questi casi, la procedura di connessione deve essere separata in due fasi distinte. La prima è proprio la fase di sincronizzazione mutua dei sistemi fisici. Questa operazione, però, deve essere eseguita una sola volta, prima di incominciare la comunicazione di scambio dati e non ripetuta sistematicamente ad ogni atto di lettura o di scrittura. La seconda fase, invece, è il semplice scambio dei dati, che è velocissimo.
 +
 +
La sincronizzazione, in molti linguiaggi di programmazione, è gestita dal comando '''open'''. In bash, invece, viene realizzata con il comando exec, in modo che l'input ouput lavori in questa maniera:
 +
 +
  * exec 5<>/dev/arduino        # apertura del dispositivo arduino sul descrittore di file 5, sia per operazioni di input che per operazioni di ouput.
 +
    sleep 5                    # forse cinque secondi è un ritardo eccessivo, ma l'operazione deve essere eseguita una volta sola.
 +
    head -n1 <&5 & echo 30 >&5
 +
    exec 5<&-                  # chiusura corretta del descrittore di file. Da utilizzare solo alla fine delle operazioni di input/output.
 +
</div>

Versione attuale delle 22:34, 1 gen 2014


Usiamo Processing?

No grazie, stiamo imparando.

Arduino è un dispositivo semplice, cerchiamo di usarlo con strumenti di base.
Dunque la bash. Bash è il linguaggio di terminale nativo su Linux. Prescelto da Torvalds fin dalla primissima versione del '91.

Premessa: configurare la porta seriale

Non sempre, quando vogliamo interagire con arduino attraverso la porta seriale, troviamo il sistema autoconfigurato correttamente. I parametri di connessione, infatti, sono spesso gestiti dai programmi di alto livello all'insaputa dell'utente finale e vengono alterati in un modo non adatto all'uso da terminale. Per non dilungarci oltre misura questo aspetto, suggeriamo di impostare la porta seriale con questo comando, testato su arduino uno:

 * stty -F /dev/arduino 1:0:1cb2:80:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

Input ed output

D'accordo. Ora chiediamoci: cosa ci dobbiamo fare, con il terminale?
Semplice. Ci dobbiamo fare input/output.
Allora, se voglio scrivere qualcosa e comunicarlo ad arduino, è un ouput.
L'output, in bash è gestito dal comando echo. Per esempio:

 * echo "Ciao" # scrive Ciao sul terminale.
   echo "Ciao" >/dev/arduino # scrive Ciao e redige l'output verso arduino.

L'input, in bash, è gestito dal comando cat, oppure dal comando head.

 * cat </dev/arduino # legge dalla porta seriale di arduino.
 * head -n3 </dev/arduino # legge le prime 3 righe provenienti dalla porta seriale di arduino.

L'ordine delle operazioni: prima leggere e poi scrivere.

Adesso dobbiamo istruire arduino a gestire la porta seriale.
Prima di cominciare, ci serve uno sketch per testare il sistema.
Questa è una soluzione minimale. Oppure possiamo usare quest'altro sketch, su cui stiamo lavorando.

Scriviamo dunque:

 * echo 30 >/dev/arduino
 * cat /dev/arduino

Sorpresa. Non esce nulla. Anzi il terminale si blocca e siamo costretti a uscirne con la combinazione di tasti Ctrl-c.

Per forza!!! Stiamo lavorando con un dispositivo fisico esterno, mica con i soliti dispositivi virtuali a cui siamo abituati. Se avessimo provato a scrivere:

 * echo 30 >/tmp/prova.txt
 * cat </tmp/prova.txt

Il risultato sarebbe molto più soddisfacente. E non si sarebbe incastrato nulla.

Qual è la differenza? Il contatto con la realtà. Se spediamo un echo verso arduino, la nostra stringa viene correttamente acquisita e processata, generando una risposta, che viene generata immediatamente.
Qualche istante dopo, eseguiamo il cat... Acciderba, troppo tardi! La risposta si è già perduta.

Davvero, comunicare con Arduino è infinitamente educativo. Soprattutto per noi insegnanti.
Dovremmo sempre comportarci così:
Prima disporci all'ascolto, e solo dopo interrogare.

Infatti, per comunicare con arduino bisogna rovesciare l'ordine delle operazioni. Proviamo così:

 * head -n1 </dev/arduino & # il simbolo & permette di eseguire il comando in batch, lasciando libero il terminale per i comandi successivi.
 * echo >/dev/arduino       # Come si diceva: prima leggere e poi scrivere!!!

Davvero. È tutta un'altra cosa.

Controllo e prontezza dell'input/output: il comando exec

Proviamo ora a includere una chiamata di input/output in uno script, oppure (che è lo stesso) a eseguire i due comandi precedenti in un'unica riga di bash:

 * head -n1 </dev/arduino & echo 30 >/dev/arduino

Questa volta i risultati saranno instabili e deludenti. Solo qualche volte si otterrà una risposta corretta, ma il più delle volte si osserverà una completa mancanza di reazione o verranno ricevute risposte incomplete e scorrette.
In precedenza, infatti, digitando manualmente due istruzioni in successione, la distanza temporale tra i comandi copriva le latenze di comunicazione del sistema, inspirandoci una soddisfazione illusoria.
Anche in questo caso, si crea una occasione per riflettere sulle differenze tra la comunicazione virtuale e la comunicazione reale.

Le operazioni di input/ouput tra due sistemi reali, infatti, sono più complesse di quanto non si possa immaginare a priori. In particolare, non si esauriscono meramente allo scambio dei dati, ma richiedono una procedura di sincornizzazione mutua che introduce delle latenze piuttosto fastidiose (nel mio sistema sono spesso superiori ai due secondi).
In queste condizioni, ovviamente, non sarebbe possibile gestire un dialogo dinamico attraverso la porta seriale.

In questi casi, la procedura di connessione deve essere separata in due fasi distinte. La prima è proprio la fase di sincronizzazione mutua dei sistemi fisici. Questa operazione, però, deve essere eseguita una sola volta, prima di incominciare la comunicazione di scambio dati e non ripetuta sistematicamente ad ogni atto di lettura o di scrittura. La seconda fase, invece, è il semplice scambio dei dati, che è velocissimo.

La sincronizzazione, in molti linguiaggi di programmazione, è gestita dal comando open. In bash, invece, viene realizzata con il comando exec, in modo che l'input ouput lavori in questa maniera:

 * exec 5<>/dev/arduino        # apertura del dispositivo arduino sul descrittore di file 5, sia per operazioni di input che per operazioni di ouput.
   sleep 5                     # forse cinque secondi è un ritardo eccessivo, ma l'operazione deve essere eseguita una volta sola.
   head -n1 <&5 & echo 30 >&5
   exec 5<&-                   # chiusura corretta del descrittore di file. Da utilizzare solo alla fine delle operazioni di input/output.