Site icon Meccanismo Complesso

Tutorial: passare valori dal PC ad Arduino per via seriale

Arduino-tutorial-serial-4
Arduino-tutorial-serial-2

Premessa

Salve a tutti, oggi voglio scrivere un breve tutorial in risposta ad una richesta che abbiamo ricevuto ieri sul sito da parte di pensodisi. 

Spero che potrà essere utile sia a lui sia a tutti gli altri che hanno esigenze simili.

Ogni vostra richiesta o suggerimento sarà sempre per noi uno stimolo a migliorare.

Introduzione

Per chi si diletta a realizzare progetti con Arduino, prima o poi dovrà avere a che fare con lo scambio di valori tra Arduino e il PC a cui è collegato.

Se useremo Arduino collegato ad un sensore (vedi Fig.1), la scheda Arduino produrrà una serie di dati che potranno essere inviati ad un computer per poter essere immagazzinati in un file, visualizzati o elaborati in qualche modo. Se invece useremo Arduino collegato ad un attuatore (vedi Fig.2), come per esempio un motore passo passo, molto probabilmente sarà il computer a cui Arduino è collegato, che dovrà inviare una serie di dati alla scheda Arduino. Quest’ultima processerà i dati ricevuti convertendoli opportunamente in comandi da inviare al motore per farlo muovere della quantità di step necessaria.

Fig.1: Arduino invia i dati del sensore al PC
Fig.2: Arduino riceve i dati dal PC per pilotare l’attuatore

Tratterò questo argomento in due diversi articoli.

In questo tutorial vedremo l’esempio dell’uso di Arduino come controllo per un attuatore. Per rendere il tutorial il più semplice possibile, utilizzeremo come attuatore un servo motore.

Fig.3: Un servo motore per modellismo

Invece in un prossimo articolo, tratterò la raccolta dei dati da un sensore collegato ad Arduino e l’invio di questi valori ad un PC.

Per quanto riguarda i vari comandi per pilotare il servo motore, o altri tipi di motore (continuo o passo-passo) vi consiglio di fare riferimento all’articolo Controllo Motori con Arduino e la scheda Adafruit Motorshield v2.

Pilotare un servo motore con una sequenza di angoli su un file

Ho scelto un servo motore proprio per la sua semplicità, soprattutto per quanto riguarda i comandi. L’esempio di questo tutorial sarà quello di leggere un file TXT, o CSV con all’interno un elenco di angoli che il servo motore dovrà assumere nel tempo leggendo riga per riga.

Fig.4: Il file CSV contiene la sequenza degli angoli di rotazione

Ho scelto questo esempio, poichè nonostante la sua semplicità, contiene tutti gli elementi fondamentali rimanendo semplice e facilmente intuitibile. Sarà poi semplicissimo estendere questo esempio a progetti più complessi.

Diamo un occhiata allo schema generale di ciò che realizzeremo in questo tutorial:

Fig.5: questo è lo scenario del nostro tutorial

Come possiamo vedere stabiliremo una connessione seriale tra la scheda Arduino ed il PC. Sulla scheda Arduino programmeremo uno sketch che si occuperà di “mettersi in ascolto” per eventuali invii di valori (angoli) da parte del PC. Mentre sul PC attiveremo una semplice sessione in Python (ma può essere incorporato in qualsiasi programma in Python) che si occuperà di leggere il contenuto del file CSV (o TXT) inviando gli opportuni segnali via seriale alla scheda Arduino.

Ho scelto il servo motore come attuatore anche perchè è possibile collegarlo direttamente alla scheda Arduino senza l’uso di opportune schede di controllo. Fate riferimento alla figura 6 per i collegamenti.

Fig.6: Il cavetto giallo deve essere collegato al PIN 10

Per chi avesse la Motorshield v2 di Arduino può fare riferimento alla figura seguente (Fig.7).

Fig.7: Collegamento tra il servo motore e la Motorshield

Lo sketch

