[TUTORIAL] 2 – Arduino & Processing – Inviare messaggi da Arduino a Processing

Comunicazione seriale – Da Arduino a Processing

Vediamo un esempio di come fare ad inviare un messaggio sulla seriale da Arduino ad un piccolo software scritto in Processing.

Qua sotto trovate il video tutorial. Continuate invece la lettura se preferite la spiegazione testuale.

In questo esempio è stato collegato un pulsante ad Arduino. Ogni volta che il pulsante viene premuto, un contatore viene incrementato e viene inviato un messaggio sulla seriale. Il messaggio sarà così costituito:

Message,valore contatore (ad esempio: Message,5)

Ovvero viene inviata al software la stringa “Message” seguita da una virgola e quindi dal valore del contatore che indica quante volte si è premuto il pulsante.

Il risultato finale che otterrete a video con il software in Processing è riportato in questa immagine sotto.


Iscriviti al nostro canale YouTube per saperne di più! 🙂

proc_message

 

Partiamo con il codice per Arduino.

int btnPin = 7;
int cnt = 0;

void setup(void)
{
 // Start serial port
 Serial.begin(115200);
 // Set digital pin mode
 pinMode(btnPin, INPUT);
 digitalWrite(btnPin, HIGH);

}

Nella funzione setup() è necessario inizializzare la seriale con la funzione Serial.begin(115200); scegliendo il baud rate desiderato, in questo caso 115200. La variabile int cnt = 0; verrà incrementata ogni volta che il pulsante viene premuto. Il pulsante è stato collegato al pin digitale 7. Per approfondimenti su come collegare il pulsante e impostare il pin digitale potete far riferimento al video tutorial del corso su Arduino.

Nella funzione loop() viene letto lo stato del pin digitale

 
void loop(void)
{
 int digState = digitalRead(btnPin);

Se il pulsante è premuto, viene incrementato il contatore

if(digState == 0)
  cnt++;

e quindi viene inviato il messaggio sulla seriale.

 // Message that will be sent
 Serial.print("Message"); 
 Serial.print(","); // this character will be used to separate the parts of the message
 Serial.print(cnt, DEC);
 Serial.println(); // this character will be used to identify the end of the message

Il messaggio è costituito da due parti: la stringa fissa “Message” e il valore del contatore. Le due parti sono separate dal carattere “,” che serve da carattere separatore dei campi. In generale, quando volete implementare la comunicazione seriale tra due software, e potete decidere liberamente la struttura del messaggio, se dovete inviare in un unico messaggio più informazioni, è molto utile avere un carattere che separi i campi. In questo modo il software che riceve il messaggio saprà come suddividere i dati arrivati. Si potrà facilmente sapere quando inizia un campo di informazione e quando inizia il successivo.

In questo nostro esempio poteva non essere necessario (stamperemo soltanto a video il messaggio ricevuto), ma se ad esempio aveste dovuto inviare dei valori di alcuni sensori, ad esempio

11.345,-0.789

il carattere separatore, “,” in questo caso, è molto utile per capire quando inizia e finisce un valore.

Inoltre è molto utile avere un carattere che identifichi la fine del messaggio. In questo modo il software scritto in Processing saprà quando il messaggio è finito e può essere elaborato, e quando inizia il messaggio successivo. In questo caso abbiamo usato il carattere line feed  per identificare la fine del messaggio, Serial.println();.

Una volta inviato il messaggio è importante nel nostro caso introdurre un ritardo usando le funzione delay()

 // Delay to avoid multilple message
 delay(500); 
 }
}

Perchè abbiamo introdotto un ritardo? Come sapete la funzione loop() viene eseguita di continuo da Arduino. Dunque, se non vi fosse il ritardo, ad una singola pressione del pulsante, potrebbero corrispondere più esecuzioni della funzione loop() e quindi verrebbe incrementato il contatore e inviato il messaggio più di una volta per una singola pressione del pulsante. Alla fine del tutorial potete provare a commentare il delay(500); e verificare quello che succede.

Passiamo ora al codice per Processing.

Per prima cosa è necessario importare la libreria per la gestione della seriale.

import processing.serial.*;

