• Non ci sono risultati.

Le reti di sensori come prodotti di massa: un nuovo paradigma di programmazione e gestione orientato all'usabilita

N/A
N/A
Protected

Academic year: 2021

Condividi "Le reti di sensori come prodotti di massa: un nuovo paradigma di programmazione e gestione orientato all'usabilita"

Copied!
71
0
0

Testo completo

(1)

UNIVERSITÀ DI PISA

Facolta‘ di Scienze, Matematiche, Fisiche e Naturali

Corso di laurea in Informatica

Tesi di Laurea

LE RETI DI SENSORI COME PRODOTTI DI

MASSA: UN NUOVO PARADIGMA DI

PROGRAMMAZIONE E GESTIONE ORIENTATO

ALL’USABILITÀ

Relatore: Candidato:

Dott. Stefano Chessa Saverio Delpriori

Correlatore:

Chiar.mo Prof. Alessandro Bogliolo

(2)

Ai miei genitori, a Giulia

(3)

Indice

1 Introduzione 1

1.1 WSNs e IoT . . . 1

1.2 Usabilità come fattore abilitante . . . 2

1.3 Obiettivi e organizzazione . . . 3

2 Stato dell’arte e concetti di base 5 2.1 Modelli di programmazione delle WSNs . . . 5

2.1.1 Approcci node-level . . . 6

2.1.2 Approcci group-level . . . 7

2.1.3 Approcci network-level . . . 7

2.2 Virtualizzazione . . . 8

2.2.1 Benefici della virtualizzazione . . . 9

2.2.2 Virtualizzazione nelle WSNs . . . 10

2.3 Programmazione visuale . . . 10

2.3.1 Programmazione delle interfacce grafiche . . . 11

2.3.2 Programmazione general purpose . . . 11

2.3.3 Il paradigma Platform as a Service . . . 13

2.4 Dispositivi mobili . . . 13 3 Architettura di riferimento 15 3.1 Ambiente di sviluppo . . . 15 3.1.1 Blockly . . . 15 3.2 Applicazione mobile . . . 19 3.3 Nodo sensore . . . 20

3.3.1 Architettura hardware ultra-low-power . . . 20

3.3.2 Stack software e programmazione dei nodi VirtualSense 21 4 Architettura software 24 4.1 Ambiente di sviluppo . . . 25

4.1.1 Programmazione visuale . . . 25

4.1.2 Generazione dell’applicazione . . . 39

4.2 Applicazione mobile . . . 39

4.2.1 Installazione sul nodo . . . 40 iii

(4)

4.2.2 Controllo del nodo . . . 42 4.3 Nodo sensore . . . 43 5 Caso d’uso 46 5.1 Obiettivo dell’applicazione . . . 46 5.2 Implementazione . . . 47 5.2.1 Sink . . . 47 5.2.2 Node . . . 49 5.3 Installazione . . . 50

5.4 Gestione dalla Companion App . . . 50

6 Conclusioni e sviluppi futuri 53 A Allegato A 55 A.1 Codice sorgente dell’applicazione sink . . . 55

A.2 Codice sorgente dell’applicazione nodo . . . 57

Bibliografia 59

Ringraziamenti 65

(5)

Elenco delle figure

2.1 Classificazione dei paradigmi di programmazione delle WSNs. . 6

3.1 BlocklyDuino, un editor per codice sorgente eseguibile su sistemi Arduino. . . 16

3.2 Il blocco repeat. . . 18

3.3 Un semplice programma VirtualSense. . . 22

3.4 Lo stack software di VirtualSense. . . 23

4.1 La procedura di installazione proposta. . . 25

4.2 I blocchi per la dicharazione e l’inizializzazione delle variabili. . 26

4.3 Il blocco iniziale. . . 27

4.4 Il blocco di definzione di una procedura. . . 27

4.5 Il blocco di invocazione di una procedura. . . 28

4.6 La modifica dei parametri di ingresso di una procedura. . . 28

4.7 I blocchi di definizione e invocazione di una funzione . . . 29

4.8 Schema del comportamento di due thread che gesticono un evento. 30 4.9 Blocco di attesa di un evento. . . 30

4.10 Blocco di trigger di un evento. . . 30

4.11 Blocco di wait di un evento. . . 31

4.12 Blocco di wait di un interrupt. . . 31

4.13 Blocco di when associato ad un interrupt. . . 31

4.14 Blocco di schedulazione di un timer interrupt. . . 32

4.15 Blocchi di lettura dei sensori. . . 32

4.16 Blocco di controllo di un led. . . 33

4.17 Blocco del comando standby. . . 33

4.18 Blocco per la variazione della frequenza della MCU. . . 33

4.19 Blocco della scelta dell’algoritmo di routing della rete. . . 34

4.20 Blocco per l’invio di un messaggio di dati. . . 35

4.21 Blocco per la ricezione di un messaggio di dati e i suoi sottoblocchi. 35 4.22 Blocchi utilizzabili per la gestione della ricezione di messaggi da altri nodi. . . 36

4.23 Blocco per l’invio di un valore alla Companion App. . . 37

4.24 Blocco per la ricezione di un comando dalla Companion App. . 37 v

(6)

4.25 Blocco per la ricezione di un comando dalla Companion App e

per l’invio indietro della risposta. . . 38

4.26 Un’applicazione di esempio composta tramite l’App Maker . . . 39

4.27 La schermata iniziale della Companion App. . . 40

4.28 Le fasi del processo di installazione di un infuso tramite la Companion App. . . 41

4.29 Il protocollo utilizzato fra Companion App e nodo per l’instal-lazione di una nuova applicazione. . . 42

4.30 La schermata di controllo della Companion App. . . 43

5.1 Lo schema di funzionamento dell’applicazione di rete. . . 46

5.2 L’applicazione da installare nel nodo Sink. . . 48

5.3 L’applicazione da installare negli altri nodi. . . 49

5.4 Il QR Code generato dall’App Maker . . . 50

5.5 L’installazione dell’infuso tramite la Companion App. . . 51

5.6 La fase di connessione della Companion App al nodo. . . 51

5.7 L’invio del comando GET_AVG_LIGHT al nodo. . . 52

5.8 Il risultato restituito alla Companion App dal nodo. . . 52

(7)

Capitolo 1

Introduzione

1.1

WSNs e IoT

Il termine Internet of Things (IoTs) si riferisce a quell’insieme di dispositivi tecnologici come smartphone, smartTV, wearable, sensori e attuatori che grazie alla loro capacità di connettersi direttamente o indirettamente alla rete globale rendono possibili diverse forme di comunicazione fra oggetti e persone o, sempre più spesso, fra oggetti e altri oggetti anche diversi fra loro. Già nel 2008 il numero di utenti connessi alla rete veniva sorpassato da quello dei dispositivi [1] e possiamo affermare – con buona approssimazione – che oggi è sempre possibile connettere i propri dispositivi indipendentemente dal luogo e dalle condizioni in cui essi si trovano.

Nei 15 anni trascorsi dalla sua introduzione [2] il concetto di IoTs ha con-tinuato ad espandersi e mutare tanto che oggi tecnologie come RFID, comuni-cazioni wireless a corto raggio e a bassissimo consumo, localizzazione in tem-po reale, ad hoc e wireless sensor networks (WSNs) ne costituiscono le parti fondamentali. Proprio le WSNs sono uno degli elementi più importanti nel paradigma dell’IoTs.

Le WSNs sono reti wireless costituite da nodi distribuiti spazialmente, equi-paggiati con una CPU, dei sistemi di comunicazione a basso consumo e uno o più sensori tramite i quali riescono a monitorare l’ambiente in cui vengono immersi. I nodi possono essere in grado di misurare grandezze fisiche come temperatura, luminosità, umidità, pressione; particolari condizioni ambientali come il livello di inquinamento, l’affollamento dei locali pubblici, il verificarsi di incendi ecc. Una volta che ha acquisito uno o più dati, ogni nodo è in gra-do di comunicare le informazioni ai propri vicini [3]. Nonostante la potenza di calcolo sia in genere molto limitata per contenere il consumo energetico, sempre più frequentemente è possibile fare delle elaborazioni dei dati raccolti direttamente a bordo dei sensori prima di diffonderli agli altri nodi della rete. In breve, lo scopo delle WSNs è quello di rilevare dati e di fornirli agli utenti. Originariamente le reti di sensori erano pensate per applicazioni militari [4]

(8)

2 1.2 Usabilità come fattore abilitante

mentre oggi le WSNs sono utilizzate in numerosi contesti civili ed industriali. Le applicazioni sono molteplici ed eterogenee fra loro, vanno dal controllo dei processi produttivi al health-care, dal monitoraggio del consumo energetico al controllo del traffico [5]. Non mancano neppure gli utilizzi in abitazioni private come sistemi di monitoraggio della temperatura, controllo dell’illuminazione, rilevamento di gas e altro [6].

Gli importanti progressi fatti nell’ambito della ricerca e l’utilizzo ubiquo delle WSNs hanno portato ad un’ottimizzazione dei protocolli di comunicazio-ne, delle architetture hardware/software e degli algoritmi di routing in questo campo. Non si è verificato un avanzamento della stessa misura per i paradigmi di sviluppo software sui nodi sensore. La programmazione dei nodi di una rete di sensori è tuttora un compito adatto solo a chi ha competenze specifiche quali la programmazione di basso livello e spesso, una conoscenza approfondita dell’hardware utilizzato nei nodi.

