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.
Commenti