in Antima for IoT, Tutorial Python

Acquisizione ed elaborazione dati con Arduino – Il modulo antimait.plotting

Dopo aver trattato la libreria matplotlib, ed in particolare il suo modulo pyplot, nel precedente articolo di questa serie, viene naturale volere integrare le funzionalità di generazione di grafici all’interno di applicazioni basate sulla libreria antimait per quanto riguarda gli aspetti di acquisizione di dati dai nostri dispositivi con sensori.

Nonostante sia perfettamente possibile integrare queste due funzionalità sfruttando il meccanismo definito dalle classi DataSource e DataReceiver, il modulo antimait.plotting offre una soluzione già pronta a questo problema, tramite la classe Plotter presente al suo interno.

 Diagramma UML della classe Plotter

Plotter sfrutta le funzionalità di cui si è discusso nell’articolo precedente, semplificando allo stesso tempo il processo di generazione delle immagini tramite l’offerta di strumenti per la pianificazione della generazione, le modalità di salvataggio e la posizione in cui conservare i file.

La firma del costruttore è la seguente:

def __init__(self, session_name: str, frequency_mode: bool = None,
data: Union[List[float], Dict[str, int]] = None,
capacity: int = None, refresh_rate: int = None,
overwrite: bool = None, img_dir: str = None):

dove:

  • session_name è il nome che si può dare a questa sessione di plotting;
  • frequency_mode è un valore booleano, se posto a True, l’oggetto produrrà grafici a barre, andando a rappresentare la frequenza di lettura di un certo dato, adatto in situazioni in cui i dati appartengono ad un certo, piccolo, dominio e si è interessati alla loro frequenza;
  • data è un parametro tramite cui si può inizializzare l’oggetto con dei dati già a disposizione;
  • capacity è un parametro intero tramite cui è possibile impostare la capacità della struttura dati utilizzata dal plotter quando non in modalità a frequenza;
  • refresh_rate è un valore tramite cui è possibile impostare la frequenza di aggiornamento del grafico, comunicando all’oggetto ogni quante istanze di dati in arrivo bisognerà generare una nuova immagine;
  • overwrite è un valore booleano che se settato a False farà sì che ogni immagine prodotta sarà salvata senza sovrascrivere le precedenti, comportamento che di norma viene invece seguito;
  • img_dir è una stringa contente un percorso valido di una cartella in cui salvare le immagini generate, che di default, se non passato, andrà a ricadere sulla directory al momento in uso.

I tre metodi esposti dalla classe sono add tramite cui si possono aggiungere nuove istanze di dati raccolti a quelli attualmente all’interno dell’oggetto, clear che è un semplice wrapper attorno a list.clear() e dict.clear() e plot.

Quest’ultimo utilizza quanto precedentemente introdotto a proposito del modulo matplotlib.pyplot, generando un grafico ogni volta che viene invocato e restituendo un oggetto pathlib.Path contenente il percorso in cui il file è stato salvato ed il suo nome. Al suo interno viene utilizzata la funzione matplotlib.pyplot.clf() per rimuovere ogni grafico precedentemente realizzato e salvato nello stato interno di pyplot (che però non rimuoverà i file salvati); un altro aspetto importante della funzione è la modalità di assegnamento del nome al file salvato: nel caso in cui si sia inizializzato il Plotter con overwrite=False, il nome sarà generato utilizzando un timestamp per diversificarlo da file precedenti.

Come evidente dal diagramma UML riportato qui sopra, Plotter è erede di DataReceiver ed il suo metodo update utilizza le tre funzioni di cui si è appena parlato per generare grafici automaticamente (il comportamento di default della libreria è di generare un nuovo grafico ogni 10 nuovi elementi ricevuti); un esempio di utilizzo, tratto da uno script incluso nella libreria antimait è esposto qui di seguito:

import logging
import antimait
import antimait.plotting

logging.basicConfig(level=logging.INFO)

gw = antimait.Gateway()


def on_connect(interface: antimait.CommInterface, description: str) -> None:
    plotter = antimait.plotting.Plotter(description)
    interface.attach(plotter)


gw.on_connect = on_connect

try:
    gw.listen_forever()
except KeyboardInterrupt:
    gw.close()
 

Come già introdotto nel primo articolo di questa serie, il modello dei programmi scritti utilizzando antimait è sempre simile e semplice: si scelgono una o più classi eredi di DataReceiver da associare alle interfacce gestite dal gateway ed il resto viene gestito direttamente da quest’ultimo all’interno dei suoi loop di attività. In questo caso si potrà osservare come questo semplice programma genererà in automatico dei grafici dei dati ricevuti tramite seriale nella cartella in cui verrà avviato.

Qui di seguito viene riportato l’output generato utilizzando lo stesso sketch incluso nel primo articolo della serie, flashato su un Arduino Mega.

Sperando che questa prima parte della serie vi sia tornata utile, invito ad utilizzare i commenti qui sotto o il modulo contatti per eventuali dubbi e richieste di chiarimenti. I prossimi articoli si sposteranno sulla costruzione di applicazioni e casi d’uso più complessi per la libreria.

Acquisizione ed elaborazione dati con Arduino – Un’applicazione browser based →

Scrivi un commento

Commento