Definiamo quindi le variabili necessarie.

Serial myPort; // Create object from Serial class
String serial = null; // initialize the string to which the message will be assigned
int end = 10; // the number 10 is ASCII for linefeed (end of serial.println),
              // later we will look for this to break up individual messages
String message = "Waiting..."; // initial string that will be shown on the screen

Prima cosa abbiamo dichiarato l’oggetto myPort della classe Serial, Serial myPort;. Quindi è necessaria una variabile stringa String serial = null; che conterrà il messaggio ricevuto sulla seriale. La variabile int end = 10; identifica il valore in ASCII del carattere che abbiamo usato come identificatore della fine del messaggio. Ovviamente dovrà corrispondere al carattere da voi usato per identificare la fine del messaggio qualora ne abbiate usato un altro. Infine abbiamo dichiarato una variabile che servirà per visualizzare un messaggio a video, e che assumerà valore diverso in base al messaggio ricevuto, String message = “Waiting…”;.

Vediamo ora la funzione setup().

void setup() {
 
 size(400, 400);
 myPort = new Serial(this, Serial.list()[0], 115200);
 //myPort.bufferUntil(end); //Uncomment this if you want to use the second method proposed

}

Prima cosa impostiamo la dimensione della finestra che verrà mostrata a video con al funzione size(400,400); . Quindi inizializziamo l’oggetto myPort usando il costruttore della classe Serial nel seguente modo, myPort = new Serial(this, Serial.list()[0], 115200);

In breve abbiamo:

  • this: identifica il parent dell’oggetto
  • Serial.list()[0]: la funzione list() della classe Serial restituisce la lista delle seriali attualmente disponibili sul vostro PC. Se avete, come in questo caso, solo Arduino connesso, o meglio solo una COM disponibile, allora la funzione restituirà un solo elemento a cui facciamo accesso con il [0].
  • 115200: è il baud rate della seriale. Deve essere uguale a quello scelto nel codice di Arduino.

Nella funzione draw() impostiamo il background della finestra.

void draw() { 

 background(255);

Quindi andiamo a vedere se sulla seriale sono presenti dei dati.

 //as long as there is data coming from serial port, read it and store it  
 while (myPort.available() > 0) { 
    println("data available");
    serial = myPort.readStringUntil(end);
 }

La funzione myPort.available() verifica se sulla seriale sono presenti dei dati. Se restituisce un valore > 0, allora sono presenti byte da leggere. Utilizzando il ciclo while con la condizione myPort.available() > 0, si fa in modo che vengano letti i byte fino a che ci sono dati disponibili sulla seriale. Per leggere i dati e assegnarli alla variabile serial abbiamo in questo caso utilizzato la funzione myPort.readStringUntil(end); . Questa legge i dati del buffer di ricezione della seriale fino a che non incontra il carattere rappresentato dalla variabile end, che rappresenta il carattere di fine messaggio.

A questo punto la variabile serial sarà diversa da null e conterrà il messaggio ricevuto.

if (serial != null) { //if the string is not empty, do the the following 
 println("serial != null");
 String[] a = split(serial, ',');
 message = a[0] + " " + a[1];
 serial = null; 
}

Quando quindi serial != null, andiamo ad elaborare il messaggio. In questo nostro semplice esempio separeremo solo i due campi del messaggio e poi li riuniremo, mettendo uno spazio in mezzo, per visualizzarli sulla finestra. Ovviamente non sarebbe necessario, ma vogliamo mostrarvi appunto come fare a a separare i campi del messaggio per usare separatamente i valori inviati.

A questo punto entra in gioco il carattere separatore che avevamo usato in Arduino per separare i campi del messaggio, ovvero il carattere “,”. Per dividere una stringa in più parti in base ad un separatore si utilizza il metodo split() che vuole in ingresso la stringa da dividere, in questo caso serial, e il carattere in base al quale deve essere divisa, “,” . La funzione viene chiamata in questo modo String[] a = split(serial, ‘,’);.

In questo modo otteniamo quindi un vettore di stringhe String[] a , e sarà possibile prendere i singoli campi del messaggio semplicemente facendo accesso alle varie posizioni del vettore. In questo caso, ad esempio, abbiamo assegnato alla variabile message la concatenazione del primo campo a[0] , di uno spazio e del secondo campo del messaggio ricevuto a[1] . Infine impostiamo nuovamente serial = null; in attesa dell’arrivo di un nuovo messaggio.

Per concludere quindi impostiamo il color del carattere, la sua dimensione e stampiamo il messaggio a video.

  fill(50);
  textSize(32);
  text(message, 120, 200); 
}