Per prima cosa occupiamoci dello sketch da sviluppare sull’Arduino IDE. (Clicca qui per collegari alla pagina ufficiale di Arduino scaricare l’ultima release di Arduino IDE).

Per prima cosa importiamo la libreria Servo già inclusa all’interno dell’Arduino IDE

#include <Servo.h>

Questa libreria ci fornisce tutta una serie di comandi per gestire in maniera facile ed intuitiva i Servo Motori direttamente collegati ad Arduino. (Per chi è interessato può consultare qui la pagina ufficiale).

Servo myservo;
int angle = 0;
int newAngle = 0;
const int MaxChars = 4;
char strValue[MaxChars+1];
int index = 0;

Per prima cosa definiamo un oggetto myservo, che corrisponderà al nostro servo motore. Definiamo inoltre le variabili angle e newAngle che conterranno i valori degli angoli. Poi definiremo un array strValue di caratteri che conterrà al massimo 4 caratteri (per esempio ‘123,’ ). Questo array serve a immagazzinare i valori degli angoli inviati per via seriale dal PC.  Infine un indice index che ci servirà successivamente per la scansione dell’array di caratteri.

void setup()
{
 Serial.begin(9600);
 myservo.attach(10);
 angle = 90;
}
void loop()
{}

Definiamo adesso le due funzioni standard setup() e loop().

La funzione setup praticamente si occupa della fase di inizializzazione della scheda, e quindi, prima di tutto attiveremo una comunicazione seriale a 9600 baud. Poi definiremo che il nostro servo motore è collegato al PIN 10 attraverso la funzione attach() della libreria Servo. Infine definiamo un angolo di partenza del motore (HOME position) che nel mio caso ho definito come 90°.

La funzione loop invece dovrà contenere tutti i comandi che verranno eseguiti dalla scheda a ciclo continuo. Io ho lasciato vuota questa funzione, ma qui voi potete implementare tutto ciò di cui avrete bisogno per adempiere alle vostre specifiche esigenze.

Infine definiamo una nuova funzione chiamata serialEvent(). Questa funzione, anche se non è inclusa all’interno di loop(), è sempre in ascolto, e quando un evento seriale viene catturato dalla scheda Arduino, come nel nostro caso l’invio dal PC di un valore numerico, viene attivata, ed il codice contenuto all’interno viene eseguito.

void serialEvent()
{
   while(Serial.available()) 
   {
      char ch = Serial.read();
      Serial.write(ch);
      if(index < MaxChars && isDigit(ch))              {                               
            strValue[index++] = ch;                     
      }else{                               
            strValue[index] = 0;                               
            newAngle = atoi(strValue);                               
            if(newAngle > 0 && newAngle < 180){
               if(newAngle < angle)                                                
                   for(; angle > newAngle; angle -= 1) {
                   myservo.write(angle);
               }  
            else 
               for(; angle < newAngle; angle += 1){
                   myservo.write(angle);
                } 
         }
         index = 0;
         angle = newAngle;
      }  
   }
}

Ciascun valore inviato dal PC viene letto carattere per carattere ed inserito all’interno dell’array strValue. Se il carattere letto sarà un numero (da 0 a 9) verrà immagazzinato all’interno dell’array, se invece sarà un carattere non numerico (nel nostro caso la virgola ‘,’) la lettura verrà interrotta e il valore all’interno dell’array verrà convertito in un valore numerico vero e proprio attraverso la funzione atoi().

Il valore numerico così ottenuto viene immagazzinato all’interno della variabile newAngle, e rappresenta il nuovo angolo su cui dovrà impostarsi il servo motore. Questo valore per essere accettabile dovrà essere compreso tra 0 e 180 gradi. Successivamente verrà confrontato con l’angolo corrente angle, e a seconda se maggiore o minore, incrementeremo o diminuiremo gradualmente (grado per grado) l’angolo del servo motore. Questo per evitare bruschi salti da parte del servo motore. L’angolo su cui deve essere impostato il motore viene definito dalla funzione write() della libreria Servo.

