Quando Arduino incontra Linux

Connettere Arduino ad Internet significa aprire un mare di possibilità in cui poter navigare; significa dotare i nostri progetti del valore aggiunto di poter essere controllati da remoto, da qualunque parte del mondo: basta disporre di una connessione. Aggiungiamo le potenzialità di un sistema Linux e otterremo un mix con cui poter realizzare cose davvero interessanti!

Questo articolo scaturisce da alcune discussioni a cui ho partecipato sul forum di Arduino e dalle quali mi sono reso conto che cose che io davo per assodate e ormai note, non erano invece poi così scontate per altri utenti.

In questo articolo realizzeremo un semplicissimo progetto di esempio così come è venuto fuori da una discussione in particolare. Tale progetto, oltre ad illustrare come sia possibile collegare Arduino al sistema Linux e farli comunicare tra loro, cercherà di concretizzare alcune delle tantissime possibilità messe a disposizione da questo approccio in un esempio pratico.

Connettere Arduino in rete è possibile grazie all’utilizzo di shield espressamente progettate per fornire connessioni Ethernet o WiFi. Esiste però un’interessante alternativa a tali soluzioni: sfruttando l’interfaccia seriale messa a disposizione da Arduino è infatti possibile connettere il nostro microcontrollore ad un sistema Linux (eventualmente anche embedded) e trarre beneficio da tutte le funzionalità messe a disposizione da quest’ultimo.

A questo punto potremmo, ad esempio, usare uno dei vari web server disponibili per Linux, al posto di quello certamente meno performante e potente che saremmo in grado di realizzare sulla shield Ethernet; ma potremmo anche realizzare progetti ben più complessi, che richiedano potenze di calcolo che non possiamo pretendere da Arduino e che invece il sistema Linux sarà perfettamente in grado di fornirci.

In altre parole, abbiamo la possibilità di usare Arduino per i compiti più semplici e ripetitivi che possono essere espletati da sensori e/o attuatori intelligenti, mentre il sistema Linux sarà il cervello ed il tramite per la connessione via rete. Usando il bus USB possiamo collegare diversi Arduino allo stesso sistema Linux e quindi realizzare sistemi complessi con Linux come mente e i sistemi Arduino come occhi e braccia con però una intelligenza locale.

Arduino può diventare quindi il mezzo attraverso il quale riusciamo a far “affacciare” il mondo virtuale del computer in quello della realtà fisica.

Il progetto d’esempio

Il progettino che svilupperemo consisterà semplicemente nel pilotare due led collegati ad Arduino, tramite una pagina web. Tale pagina farà uso di PHP per leggere e scrivere dalla seriale e risiederà su un web server installato sul sistema Linux a cui abbiamo connesso Arduino.

L’utilità del di tale applicazione potrebbe apparire nulla (ed in effetti lo è…), però pensate di sostituire i led con qualcosa di più “significativo” come ad esempio dei relè o delle elettrovalvole. Il passo da qui a ragionare su di un’applicazione di domotica non vi sembra più breve? ;)

Come sistema Linux è possibile scegliere sia un normale pc, che un qualche sistema embedded come ad esempio un SBC (Single Board Computer). Chiaramente il sistema andrà dimensionato alle esigenze del progetto che vogliamo realizzare. Personalmente, con la tecnica spiegata in questo articolo, ho realizzato una IPCam con l’intento di installarla su un piccolo rover. Ho utilizzato la scheda di un router con installato OpenWRT come sistema Linux, una webcam, due servomotori in configurazione pan/tilt ed il software motion… per poi rendermi conto, a progetto ultimato, che la dotazione hardware di tale scheda non era sufficiente per uno streaming video abbastanza fluido…

Arduino potrà essere connesso al sistema Linux attraverso la porta USB (in realtà una seriale emulata), se ne abbiamo a disposizione, o in alternativa attraverso i pin connessi alla seriale del microchip Atmel.

Faccio un esempio: Arduino Uno ha una porta seriale connessa ai pin 0 e 1. Il router che ho utilizzato nel progetto di cui parlavo sopra ha una UART. Il collegamento tra le due seriali può avvenire in questo modo:

 

ARDUINO                        EDIMAX BR-6104KP

TX (pin 1)  —————–   RX (pin 1)

RX (pin 0)  —————–   TX (pin 7)

GND         —————–  GND (pin 8)

 

È chiaro che sarà necessario verificare se avremmo bisogno di un adattatore di livelli per effettuare tale collegamento.

Nel mio caso non era necessario perché, pur essendo l’UART del router una TTL 3.3V, Arduino è in grado di interpretare tale tensione come 1 logico, mentre il chip ADM5120 del router è 5V tollerant. Al limite, per essere più sicuro, avrei potuto usare due resistenze per creare un partitore di tensione che abbassasse i 5V provenienti da Arduino a circa 3.3V…

