Comunicazione seriale con Arduino e Python
Se mai avete avuto necessità di scambiare dei dati in seriale fra la nostra board Arduino e il noto linguaggio di programmazione, Python. Ecco un esempio che chiarirà molti dubbi.
Inviare e ricevere numeri interi in Seriale
L'invio di interi è forse una delle operazioni basilari più utili e meno trattate in rete. Io stesso ho dovuto perderci un pò di tempo per venire a capo ad alcuni problemi che insorgevano irremediabilmente quando si desidera inviare dei valori interi composti da cifre decimali. Da e verso Arduino.
Per questo esempio ho usato le libreria pyserial di Python 3.4 e la funzione Serial.parseInt() di Arduino.
Nativamente l'installazione di Python non include la libreria pyserial, motivo per cui, bisogna installarla. Per farlo, è sufficiente recarsi (da linea di comando) nella cartella d'installazione di Pyhon, nel mio caso: C:\Python34 e lanciare il comando python -m pip install pyserial. Questo avvierà il download e l'installazione automatica della libreria che ci serve.
Serial.parseInt() invece, è una funzione di arduino per restituire il primo numero intero valido dal buffer seriale. I caratteri che non sono interi vengono ignorati. La funzione viene terminata dal primo carattere che non è un numero.
Dunque passiamo al codice operativo per Arduino, ben commentato:
void setup() {
// apriamo la porta seriale:
Serial.begin(9600);
}
void loop() {
// controlliamo eventuali dati in arrivo sulla seriale:
if (Serial.available() > 0) {
// leggiamo l'intero in arrivo:
int inDigit = Serial.parseInt();
// Spediamo indietro il valore ricevuto:
Serial.write(inDigit);
}
}
E qui invece il codice per Python 3.4, anch'esso commentato:
import serial #Per installare la libreria in python 3.4: C:\Python34>python -m pip install pyserial
import sys
import time
port = "COM5" # porta seriale, se non specificata viene selezionata la prima disponibile
def scan():
"""scan for available ports. return a list of tuples (num, name)"""
available = []
for i in range(256):
try:
s = serial.Serial(i)
available.append( (i, s.portstr))
s.close() # explicit close 'cause of delayed GC in java
except serial.SerialException:
pass
return available
def connessione_seriale(port):
""" funzione per connessione alla porta seriale """
try:
return serial.Serial(port, 9600)
except serial.SerialException:
print("verificatosi ERRORE...")
porte = scan()
if len(porte) or len(port): # porte seriali libere
porta = porte[0][1] # ci connettiamo alla prima porta disponibile
if len(port) > 1:
porta = port # se gia' conoscete la porta e' sempre meglio inserirla manualmente
print("Porta Seriale usata: " + porta)
ser = connessione_seriale(porta)
def invia_num(valore):
if valore.isdigit() and int(valore) in range(0, 101):
# gli sleep qua sotto sono necessari per evitare che arduino vada in reset, passa troppo poco tempo fra la connessione e l'invio del comando in seriale altrimenti
time.sleep(1) # attesa
ser.setDTR(level=0)
time.sleep(1) #tempo di attesa di un secondo dovrebbe essere sufficiente
#cmd = sys.argv[1] # cmd ricevuto da linea di comando
ser.write(bytes(valore, 'UTF-8')) #inviamo il valore in seriale
time.sleep(1)
#ser.write(comando.encode("latin1"))
print("Valore inviato!")
time.sleep(0.5)
#ser.close()
else:
print("Prego inserire un valore intero compreso fra 0 e 100.")
else:
print("Nessun dispositivo seriale connesso oppure porta seriale occupata!")
'''
print("Found ports:")
for n,s in scan():
print("(%d) %s" % (n,s))
'''
if __name__ == "__main__":
inp = ""
while inp != "stop":
if inp == "stop":
break
else:
inp = input()
print("Invio valore: "+inp)
invia_num(inp)
out = b""
while ser.inWaiting() > 0:
out += ser.read(1)
if out != '':
print("risposta: " + str(ord(out.decode('utf-8')))) # la funzione ord() traduce un carattere con il corrispondente numero nella tabella ascii
#print(type(out.decode('utf-8')))
I valori accettati dallo script in python, sono interi compresi fra 0 e 100.
Una precisazione va fatta per quanto riguarda la porta seriale a cui è connesso il nostro arduino. Nel codice è presente una funzione che automaticamente ci connette alla prima porta seriale disponibile, che può non essere quella giusta. Questo perchè per poter effettivamente rilevare a quale porta è connesso arduino, bisognerebbe implementare un protocollo di handshake. Quest'ultimo non è lo scopo di questa guida, quindi tralasciamo e limitatevi a inserire la porta corretta manualmente nel codice Python.
Per qualsiasi dubbio o eventuali miglioramenti, commentate.