05 ComunicazioneArduino
05 ComunicazioneArduino
Programmazione
Raspberry Pi
Comunicazione con Arduino
Raspberry Pi – Comunicazione Arduino
Comunicazione Seriale
2. In seguito aprire VirtualBox e cliccando con tasto destro sull’icona della macchina virtuale del
Raspberry pi selezionare Impostazioni e poi USB
3. Dal menù aggiungere un nuovo dispositivo e selezionare Arduino Uno, poi premere Ok per
confermare.
Raspberry Pi – Comunicazione Arduino
Verificare il collegamento
• Per verificare se il dispositivo è stato correttamente riconosciuto (sia per il Raspberry sia per la
macchina virtuale) utilizzare il comando lsusb
Raspberry Pi – Comunicazione Arduino
Riconoscere la porta seriale
dmesg serve a stampare tutti gli eventi recenti del sistema operativo
grep tty dice al sistema di cercare nell’output del comando precedente (dmesg) tutte le righe che
contengono la stringa ‘tty’
Nel caso in esempio vediamo che la porta seriale dell’Arduino è la porta ttyACM0 (sarebbe
l’equivalente di una COM1 su windows)
• Per verificare il funzionamento della libreria pyserial realizzare uno script con il seguente
contenuto:
Raspberry Pi – Comunicazione Arduino
• Il risultato dovrebbe essere come il seguente (non considerate la riga con ttyAMA0)
• Questo risultato significa che la libreria ha correttamente riconosciuto Arduino sulla porta seriale
Raspberry Pi – Comunicazione Arduino
Pyserial – breve guida
• Per inizializzare la comunicazione seriale la prima cosa da fare è creare un oggetto Serial tramite il
costruttore:
s_obj = serial.Serial(port_name, baudrate=9600)
• Port_name è il nome della porta seriale a cui è collegato arduino, quello che ci ha restituito il
file precedente (/dev/ttyACM0 nel mio caso)
• Baudrate deve essere lo stesso impostato su Arduino altrimenti la comunicazione seriale non
sarà corretta
• La porta verrà automaticamente aperta quando viene creata
• Per conoscere il numero di byte in attesa di essere letti e presenti sulla seriale si utilizza:
s_obj.in_waiting
• ATTENZIONE! Questo è un attributo (quindi una variabile) e non un metodo (quindi una
funzione), è corretto utilizzarlo senza parentesi alla fine!
Raspberry Pi – Comunicazione Arduino
Pyserial – breve guida
• Per leggere dalla porta seriale che è stata aperta un numero di byte pari alla size specificata si può
utilizzare:
s_obj.read(size)
• Questa chiamata attende fino a che non saranno presenti abbastanza byte da leggere sulla
seriale, a meno che non venga impostato un timeout. Fate attenzione perché stiamo parlando di
BYTE e non di CARATTERI
• Per scrivere sulla seriale invece si utilizza la funzione:
s_obj.write(data)
• ATTENZIONE! Data deve essere in formato bytes e NON una stringa
Raspberry Pi – Comunicazione Arduino
Esempio
• Creare un programma per Arduino che scriva «Hello there!» durante la funzione di setup
Dec 72 101 108 108 111 32 119 111 114 108 100 33
Hex 0x48 0x65 0x6c 0x6c 0x6f 0x20 0x77 0x6f 0x72 0x6c 0x64 0x21
H e l l o w o r l d !
• Il problema è che questa codifica ha un numero limitato di caratteri e permette quindi di scrivere
solo le cifre arabe, i simboli di base e le lettere utilizzate in inglese (niente accenti e niente
caratteri non presenti nell’alfabeto inglese). Per questo, nel tempo sono state create altre
codifiche.
Raspberry Pi – Comunicazione Arduino
Codifica UTF-8
• È una delle codifiche più utilizzate. Questa codifica permette di scrivere tutti i caratteri in latino e
latino esteso, i simboli e i caratteri di tutti i linguaggi alfabetici (Greco, Cirillico, Arabo …) A
seconda del carattere rappresentato esso può occupare anche più di un byte.
Hex 0x63 0x69 0xc3b2 0x20 0xc3a8 0x20 0x75 0x74 0x66 0x2d 0x38
c i ò è u t f - 8
• I byte si possono dichiarare mettendo una b davanti ad una stringa a patto che contenga solo
caratteri ascii:
my_bytes = b’ciao_ciao’ my_bytes = b’ciaoèciao’
• Oppure è possibile utilizzare il metodo encode() specificando il formato, per esempio utf-8
my_bytes = ’ciao_ciao’.encode(‘utf-8’)
my_bytes = ’ciaoèciao ’.encode(‘utf-8’)
• Per trasformare correttamente una sequenza di byte in una stringa utilizzare il metodo decode()
sempre specificando la codifica da utilizzare
print(my_bytes.decode(‘utf-8’)) #-> ciao è ciao
Raspberry Pi – Comunicazione Arduino
Da Byte a String
• Lungo le connessioni della seriale transitano quindi solo byte, per poterli trasmettere e ricevere
correttamente sarà necessario codificarli tramite encode prima dell’invio e poi decodificarli
appena dopo averli ricevuti
decode
Bytes String
encode
Raspberry Pi – Comunicazione Arduino
Scambio messaggi con Arduino
• Proviamo ora a scrivere un messaggio ad Arduino, facciamo un modo che Arduino legga il nostro
messaggio e risponda con lo stesso seguito da «ricevuto». Ovviamente non possiamo utilizzare il
monito seriale dell’IDE altrimenti sarà lui a leggere i dati e non il nostro script python!
Inizializzo una stringa vuota che riceve il messaggio
• CSV è l’acronimo di Comma Separated Values, è infatti un file di testo che utilizza le virgole per
separare i dati all’interno di celle diverse in una tabella
• La prima riga contiene l’intestazione, quindi nel nostro caso sarà:
• Mentre tutte le righe successive conterranno sulla prima colonna il tempo in secondi a cui è
avvenuta la lettura e sulla seconda colonna (separata da una virgola) il valore di millivolt letto
Raspberry Pi – Comunicazione Arduino
Parte Arduino Leggo i segnali sulla porta A0
Scrivo tempo e
tensione nel file
Quando viene premuto ctrl+c csv
chiudo il file e la porta seriale
prima di uscire
Raspberry Pi – Comunicazione Arduino
File voltage_log.csv
Se il programma è stato fatto correttamente, una volta chiuso, nella stessa cartella è possibile
trovare il file voltage_log.csv che, se aperto con un editor di testo ha questa struttura:
Raspberry Pi – Comunicazione Arduino
File voltage_log.csv
La particolarità dei file csv è che possono essere aperti con un foglio di calcolo e quindi utilizzati per
calcoli e grafici (nell’immagine lo stesso file aperto con LibreOffice Calc e con un grafico generato):
Raspberry Pi – Comunicazione Arduino
Funzione millis()
• Finora abbiamo visto come è possibile trasmettere un singolo valore tra due dispositivi. MA se
occorresse tramettere più di un valore come si può fare? Per esempio se devo trasmettere 1 int
(1234) 1 float (23.5) e 1 bool (True)
Dec 49 50 51 52 36 50 51 46 53 36 49
Hex 0x31 0x32 0x33 0x34 0x24 0x32 0x33 0x2e 0x35 0x24 0x31
1 2 3 4 $ 2 3 . 5 $ 1
• Posso poi riottenere i valori che cercavo utilizzando una funzione di split sulla stringa con ‘$’
come separatore
Raspberry Pi – Comunicazione Arduino
2. Posso utilizzare un tipo di serializzazione standard, per esempio JSON
Dec 91 49 50 51 52 44 32 50 51 46 53 44 32 116 114 117 101 93
Hex 0x5b 0x31 0x32 0x33 0x34 0x2c 0x20 0x32 0x33 0x2e 0x35 0x2c 0x20 0x74 0x72 0x75 0x65 0x5d
[ 1 2 3 4 , 2 3 . 5 , t r u e ]
• Questa soluzione è molto più flessibile e il parsing può essere delegato a librerie specializzate.
L’unico lato negativo è che può aumentare il numero di byte trasmessi e il tempo di
codifica/decodifica.
• Posso sapere in anticipo quanti caratteri utilizza ogni numero, il problema è che il limita molto i
valori numerici che posso tramettere
Raspberry Pi – Comunicazione Arduino
• Modificare il programma precedente in modo che siano inviati dati di 2 porte analogiche.
• Le funzioni principali JSON che andranno utilizzate su Arduino:
1. DynamicJsonDocument var(size): crea un oggetto di tipo DynamicJsonDocument che
deve essere utilizzato dalle funzioni della libreria JSON ma di fatto si comporta come un
dizionario Python
2. serializeJson(var, Serial): var deve essere del tipo DynamicJsonDocument e tramite
questa funzione è possibile inviare i dati contenuti nel dizionario sulla seriale
• Le funzioni principali JSON che andranno utilizzate su Raspberry Pi:
1. json.loads(input_string): deserializza la stringa appena ricevuta dalla seriale utilizzando il
formato json e permette di ottenere un dizionario con i dati ricevuti
Raspberry Pi – Comunicazione Arduino
Parte Arduino Aggiungo le definizioni della seconda porta
• Creare un programma che permetta di attivare le porte dalla 2 alla 13 e una minima interfaccia
testuale per comandarlo.
• Le funzioni principali JSON che andranno utilizzate su Arduino:
1. DeserializeJson(var, Serial): è l’opposto di serializeJson quindi permette di riceve i dati
dalla seriale e salvarli nella variabile var di tipo DynamicJsonDocument
2. DeserializationError e: è la variabile che ritorna la funzione DeserializeJson e permette di
controllare se tutto è andato a buon fine, ovvero se e assume il valore
DeserializationError::Ok
• Le funzioni principali JSON che andranno utilizzate su Raspberry Pi:
1. json.dumps([data1,data2…], ): converte i dati in json, questo andrà poi codificato in utf-8
per inviarlo sulla seriale
Raspberry Pi – Comunicazione Arduino
Parte Arduino Creo un elenco di porte valide così evito di fare
dei danni per errore