Una cosa da tener ben presente è che Arduino effettua un reset automatico ad ogni connessione che riceve sulla seriale emulata da USB. Ciò è utile in fase di caricamento degli sketch, perché ci evita di dover premere ogni volta il pulsante del reset a mano, ma è al contrario un grosso svantaggio qualora volessimo connettere il sistema Linux ad Arduino utilizzando la porta USB: in tal caso infatti, la comunicazione seriale non avverrebbe in modo corretto.

Un modo molto semplice per evitare il reset automatico è quello di porre un condensatore da 10uF tra i pin gnd e reset di Arduino (Attenzione: funziona SOLO con Arduino Uno. Per la Duemilanove ho letto di una resistenza da 120 ohm tra reset e 5V, ma sinceramente non ho mai avuto modo di provare).

Tale condensatore andrà rimosso ogni volta che si vuole caricare uno sketch, pena il mancato caricamento dello stesso e l’uscita con uno stato di errore da parte dell’IDE.

Per le connessioni sui pin collegati direttamente alla seriale del micro, invece, non c’è reset automatico, quindi si può fare a meno del condensatore (o della resistenza).

I sorgenti

Questo è il codice dello sketch da caricare su arduino:

int led = 12; 
int led2 = 13;
int incomingByte = 0;
int stato = ‘s’;
int stato2 = ‘t’;
 
void setup() {
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
  delay(2000); //evita di bloccare la seriale di arduino
  //inizializzo la seriale
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {//se c’è qualcosa in arrivo sulla seriale…
    incomingByte = Serial.read(); //… leggo il dato
    switch(incomingByte) {
      case ‘H’: //se arriva una ‘H’ accendo led
        digitalWrite(led, HIGH);
        stato = ‘a’;
        break;
      case ‘L’: //se arriva una ‘H’ accendo led
        digitalWrite(led, LOW);
        stato = ‘s’;
        break;
      case ‘S’: //se arriva una ‘S’ comunico lo stato di led
        switch (stato) { //al sistema Linux, scrivendolo sulla seriale:
          case ‘a’: //’a’ => acceso, ‘s’ => spento
            Serial.println(“a”);
            break; 
          case ‘s’:
            Serial.println(“s”);
            break;
        }
        break;
      case ‘I’: //’I’ accendo led2
        digitalWrite(led2, HIGH);
        stato2 = ‘u’;
        break;
      case ‘M’: //’M’ spengo led2
        digitalWrite(led2, LOW);
        stato2 = ‘t’;
        break;
      case ‘T’:
        switch (stato2) {
          case ‘u’: //’u’ => acceso
            Serial.println(“u”);
            break;
          case ‘t’: //’t’ => spento
            Serial.println(“t”);
            break;
        }
        break;
    }
  }
}

Il codice di per sé è molto semplice e non credo abbia bisogno di ulteriori spiegazioni.

Il protocollo usato per la comunicazione tra Arduino ed il sistema Linux è quasi banale…

L’idea di base è quella di controllare l’esecuzione dello sketch dal programma PHP sul sistema Linux, inviando dei comandi sulla seriale: nel caso d’esempio, semplici lettere a cui Arduino risponderà in modo opportuno.

Questa è invece la pagina web di controllo:

<?php

  /***** Device seriale *****/
  $serial = “/dev/ttyACM0”;
  /**************************/

 

  if (isset($_POST)) {

    $fp = @fopen($serial, “rb+”); //apro il device seriale

    if (isset($_POST[‘dir’])) {
      if ($_POST[‘dir’] == ‘accendi’) { //accendi led: invio una ‘H’ sulla serale
        fwrite($fp, “H”);
      }
      else if ($_POST[‘dir’] == ‘spegni’) { //spegni 1ed: invio una ‘L’
        fwrite($fp, “L”);
      }
    }
    else if (isset($_POST[‘dir2’])) {
      if ($_POST[‘dir2’] == ‘accendi’) { //accendi led2: invio una ‘I’
        fwrite($fp, “I”);
      }
      else if ($_POST[‘dir2’] == ‘spegni’) { //spegni led2: invio una ‘M’
        fwrite($fp, “M”);
      }
      fclose($fp);
    }
  }

  $stampa = ”;
  $stampa2 = ”;

  $handle = fopen($serial, “rb+”);
  fwrite($handle, “S”); //check stato led1
  sleep(1); //ritardo necessario per sincronizzare la lettura
  $content = fread($handle, 1);
  fclose($handle);

  $handle = fopen($serial, “rb+”);
  fwrite($handle, “T”); //check stato led2
  sleep(1);
  $content2 = fread($handle, 1);
  fclose($handle);

  if ($content == ‘a’) {
    $stampa=’Il led &egrave; acceso’;
  }
  else if ($content == ‘s’) {
    $stampa=’Il led &egrave; spento’;
  }

  if ($content2 == ‘u’) {
    $stampa2=’Il led &egrave; acceso’;
  }
  else if ($content2 == ‘t’) {
    $stampa2=’Il led &egrave; spento’;
  }