1.2

Usabilità come fattore abilitante

Le WSNs non sono l’unico campo applicativo in cui la mancanza di cono-scenze prettamente tecniche, non strettamente legate al dominio applicativo in esame, può ostacolare il processo di ricerca e sviluppo nel campo stesso. La difficoltà di coniugare in una stessa figura, o in uno stesso gruppo, domain expert e software expert è un problema che affligge anche maggiormente altri campi della ricerca in cui i profili delle due figure sono ancora più distanti. Pensiamo ad un sociologo che affronti una ricerca per la quale sia necessa-rio sviluppare un simulatore ad agenti che simuli il comportamento di diversi gruppi sociali1, con tutta probabilità si dovrà rivolgere ad un esperto in svi-luppo di sistemi multi-agente e, tramite quest’ultimo, potrà provare a tradurre le specifiche esigenze del proprio campo applicativo nel contesto dell’esperto di software. Questo è solo un esempio di un processo che spesso richiede svariate iterazioni di approssimazione fra i due domini. Nel caso delle WSNs, la scarsa attenzione all’usabilità ne limita il campo di applicazione e il mercato, impe-dendo il raggiungimento di quelle economie di scala che potrebbero concorrere al raggiungimento del punto di breakeven in un larghissimo insieme di contesti applicativi.

Ultimamente sono stati sviluppati degli strumenti che consentono la pro-grammazione tramite la manipolazione grafica degli elementi e non tramite sintassi scritta. Sebbene alcuni siano più efficaci di altri nei diversi contesti di applicazione, questi strumenti, detti di programmazione visuale, consentono anche a chi non ha particolari conoscenze informatiche di implementare algorit-mi, anche complessi, in modo relativamente semplice. La particolarità di questi strumenti è che riescono ad incapsulare la complessità del processo di sviluppo

1

TODO: mettere un riferimento al libro Scelta razionale e sociologia del crimine. Un approccio critico e un modello di simulazione ad agenti?

(9)

1.3 Obiettivi e organizzazione 3

software in modo tale che concetti ostici da interiorizzare come i formalismi e le regole grammaticali di un linguaggio di programmazione, non debbano essere preventivamente noti dal loro utilizzatore. Spesso non è solamente la scrittura del codice ad essere semplificata, Software come MIT App Inventor2 permettono di portare a termine tutto il processo di sviluppo software fino ad ottenere un programma – nel caso specifico un’applicazione per dispositivi mobili Android – distribuibile anche a parti terze, senza avere conoscenze spe-cifiche riguardo alla programmazione sulla piattaforma di destinazione. Cade anche la necessità di configurare e installare l’ambiente di sviluppo poiché MIT App Inventor segue il paradigma SaaS (Software as a Service) ed è utilizzabile direttamente dal browser.

Questi strumenti di programmazione visuale si sono rivelati utili per col-mare la distanza fra il dominio applicativo di un software e la sua specifica tec-nica [7], la ricerca scientifica non è però l’unico contesto in cui possono trovare un’applicazione pratica. È stato infatti dimostrato [8] come la caratteristica di mascherare la complessità del processo di sviluppo dietro ad un’interfaccia pensata per essere usata senza delle conoscenze pregresse di programmazio-ne, o quasi, sia utilizzabile anche in ambito didattico pre-universitaro, non solo nell’ambito specifico della programmazione software ma in generale per lo sviluppo delle capacità di Computational Thinking [9].

1.3

Obiettivi e organizzazione

Lo scopo di questa tesi è quello di progettare e realizzare un sistema software che permetta la programmazione dei nodi di una WSN anche a chi ha poche o nessuna conoscenza di programmazione di sistemi embedded.

Nell’ambito del lavoro verranno sfruttate tecnologie di programmazione visuale, programmazione mobile su sistemi Android ed embedded, al fine di creare un sistema che permetta la massima semplificazione del procedimento di sviluppo e installazione di applicazioni per nodi sensore VirtualSense [10]. L’architettura hardware e software di questi nodi si adatta in modo ottimale al nostro scopo e verrà trattata estensivamente più avanti.

Per far sì che l’usabilità del sistema sia tale da essere abilitante anche per chi non ha tutte le conoscenze necessarie per effettuare le stesse operazioni tra-mite gli strumenti di programmazione tradizionali, verranno impiegati diversi paradigmi: l’utilizzo di una sintassi e una grammatica intuitive tramite la pro-grammazione visuale, la realizzazione di un ambiente di sviluppo disponibile in cloud senza ulteriori configurazioni necessarie e, infine, la messa a disposizio-ne di una Companion App che tramite un’interfaccia multitouch permetta la gestione e la programmazione OTA (Over the air ), a caldo, delle applicazioni nei nodi VirtualSense.

(10)

4 1.3 Obiettivi e organizzazione

La restante parte di questo lavoro si suddivide nel seguente modo: nel capi-tolo 2 verranno introdotti i concetti di base, fondamentali per la comprensione di quanto sviluppato in seguito; nel terzo capitolo verrà introdotta l’architet-tura di riferimento dei vari componenti software e hardware utilizzati per lo sviluppo, mentre nel quarto capitolo verrà spiegata l’architettura del software sviluppato. Nel capitolo 5 si tratteranno dei casi esemplificativi di applicazione del sistema e nell’ultimo capitolo verranno presentate le conclusioni e suggeriti i possibili sviluppi futuri.

(11)

Capitolo 2

Stato dell’arte e concetti di base

2.1

Modelli di programmazione delle WSNs

Negli ultimi anni c’è stato un grande interesse verso le WSNs, sia in ambi-to scientifico che commerciale. Questa grande attenzione si è tradotta nello sviluppo di un altrettanto grande quantità di prodotti diversi fra loro che, al tempo stesso, hanno componenti di base dalle caratteristiche molto simili fra loro. Questo non è poi molto sorprendente dal momento che la prerogativa generale dei nodi di una WSN è quella di dover sottostare a vincoli energetici, vincoli sulle performance, di scalabilità e di resistenza ai guasti spesso molto stringenti.

Molte piattaforme montano microcontrollori a 8/16 bit, i più comuni sono il Texas Instruments MSP430 o i chip della famiglia Atmel ATMega. Grazie ai progressi nella riduzione del consumo energetico delle CPU, recentemente vengono utilizzati anche controllori a 32 bit. Molti nodi hanno una quantità di RAM che non supera, e quasi mai raggiunge, i 512 KB mentre la memoria non volatile dedicata al codice binario da eseguire va dai 32 KB ai 128 KB. Lo spazio di memorizzazione su disco è spesso non necessario dato il carattere particolare delle applicazioni a cui le WSNs sono dedicate ma, quando è pre-sente, può arrivare anche a diversi gigabyte. La maggioranza delle piattaforme ha un hardware che permette di sfruttare la banda di comunicazione dei 2.4 GHz ISM, con supporto allo standard IEEE 802.15.4. I sensori e gli attuatori costituiscono un discorso a parte in quanto dipendono strettamente dallo scopo della particolare WSN [11].

I sistemi operativi utilizzati nei nodi delle WSNs sono ben distanti da quelli utilizzati nei comuni sistemi desktop. Essi mettono a disposizione funzionalità piuttosto elementari e, a volte, consistono in vere e proprie librerie che ven-gono collegate alle applicazioni per far sì che queste possano essere eseguite sull’hardware sottostante. Ciononostante la necessità di trovare il modo mi-gliore per programmare e configurare un sistema complesso come le WSNs ha

(12)

6 2.1 Modelli di programmazione delle WSNs

portato nel tempo ad una vera e propria proliferazione dei paradigmi di svi-luppo. Nel classificare questi paradigmi ci baseremo sull’estensiva analisi fatta da Sugihara et al [13].

Figura 2.1: Classificazione dei paradigmi di programmazione delle WSNs. Come mostrato in figura 2.1, i paradigmi di programmazione delle WSNs possono essere classificati con diverse granularità. Una prima divisione è quella fra approcci di basso livello o node-level, focalizzati su un’astrazione dell’hard-ware in grado di garantire una buona flessibilità nella programmazione del comportamento dei nodi, e approcci di alto livello, che adottano un punto di vista incentrato sul compito che l’intera rete di sensori deve svolgere. Questi ultimi possono essere divisi a loro volta in group-level e network-level.

2.1.1 Approcci node-level

Il più famoso sistema operativo dedicato alle WSNs, che è stato considerato lo standard de facto per alcuni anni, è sicuramente TinyOS [12]. Programmabili in nesC – un dialetto del C – le applicazioni sviluppate per TinyOS seguono un paradigma event-driven e sono composte da routine di gestione degli eventi che possono registrare dei task, i quali verranno poi schedulati dal sistema opera-tivo. L’approccio di TinyOS è estremamente flessibile e permette di calibrare esplicitamente ogni parametro, per contro, il livello di astrazione è talmente basso che scrivere anche un semplice programma può risultare ostico.