Fig.8: Il codice (prima parte)
Fig.9: Il codice (seconda parte)

Se adesso eseguiamo il codice, vedremo il servo motore ruotare per portarsi alla posizione corrispettiva all’angolo di 90°. Poi attenderà immobile in ascolto dei valori inviati dal PC.

Prima di passare a Python, facciamo un po’ di prove. Attiviamo il Monitor Seriale all’interno dell’Arduino IDE, cliccando sulla voce Menu Strumenti > Monitor Seriale.

Fig.10: apri il Monitor Seriale dal menu

Una nuova finestra ci apparirà, il Monitor Serial appunto, in cui potremo fare delle prove scrivendo direttamente gli angoli a cui vogliamo impostare il servo Motore. Scriviamo per esempio ‘123;’ e premiamo INVIO.

Fig.11: inserisci direttamente i valori degli angoli

Se abbiamo scritto correttamente lo sketch ed effettuato tutti i collegamenti, vedremo ruotare il servo motore dalla posizione HOME (90°) a quella di 123° appena inviata.

I Comandi da Python

Adesso occupiamoci della parte Python per quanto riguarda il lato PC.

Per prima cosa avviamo una shell di Python. Se non l’avete ancora installato sul vostro PC andate qui.

Fig.12: La shell di Python

Una volta aperta la shell importiamo la libreria serial, e creiamo una connessione seriale ser sulla porta in ascolto della scheda Arduino anche questa a 9600 baud.

import serial
ser = serial.Serial('/dev/ttyACM1',9600)

Attenzione la porta USB in ascolto può variare, quindi controllate dall’Arduino IDE la porta (Per es. su Windows può essere una COM 1,2,3 o 4). Quindi sostituite la porta all’interno della funzione Serial().

Adesso se scrivete

ser.write('110,')

otterrete un risultato identico a quello ottenuto prima con il Monitor Serial. Il servo motore ruoterà fino ad assumere la posizione corrispettiva all’angolo 110°.

Ma il nostro scopo è quello di leggere una sequenza di valori elencati all’interno di un file CSV. Quindi creiamo un file CSV con una sequenza di angoli e salviamolo come samples.csv.

Copiamo il file appena creato nella working directory della shell di Python. Se non vi ricordate o non sapete quale sia, inserite i seguenti comandi:

import os
os.getcwd()

Vi apparirà la directory dove la shell di Python va a leggere direttamente. Copiato il file, scriviamo

import time
file = open('samples.csv')
while 1:
   line = file.readline()
   if not line:
         break
   ser.write(line)
   time.sleep(3)

Ogni 3 secondi (definito da time.sleep()) la shell di Python leggerà un riga dal file CSV inviando il valore contenuto, cioè l’angolo, alla scheda Arduino in ascolto, che a sua volta azionerà il servo motore.

Una volta concluso, chiudete la lettura del file con il comando.

file.close

Conclusioni

Come potete vedere il tutorial è essenziale, semplice e facilmente producibile. E’ un buon punto di partenza per qualsiasi progetto che ha tra le sue funzioni lo scambio di dati.

Le righe di comando di Python possono essere implementate in un programma, e per la comunicazione seriale potremmo utilizzare una libreria specifica, come per esempio la llibreria pySerial.

Per quanto riguarda i valori io ho usato il valore degli angoli, ma potrebbe essere usato qualsiasi tipo di valore, per esempio gli step, una distanza, ecc.

Inoltre, nel caso di più motori, per esempio in un’automazione CNC a 2 motori (XY) o a 3 motori (XYZ) è possibile passare una riga con più valori, per esempio il primo valore il numero degli step e come secondo valore il motore da muovere (X o Y o Z).

Insomma questo tutorial vi dovrebbe aprire la strada a molti progetti. E se vi sarà di ispirazione, pubblicate i vostri progetti sul sito Meccanismo Complesso, ne saremmo fieri.[:en]

Exit mobile version