?>


<html>
    <head>
        <title>Controllo Arduino via PHP</title>
    </head>
    <body>
        <h1>Controllo Arduino via PHP</h1>
        <form name=”input” action=”<?php $_SERVER[‘PHP_SELF’] ?>” method=”post”>
            <fieldset>
                <legend>Led 1:</legend>
                <input type=”submit” name=’dir’ value=”accendi” />
                <input type=”submit” name=’dir’ value=”spegni” />  
                <p>&lt;?php echo $stampa ?&gt;</p>
            </fieldset>
            <fieldset>
                <legend>Led 2:</legend>
                <input type=”submit” name=’dir2′ value=”accendi” />
                <input type=”submit” name=’dir2′ value=”spegni” />
                <p><?php echo $stampa2 ?>;</p>
            </fieldset>
        </form>
    </body>
</html>

Credo che anche questo codice non abbia bisogno di ulteriori spiegazioni. Il device seriale dell’esempio è /dev/ttyACM0, che chiaramente andrà modificato qualora il vostro abbia un nome differente.

Segnalo inoltre che un utente del forum ha avuto problemi a rilevare lo stato di led2 con questo codice. Problemi che sono stati risolti dividendo la form html in due, che richiamano file php differenti, ciascuno dei quali gestisce le operazioni relative ad uno dei due led.

La velocità della seriale sullo sketch Arduino era stata settata a 9600 baud, quindi anche sul sistema Linux dovremmo fare la stessa cosa:

$ stty -F /dev/ttyACM0 9600

Adesso disponiamo di una pagina web che ci permette di controllare i led connessi ad Arduino dovunque ci troviamo.

Conclusioni

Quello che abbiamo realizzato in questo breve articolo è un sistema di controllo remoto di sensori e/o attuatori collegati ad Arduino che, seppur nella sua estrema semplicità, ha una valenza piuttosto generale (ripensiamo all’esempio della domotica fatto precedentemente).

Per il collegamento tra Arduino ed il sistema Linux, io ho utilizzato l’interfaccia seriale. Esistono altri metodi, che personalmente non ho ancora sperimentato, come ad esempio SPI o I2C.

Spero che l’esempio illustrato, per quanto semplice, sia riuscito a dare un’idea delle potenzialità offerte dal binomio Arduino-Linux.

Non solo è possibile controllare attraverso Internet (nell’esempio tramite interfaccia web, ma anche un’applicazione per smartphone sarebbe una scelta papabile) qualunque sensore e/o attuatore collegato ad Arduino, ma è anche possibile sfruttare la potenza di un sistema Linux, opportunamente scelto, per compiti gravosi che Arduino non sarebbe in grado di espletare da solo, come ad esempio la computer vision.

Sottolineo ancora una volta che, mentre nell’esempio citato è stato connesso un solo Arduino al sistema Linux, è in realtà possibile (ed auspicabile) connetterne diversi, che gestiscano differenti compiti.

Come si dice in questi casi, l’unico limite è la fantasia. ;)


 


 

P.S. Colgo l’occasione per salutare tutta la comunità che ruota attorno ad Arduino e che, condividendo la propria conoscenza e le proprie esperienze, contribuisce ogni giorno a far crescere questo fantastico progetto open source.

Su Rodolfo Giometti

Ingegnere informatico libero professionista ed esperto GNU/Linux offre supporto per: - device drivers; - sistemi embedded; - sviluppo applicazioni industriali per controllo automatico e monitoraggio remoto; - corsi di formazione dedicati. Manutentore del progetto LinuxPPS (il sottosistema Pulse Per Second di Linux) contribuisce attivamente allo sviluppo del kernel Linux con diverse patch riguardanti varie applicazioni del kernel e dispositivi (switch, fisici di rete, RTC, USB, I2C, network, ecc.). Nei 15+ anni di esperienza su Linux ha lavorato con le piattaforme x86, ARM, MIPS & PowerPC.

Lascia un commento

Utilizzando il sito, accetti l'utilizzo dei cookie da parte nostra. maggiori informazioni

Questo sito utilizza i cookie per fonire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo.

Chiudi