A partire da TinyOs sono stati proposti diversi modelli. Alcuni tentano di superare la complessità fornendo primitive di message-passing asincrono come TinyGALS [14], SOS [15] e CoMOS [16]; altri forniscono primitive più astratte sfruttando la stratificazione dei livelli software e definendo nuovi linguaggi di programmazione, alcuni esempi sono SNACK [17] e T2[18].

(13)

2.1 Modelli di programmazione delle WSNs 7

In contrapposizione con il paradigma event-driven sono state sviluppate soluzioni basate sul modello a thread che, a fronte di una richiesta di risorse maggiore, permettono di semplificare la programmazione dando la possibilità di sfruttare più contesti di esecuzione in parallelo. Alcuni esempi di questo ultimo approccio sono Mantis OS [19] e Fiber [20] oltre a Protothreads [21] una libreria per il multithreading utilizzabile su Contiki [22]. Quest’ultimo è un sistema operativo le cui applicazioni sono facilmente programmabili in C. Contiki ha alcune caratteristiche interessanti fra le quali proprio l’utilizzo dei protothread, thread adatti all’uso su sistemi con severe limitazioni in termini di memoria, che non impiegano l’uso dello stack. Proprio Contiki è alla base dello stack software implementato dai nodi VirtualSense.

2.1.2 Approcci group-level

Gli approcci group-level forniscono linguaggi di programmazione i cui costrutti permettono di gestire gruppi di nodi e di definirne agevolmente il comporta-mento. Questi approcci possono essere ulteriormente divisi in base al crite-rio seguito per definire i gruppi. Paradigmi che definiscono gruppi basati sul concetto di vicinanza fisica fra i nodi sono detti neighborhood-based e sfrutta-no la natura intrinsecamente broadcast delle comunicazioni wireless. Alcuni espongono primitive per gestire gruppi di nodi considerati vicini in base al-la topologia delal-la rete o geograficamente (AbstractRegions[23]), mentre altri considerano vicini due nodi che possono comunicare direttamente fra di loro (Hood [24]). Un altro modo di definire quali nodi di una rete possono essere raggruppati è quello di mettere nello stesso insieme nodi con caratteristiche si-mili, non necessariamente vicini tra loro. Questo approccio, detto logic-based, è ad un gradino di astrazione più in alto del precedente poiché la caratteristica in base alla quale i nodi vengono scelti può essere fisica o definita dinamica-mente. Ad esempio un gruppo di nodi può essere raggruppato in base alle loro proprietà hardware o in base agli input che ricevono in un dato momento dall’esterno. Soluzioni basate su questo tipo di divisione sono EnviroTrack[25] e il linguaggio SPIDEY [26].

2.1.3 Approcci network-level

Considerare l’intera rete come una singola entità è il livello di astrazione alla base degli approcci network-level, identificati anche col termine macroprogram-ming [13]. Esistono modelli in cui le WSNs vengono considerate come astra-zioni di una sorgente di dati organizzata o, più correttamente un database. TinyDB [27] ad esempio, permette all’utente di specificare query in un lin-guaggio dichiarativo SQL-like. Un’interfaccia simile è fornita da SINA [28] che però permette anche di specificare task in un linguaggio imperativo. Un altro approccio è quello proposto da MaD-WiSe [29] che diversamente da TinyDB, offre la possibilità di effettuare operazioni di join temporale direttamente nei

(14)

8 2.2 Virtualizzazione

sensori e prevede diversi meccanismi di ottimizzazione delle query. Altre solu-zioni, come MiLAN [30], danno la possibilità di dichiarare query specificando i parametri di QoS (Quality of Service).

Questo tipo di astrazione tuttavia, si rivela troppo di alto livello per poter efficacemente esprimere il comportamento adatto ad ogni possibile applicazio-ne di una WSN. Esiste un’altra classe di paradigmi che, pur considerando la rete come un’unica entità, permettono di specificare il comportamento di ogni nodo e la gestione di ogni dato interno alla rete, mantenendo un’astrazione tale da sollevare l’utente dal compito di preoccuparsi dei dettagli della comu-nicazione fra le entità coinvolte. Ricadono in questa categoria il linguaggio funzionale Regiment [31], il modello di programmazione Spatial Programming e l’interessante Semantic Streams [32]. Quest’ultimo, implementato in Prolog, sfrutta regole di inferenza per interpretare semanticamente eventi complessi come “Temperatura oltre la soglia”.

Il numero e l’eterogeneità degli approcci presentati lascia intuire quanto il problema della gestione e programmazione delle WSNs sia sentito nella comu-nità scientifica. La necessità di progettare delle WSNs che siano utilizzabili direttamente da application-expert e non solo da programmatori è manifestata chiaramente anche in contributi recenti [33][34].

2.2

Virtualizzazione

Una definizione sufficientemente generale di virtualizzazione è quella data da Singh et al. [35]: “Virtualization is a framework or methodology of dividing the resources of a computer into multiple execution environments, by applying one or more concepts or technologies such as hardware and software partitio-ning, time-sharing, partial or complete machine simulation, emulation, quality of service, and many others.”1. Esistono molte applicazioni possibili della vir-tualizzazione e, sebbene una classificazione estensiva sia aldilà dello scopo di questo lavoro, ne descriviamo brevemente alcune fra le più conosciute.

Per virtualizzazione hardware o platform virtualization si intende la crea-zione di una macchina virtuale capace di comportarsi nei confronti con un sistema operativo, esattamente come una macchina reale. Il software che viene eseguito in questa macchina (guest ) è isolato dalle risorse hardware vere e pro-prie della macchina sottostante (host ). A seconda della modalità di astrazione dei componenti fisici la virtualizzazione hardware è classificabile ulteriormente in full virtualization, partial virtualization o paravirtualization.

1

“La virtualizzazione è un framework o una metodologia per la divisione delle risorse di un computer in molteplici contesti di esecuzione. Questa divisione è operata applicando uno o più concetti o tecnologie come il partizionamento dell’hardware e del software, il time-sharing, la simulazione parziale o completa della macchina host, l’emulazione, la qualità del servizio ecc.”

(15)

2.2 Virtualizzazione 9

Un altro tipo di virtualizzazione è la desktop virtualization che ha lo scopo di replicare i benefici ottenibili con il disaccoppiamento dell’ambiente operativo dell’utente, dalle risorse di elaborazione della macchina fisica (il desktop o il notebook dell’utente). L’approccio che ne deriva è quello client-server, in cui uno o più server centrali, non necessariamente remoti, elaborano le informazioni mentre il client si occupa esclusivamente di gestire l’input/output da e verso l’utente.

Altri modelli da menzionare sono la virtualizzazione del database, della rete e delle applicazioni. Quest’ultima consiste nell’isolare il contesto di esecuzione di un’applicazione dal sistema operativo sottostante, un approccio utilizzato in situazioni anche molto diverse tra loro. Degli esempi sono l’implementazione per applicazioni desktop del recente Microsoft Application Virtualization [36] e quella per nodi di WSNs che vedremo nello stack software di VirtualSense.

2.2.1 Benefici della virtualizzazione

Astraendo dalle sue varie declinazioni possiamo elencare, semplificando, al-cuni benefici che l’utilizzo della virtualizzazione comporta in una generica architettura software [37]:

• Isolamento

Un contesto isolato di esecuzione garantisce che il software non si debba preoccupare di quanto accade all’esterno della sua macchina virtuale, a qualsiasi livello di astrazione.

• Contenimento degli errori

Da un punto di vista invertito rispetto al punto precedente, se all’interno di una macchina virtuale si verifica un errore, anche grave, questo non si propaga ai livelli inferiori rispetto a quello di virtualizzazione.

• Mascheramento della complessità dei sistemi

La separazione dei contesti di esecuzione permette di astrarre anche en-tità molto complesse come un database distribuito o una rete di host strutturata su più livelli.

• Ottimizzazione delle risorse

Il sistema host può implementare politiche di risparmio energetico e di accesso intelligente alle risorse hardware.

• Ripristino e migrazione dei contesti

Possono essere fatte delle istantanee dello stato di un contesto di esecu-zione: questo ne permette il ripristino in seguito ad un problema nonché lo spostamento su una diversa macchina virtuale, senza che il software che esegue all’interno si accorga del cambiamento.

• Portabilità delle applicazioni

(16)

10 2.3 Programmazione visuale

uno stesso software può essere eseguito su sistemi diversi, altrimenti incompatibili fra loro.

Per contro, quasi tutti i paradigmi di virtualizzazione hanno requisiti hard-ware non banali.

2.2.2 Virtualizzazione nelle WSNs