Caricate quindi il codice su Arduino ed eseguite il codice scritto con Processing.

Premendo il pulsante, ad esempio 5 volte, quello che dovete ottenere è quello riportato in figura.

proc_message

Se qualcosa non dovesse funzionare, assicuratevi che il baudrate della seriale sia correttamente impostato e che venga presa la corretta seriale con la funzione Serial.list().

Ricordate del delay(500); che avevamo introdotto nel codice di Arduino? Se ora provate a commentarlo, vedrete quanto ho detto prima. Premendo una sola volta il pulsante vedrete, nella finestra creata con Processing, che il contatore del messaggio non è aumentato di 1, ma di un numero maggiore. Ricordatevi poi di scommentare la riga delay(500); e ricaricare il codice.

Vediamo ora un altro metodo in Processing per poter leggere i dati della seriale. Questo sfrutta l’evento serialEvent().

Per provare questo secondo metodo potete modificare il vostro codice in modo che appaia come quello riportato qua sotto.

import processing.serial.*; 

Serial myPort; // Create object from Serial class
String serial = null; // initialize the string to which the message will be assigned
int end = 10; 
String message = "Waiting..."; // initial string that will be shown on the screen

void setup() {
 
 size(400, 400);
 myPort = new Serial(this, Serial.list()[0], 115200);
 myPort.bufferUntil(end); 

}

void draw() { 
 background(255); 
// while (myPort.available() > 0) { 
//  println("data available");
//  serial = myPort.readStringUntil(end);
// }
// if (serial != null) { //if the string is not empty, do the the following 
//     println("serial != null");
//     String[] a = split(serial, ','); 
//     message = a[0] + " " + a[1];
//     serial = null; 
// }

 fill(50);
 textSize(32);
 text(message, 120, 200); 
 
}

void serialEvent(Serial whichPort) {
 println("event");
 serial = whichPort.readStringUntil(end);
 if (serial != null) { //if the string is not empty, do the the following 
    println("serial != null");
    String[] a = split(serial, ','); 
    message = a[0] + " " + a[1];
    serial = null; 
 }
}

Le parti del codice precedente non necessarie sono state commentate. Abbiamo aggiunto l’implementazione della funzione serialEvent() e richiamato myPort.bufferUntilEnd(end); nel metodo setup().

serialEvent() è un evento che viene automaticamente scatenato quando sono presenti dei byte sulla seriale. Verrà eseguito il codice che avete inserito nella funzione serialEvent().

Nella funzione setup() abbiamo aggiunto myPort.bufferUntilEnd(end); per far si che l’evento serialEvent() non venga scatenato ad ogni byte ricevuto, ma solo dopo che è stato ricevuto il carattere di fine messaggio rappresentato dalla variabile end. In questo modo i byte precedenti verranno memorizzati nel buffer di ricezione e solo una volta che il messaggio è finito, verrà eseguita la funzione per la lettura del messaggio.

Se eseguite questo nuovo codice vedrete che il comportamento del software è del tutto analogo al caso precedente.

Questo è un piccolo esempio di come poter inviare messaggi da Arduino a Processing. Ovviamente potrete variare a vostro piacimento la struttura del messaggio scritto, facendo attenzione ad elaborare nel modo corretto l’informazione ricevuta da Processing.

Per maggiori informazioni sulla classe Serial di Processing potete far riferimento a questo link.

Per informazioni invece sulla classe Serial di Arduino andate a questa pagina.

I sorgenti per questa parte del tutorial sono scaricabili da https://github.com/nerdityourself/ArduinoToProcessing

 

 

 

Una risposta a “[TUTORIAL] 2 – Arduino & Processing – Inviare messaggi da Arduino a Processing”

I commenti sono chiusi.