Solo ultimamente i nodi delle WSNs sono diventati in grado di sostenere gli elevati carichi computazionali necessari ad un ambiente di virtualizzazione. Processori come l’MSP430 hanno specifiche hardware tali [38] da assicurare una velocità di esecuzione accettabile con un consumo energetico molto conte-nuto [39]. Sul fronte software ci sono stati diversi tentativi di sviluppare una VM (Virtual Machine) che fornisse primitive di alto livello, tipicamente dispo-nibili su sistemi con una potenza di calcolo elevata, e che fosse eseguibile con l’hardware tipico dei nodi di una WSN. Un buon risultato è stato raggiunto con Darjeeling [40], un sistema che, accanto ad un runtime efficiente, utilizza degli strumenti di ottimizzazione offline come il post compilatore, chiamato Infuser, che ottimizza il codice creando dei moduli caricabili a run-time dalla macchina virtuale. Darjeeling implementa una versione modificata delle Ja-va Virtual Machine che supporta il multithreading ed è progettata per essere eseguita sui nodi di una WSN. Funzionalità di alto livello come la garbage col-lection, l’ereditarietà e il supporto ai thread sono garantite pur mantenendo l’uso di memoria al minimo. Approcci simili a quello di Darjeeling sono Ma-té [41] e ASVM [42], entrambi implementano delle VM eseguibili su TinyOS. Tutti gli esempi citati hanno in comune una forte ottimizzazione del runtime e del codice generato, senza la quale sarebbero difficilmente compatibili con le caratteristiche di un tipico nodo di una WSN.

L’utilizzo di una VM nei nodi di una WSN implica alcune caratteristiche interessanti quali la possibilità di programmare a caldo i nodi, generando al bisogno nuovi contesti di virtualizzazione; la diminuzione della dimensione del codice delle applicazioni, importante in contesti in cui la banda di trasmissione è spesso limitata; l’astrazione dalla piattaforma di base non sempre la stessa in tutti i nodi di un’unica WSN.

2.3

Programmazione visuale

Il concetto di programmazione visuale è stato già introdotto in 1.2, provere-mo ora ad approfondire la trattazione presentando brevemente le caratteri-stiche peculiari e tentando di categorizzare le varie applicazioni che seguono quest’approccio.

La prima considerazione da fare è quella che la programmazione visua-le non è un approccio molto recente. La programmazione non è in generavisua-le un’attività percepita come semplice da chi ci si accosta per la prima volta e

(17)

2.3 Programmazione visuale 11

cercare approcci che riescano in qualche modo a moderare tale complessità è stata una scelta necessaria. Con lo sviluppo e l’aumento dell’espressività dei linguaggi orientati alla produzione di contenuti web è stato possibile produrre degli strumenti adatti a mascherare il processo di produzione di un software con un’interfaccia amichevole e semplice da utilizzare.

2.3.1 Programmazione delle interfacce grafiche

I primi software maturi dal punto di vista funzionale che permettevano agli utenti di scrivere codice interfacciandosi solamente con astrazioni grafiche, sen-za dover intervenire successivamente sul sorgente prodotto, erano dedicati alla programmazione di layout grafici. Gli strumenti di sviluppo software dotati di interfaccia grafica integrano da molto tempo editor visuali che permettono ai programmatori di avere un’anteprima dell’aspetto finale delle proprie applica-zioni. Più recentemente hanno preso piede approcci di programmazione volti a separare la logica applicativa dall’interfaccia grafica del software. Questa divisione è spesso ottenuta lasciando al programmatore la libertà di specificare il comportamento logico dell’applicazione tramite un linguaggio di program-mazione general purpose e obbligandolo a definire l’interfaccia grafica tramite linguaggi XML-based. Dal momento che gli elementi grafici contenuti in un layout e il linguaggio XML godono entrambi della proprietà di composiziona-lità [43] è facile progettare un software che permetta di tradurre un dominio nell’altro. Un esempio recente è dato dai vari IDE (Integrated Development Environment ) messi a disposizione per creare app per dispositivi mobili: Xco-de2, AndroidStudio3 e VisualStudio4, mettono tutti a disposizione un editor visuale WYSIWYG (What You See Is What You Get ) per la creazione dei layout delle applicazioni.

2.3.2 Programmazione general purpose

Sebbene l’uso della programmazione visuale sia ormai consolidato per la defi-nizione di layout grafici, lo stesso approccio è meno popolare quando si tratta di programmazione general purpose. In particolare, quando si tratta di scri-vere algoritmi o definire i comportamenti di un’entità software, esistono pochi editor grafici che costituiscano una valida alternativa alla scrittura diretta del codice sorgente.

Possiamo trovare alcune caratteristiche comuni a molti sistemi che per-mettono di scrivere codice general purose seguendo il paradigma della pro-grammazione visuale. La quasi totalità dei sistemi è basata su HTML, CSS e JavaScript, una suite suffientemente espressiva, flessibile e che permette una

2https://developer.apple.com/xcode/ 3

https://developer.android.com/sdk/installing/studio.html

(18)

12 2.3 Programmazione visuale

certa coerenza su piattaforme diverse. Molte delle soluzioni sono pacchettiz-zate come WebApp, disponibili in cloud secondo il modello di distribuzione SaaS, e sfruttano la semplicità del drag&drop per rendere l’interfaccia di pro-grammazione il più intuitiva possibile. Spesso le soluzioni proposte presentano limitazioni anche importanti che inficiano fortemente la validità dell’approccio in contesti professionali.

Un’analisi esaustiva dei software di programmazione visuale va ben aldilà degli scopi di questo lavoro, ciononostante è possibile tentare una classifica-zione basata sullo scopo a cui questi software sono destinati. Molti sistemi rientrano nella classe dei software didattici, il cui obiettivo principale è quello di introdurre ai concetti base della programmazione, della geometria, della ma-tematica o di altre scienze. Il software prodotto tramite questi strumenti non ha una finalità particolare ma è funzionale all’educazione dell’utente. L’esem-pio più celebre è sicuramente XLogo, un tool di programmazione visuale basato su LOGO, un linguaggio di programmazione pensato per la didattica della geo-metria di base [44]. Un altro esempio molto conosciuto è Scratch5, un ambiente di programmazione didattica sviluppato dal MIT (Massachusetts Institute of Technology) nel 2006 con un approccio orientato agli oggetti (denominati Spri-tes). Scratch consente di elaborare storie interattive, giochi, animazioni, arte e musica. Inoltre permette di condividere i progetti fra gli utenti.

L’altra grande classe di ambienti di programmazione visuale è costituita da quei sistemi il cui scopo finale è la vera e propria produzione di un software. Questo insieme può essere a sua volta suddiviso in sistemi per la produzio-ne di programmi ad uso prevalentemente privato e sistemi che permettono di realizzare prodotti sufficientemente completi da poter essere distribuiti a terzi. Nella prima sottocategoria rientrano Pocket Code6 e Automator7 mentre l’e-sempio migliore di sistema di programmazione visuale in grado di fornire tutte le funzionalità necessarie alla produzione di un software distribuibile è MIT App Inventor. Quest’ultimo è una WebApp che permette anche ad utenti non esperti di programmazione di creare applicazioni Android complete. MIT App Inventor è al tempo stesso talmente semplice da usare da essere adatto ai novi-zi della programmanovi-zione e sufficientemente flessibile da essere spesso indicato come alternativa agli IDE ufficiali della piattaforma.

Molte delle soluzioni elencate si basano su un’interfaccia a blocchi imple-mentata grazie ad una libreria open-source sviluppata da Google, chiamata Blockly8. La stessa libreria verrà utilizzata per fornire un’astrazione grafica

intuitiva alle primitive di programmazione embedded fornite dalla piattaforma VirtualSense. 5 http://scratch.mit.edu/ 6https://pocketcode.org/ 7 http://www.automator.us/leopard/index.html 8https://code.google.com/p/blockly/

(19)

2.4 Dispositivi mobili 13

2.3.3 Il paradigma Platform as a Service

Come molti dei sistemi appena descritti, l’ambiente di programmazione che si vuole realizzare in questo lavoro rientra fra i sistemi identificati come PaaS (Platform as a Service). I sistemi PaaS sono generalmente web app che forni-scono una piattaforma le cui funzionalità coprono tutti i passaggi dello sviluppo di un particolare tipo di applicazione. L’utente che ne usufruisce, generalmen-te, cerca un ambiente di programmazione facile da utilizzare e che gli eviti il costo e la complessità di dover gestire tutti gli strumenti hardware/software necessari allo sviluppo. La piattaforma può essere completamente online o essere integrata da un software installabile su un normale sistema desktop o, più frequentemente, su un dispositivo mobile. Spesso i sistemi PaaS sfruttano i vantaggi di un’architettura distribuita per dare la possibilità di lavorare in gruppo sullo stesso progetto [48].

Un tale strumento non è utilizzabile solamente dai programmatori e per-mette anche a chi non è esperto di sviluppo software di contribuire signifi-cativamente alla realizzazione del prodotto finale, in tutte le fasi del lavoro. Uno dei vantaggi principali nell’utilizzo di queste piattaforme è che l’impie-go di linguaggi di specifica ad alto livello permette ad un domain-expert di definire direttamente le funzionalità richieste. Inoltre, essendo fornito come un sistema completo, l’ambiente messo a disposizione maschera al suo uti-lizzatore la complessità della gestione, dell’aggiornamento, dell’integrazione e dell’ottimizzazione dei vari tool che lo compongono.

La semplicità di utilizzo spesso implica una minore flessibilità, infatti il fornitore del servizio è obbligato a fare delle scelte riguardo alla piattaforma che mette a disposizione. L’utente dovrà sottostare a tali scelte se vuole utilizzare quel particolare servizio [49].

Citiamo a titolo di esempio, e senza pretesa di completezza, alcuni fornitori di servizi PaaS: Google App Engine9, Microsoft Windows Azure10 e MIT App Inventor.

2.4

Dispositivi mobili

I dispositivi mobili sono presenti da moltissimo tempo nella vita di tutti i giorni ma solo dal 2007 [45] questa presenza è diventata talmente importante da influenzare anche ambiti ben al di fuori della sfera tecnologica. Questo cambiamento è stato possibile grazie all’introduzione di nuove e più efficaci modalità di utilizzo. L’avvento degli smartphone di ultima generazione ha introdotto dei paradigmi di fruizione che hanno avvicinato alla tecnologia anche persone prima completamente disinteressate. Potremmo pensare che la ragione di un tale successo sia che gli smartphone sono stati la soluzione di un problema

9

https://cloud.google.com/appengine/

(20)

14 2.4 Dispositivi mobili

già presente e diffuso ma un’analisi più attenta rivela come gli utenti abbiano iniziato ad utilizzare in massa queste tecnologie in gran parte perché era per loro facile farlo.

L’introduzione di un’interfaccia touch finalmente usabile, il mascheramento della complessità interna del sistema e il paradigma di installazione delle app – come vengono comunemente chiamate le applicazioni sviluppate per i sistemi operativi degli smartphone – standardizzato dagli app store11sono state alcune delle ragioni che hanno portato ad un grande consenso da parte dei consumatori [46]. In particolare, per quanto riguarda il procedimento di installazione di un software, la differenza con i sistemi desktop a cui si era abituati è evidente. Da una parte bisogna cercare l’applicazione in rete, scaricarla (o acquistarla su un supporto fisico), passare attraverso tutti i passaggi del tool di installazione e poi, finalmente, iniziare ad utilizzarla; lo stesso procedimento nell’ambito mobile si traduce in cercare l’app tramite una semplice ricerca testuale nell’app store e decidere se installarla o meno, da qui in avanti è il sistema ad occuparsi di tutto.

Volendo rendere il procedimento di installazione di una nuova app sulla piattaforma VirtualSense il più semplice e intuitivo possibile, cercheremo di trarre vantaggio dall’esperienza avuta con i sistemi mobili sfruttando lo stesso paradigma degli app store.

11

Sebbene il nome AppStore sia un copyright registrato dalla Apple inc. nel testo ci si riferirà all’AppStore (iOS), a Google Play (Android), al Windows Store (Windows Phone) e agli altri sistemi cloud di distribuzione delle applicazioni mobili indicandoli genericamente come app store.

(21)

Capitolo 3

Architettura di riferimento

3.1

Ambiente di sviluppo

Il sistema di sviluppo al centro di questo lavoro si compone di varie parti. Alcune di queste coinvolgono la realizzazione di una serie di servizi cloud che permettono anche ad un utente non esperto nel campo della programmazione embedded, di ottenere semplicemente l’eseguibile da installare sui nodi Vir-tualSense appena descritti. Si andranno ora ad analizzare i framework e le piattaforme tramite le quali l’ambiente di sviluppo PaaS in oggetto è stato implementato.

3.1.1 Blockly

Volendo creare un ambiente per la programmazione di sensori che sia usabile e accessibile anche a chi non ha molta esperienza con lo sviluppo software, si deve porre una particolare attenzione nella scelta dell’interfaccia di programmazione con cui l’utente dovrà lavorare. Costringere un non esperto a dover scrivere direttamente il codice da eseguire, non sembra essere una strada percorribile senza che venga fortemente inficiata la semplicità del processo di sviluppo.

In questo progetto ci si è orientati su una libreria utilizzata per fornire un’interfaccia di programmazione il più semplificata possibile. Seguendo l’e-sempio di progetti di successo e identificando la programmazione visuale come uno strumento utile allo scopo[50], si è scelto di utilizzare Blockly.

Blockly è un web editor per la programmazione visuale. È scritto in JavaScript e reso disponibile con licenza open-source.

Blockly implementa un efficace sistema di drag&drop di blocchi, in cui ogni blocco rappresenta un’espressione nel linguaggio di programmazione scelto. L’utente “scrive” il codice sorgente del programma semplicemente spostando e assemblando i blocchi sullo stage. Man mano che il programma viene composto, i blocchi vengono tradotti in codice sorgente vero e proprio. I linguaggi che Blockly supporta nativamente sono JavaScript e Python; entrambi si adattano bene alla struttura dell’applicazione ma è possibile modificare il sorgente di

(22)

16 3.1 Ambiente di sviluppo

Figura 3.1: BlocklyDuino, un editor per codice sorgente eseguibile su sistemi Arduino.

Blockly in modo da rendere possibile la programmazione in linguaggi diversi, come Java o un dialetto del C. In figura 3.1 è possibile vedere una versione modificata di Blockly che permette di scrivere codice per sistemi Arduino1.

Blockly è un framework che permette di specificare diversi generator, ovve-ro moduli che si occupano di tradurre i blocchi nella sintassi di un linguaggio di programmazione. Si può indicare una nuova traduzione per i blocchi messi a di-sposizione nativamente, come quelli rappresentanti le operazioni matematiche, gli operatori logici e gli operatori di controllo, oppure definire nuovi blocchi.

La definizione di un blocco ex novo consta di due fasi principali: la definizio-ne della grafica e la specifica della traduziodefinizio-ne in codice. Oltre a queste, per ogni blocco creato è necessario inserire un elemento HTML nel file template.soy e lanciare lo script build.py che si occupa di processare i sorgenti e di crearne la versione minified2.

Vediamo ora più in dettaglio le due fasi principali.

1

http://www.arduino.cc/

2Per una definizione più completa del procedimento di personalizzazione di

Blockly si consiglia la consultazione del wiki ufficiale raggiungibile all’indirizzo: https://code.google.com/p/blockly/wiki/DefiningBlocks

(23)

3.1 Ambiente di sviluppo 17

Definizione della grafica

L’aspetto grafico di un blocco non ha soltanto un valore estetico. La struttu-ra, la forma e persino il colore dei blocchi assumono per l’utente che li deve comporre, un valore intrinsecamente semantico. Le regole di un linguaggio di programmazione, i suoi formalismi sintattici e semantici vengo incapsulati e tradotti proprio nell’aspetto grafico dei blocchi. Per questi motivi è essenziale trovare il modo più adatto di rappresentare ogni parte di codice che si vuole sintetizzare in una nuova entità grafica.

In Blockly è possibile definire quattro tipi di blocchi: • Senza connessioni

Il blocco è a sé stante e non può essere abbinato ad altri componenti. Questo tipo di costrutto si usa per definire metodi, procedure o classi. • Connessioni a sinistra

Usato per i blocchi facenti parte di valutazioni di espressioni logiche o come argomento in una espressione di assegnazione. In questo caso è necessario scegliere anche il tipo di output del blocco che può essere una stringa, un numero o un valore logico.

• Connessioni verticali

Questi blocchi possono essere concatenati con qualsiasi altro blocco dello stesso tipo. Indicano tipicamente una istruzione o la chiamata di una procedura.

• Connessioni solo in alto o solo in basso

Sono blocchi di questo tipo tutti quelli che non prevedono che altre istru-zioni possano essere concatenate prima o dopo di loro. Esempi sono la dichiarazione di una funzione (o di un metodo) e l’istruzione di ritorno. Di un blocco può essere personalizzato il colore, il testo, possono essere aggiunti dei campi supplementari come, ad esempio, i parametri di ingresso di una funzione oppure si può specificare se può contenere altre istruzioni, come accade per le procedure.

L’aspetto grafico di un blocco deve essere specificato in JavaScript, all’in-terno della directory blocks.

Blockly.Blocks[’controls_repeat’] = { init: function() { this.setHelpUrl(Blockly.Msg.CONTROLS_REPEAT_HELPURL); this.setColour(120); this.appendDummyInput() .appendField(Blockly.Msg.CONTROLS_REPEAT_TITLE_REPEAT) .appendField(new Blockly.FieldTextInput(’10’, Blockly.FieldTextInput.nonnegativeIntegerValidator),

(24)

18 3.1 Ambiente di sviluppo ’TIMES’) .appendField(Blockly.Msg.CONTROLS_REPEAT_TITLE_TIMES); this.appendStatementInput(’DO’) .appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(Blockly.Msg.CONTROLS_REPEAT_TOOLTIP); } };

Il codice precedente mostra come può essere definito un blocco associato ad un istruzione di controllo del flusso repeat, mentre la figura 3.2 ne mostra l’aspetto grafico finale.

Figura 3.2: Il blocco repeat.

Definizione della traduzione in codice

Definire il codice da associare ad un particolare blocco è un’operazione delicata. È necessario che la sintassi generata sia compatibile con quella di tutti i blocchi che è possibile associare a quello che si sta creando.

Nella directory generators, si definisce una directory con il nome del lin-guaggio di cui vogliamo implementare la traduzione dei blocchi. All’interno di quest’ultima è necessario creare una file con lo stesso nome di quello in cui abbiamo definito la grafica del blocco.

Volendo specificare la traduzione JavaScript del blocco mostrato in figure 3.2 scriveremo un codice simile a quello qua sotto.

Blockly.JavaScript[’controls_repeat’] = function(block) { var repeats = Number(block.getFieldValue(’TIMES’));

var branch = Blockly.JavaScript.statementToCode(block, ’DO’); branch = Blockly.JavaScript.addLoopTrap(branch, block.id); var loopVar = Blockly.JavaScript.variableDB_

.getDistinctName(’index’, Blockly.Variables.NAME_TYPE); var code = ’for (short ’ + loopVar + ’ = 0; ’ +

loopVar + ’ < ’ + repeats + ’; ’ + loopVar + ’++) {\n’ +

(25)

3.2 Applicazione mobile 19

branch + ’}\n’; return code;

};

Come è possibile notare, quello si definisce una vera e propria funzione di mapping. Nella prima parte del corpo di tale funzione si acquisiscono le informazioni necessarie, nella seconda si assembla la sintassi JavaScript del blocco.

Aggiungendo altri blocchi è possibile tradurre il blocco sopra definito nel codice seguente:

for(short index = 0; index < 10; index++) { counter = counter * 5;

}

3.2

Applicazione mobile

Per quanto riguarda il modo in cui l’applicazione embedded creata dall’utente debba essere caricata sui nodi VirtualSense, è necessario prevedere un mecca-nismo intuitivo, che renda questa fase dello sviluppo semplice e immediata.

Come già anticipato in 2.4, verrà sfruttato il paradigma di distribuzione degli app store. Questa scelta può essere concretizzata in due modi, il pri-mo dei quali è realizzare un vero e proprio app store, in cui le applicazioni create tramite la piattaforma di sviluppo siano scaricabili sotto forma di app. Ogni applicazione avrebbe il compito di contenere un infuso e di fornire le funzionalità di installazione sui nodi VirtualSense.

L’altra alternativa è quella di creare un’unica applicazione mobile, che sia in grado di scaricare il file infuso creato tramite la piattaforma web. La stessa app potrebbe mettere a disposizione le funzionalità di installazione sui nodi di una rete VirtualSense.

Il primo approccio è già stato sperimentato nell’ambito della distribuzione di applicazioni per nodi di una WSN [51], tuttavia il secondo è preferibile, dal momento che lo strumento descritto in questo lavoro è pensato per lo sviluppo di applicazioni la cui distribuzione al pubblico avrebbe poco o nessun senso. Inoltre, la seconda modalità evita che le stesse funzionalità siano replicate su molte applicazioni, diverse fra loro solamente per l’infuso che contengono.

Una volta deciso il paradigma da implementare, ci si è focalizzati sulla scelta della tecnologia e del sistema operativo mobile più adatto alle finalità del progetto. Tale scelta è ricaduta sul sistema operativo Android, per due motivi principali. Android è un sistema stabile, rilasciato con licenza open source, che mette a disposizione delle API complete, tramite le quali è possibile sviluppare un’applicazione mobile con tutte le caratteristiche necessarie al progetto in questione. La seconda motivazione è che, volendo dare l’accesso più vasto

(26)

20 3.3 Nodo sensore

possibile all’attività di programmazione di una WSN, è stato naturale orientarsi su un sistema operativo che è, con ampio margine, il più utilizzato3.

Seguendo gli stessi principi si è deciso di non avvalersi del framework di sviluppo ufficiale della piattaforma: la Companion App è stata sviluppata uti-lizzando il framework Xamarin4che permette di implementare la core business logic della propria applicazione astraendo dalla piattaforma di destinazione [52]. In questo modo, eventuali implementazioni della Companion App su al-tre piattaforme, potranno trarre vantaggio del codice già sviluppato durante questo lavoro.

3.3

Nodo sensore

Come già anticipato, questo lavoro è incentrato sulla progettazione e la realiz-zazione di una paradigma di sviluppo per i componenti di una rete di sensori VirtualSense. Presentiamo ora brevemente l’architettura hardware/software di questi nodi.

3.3.1 Architettura hardware ultra-low-power

VirtualSense è un sistema di nodi open hardware e ultra low power che mette a disposizione un runtime virtuale Java-compatibile. VirtualSense è basato su Contiki OS e Darjeeling VM, opportunamente modificati in modo da esporre esplicitamente ai livelli superiori dello stack software le primitive di controllo del consumo energetico e degli stati di esecuzione low-power, di cui la piat-taforma dispone grazie all’utilizzo di un microcontrollore Texas Instruments’ MSP430F5418a [47].

Il consumo medio di un nodo VirtualSense è di circa 13mW in modalità di esecuzione standard e 66mW durante la trasmissione di dati. Esistono poi degli stati cosiddetti low power quali lo stato standby, in cui la CPU non è alimentata ma il clock di sistema è in esecuzione, cosa che rende il nodo capace di auto-svegliarsi e tornare in stato active per mezzo dei timer interrupts. Lo stato sleep è simile a quello di standby, ma in questo caso anche il clock di sistema è spento perciò l’unità viene riportata allo stato attivo solo per mezzo di interrupt esterni. L’hibernation è lo stato con il minore consumo energetico, in cui anche la memoria di sistema non è alimentata perciò quando il nodo entra in questa modalità il sistema si occupa di salvare lo stato dell’heap della macchina virtuale nella memoria non volatile. Per tornare attivo il nodo deve ricevere un interrupt esterno e ripristinare lo stato corrente nella memoria volatile. Il consumo energetico in questi stati è di 14,67 µW in standby, 1,32

3

Al momento della stesura di questo lavoro le statistiche riportano che il sistema ope-rativo Android è installato su circa l’85% dei dispositivi mobili utilizzati. Il lettore inte-ressato può verificare il dato corrente sul market-share dei sistemi operativi mobili sul sito: http://www.netmarketshare.com

(27)

3.3 Nodo sensore 21

µW in sleep, 0,36 µW in hibernation e i tempi di wake-up vanno dai 25 ms per i primi due stati ai 500 ms dell’ultimo.

Per concludere, un nodo VirtualSense può eseguire i tipici compiti di un mote di una WSN con un consumo medio di qualche micro Watt.

Anche a livello Java è possibile gestire gli stati low power del nodo tramite l’API messa a disposizione dalla classe PowerManager.

3.3.2 Stack software e programmazione dei nodi VirtualSense

Lo strato più basso che si incontra percorrendo lo stack software di Virtual-Sense dal basso verso l’alto è quello di Contiki, un sistema operativo real-time embedded, pensato specificamente per nodi di una rete di sensori. Come già accennato nella sezione 2.1.1 il modello di programmazione di Contiki è ba-sato sull’utilizzo dei protothread. Un protothread è un astrazione utilizzata su sistemi con scarsa memoria che combina le caratteristiche del paradigma di programmazione multithreading e quello event-driven, pur mantenendo un overhead di memoria molto basso. Il kernel invoca i protothread di un proces-so in risposta ad eventi interni o esterni, altrimenti si assume che questi siano schedulati in modo cooperativo fra loro. Questo significa che un processo Con-tiki deve restituire esplicitamente il controllo al kernel ad intervalli regolari, invocando le funzioni PROCESS_WAIT_EVENT() o PROCESS_YIELD().

Il livello di astrazione software immediatamente sopra Contiki è costituito da Darjeeling. Darjeeling è una macchina virtuale ottimizzata per l’uso sui no-di no-di una WSN che espone un sottoinsieme significativo delle librerie standard di Java, con delle richieste hardware minimali. La macchina virtuale suppor-ta l’esecuzione di una singola applicazione Java multithread per volsuppor-ta. Ogni VM Darjeeling è implementata come un singolo processo Contiki e dispone di un proprio scheduler che utilizza una politica Round-Robin per la partizione temporale. Lo strato software di VirtualSense è implementato aggiungendo ad una normale VM Darjeeling le funzionalità tipiche della piattaforma.

Un’applicazione VirtualSense consiste di uno o più file Java nei quali c’è una classe in cui viene implementato il metodo public static void motemain(), che costituisce il punto di ingresso di ogni programma VirtualSense. Il codice Java viene compilato in byte code, questo viene verificato e trasformato offline da un tool chiamato Infuser che prende in input i file .class e restituisce un modulo chiamato infusion (o infuso). Un infuso contiene un’intera applicazione che a sua volta può essere costituita da diversi thread. Questo modulo può essere trasmesso, installato ed eseguito in qualsiasi nodo VirtualSense.

Per meglio capire quale sia l’aspetto del codice sorgente di un’applicazione VirtualSense prima che questo venga compilato e trasformato in un infuso, riportiamo in figura 3.3 un esempio molto semplice di applicazione, tratto direttamente dalla documentazione ufficiale5.

(28)

22 3.3 Nodo sensore

Figura 3.3: Un semplice programma VirtualSense.

Come è possibile vedere dall’immagine, il codice è quasi identico a quello di una applicazione simile scritta in Java, l’unica modifica significativa è proprio il metodo motemain() che sostituisce il normale metodo main().

VirtualSense permette di installare ed eseguire più applicazioni (chiamate Task ) contemporaneamente sullo stesso nodo. Il multitaking permette ai vari task di condividere la CPU, inoltre ogni thread Java è mappato in un thread nativo. Il risultato è un’esecuzione fortemente concorrente fra i vari thread di ogni task.

La figura 3.4 mostra uno schema dello stack software implementato in ogni nodo sensore. I Task sono rappresentati in cima allo stack mentre il livello hardware è quello più in basso. Contiki OS è il primo livello che si incontra partendo dal fondo. Immediatamente sopra c’è il runtime di VirtualSense che include la VM Darjeeling e tutte le librerie interne che non vengono esposte nelle API, queste ultime sono invece rappresentatate nel blocco VirtualSense Libs che include i metodi di controllo dell’interfaccia Network, della gestione dei sensori, degli attuatori e delle funzionalità di power-management, insieme alle altre funzionalità principali esposte alle applicazioni.

Da notare che l’architettura appena descritta è abbastanza generale da permettere, grazie al livello di virtualizzazione introdotto da Darjeeling, il ca-ricamento a caldo delle applicazioni, una volta installate sul nodo. Per poter

(29)

3.3 Nodo sensore 23

Figura 3.4: Lo stack software di VirtualSense.

essere eseguito, un Task VirtualSense deve prima essere caricato nella macchi-na virtuale, avviato e, quando è necessario, fermato, dopodiché le sue risorse sono rimosse dalla macchina virtuale. In VirtualSense è stato implementato un processo nativo Contiki che si occupa di queste operazioni e che prende il nome di TaskManager.

Il TaskManager si preoccupa di eseguire queste quattro operazioni prin-cipali in seguito ad un comando esterno. La prima è l’operazione di LOAD: il TaskManager riceve in ingresso l’Id dell’applicazione da caricare, attraver-so l’ApplicationTable viene identificato il punto preciattraver-so della memoria flash interna al nodo dove è stato salvato l’infuso dell’applicazione, una volta identi-ficato il codice viene caricato nella memoria principale e un nuovo Task viene creato. Il comando di START ha l’effetto di fare iniziare l’esecuzione del Task invocando il metodo motemain() precedentemente descritto. Il comando STOP interrompe l’esecuzione di un Task e, poiché ogni applicazione può contenere più thread lo stesso comando viene inviato ad ognuno di questi. Una volta fermato ogni Task può essere sia eliminato dalla memoria principale con il co-mando UNLOAD sia rieseguito nuovamente tramite una nuova invocazione del comando START.

(30)

Capitolo 4

Architettura software

Il sistema di sviluppo e gestione realizzato in questo lavoro si compone di diverse parti, eterogenee fra loro per struttura e scopo. Prima di analizzare nel dettaglio i vari moduli, si proverà a dare una descrizione generale del processo di programmazione, mentre il processo di controllo dei nodi verrà esaminato nel dettaglio nella sezione 4.2.2.

La programmazione di un nodo di una WSN è un’attività intrisecamente complessa. Passare dall’ideazione di un software per una rete di sensori alla sua realizzazione richiede normalmente numerosi passi intermedi: in partico-lare, la programmazione dei nodi VirtualSense consiste in una serie di atti-vità ben definite, la prima delle quali è la scrittura del codice sorgente della propria applicazione. Nella sezione 3.3 è stata data una spiegazione di cosa questo comporti. Una volta ottenuto un codice corretto dal punto di vista della sua specifica funzionale, che abbia una sintassi compatibile il linguaggio di programmazione, lo si compila ottenendo un infuso installabile. Per l’instal-lazione è solitamente necessario connettere fisicamente il PC sul quale risiede l’infuso e il nodo. Il procedimento vero e proprio di caricamento dei dati nella memoria flash del sensore VirtualSense può avvenire attraverso un’interfaccia seriale JTAG oppure attraverso un Boot Strap Loader specifico per la piatta-forma (chiamato virtualsense-bsl). Completati questi passi il nodo viene riavviato automaticamente e l’esecuzione dell’applicazione ha inizio.

La procedura descritta è quella seguita normalmente per la produzione e l’installazione di un’applicazione VirtualSense. La metodologia alternativa proposta in questo lavoro è decisamente più semplice, ed essendo in gran parte automatizzata, richiede all’utente meno competenze selettive.

I vari passi della procedura proposta sono schematizzati in figura 4.1. Ve-diamo come la fase di scrittura del codice dell’applicazione sia mediata dalla piattaforma web che il sistema mette a disposizione. Una volta che il compor-tamento dell’applicazione è stato definito tramite lo strumento di programma-zione visuale, il programma viene compilato automaticamente, in modo tra-sparente all’utente. Se non si verificano errori, viene restituito un QR Code.

(31)

4.1 Ambiente di sviluppo 25

Figura 4.1: La procedura di installazione proposta.

A questo punto entra in gioco la Companion App installata nello smartphone di chi completerà il processo di installazione. Tramite questa app è possibile scansionare il codice QR e scaricare l’infuso VirtualSense al quale il codice è associato. Una volta che il download è stato completato, si può sfruttare la stessa app per la programmazione over the air dei nodi VirtualSense. Avvian-do il processo di installazione dalla Companion App, sarà questa ad occuparsi di stabilire una connessione Bluetooth al nodo specificato, di negoziare i para-metri di programmazione e, infine, di inviare il codice. Una volta che il codice è stato caricato, l’app invia il comando di caricamento della nuova applicazione, che viene infine eseguita senza il nodo debba essere riavviato.

Nelle sezioni seguenti approfondiremo l’achitettura software e il funziona-mento delle varie componenti del sistema sviluppato.

4.1

Ambiente di sviluppo

Il primo componente della piattaforma di sviluppo con cui l’utente si trova ad operare è quello che chiamaremo App Maker. Per come appare al suo utilizzatore, questo strumento permette di definire il comportamento che l’ap-plicazione deve avere una volta installata nei nodi e produce l’infuso da in-stallare. Di seguito verrà descritto il modo in cui queste due funzionalità sono implementate.

4.1.1 Programmazione visuale

L’ambiente di programmazione Blockly supporta nativamente la traduzione in Javascript e in Python, entrambi linguaggi basati su una tipizzazione debole delle variabili, mentre l’obiettivo è quello di fornire un’interfaccia a blocchi per poter stilare un file sorgente in Java, il linguaggio utilizzato per le applicazioni VirtualSense. Quest’ultimo prevede la tipizzazione forte delle variabili perciò non è possibile riutilizzare quasi nulla dei generatori di linguaggio già disponibi-li. Al contrario, dovranno essere ridefinite, o create da zero, anche le strutture

(32)

26 4.1 Ambiente di sviluppo

base come l’inizializzazione di variabile o la definizione di funzioni e procedure. Inoltre per rendere funzionale l’App Maker si dovranno aggiungere i costrutti grafici associati ad ognuna delle API specifiche della piattaforma VirtualSense che includono la gestione del PowerManager, degli stati low-power, dei sensori e degli attuatori, oltre alle funzionalità di comunicazione fra nodi, e fra nodo e Companion App.

Figura 4.2: I blocchi per la dicharazione e l’inizializzazione delle variabili. Un’altra considerazione fondamentale è che VirtualSense supporta il mul-tithreading ma, se si vuole che la specifica di un’applicazione sia un’attività accessibile anche ai programmatori non esperti, si dovranno prevedere dei co-strutti grafici di alto livello che mascherino la complessità della gestione dei thread.

Per rendere la lettura meno ripetitiva verranno riportati i dettagli della definizione grafica e funzionale dei costrutti più interessanti fra quelli intro-dotti nella piattaforma, mentre saranno omessi quelli sui costrutti base del linguaggio. Il lettore interessato potrà approfondire sperimentando da sé il funzionamento del prototipo della piattaforma.

Lo stage

Lo stage è la zona dell’interfaccia destinata al componimento del programma. Al suo interno è presente un blocco di default che rappresenta il punto di in-gresso della funzione principale motemain() introdotta nella sezione 3.3.2. Dal momento che la presenza di tale funzione è necessaria perché un programma VirtualSense sia valido, lo stesso vale per il blocco in esame. Esso non può essere rimosso dallo stage e devono essere introdotti dei blocchi al suo interno per non sollevare un errore in fase di generazione del QR Code (e dell’infuso).

La traduzione del blocco è la seguente: public class VSenseApp {

public static void motemain() { ...

} }

(33)

4.1 Ambiente di sviluppo 27

Figura 4.3: Il blocco iniziale.

Funzioni e procedure

Per quanto si cerchi di mascherare la sintassi del linguaggio Java, non rende-re disponibile un costrutto basilarende-re come quello della definizione di funzione rischierebbe di complicare la programmazione, piuttosto che semplificarla.

Pertanto si è scelto di introdurre due costrutti di base, uno per le funzioni e un altro per le procedure (cioè quelle funzioni che non ritornano valori). La particolarità di questi costrutti è che il numero dei loro parametri in ingresso è variabile. Fortunatamente le funzionalità di Blockly rendono possibile definire dei blocchi configurabili a piacere dall’utente.

Un’altra considerazione è che, essendo Java un linguaggio ad oggetti, non permette di definire delle funzioni che non siano associate ad una classe. Questa complicazione è facilmente risolvibile introducendo una classe destinata proprio a contenere le funzioni e le procedure, le quali saranno definite come metodi pubblici e statici della classe stessa.

Figura 4.4: Il blocco di definzione di una procedura.

La figura 4.4 mostra il blocco rappresentante una procedura. Come è pos-sibile notare, questo costrutto sintattico corrisponde ad un oggetto grafico a sé stante, privo di connessioni esterne ma che può ospitare al suo interno un insieme di istruzioni. Una volta che una procedura è stata definita questa deve poter essere invocata. L’invocazione di una procedura corrisponde al blocco in figura 4.5. È da notare come questo blocco compaia fra quelli disponibili all’utente solo dopo che il blocco di definizione è stato istanziato nello stage.

La caratteristica di avere un numero e un tipo di parametri in ingres-so variabili è rappresentata nei blocchi con la possibilità di modificare la rappresentazione grafica in modo da poter ospitare il numero di parametri desiderato.

(34)

28 4.1 Ambiente di sviluppo

Figura 4.5: Il blocco di invocazione di una procedura.

Figura 4.6: La modifica dei parametri di ingresso di una procedura.

Il codice generato dal blocco rappresentante la definizione di una procedura è:

class Procedures {

public static void doSomething(){ ...

} ... }

Mentre il blocco della sua invocazione genera questo codice: Procedures.doSomething();

I blocchi delle funzioni sono molto simili alle procedure eccetto che, lavo-rando con dei dati tipizzati, anche i blocchi delle loro definizioni sono distinti in base al tipo di parametro in uscita. Inolte, mentre l’invocazione delle pro-cedure è rappresentata da un semplice blocco con connessioni verticali, quello delle funzioni ha connessioni a sinistra poiché può essere utilizzato come un valore da utilizzare.

Il codice generato dai blocchi delle funzioni è simile a quello già riportato per le procedure.

(35)

4.1 Ambiente di sviluppo 29

Figura 4.7: I blocchi di definizione e invocazione di una funzione

Eventi

La descrizione dei costrutti grafici che rappresentano il concetto di evento richiede una piccola digressione.

L’evento è un’astrazione di alto livello che non corrisponde ad un costrutto base del linguaggio Java. Grazie alla capacità di VirtualSense di supportare applicazioni multithread è possibile mettere a disposizione questo tipo di bloc-co all’utente, ma è necessario mascherare la bloc-complessità che si nasbloc-conde dietro al costrutto grafico. Per implementare un evento si deve ricorrere alla program-mazione concorrente, facendo uso di thread e semafori. La soluzione adottata prevede che ogni volta che vengono associate delle istruzioni ad un evento, que-sto si rifletta nella creazione di un nuovo thread, nel cui metodo run() sono definite le istruzioni specificate. La gestione dell’evento si traduce nel codice in questo modo: all’avvio del metodo principale viene avviato il thread relativo, la cui prima istruzione è un acquire() di un semaforo inizializzato con zero permessi. In questo modo l’esecuzione del thread viene sospesa fino a che, un altro thread, che ha il compito di sollevare gli eventi, non invoca il metodo release() sullo stesso semaforo. Una volta eseguite le istruzioni associate ad un evento, il thread si rimette in attesa con una nuova acquire().

La figura 4.8 mostra uno schema del comportamento dei due thread che gesticono un evento

Un blocco esemplificativo di quanto questa gestione della concorrenza sia trasparente all’utente è quello in figura 4.9

Che corrisponde al codice:

class EventThread_event extends Thread{ Semaphore mySem;

public EventThread_<event name>(Semaphore sem){ this.mySem = sem;

}

(36)

30 4.1 Ambiente di sviluppo

Figura 4.8: Schema del comportamento di due thread che gesticono un evento.

Figura 4.9: Blocco di attesa di un evento.

while(true){ this.mySem.acquire(); ... } } }

Non esistono degli eventi predefiniti dall’editor, questi vengono resi sele-zionabili nelle istruzioni che ne prevedono l’attesa, solo dopo che sono stati definiti tramite il blocco trigger in figura 4.10

Figura 4.10: Blocco di trigger di un evento.

che nel codice corrisponde al’invocazione del metodo release() di un semaforo.

(37)

4.1 Ambiente di sviluppo 31

sem_event.release();

Viene data la possibilità all’utente di aspettare esplicitamente un evento, inserendo un blocco wait fra due istruzioni.

Figura 4.11: Blocco di wait di un evento.

Simili agli eventi, sono gli interrupt di sistema. VirtualSense mette a di-sposizione 5 pin di interrupt, insieme ad una API per la loro gestione, tramite la quale è possibile mettersi in attesa su uno specifico pin. L’attesa di un in-terrupt è rappresentata in blocchi in due modi possibili: sotto forma di attesa esplicita come mostrato in figura 4.12, oppure registrando una callback, come in figura 4.13.

Figura 4.12: Blocco di wait di un interrupt.

Figura 4.13: Blocco di when associato ad un interrupt. L’attesa esplicita si traduce nel codice:

Interrupt int_<pin> = new InterruptPin(true, InterruptPin.<pin>); int_<pin_num>.waitForInterrupt();

Mentre tralasciamo il codice del blocco when poiché simile a quello già mostrato per gli eventi generici.

VirtualSense è dotato di un timer interno che può essere programmato per inviare un interrupt dopo una determinata quantità di tempo. Oltre ai blocchi necessari per attendere questo interrupt (chiamato timer interrupt ) simili a quelli già mostrati, la piattaforma mette a dispozione anche un blocco per

(38)

32 4.1 Ambiente di sviluppo

la programmazione di questo timer. Fortunatamente VirtualSense fornisce un API dedicata allo scopo per cui il codice Java corrispondente al blocco in figura 4.14 è piuttosto semplice:

PowerManager.scheduleRTCInterruptAfter(time);

Figura 4.14: Blocco di schedulazione di un timer interrupt.

Sensori

VirtualSense è ancora una piattaforma in corso di sviluppo ma i sensori at-tualmente disponibili nei nodi sono di tre tipi: di temperatura, di luminosità e di pressione. Il valore di ognuno di questi sensori è consultabile tramite dei comodi metodi statici messi a disposizione dalla piattaforma, grazie a questi, il codice da scrivere per ottenere i valori misurati è lineare:

short temp = Temperature.getValue();

Allo stesso modo i blocchi che rappresentano queste operazioni di lettura sono piuttosto semplici (figura 4.15).

Figura 4.15: Blocchi di lettura dei sensori.

Attuatori

Per ora, gli attuatori disponibili sulla piattaforma sono tre led la cui accensione e spegnimento sono controllabili tramite le API. Ogni led è identificato da un indice numerico che va specificato sotto forma di intero nel blocco in figura 4.16

(39)

4.1 Ambiente di sviluppo 33

Figura 4.16: Blocco di controllo di un led.

Power Manager

L’interfaccia della classe PowerManager mette a dispozione dei metodi che per-mettono di passare ad uno dei stati low power per un determinato periodo di tempo. Ad esempio, per mandare il nodo in standby basta istanziare il blocco in figura 4.17 che verrà tradotto nel codice seguente.

PowerManager.scheduleRTCInterruptAfter((short)time); PowerManager.standby()

Figura 4.17: Blocco del comando standby.

Tramite le API del PowerManager è possibile variare la frequenza operativa della MCU del nodo, alterandone di conseguenza le capacità di elaborazione e il consumo energetico. Il blocco in figura 4.18 incapsula questa operazione met-tendo a dispozione un menù a tendina attraverso il quale è possibile scegliere la nuova frequenza operativa tra quelle predefinite.

Figura 4.18: Blocco per la variazione della frequenza della MCU. Il codice associato a questo nodo è:

PowerManager.setMCUFrequency(PowerManager.MCU_<value>MHZ); Comunicazione nodo a nodo

Modellizzare la comunicazione fra nodi e introdurre un’astrazione che sia in grado di mascherare la complessità di tale procedimento, senza limitare forte-mente le possibilità implementative, sono operazioni estremaforte-mente complesse.

Figura

Figura 2.1: Classificazione dei paradigmi di programmazione delle WSNs.
Figura 3.1: BlocklyDuino, un editor per codice sorgente eseguibile su sistemi Arduino.
Figura 3.2: Il blocco repeat.
Figura 3.3: Un semplice programma VirtualSense.
+7

Riferimenti

Documenti correlati

Lo studente dovrà inoltre acquisire 4 CFU attraverso ulteriori attività nel SSD SECS- P/07 (Economia aziendale), coordinate da un docente, organizzate anche in raccordo con la

Al fine di consentire il corretto svolgimento delle attività dovrà essere impiegato un numero di tecnici tale da garantire la costante verifica del rispetto di quanto previsto,

[r]

Risultati attesi Le nanostrutture di sintesi, potendo essere controllate in funzione delle dimensioni, della forma e della chimica di superficie, si dimostrano strumenti di

(a) Per poter confrontare due espressioni booleane bisogna portarle in una forma “unica”, cio` e la somma di prodotti completa oppure la somma di tutti gli

 La realizzazione di palificazioni per telecomunicazioni viene descritta nella Norma CEI 103-2 (“Costruzione delle linee di telecomunicazione aeree esterne negli attraversamenti e

arri o. a) Indi iduare locali idonei per l'istitu ione dei seggi ospedalieri e/o speciali, al fine di garantire adeguata area ione degli stessi e il rispetto delle opportune misure

- Frattura del collo del femore: intervento chirurgico entro 2 giorni - Frattura della Tibia e Perone: tempi di attesa per int.. chirurgico - Intervento di protesi di