• Non ci sono risultati.

Progettazione ed implementazione di un sistema IoT adattivo tramite un linguaggio orientato al contesto

N/A
N/A
Protected

Academic year: 2021

Condividi "Progettazione ed implementazione di un sistema IoT adattivo tramite un linguaggio orientato al contesto"

Copied!
152
0
0

Testo completo

(1)

URN etd-06192018-131624

Autore (Matricola) ROLLA, RICCARDO (194337) Indirizzo email riccardo.rolla@gmail.com

Struttura INFORMATICA

Corso di studi TECNOLOGIE INFORMATICHE

Commissione • Prof. Ferrari, Gian Luigi - relatore Tipo di tesi Tesi di laurea specialistica

Titolo Progettazione ed implementazione di un sistema IoT adattivo tramite un linguaggio orientato al contesto Data inizio appello 20/07/2018

Data inizio

(2)
(3)

Progettazione ed implementazione di

un sistema IoT adattivo tramite un

linguaggio orientato al contesto

Riccardo Rolla

Dipartimento di Informatica

Università di Pisa

(4)
(5)
(6)
(7)

Riassunto analitico

L’obiettivo di questa tesi è lo sviluppo di un sistema IoT tramite il linguaggioMLCoda, un linguaggio orientato al contesto. La scelta di utilizzare Raspberry Pi ha consentito di costruire, senza avere conoscenze di elettronica, un piccolo rover con tecnologie hardware a basso costo, dotato di Camera, LED, ruote e sensori di distanza. La necessità di ottimizzare il sistema per l’interazione con un ambiente reale ha portato a definire il sistema di controllo software con caratteristiche di eterogeneità ed interoperabilità. Viene poi mostrata una sessione di test del sistema realizzato che mostra il funzionamento della componente self-adaptive durante l’esecuzione. Infine vengono valutati i vantaggi e i limiti di questa implementazione.

(8)
(9)

Indice

Elenco delle figure ix

Elenco delle tabelle xi

Lista dei codici sorgenti xiii

1 Introduzione 1

2 Preliminari 5

2.1 Raspberry Pi . . . 6

2.2 General Purpose Input/Output . . . 9

2.3 Raspberry Camera . . . 11

2.4 L298N Motor Controller . . . 12

2.5 HC-SR04 . . . 13

2.6 Altri componenti hardware . . . 16

2.7 Mono . . . 19

2.8 Raspberry# . . . 19

2.9 Node.js . . . 23

2.10 Telegram API Bot . . . 26

2.11 Microsoft Cognitive Service . . . 27

2.12 MLCoda. . . 29 2.12.1 DataLog . . . 29 2.12.2 F#Coda . . . 30 2.12.3 ToolchainMLCoda . . . 31 3 Architettura Software 35 3.1 Componenti . . . 35

3.2 Ambiente di Sviluppo, Test e Produzione . . . 37

(10)

3.4 rpi-service.js . . . 41 3.4.1 REST API . . . 43 3.5 fsc-rover . . . 46 3.5.1 fsc-context . . . 46 3.5.2 Fsc.utils . . . 49 3.5.3 Program.fs . . . 51 4 Testing 61 4.1 Avvio . . . 61 4.2 Comandi Utente . . . 65 4.3 Controllo Automatico . . . 77

4.4 Chiusura del Sistema . . . 79

5 Cosa abbiamo imparato 83 5.1 Versione non adattiva inF# . . . 84

5.2 Versione adattiva inMLCoda . . . 84

5.3 Versione adattiva inMLCodacon API REST . . . 87

5.4 Prestazioni e Considerazioni . . . 88

6 Conclusioni 91

Appendice A Hardware 95

Appendice B Ambiente di esecuzione 99

Appendice C Codice Sorgente 101

(11)

Elenco delle figure

2.1 RaspberryPi 3 . . . 8 2.2 Raspberry Camera . . . 11 2.3 L298N Motor Controller . . . 14 2.4 Sensore ad ultrasuoni HC-SR04 . . . 15 2.5 Rover Chassis . . . 17 2.6 Basetta "sperimentale" . . . 17 2.7 T-Cobbler . . . 18

2.8 Common Language Infrastructure . . . 20

2.9 Node.js: Modello di elaborazione . . . 24

2.10 Esempio di chiamata al Microsoft Vision Service . . . 28

2.11 MLCoda. . . 33

3.1 Architettura . . . 36

3.2 Ambienti di sviluppo e produzione . . . 37

4.1 Rover: Immagine Frontale . . . 62

4.2 Rover: Immagine dal Basso . . . 63

4.3 Telegram: Messaggio Broadcast . . . 66

4.4 Telegram:help . . . 70 4.5 Telegram:right . . . 72 4.6 Telegram:distance . . . 73 4.7 Telegram:photo . . . 75 4.8 Telegram:discovery . . . 78 4.9 Rover: Led . . . 80 4.10 Rover: Breadboard . . . 82

A.1 Rover: Schema hardware . . . 97

(12)
(13)

Elenco delle tabelle

2.1 Comparazione modelli Raspberry Pi . . . 7

2.2 General Purpose Input/Output . . . 10

2.3 Configurazione controllo motori . . . 13

3.1 Valori contenuti in rpi-rover.json . . . 39

3.2 Valori contenuti in rpi-service.json . . . 42

3.3 Valori contenuti in fsc-rover.json . . . 50

5.1 Tempi esecuzione Memoization e API REST . . . 89

(14)
(15)

Lista dei codici sorgenti

C.1 simcmd.bat . . . 102 C.2 rpi-rover Main 1/2 . . . 103 C.3 rpi-rover Main 2/2 . . . 104 C.4 rpi-rover Configuration . . . 105 C.5 rpi-rover Led . . . 106 C.6 rpi-rover Button . . . 107 C.7 rpi-rover TwoMotorsDriver . . . 108 C.8 rpi-rover Motor . . . 109 C.9 rpi-rover UltrasonicDistanceSensor . . . 110 C.10 rpi-service.js Configuration . . . 111

C.11 rpi-service.js Telegram e Express . . . 112

C.12 rpi-service.js rpi-rover . . . 113 C.13 rpi-service.js rpi-rover . . . 114 C.14 rpi-service.js photo . . . 115 C.15 rpi-service.js video . . . 116 C.16 rpi-service.js Telegram 1/2 . . . 117 C.17 rpi-service.js Telegram 2/2 . . . 118 C.18 rpi-service.js whatdoyousee . . . 119 C.19 fsc-context.P . . . 120 C.20 fsc-utils Configuration . . . 121 C.21 fsc-utils ImageRecognition . . . 122

C.22 fsc-utils Message e Command . . . 123

C.23 Program.fs utils 1/2 . . . 124

C.24 Program.fs 2/2 . . . 125

C.25 Program.cs InitFacts 1/2 . . . 126

C.26 Program.cs InitFacts 2/2 . . . 127

(16)
(17)

Capitolo 1

Introduzione

Negli ultimi anni, le applicazioni self-adaptive[1], in grado di operare sempre e ovunque e modificare il proprio comportamento a seconda del contesto di esecuzione, hanno acquisito un’importanza sempre maggiore.

Uno scenario tipico per la realizzazione di questi sistemi, che richiedano ridotti interventi di amministrazione, è nell’ambito dell’Internet of Things[2], IoT, dove dei dispositivi connessi e spesso mobili hanno la necessità di interagire con un ambiente fisico.

Il software di controllo di questi dispositivi deve sapere affrontare il cambiamento del-l’ambiente in cui lavorano, e saper decidere in autonomia, senza intervento utente, quali operazioni effettuare senza compromettere la sicurezza e la qualità del servizio.

In questa tesi è stato implementato un sistema IoT che utilizzerà nella sua parte di controllo un software sviluppato in MLCoda[3], un linguaggio che supporta astrazioni ad hoc per l’implementazione di software self-adaptive.

L’assemblaggio fisico del dispositivo hardware IoT, durante la sperimentazione, ha avuto come scopo quello di valutare quale tecnologie a basso costo fossero disponibili nel mercato per consentire ad un non esperto di elettronica la costruzione di un piccolo robot rover, dotato di due ruote, controllo motore, foto e videocamera e sensore di distanza.

Nella fase di sviluppo è stato definito un sistema software con caratteristiche di eterogeneità, cioè composto da più sottosistemi implementati su linguaggi ed ambienti di esecuzione diversi scelti in base alle funzionalità che questi componenti devono svolgere, ed interopera-bilità, grazie alla realizzazione di una REST API, REpresentational State Transfer Application Programming Interface[4], che consente di interagire ed integrarsi con altri sistemi remoti. Il rover può muoversi in un edificio e rilevare gli oggetti in esso presenti ed alcune delle loro caratteristiche, inoltre interagisce con altre applicazioni che utilizzano le informazioni raccolte, scambiando messaggi su Internet.

(18)

Questo sistema può sia eseguire delle operazioni in autonomia sia svolgere delle azioni ricevute da utente attraverso il servizio di messaggistica Telegram[5].

Nella prima parte della tesi verranno illustrate le scelte tecnologiche, hardware e software fatte per l’implementazione dell’intero progetto.

Per la piattaforma hardware è stato deciso di adottare il computer Raspberry Pi versione 3[6], che, per le sue caratteristiche di calcolo e di connessione Wireless e per la possibilità di collegare sensori ed attuatori grazie alle porte I/O, è risultato essere una soluzione a basso costo ideale per la realizzazione di questo progetto.

La scelta della piattaforma software è stata dettata dalle scelte architetturali, decise per l’implementazione della parte controllo, oggetto della tesi, realizzata inMLCoda, che necessita del Common Language Infrastructure [7], CLI.

Raspberry Pioffre la possibilità di utilizzare l’ambienteMono[8], un’implementazione

open-source del CLI, all’interno di una distribuzione Linux chiamata Raspian[9]. E’ stato scelto questo ambiente sia per implementare il controllo diretto dei sensori attraverso la libreria

Raspberry#[10] sia per l’implementazione della parte software, scritta inMLCoda.

La componente software di controllo realizzata inMLCodanon interagisce direttamente con l’hardware e i servizi remoti ma attraverso un middleware[11] che svolge funzionalità di interfacciamento sia con il sistema operativo sia con i servizi su internet. Il middleware è realizzato in Javascript[12] sfruttando il frameworkNode.js[13] e i moduli aggiuntivi

che estendono questa piattaforma software, in modo particolare saranno impiegati quelli che semplificano l’utilizzo delle REST API offerte dai servizi cloud[14], utilizzati nella sperimentazione condotta nella tesi, ovvero Telegram e Microsoft Cognitive Service[15]. Nella seconda parte della tesi vengono descritte le scelte architetturali fatte per la realizza-zione del software di controllo del rover, dove la scelta più importante, come già anticipato, è stata quella di definire e implementare tre componente distinti:

1. una componente a diretto contatto con le primitive di accesso all’hardware;

2. un layer, che implementa un middleware che consente attraverso una REST API sia di interagire con la parte hardware della piattaforma sia di funzionare come API Gateway[16] con i servizi cloud;

3. una componente adattiva che implementa le funzionalità di controllo del sistema, realizzata inMLCoda, che sfrutta la REST API offerta dal middleware implementato in Node.jsper interagire sia con le componente hardware sia con i servizi cloud.

Nella terza parte viene mostrata una sessione di test di esecuzione del sistema, in cui viene descritto e commentato il funzionamento della componente scritta inMLCoda.

(19)

3

Infine nell’ultima parte della tesi saranno illustrate le difficoltà incontrate nella realiz-zazione del progetto, le motivazioni delle scelte architetturali e i vantaggi a quali porta l’ingegnerizzazione di un’applicazione self-adaptive.

(20)
(21)

Capitolo 2

Preliminari

In questo capitolo, saranno presentate le tecnologie che sono state utilizzate per l’imple-mentazione del rover oggetto della tesi.

Il rover sarà dotato del seguente hardware:

• due ruote motorizzate collegate ad un controllo motore;

• un sensore di distanza che può individuare se di fronte sono presenti ostacoli; • una camera con la quale è possibile scattare foto e fare piccoli filmati;

• due LED[17] ed un bottone per mostrare l’output e far interagire l’utente direttamente con il rover;

Inoltre, grazie alla possibilità di collegarsi ad internet attraverso la connettività wireless, potrà:

• interagire con diversi utenti via chat sfruttando le Telegram Bot API[18];

• "interpretare" quello che vede utilizzando le Computer Vision API[19] offerte dal Microsoft Cognitive Service.

Nella prima parte di questo capitolo saranno illustrate le tecnologie hardware utilizzate per la realizzazione del progetto, Raspberry Pi, scelto come piattaforma hardware a basso costo che può essere utilizzato per progetti IoT, sul quale è possibile installare un modulo hardware che implementa una fotocamera, Raspberry Camera[20], e sfrutta le interfaccie General Purpose Input/Output[21], GPIO, sulle quali è possibile installare un sensore di distanza,HC-SR04[22] , un controller motore,L298N[23]. per controllare i movimenti del

(22)

Il sistema operativo utilizzato su questa architettura è Raspian, una distribuzione Linux pen-sata per Raspberry Pi, dove sono presenti due software a linea di comandoraspistill[24]

che saranno utilizzate per acquisire foto eraspivid[25] per ottenere i video.

Nella parte successiva vengono descritti gli ambienti di esecuzione e le relative librerie utilizzate per l’implementazione dei componenti software :

1. Monoper la realizzazione sia della parte di interfacciamento con l’hardware, attraverso

la libreriaRaspberry#[10], sia della componente adattiva, utilizzandoMLCoda. 2. Node.jsper la definizione di un servizio che attraverso l’implementazione di una

REST API realizza un layer di astrazione alle funzionalità hardware e verso dei servizi cloud, Computer Vision API e Telegram Bot API.

L’ultima parte del capitolo viene introdottoMLCoda, viene descritto come utilizzare Data-log[26] per la definizione del contesto ed i costruttiMLCodache permettono di estendere il linguaggioF#[27] per l’interrogazione e modifica del contesto[28]. Infine viene mostrato il

processo di compilazione utilizzato per generare software che utilizzaMLCoda.

2.1 Raspberry Pi

Il Raspberry Pi è un calcolatore a basso costo di dimensioni molto ridotte realizzato dalla Rasp-berryPi Fondantion. Esistono diverse versioni di questo piccolo computer con configurazioni hardware differenti, così come riportato nella tabella 2.1.

(23)

2.1 Raspberry Pi 7 Tab ella 2.1 Comparazione mo delli Raspb err y Pi Mo dello Raspb err y 1 Raspb err y 2 Rpi 2 v1.2 Raspb err y 3 Data di intr oduzione 2014-07-01 2015-02-01 2016-10-01 2016-02-01 Pr ocessor e SoC Br oadcom BCM2835 Br oadcom BCM2836 Br oadcom BCM2837 Ar chitettura ARMv6Z (32 bit) ARMv7-A (32 bit) ARMv8-A (32/64 bit) CP U ARM11 ARM Corte x A7 ARM Corte x A53 Numer o di cor e 1 4 4 4 Fr equenza CP U (Mhz) 700 900 1200 GP U Br oadcom Vide oCor e IV Memoria SDRAM 512 1024 Porte Usb 2.0 4 4 4 4 Input vide o Connettor e 15-pin MIPI CSI usato con la Raspb err y Pi camera Output Vide o HDMI (r ev 1.3), vide o comp osito TRRS 3.5 jack, MIPI display interface DSI per pannelli LCD Input A udio su boar d attrav erso porte I2S Output A udio analogico via jack 3.5mm, digitale via HDMI e su boar d I2S Storage Slot SD Micr oSDHC Ethernet 10/100 Mbit/s Wi-Fi no 802.11n wir eless Blueto oth no Blueto oth 4.1 GPIO 17 × GPIO plus the same sp ecific functions, and HA T ID bus Alimentazione 600mA (3.0W) 800 mA(4.0 W) dimensione 85.60 mm × 56.5 mm Peso 45g

(24)

La scelta per il progetto è stata a favore del Raspberry Pi 3 (Figura 2.1) che sarà indicato da questo momento come Rpi3, perché rispetto alle versioni predenti è dotato di un chip che fornisce connettività senza fili ed ha a disposizione una potenza di calcolo superiore grazie alSoC BCM2837[29].

Figura 2.1 Raspberry Pi 3

Le connettività senza fili, WiFi b/g/n[30] e Bluetooth[31], consentite dal chip BCM43438[32], eliminano la necessità di utilizzare adattatori USB[33] per le comunicazioni WiFi; inoltre, l’antenna usata si trova sul bordo esterno della scheda, fuori dalla portata di possibili interferenze causate da eventuali dispositivi e componenti aggiuntivi.

Come nelle versioni precedenti, sono presenti: • un lettore di memorie MicroSD[34];

• 17 pin GPIO, a cui è possibile collegare dispositivi aggiuntivi;

• un’interfaccia CSI, Camera Serial Interface[35], che consente di connettere una perife-rica di input video;

• una porta Ethernet 10/100 Mbit, che condivide il bus con quattro porte USB. L’alimentazione avviene attraverso una porta MicroUSB[36].

(25)

2.2 General Purpose Input/Output 9

Nel dispositivo non è presente nessun tipo di memoria di massa ma è possibile far avviare il sistema attraverso una MicroSD, inserita in un apposito lettore, dove all’interno c’è una partizione con sopra il firmware, il kernel e la configurazione del sistema.

Questa piattaforma hardware risulta ideale per lo sviluppo di un sistema IoT perché, oltre alle piccole dimensioni, all’elevata capacità di calcolo, alla possibilità di utilizzare reti senza fili e collegare componenti aggiuntivi, è stata progettata per funzionare con diversi sistemi operativi: Linux Raspian, RiscOS[37] e Windows Core Iot[38]. Per questo progetto su Rpi3, verrà installato Raspian, una distribuzione Linux pensata per Raspberry Pi, e non sarà utilizzato Windows Core Iot perché questa versione di Windows richiede che i componenti software realizzati per utilizzare .NET Framework[39], siano compilati in modo nativo, modalità ancora non supportata dal compilatore F# di Microsoft[40].

2.2 General Purpose Input/Output

Nel System On a Chip[41], SoC, installato sul Rpi3, sono presenti 54 linee GPIO[42] e, di queste linee, molte in Rpi3 sono riservate ai diversi componenti presenti nella scheda, come il lettore di schede MicroSD, l’uscita audio, l’ingresso CSI, l’uscita DSI[43] e i vari LED di stato.

I GPIO che interessano di più sono quelli che si trovano nel pettine da 40 pin, visibile nella scheda su due linee da 20 pin, che forniscono il supporto per SPI, I2C[44], PWM[45] e UART Seriale[46]. La numerazione di questi pin avviene dall’alto in basso e da sinistra a destra, e il primo pin viene indicato sulla scheda per facilitarne l’individuazione.

Inizialmente tutti i pin sono impostati a GPIO, a parte i GPIO 14 e GPIO 15 che sono inizializzati per l’utilizzo di UART, ma via software anche questi possono essere riconfigurati a GPIO: in totale possono essere utilizzati 17 GPIO.

Per motivi di architettura, la numerazione GPIO cambia rispetto alla numerazione del pin fisico e a come le librerie utilizzate per l’accesso ai pin li numerano: con BCM ci si riferisce alla numerazione Broadcom[42] mentre con WiringPI alla numerazione prevista dalla libreria Wiring Pi[47], quindi occorre fare riferimento alla tabella 2.2 per individuare il pin associato. Inoltre, bisogna fare attenzione a lavorare con queste linee perché richiedono 3.3 V e non tollerano i 5 V; collegare qualcosa che immetta 5 volt su un pin GPIO equivale a danneggiare il SoC.

I GPIO di Rpi3 hanno una resistenza interna di pull-up, o di pull-down, che può essere azionata per garantire il livello logico di un pin di ingresso nel caso in cui si verifichi una situazione di alta impedenza o se il circuito ad esso collegato risulta aperto.

(26)

Tabella 2.2 General Purpose Input/Output

BCM WiringPi Function Pin Fisico Function WiringPi BCM

3.3v 1 2 5v 2 8 i2c 3 4 5v 3 9 i2C 5 6 GND 4 7 7 8 UART 15 14 GND 9 10 UART 16 15 17 0 11 12 PWM 1 18 27 2 13 14 22 3 15 16 4 23 3.3v 17 18 5 24 10 12 SPI 19 20 9 13 SPI 21 22 6 25 11 14 SPI 23 24 SPI 10 8 GND 25 26 SPI 11 7 0 30 I2C 27 28 I2C 31 1 5 21 29 30 6 22 31 32 PWM 26 12 13 23 PWM 33 34 19 24 35 36 SPI 27 16 26 25 37 38 SPI 28 20 GND 39 40 SPI 29 21

(27)

2.3 Raspberry Camera 11

Ogni GPIO supporta gli interrupt che possono essere di una delle seguenti tipologie: high, low, rise, fall e change.

Nel kernel ufficiale di Linux non è presente la possibilità di utilizzare questi interrupt ma esiste una patch che li abilita[48]. Per poter sfruttare gli interrupt GPIO senza applicare le patch al kernel, utilizzerò la distribuzione Raspbian che include il kernel con il supporto degli interrupt.

2.3 Raspberry Camera

Tramite la porta CSI, posta sulla scheda, è possibile collegare una camera a Rpi3, come mostrato nella Figura 2.2. Questa piccola camera, venduta dalla Raspberry Pi Fondation, consente, grazie al sensore CMOS IMX219PQ Sony da 8 megapixel[20], di scattare fotografie digitali di alta qualità e realizzare video in alta definizione con modalità 1080p30, 720p60 e VGA90.

Figura 2.2 Raspberry Camera

Esistono due versioni di questa camera: una con filtro ad infrarosso per le immagini diurne e l’altra indicata con NoIR senza il filtro infrarosso che permette di realizzare immagini notturne.

(28)

In Raspian i principali comandi che permettono di utilizzare la Raspberry Camera sono i seguenti tre:

1. raspi-config[49] è lo strumento di configurazione di Raspberry Pi, che permette

anche di abilitare l’interfaccia CSI per l’uso della Raspberry Camera;

2. raspistill[24] è un comando che cattura delle fotografie con il modulo telecamera

e le salva su un file;

3. raspivid[25] permette di registrare un video e salvarlo su un file.

Il primo comandoraspi-configva lanciato soltanto in fase di configurazione del sistema

per abilitare la camera, mentreraspistilleraspividverranno utilizzati nel progetto

per acquisire immagini e filmati. Questi comandi, per essere utilizzati, richiedono elevati diritti di esecuzione.

2.4 L298N Motor Controller

Si tratta di un modulo elettronico, basato sull’integrato L298[23], che sarà utilizzato per pilotare motori. Così come mostrato nella Figura 2.3, è possibile utilizzare questo circuito utilizzando la seguente interfaccia:

• quattro connettori laterali ai quali collegare i motori: 1. MOTORA+: polarità positiva motore A;

2. MOTORA-: polarità negativa motore A; 3. MOTORB+: polarità positiva motore B; 4. MOTORB-: polarità negativa motore B; • tre connettori per l’alimentazione:

1. POWER: la linea con la quale è possibile alimentare i motori; 2. GND: la massa;

3. 5VOUT: quando il modulo è alimentato a 12 volt, è possibile prelevare una tensione a 5 volt per alimentare altri componenti;

• tre jumper:

1. J12V: consente di regolare l’alimentazione del modulo a 5V, da rimuovere se si utilizza una tensione di alimentazione superiore a 12V DC;

(29)

2.5 HC-SR04 13

2. ENA: abilita o meno il motore A oppure determina la potenza se viene applicato un segnale di tipo PWM;

3. ENB: idem a ENA ma per il motore B; • quattro connessioni logiche:

1. IN1: connessione logica A per motore A; 2. IN2: connessione logica B per motore A; 3. IN3: connessione logica A per motore B; 4. IN4: connessione logica B per motore B.

Se i jumper ENA e ENB sono presenti, la tensione d’uscita connessa ai motori dipenderà dai quattro stati logici di IN1, IN2, IN3 e IN4, come mostrato nella tabella 2.3.

Tabella 2.3 Configurazione controllo motori

IN1 IN2 IN3 IN4 motorA motorB rover

0 0 0 0 stop stop stop

0 0 0 1 stop backward

-0 0 1 0 stop forward

-0 0 1 1 stop -

-0 1 0 0 backward stop

-0 1 0 1 backward backward backward

0 1 1 0 backward forward turn left

0 1 1 1 backward -

-1 0 0 1 forward backward turn right

1 0 1 0 forward forward forward

1 0 1 1 forward - -1 1 0 0 - stop -1 1 0 1 - backward -1 1 1 0 - forward -1 1 1 1 - -

-2.5 HC-SR04

Il sensore ad ultrasuoni HC-SR04[22] emette un impulso ad ultrasuoni e calcola il tempo impiegato dall’impulso per raggiungere il primo ostacolo di fronte a lui e tornare indietro.

(30)
(31)

2.5 HC-SR04 15

Figura 2.4 Il sensore ad ultrasuoni hc-sr04

Come si può vedere nella Figura 2.4, il sensore, oltre ad essere composto dall’emettitore e dal ricevitore, dispone dei seguenti 4 pin:

1. Vcc(+5V)

2. Trigger

3. Echo

4. GND

Il funzionamento del sensore avviene nel seguente modo:

1. il software invia un impulso high sul pinTriggerper almeno 10 microsecondi;

2. il sensore invia il ping sonoro e aspetta il ritorno delle onde riflesse;

3. il sensore risponderà sul pinEchocon un impulso high della durata corrispondente a

quella di viaggio delle onde sonore.

Conoscendo la velocità di propagazionevar i adel suono nell’aria[50] e il tempot, che passa

dall’invio del segnale al Triggeralla ricezione del segnale Echo, è possibile stabilire la

distanzadeo fra il sensore e l’ostacolo grazie all’equazione della velocità var i a=

s t

(32)

dove s è la somma della distanza tra emettitore-oggetto deo e della distanza

oggetto-ricevitoredor.

Considerandodeo= dor, avrò ches = 2 · deo, quindi la formula per ottenere la distanza sarà

deo=

var i a· t 2

C’è da notare che nell’aria, la velocità del suono è di 331,45 m/s a0oC (pari a 1 193,04

km/h) e di 343,8 m/s (pari a 1 237,68 km/h) a20oC (in generale varia secondo la relazione var i a= 331, 45 + 0, 62 · vδconla misura inoC della temperatura). Considerando che il

rover lavorerà in un ambiente chiuso climatizzato, è possibile ipotizzare una temperatura di circa20oC quindi unavar i a di 343,8 m/s.

quindi la formula sarà

deo=343, 8 · t 2

Se il tempo risulta maggiore di 38 microsecondi, si considera che non sia stato incontrato nessun ostacolo e per sicurezza si aspettano 50 microsecondi per fare in modo che non ci siano interferenze con la misura successiva.

2.6 Altri componenti hardware

Nella realizzazione del progetto, oltre a quelli descritti precedentemente, sono stati utilizzati anche i seguenti componenti:

Chassis su cui sono installati il Raspberry e tutti i componenti per il funzionamento del rover. Figura 2.5.

breadboard in italiano "basetta sperimentale". Permette di riprodurre il comportamento di un circuito stampato senza richiedere saldatura di componenti, per cui è possibile semplicemente inserire i componenti nei fori predisposti sulla board. La basetta che sarà utilizzata ha 830 fori. Come è possibile vedere nella Figu-ra 2.6, questo tipo di board ha due linee di punti lateFigu-rali che corrono sui due lati per tutta la lunghezza della breadboard. Tutti i punti di una stessa linea sono connessi tra loro. Queste quattro linee laterali saranno utilizzate per la distribuzione dell’alimentazione e la massa. Invece, le linee di punti interne della breadboard sono collegate a gruppi di due: i due gruppi sono divisi da una scanalatura centrale ed ognuno è composto da 5 punti collegati tra loro.

(33)

2.6 Altri componenti hardware 17

Figura 2.5 Rover Chassis con ruote, vano batteria

(34)

Tutti i punti della basetta hanno una distanza di 2.54 mm tra loro e sono contrassegnati da un numero o da una lettera per facilitare la lettura della posizione.

T-cobbler questo componente è utilizzato per facilitare la costruzione e il testing. Per-mette grazie ad un cavo piatto a 40 pin di connettere Rpi3 alla breadboard. Questo consente di accedere ai pin del Raspberry Pi direttamente nella basetta sperimentale, semplicemente utilizzando dei jumper di vari colori e lunghezze per collegare i vari elementi: la Figura 2.7 mostra questi oggetti.

Figura 2.7 I jumper, Cavo 40 Pin e T-Cobbler

LED Light Emitting Diode, in italiano "diodo a emissione di luce", è un tipo di componente che può trasformare l’energia elettrica tramite giunzione P-N. Quando al LED viene fornita una tensione di 2v-3v, questo lampeggerà solo se la corrente fluisce in avanti. Il LED di solito emette luce se alimentato con corrente 5mA-30mA, e in genere viene utilizzato con 10mA-20mA. Quindi, per evitare un sovraccarico, è necessario collegarlo ad una resistenza. Questo componente ha un orientamento, infatti le due estremità di collegamento hanno lunghezze diverse. Il catodo (-) è più corto, mentre l’anodo (+) è più lungo.

(35)

2.7Mono 19

Button è un pulsante collegato ad un GPIO di input. Se il tasto viene premuto, fa passare lo stato del GPIO a low, mentre quando non è premuto passa ad high.

2.7

Mono

Monoè un progetto opensource coordinato da Xamarin, azienda che dal 2015 è diventata

sussidiaria di Microsoft[51], che ha lo scopo di realizzare un insieme di strumenti compatibili con il .NET Framework di Microsoft ed aderenti allo standard ECMA Common Language Infrastructure(CLI) anche per ambienti non Windows.

La specifica CLI è divisa in quattro parti:

1. il Common Type System o CTS: un insieme di tipi dato e di operazioni su essi; 2. i Metadata: le informazioni sulla struttura del programma. Esse sono indipendenti

dal linguaggio di partenza per permettere a programmi scritti in linguaggi differenti di comunicare tra loro;

3. la Common Language Specification o CLS;

4. il Virtual Execution System o VES: il sistema che esegue i programmi CLI.

L’implementazione VES di .NET è chiamata Common Language Runtime o CLR, e questo acronimo sarà utilizzato durante la trattazione della tesi come sinonimo per indicare VES.

Un programma scritto in un linguaggio ad alto livello, C# oF#, in fase di compilazione

viene tradotto in istruzioni di tipo Common Intermediate Language (CIL), linguaggio in-termedio indipendente dalla piattaforma, e successivamente, come mostrato in Figura 2.8, un VES specifico per la piattaforma traduce le istruzioni CIL in linguaggio macchina, cioè direttamente comprensibile dal processore della piattaforma. Il progetto Mono implementa sia VES per l’esecuzione dei programmi .NET su diverse piattaforme sia compilatori per diversi linguaggi di programmazione: tra le VES implementate c’è anche quella per Linux su processori x64 ARM; tra i compilatori di linguaggi implementati da Mono c’è sia il compilatore perC#che quello perF#, che verranno utilizzati in questo progetto.

2.8

Raspberry#

Nel progetto saranno utilizzate le seguenti due librerie rilasciate dalla communityRaspberry#,

che consentono di utilizzare le funzionalità di Raspberry Pi in ambiente .Net/Mono, quindi utilizzabili sia con il linguaggioC#che con il linguaggioF#:

(36)
(37)

2.8Raspberry# 21

Raspberry.IO.GeneralPurpose: contiene classi che permettono di utilizzare

l’hard-ware GPIO, il cui accesso richiede elevati privilegi di esecuzione e, per ottenerli, i programmi che utilizzeranno queste funzionalità dovranno essere seguiti, sotto Raspian, usando il comandosudo[52];

Raspberry.System: offre delle funzionalità di utilità per il sistema Rpi, come la

rilevazione automatica del modello e l’implementazione di timer ad alta risoluzione. InRaspberry.IO.GeneralPurposesono presenti tre driver per accedere a basso livello

all’hardware GPIO:

MemoryGpioConnectionDriver: accede ai pin GPIO attraverso il loro indirizzo di

memoria;

GpioConnectionDriver: accede ai pin GPIO attraverso il loro indirizzo di memoria

e, in più, utilizza un meccanismo di pseudo-interrupt per individuare il cambiamento di stato del pin;

FileGpioConnectionDriver: questa implementazione usa, invece, i file virtuali per

accedere ai pin GPIO.

Tutti questi driver sono implementazioni dell’interfacciaIGpioConnectionDriver, che

definisce i seguenti cinque metodi:

1. void Allocate(ProcessorPin pin, PinDirection direction);

Alloca un pin: attiva il pin in base al numero di pin dato e alla direzione. Parametri:

• pin: il pin, numerazione BCM.

• direction: la direzione del pin direction, che può assumere valori PinDirection.InputoPinDirection.Output.

2. void SetPinResistor(ProcessorPin pin, PinResistor resistor);

Abilita la resistenza pull-up/down di un pin di ingresso. Parametri:

• pin: il pin, numerazione BCM.

(38)

3. void Release(ProcessorPin pin);

Rilascia un pin; si smette di utilizzare il pin specificato nel parametro. Parametro:

• pin: il pin, numerazione BCM.

4. bool Read(ProcessorPin pin);

Legge lo stato corrente del pin di input specificato come parametro. Il valore di ritorno è un booleano e rappresenta lo stato del pin.

Parametro:

• pin: il pin, numerazione BCM.

5. void Write(ProcessorPin pin, bool value);

Aggiorna lo stato del pin specificato con il valore dato. Parametri:

• pin: il pin, numerazione BCM.

• value: il nuovo valore booleano del pin.

E’ possibile ottenere un maggiore livello di astrazione dell’hardware con i seguenti due metodi, definiti come estensione dell’interfacciaIGpioConnectionDriver:

1. public GpioOutputBinaryPin Out(ProcessorPin pin);

Dato unProcessorPin, ritorna l’interfacciaIOutputBinaryPin.

Parametro:

• pin: il pin, numerazione BCM.

2. public GpioInputBinaryPin In(ProcessorPin pin);

Dato unProcessorPin, ritorna l’interfacciaIInputBinaryPin.

Parametro:

(39)

2.9Node.js 23

Sull’interfacciaIInputBinaryPinè presente un metodo che sarà molto utile per utilizzare

il sensoreHC-SR04:

public TimeSpan Time(bool waitForUp, TimeSpan phase1Timeout, TimeSpan phase2Timeout);

Questo metodo attende che il pin raggiunga un determinato stato, quindi misura il tempo che rimane in questo stato.

Parametri:

• waitForUp: se è impostato a true, aspetta che il pin sia in high.

• phase1Timeout: il timeout della prima fase.

• phase2Timeout: il timeout della seconda fase.

Il valore di ritorno è la durata dell’intervallo tra le due fasi, quindi il tempo che il pin rimane in high.

Infine nel packageRaspberry.Systemverrà utilizzatoTimer.Sleep(TimeSpam), un

me-todo che implementa un timer ad alta risoluzione.

2.9

Node.js

Node.jsè un ambiente di esecuzione Javascript opensource, disponibile per molte

archi-tetture. Questa piattaforma, basata sul Javascript Engine V8[53] di Google, ha lo scopo di implementare processi server-side.

Un processo Node.js non si basa sul multithreading per consentire l’esecuzione simultanea di più flussi di esecuzione ma su un modello Event-driven di eventi I/O asincroni[54]. Grazie alla sua architettura, quasi nessuna funzione in Node.js effettua direttamente

operazioni di I/O.

Come è possibile vedere dalla Figura 2.9, nel momento in cui viene fatta un’operazione di questo tipo,Node.jstrasferisce la chiamata su un thread disponibile nel suo thread-pool, e

non blocca il flusso principale che potrà continuare la sua esecuzione. Quando l’operazione collegata al thread sarà terminata, questo potrà ritornare ad essere a disposizione del processo principale.

(40)
(41)

2.9Node.js 25

Per semplificare l’utilizzo di questo modello asincrono, ogni funzione che richiede un I/O sarà del tipo:

function (... parameters ..., callback)

La function, dopo aver richiesto un’operazione di I/O, restituisce il controllo al flusso

di esecuzione senza attendere il termine dell’operazione e lacallbacksarà invocata nel

momento in cui le operazioni richieste dallafunctionsaranno terminate.

Nella trattazione corrente,Node.jsverrà usato come ambiente di esecuzione per lo sviluppo

in Javascript di un servizio che implementa una REST API. La scelta di questa piattaforma è motivata da tre fattori:

• la possibilità di utilizzare meccanismi asincroni per gestire richieste HTTP;

• la disponibilità di installarlo su molte architetture e piattaforme, tra cui Windows e Raspbian, che sarà sfruttata nella fase di test e nell’implementazione del progetto; • l’esistenza di un vasto archivio di codice facilmente integrabile attraverso pacchetti

grazie allo strumentonpm[55], Node Package Manager, incluso nell’installazione di Node.js.

Nel progetto saranno utilizzati diversi pacchetti provenienti da questo repository, tra cui: • Express.js[56]: mette a disposizione dei Router, sui quali è possibile definire rotte, ed

endpoint dei servizi. Il loro uso è molto semplice per il metodo HTTP GET, come si può vedere nel seguente esempio:

var express = require('express');

var router = express(); router.get(PATH,HANDLER);

dove:

– PATH: una stringa che definisce la rotta. Può contenere parametri ed espressioni

regolari.

– HANDLER: una funzione che viene eseguita se richiesta una risorsa che coincide

con quella definita daPATH. In ingresso arrivano gli oggetti che rappresentano

larequeste laresponse.

• node-telegram-bot-api[57]: aiuta ad interfacciarsi al servizio Telegram. • cognitive-services[58]: semplifica l’utilizzo dei Cognitive Service.

(42)

2.10 Telegram API Bot

Telegram[5] è un servizio di messaggistica istantanea. I client ufficiali di Telegram sono distribuiti come software libero per diverse piattaforme. Caratteristiche di questo servizio sono la possibilità di stabilire conversazioni cifrate punto-punto, scambiare messaggi vocali, fotografie, video, stickers e file, di qualsiasi tipo, grandi fino a 1,5 GB.

Questo servizio offre la possibilità di creare dei Bot, chat che possono essere controllate da un software.

Per consentire questo, Telegram rende disponibile agli sviluppatori una REST API per integrare le loro funzionalità negli applicativi.

Come accennato precedentemente, per semplificare l’utilizzo di questo servizio, verrà utilizzato il pacchetto node-telegram-bot-api disponibile nel repositoryNPM.

Quindi, per utilizzare questa funzionalità di creazione dei Bot inNode.js, unTelegramBot

sarà creato nel seguente modo, dopo aver richiamato il pacchetto:

var TelegramBot = require('node-telegram-bot-api');

var bot = new TelegramBot(telegram_key, {polling: true});

dove:

telegram_keyè il codice di autorizzazione per il bot,

{polling:true}l’oggetto controlla automaticamente la presenza di messaggi nella

chat.

Nel corso del progetto, utilizzerò i sequenti quattro metodi offerti daTelegramBot:

1. bot.on(’message’, HANDLER);

Permette di associare l’esecuzione della funzioneHANDLERall’evento della ricezione di

un messaggio nella chat. Questa funzione avrà in ingresso il contenuto del messaggio rilevato nella chat.

2. bot.sendMessage(idchat,message);

Invia alla chat, identificata daidchat, il contenuto testuale contenuto in messagge.

3. bot.SendPhoto(idchat,filename,{caption:description});

Invia alla chat l’immagine contenuta nel file filename: i formati accettati sono PNG e JPEG;{caption:description}permette di mettere un titolodescription

(43)

2.11 Microsoft Cognitive Service 27

4. bot.SendVideo(idchat,filename,{caption:description});

Invia alla chat un video contenuto nel filename in formato H264[59];

{caption:description} permette di mettere un titolo descriptional video da

mostrare nella fase di visualizzazione della chat.

2.11 Microsoft Cognitive Service

Cognitive Service è un insieme di servizi cloud, offerti da Microsoft, che permettono di aggiungere alle applicazioni delle funzionalità che abilitano la comprensione del mondo che le circonda.

Nel progetto saranno utilizzati i servizi Cognitive Service che rientrano nella categoria Vision Servicese che permettono di analizzare immagini o video alla ricerca di informazioni. Il Computer Vision offre agli sviluppatori l’accesso ad algoritmi avanzati per l’elaborazione di immagini e il recupero di informazioni associato alle immagini processate.

L’endpoint URL per utilizzare l’API è il seguente:

https://westcentralus.api.cognitive.microsoft.com/vision/v1.0

L’immagine da processare andrà inviata come body di una richiesta POST come

multipart/form-data, e, per essere elaborata dal servizio, dovrà essere:

• in formato JPEG,PNG,GIF e BMP; • di dimensione meno di 4MB;

• con una risoluzione maggiore di 50x50 di pixel.

La risposta restituisce, in formato JSON[60], le seguenti informazioni:

• un insieme ditagdegli oggetti riconosciuti nell’immagine, non soltanto nel soggetto

principale ma anche negli oggetti in secondo piano.

• una descrizionecaptionscioè una frase in inglese che descrive il contenuto

dell’im-magine e laconfidenceassociata alla descrizione.

Ogni tag ed ogni captions avrà associata nella risposta un valore di stima tra 0 e 1,

chiamata confidence: più questo valore si avvicinerà ad 1, più si avrà la certezza che

l’informazione associata sia corretta.

(44)

curl -k -v -X POST "https://westcentralus.api.cognitive.microsoft.com/vision/v1.0" -H "Content-Type: multipart/form-data" -F "body=@./polarbear.jpg"

Description { "type": 0, "captions": [ { "text": "a polar bear in the snow", "confidence": 0.76316301841105 } ] }

Tags [ { "name": "polar", "confidence": 0.9993528723716736 }, { "name": "snow",

"confidence": 0.9992809891700745 }, { "name": "mammal", "confidence": 0.9958090782165527, "hint": "animal" }, { "name": "outdoor", "confidence": 0.9908333420753479 }, { "name": "animal", "confidence": 0.9869094491004944 }, { "name": "white", "confidence":

0.9018636345863342 }, { "name": "bear", "confidence": 0.5099555253982544, "hint":

"animal" }, { "name": "hillside", "confidence": 0.10757798701524734 } ]

(45)

2.12MLCoda 29

2.12

ML

Coda

MLCodaè un linguaggio di programmazione orientato al contesto, cioè consente con alcuni costrutti di adattare il programma al contesto in cui viene eseguito.

Il contesto è l’ambiente in cui le applicazioni vengono eseguite ed è un concetto fondamen-tale per il software adattivo e che può essere visto come composto da due parti:

• il contesto di sistema, che è la parte indipendente dall’applicazione, ad esempio l’hard-ware su cui viene eseguito l’applicativo e l’ambiente fisico con cui il sistema può interagire;

• il contesto applicativo, che è dipendente dall’applicazione, come possono essere delle configurazioni utente.

Entrambe le parti inMLCodasono rappresentate e gestite in maniera omogenea. Come è possibile vedere dalla Figura 2.11,MLCodaè composto da due componenti:

• una dichiarativa, che permette di definire il contesto attraverso la scrittura di codice Datalog[26], che in fase di compilazione viene trasformato dal compilatoreypc[61]

in codice C#;

• una funzionale, attraverso il linguaggio F# arricchito con alcuni statement[28], ag-giunti a tempo di esecuzione attraverso tecniche di metaprogrammazione[62], che consentono di modificare e interrogare il contesto.

Questi due componenti favoriscono l’indipendenza tra la definizione del contesto e la Business Logic[63] dell’applicazione. Sia il compilatoreypcche gli statement aggiunti da MLCodasi basano sulla libreria .NET chiamataYieldProlog[64].

2.12.1

DataLog

Il linguaggio Datalog permette di definire clausole secondo la seguente forma:

P0: −P1, P2, ...Pn

OgniPi è chiamato letterale ed è un nome seguito da un elenco di termini separati da una

virgola messi tra parentesi, dove un termine può essere una variabilev o una costantec.

Le clausole possono essere composte da una testa, head, e da un corpo opzionale, body. Il segno:-separa la testa,P0, dal corpo della regola,P1, P2, ...Pn.

Quando non è presente il corpo, la clausola definisce un fatto, fact, mentre, quando è presente, definisce una regola, rule. Nel corpo è possibile negare il letterale usando il segno

(46)

\+. Una clausola è safe quando ogni variabile nella testa è presente in qualche letterale del

suo corpo. La conoscenza del sistema, Knowledge Base, sarà definita da un insieme di regole e fatti.

2.12.2

F#Coda

La componente funzionale , che verrà chiamataF#Coda, estendeF#con alcune istruzioni

che permettono di modificare e interrogare la Knowledge Base definita in Datalog. Per modificare il contesto, è possibile utilizzare i seguenti due comandi:

1. tell <| P

Aggiunge il fattoPnel contesto e quindi nella conoscenza del sistema.

2. retract <| P

Ritratta il fattoPdalla Knowledge Base del sistema, e lo rimuove dal contesto.

Per interrogare il contesto sono presenti i seguenti tre comandi:

1. let x = expression1 |- Goal [in] expression2

xassume il valore dell’expression1che rende vero ilGoalnel contesto attuale:Goal

è un letterale dove possono essere presenti variabili del contesto, queste variabili sono indicate con il prefissoctx?.

Nella valutazione diexpression1potranno essere usate le variabili di contesto che

verificanoGoal.

2. match ctx with | _ when !- Goal -> expression

Questa istruzione, che esplicitamente con ctx fa riferimento al contesto, valuta

l’expressionse ilGoalè vero.

(47)

2.12MLCoda 31

Itera la valutazione diexpressionsu tutte le soluzione diGoal. Anche qui le variabili

di contesto saranno indicate con prefisso ctx?, e potranno essere utilizzate nella

risoluzione diexpression. Questo statement genera eccezioni quanto il Goal non è

definito nel contesto oppure se durante l’iterazione viene modificato.

Attributi Per utilizzareF#CodadiMLCoda, è necessario utilizzare degli attributi nel mo-mento della scrittura del codice; gli attributi sono i seguenti quattro:

1. [<CoDa.Code>]

Il codiceMLCodadeve essere contrassegnato con questo attributo, altrimenti viene sollevata un’eccezione quando sono invocate le istruzioni. Questo attributo è un alias diCore.ReflectedDefinitionAttribute, che segna moduli e componenti

utilizzati in fase di esecuzione attraverso la reflection[65].

2. [<CoDa.Context(context1)>]

Descrive context1 come parte necessaria per l’applicazione.

3. [<CoDa.ContextInit>]

Questo attributo indica quale parte del codice inizializza il contesto.

4. [<CoDa.EntryPoint>]

La funzione marcata da questo attributo viene avviata dalla funzione run() (o debug()) che viene lanciata al momento dell’avvio dell’applicazione scritta inMLCoda.

2.12.3 Toolchain

MLCoda

Un programma scritto inMLCodaha bisogno di un processo di compilazione ben preciso nel quale è possibile individuare i seguenti passi:

1. Il codice Datalog viene processato da un compilatore chiamatoypc, basato sulla

libreria YieldProlog[64] che funge da motore Datalog, che genera un codice C#

(48)

2. Il codiceC#generato nella fase precedente viene compilato per ottenere una libreria

Dinamic Link Library, DLL, che contiene le primitive che potranno essere usate per modellare il contesto nell’applicativoF#Coda. In questo modo l’interazione tra

l’applicazione e il contesto sono completamente trasparenti poiché viene utilizzato il CLR/.Net in entrambe le componenti.

3. Il codice F# edF#Codaviene compilato dal compilatoreF#e linkato aCoda.dlle alla

DLL generata nella fase precedente

Il codice risultante sarà un eseguibile che utilizzerà la libreria di contesto,Coda.dllche

a loro volta utilizzeranno YieldProlog. La parte funzionale di MLCoda che estende F#

viene implementata tramite la compilazione Just In Time, JIT: quando viene eseguita una funzione annotata conCode.Code, viene richiamato il runtimeMLCodaper attivare la fase di compilazione.

Per implementare il processo di costruzione dell’applicativoMLCodaverranno utilizzati gli strumenti e formati offerti da Microsoft utilizzabili attraversomsbuild[66] in ambiente

Windows e su Raspian con il comando omologoxbuild[67]:

• L’insieme dei progetti è definito da un file Solution,.sln[68];

• File progetto[69]csprojper codiceC#;

• File progettofsprojper codiceF#;

• Le dipendenze di ogni progetto saranno indicate in un filepackages.configgestite

(49)

2.12MLCoda 33

(50)
(51)

Capitolo 3

Architettura Software

In questo capitolo, verrà descritta la realizzazione di un piccolo robot rover, la cui logica sarà implementata da un software adattivo, scritto inMLCoda.

Inizialmente verrà mostrata l’architettura del sistema software che sarà composto da tre componenti distinti, e la possibilità di definire degli ambienti di sviluppo,test e produzione che questa architettura mi consente di realizzare.

Nella parte successiva verranno dettagliati i tre componenti software:

1. rpi-roveril componente che interagisce direttamente con l’hardware;

2. rpi-service.jsil layer di astrazione che verrà usato dal componente adattativo;

3. fsc-roveril software adattivo che implementa la Business Logic del sistema.

Nel capitolo successivo sarà mostrato il funzionamento delfsc-roverdurante una sessione

di test.

3.1 Componenti

Il sistema software sarà composto da tre sottosistemi distinti secondo un’architettura n-Tier[71]:

• rpi-rover: un software a linea di comando, sviluppato in C#, che interagisce

direttamente con l’hardware ed utilizzerà le librerieRaspberry#;

• rpi-service.js: un servizio che espone delle API che consentono di interagire con

i comandi della fotocamera e conrpi-rover, ed offre funzionalità di API Gateway

(52)
(53)

3.2 Ambiente di Sviluppo, Test e Produzione 37

• fsc-rover: il demone, realizzato inMLCoda, che implementa la logica del sistema e sfrutta le API messe a disposizione darpi-service.jsper interagire con l’hardware

e i servizi cloud.

Ogni componente sarà configurabile con un apposito file in formato JSON, che conterrà informazioni per la configurazione dell’ambiente su cui verrà eseguito. Questa caratteristica risulterà molto utile in fase di sviluppo e di test.

3.2 Ambiente di Sviluppo, Test e Produzione

Il servizio, implementato da rpi-service.js, svolge la funzione di collegamento tra fsc-rover, i servizi cloud e le funzionalità GPIO di Raspberry Pi. Questa architettura

permette sia di svincolarsi dall’hardware Rpi3 sia di semplificare il processo di sviluppo e test.

(54)

Durante lo sviluppo del sistema saranno utilizzati due ambienti:

• ambiente di produzione, Rpi3 con sistema operativo Raspian, dove saranno presenti, oltre a tutti i componenti hardware necessari per il funzionamento del rover, anche l’ambiente di esecuzione necessario perNode.jseMono;

• ambiente di sviluppo, Windows 10 Pro, dove verrà utilizzato lo strumento di sviluppo Microsoft Visual Studio[72], per scrivere e testare il codiceC#edF#, eNode.jsper

eseguirerpi-service.js.

In una prima fase, lo sviluppo e il debug dirpi-service.jsefsc-roverpotranno essere

direttamente eseguiti sull’ambiente di sviluppo di Windows, sfruttando lo script Batch

simcmd.bat[73](codice sorgente C.1) per simulare i comandi che interagiscono con

l’hard-ware. Mentre, per quanto riguardarpi-rover, a causa dell’utilizzo dell’hardware, dovrà

essere testato direttamente sull’ambiente di produzione.

Successivamente in una seconda fase, come mostrato dalla Figura 3.2, quando i componenti

rpi-service.jserpi-roversaranno completati, il debug e il test difsc-roverpotranno

continuare nell’ambiente di sviluppo facendolo puntare alrpi-service.jsdell’ambiente

di produzione.

3.3 rpi-rover

rpi-roverè un applicazione console, realizzata inC#, che utilizza le librerieRaspberry#

per il controllo, attraverso le porte GPIO , i led, i bottoni, i motori e il sensore HR-SR04, che possono essere installati sul Raspberry Pi.

Questa è l’interfaccia a linea di comando che il programma offre all’utente:

rpirover [led <numled> on|led <numled> off|button <numbtn> | motor <action>|uds]

dove:

• ledaccende il led indicato dalnumledse seguito daonaltrimenti lo spegne;

• buttonlegge lo stato del bottone indicato dalnumbtne restituisce1se è premuto

altrimenti mostra0a console;

• motorpermette di controllare i motori, doveactionspecifica per quale attività:

– forwardper procedere in avanti,

(55)

3.3 rpi-rover 39

– leftper girare a sinistra,

– rightper svoltare a destra,

– stopper fermarsi;

• udsrestituisce nell’output della console la distanza in centimetri dall’ostacolo.

Il programma, ogni volta che viene invocato con un’opzioneledomotor, dopo aver eseguito

l’operazione, restituisce a console il messaggioOKe si chiude.

Il punto di ingresso, cioè il punto in cui il controllo del programma inizia e termina, è costituito dal metodoMain, come mostrato dal codice sorgente C.2 e C.3.

Questo metodo ha come parametrostring[] args, contenente gli argomenti da riga di

comando passati all’applicativo via console:args[0]sarà il primo argomento passato al

comandorpi-rover,args[1]il secondo e così via.

La prima operazione che ilMainesegue è l’invocazione di un metodo statico della classe Configuration. Una volta richiamato questo metodorpi-rover, avrà le informazioni

necessarie per l’esecuzione del comando invocato.

La classeConfiguration, codice sorgente C.4, definisce una serie di metodi che consentono

di leggere il file di configurazionerpi-rover.json, che descrive quali pin fisici GPIO di

Rpi3 saranno utilizzati per controllare le periferiche collegate: nella tabella 3.1 si possono trovare i nomi e la descrizioni dei valori che sono contenuti in questo file.

Tabella 3.1 Valori contenuti in rpi-rover.json

Nome Tipo Descrizione

led int[] led[i] = pin usato dal led i

button int[] button[i] = pin usato dal button i motor int[4] Motor[0] = pin A motore sinistro motor[1] = pin B motore sinistro motor[2] = pin A motore destro motor[3] = pin B motore destro uds int[2] uds[0]=pin echo

uds[1]=pin trigger

timestep float tempo di attesa in secondi dopo comando motor

NelMain, successivamente, unoswitchcontrollaarg[0]se è uno dei seguenticase: led: istanzia un oggettoLed, identificato dal numero specificato daarg[1].

Come si può vedere dal codice sorgente C.5, il costruttoreLed(int pin)istanza

(56)

pin), converte ilpindi tipointin unProcessorPinche viene allocato come PinDirection.Output.

Seargs[2] contieneon, sarà invocato il metodoon()dell’oggettoLed,

altri-menti sarà invocato il metodooff(), e al termine dell’esecuzione restituisceOK

a console;

button: crea un Button con la configurazione identificata da args[1] e richiama il

metodoreadper leggere l’output del pin. Se lo stato èhigh, ritorna1, altrimenti

ritorna 0. Il costruttore Button(int pin), come mostrato dal codice C.6, a

differenza di Led, alloca ProcessorPin in PinDirection.Input e imposta SetPinResistorinPinResistor.PullUp;

motor: istanzia un oggettoTwoMotorsDriverin base alle informazioni contenute nel

fi-le di configurazionerpi-rover.jsoned attiva, in base al contenuto diargs[1],

uno dei seguenti cinque metodi: • Stop()ferma il rover;

MoveForward()attiva in avanti entrambi i motori;

MoveBackward()li aziona all’indietro;

TurnRight()comanda in avanti il motore sinistro e indietro quello destro,

questo permette al rover di girare a destra;

TurnLeft()funziona in modo complementare al metodo precedente, gira

il rover a sinistra.

Infine ilMain, dopo aver atteso un tempotimespamdefinito nella configurazione,

ferma il rover, restituisceOKnello standard output e termina.

Nel descrivere il comportamento delMain, viene fatto riferimento ad un oggetto TwoMotorsDriver(codice sorgente C.7), il cui costruttore istanzia due oggetti Motor, uno per controllare il motore della ruota sinistra e l’altro per la ruota

destra.

La classeMotor(codice sorgente C.8) modella il controllo di ognuno dei due

motori. Al momento della creazione di questo oggetto, vengono allocati 2 pin di output: PinAePinB.

Questi due pin verranno utilizzati dai seguenti tre metodi:

MoveForward()pone ilPinAa truee ilPinBa false, questo consente

(57)

3.4 rpi-service.js 41

MoveBackward() imposta il PinA a false e il PinB a true , in questa

configurazione il motore gira indietro;

Stop()quando entrambi i pin hanno valorefalse, il motore si ferma; uds: crea un oggettoUltrasonicDistanceSensorcon i pin necessari al

funziona-mento del sensore dichiarati nella configurazionerpi-rover.json.

La classeUltrasonicDistanceSensor(codice sorgente C.9) utilizza, nel

meto-dogetDistance(), le interfacceIOutputBinaryPinsutriggerPineIInputBinaryPin

suEchoPinper interagire con il sensore HR-SR04.

Il metodogetDistance()svolge le seguenti operazioni:

1. scrive un valorehighsutriggerPin,

2. dopo aver atteso un tempotriggerTime, impostatriggerPinsulow,

3. suEchoPinviene invocato il metodoTime, il cui risultato viene utilizzato

per calcolare la distanza,

4. ritorna la distanza calcolata in centimetri tra il sensore e l’oggetto che ha di fronte. Se si è verificato un errore, ripete dal punto 1.

NelMainviene richiamato due volteGetDistance(): prima per inizializzare il

sensore, poi per ottenere il risultato e mostrarlo a console; infine è invocato il metodoClose()di questa classe per disallocarepinEchoepinTrigger.

3.4 rpi-service.js

Il serviziorpi-service.jsimplementa l’API attraverso una serie di comandi accessibili

usando richieste HTTP GET[74]. Questi comandi si differenziano in tre classi di funzionalità: 1. rpi raccoglie tutte le operazioni che è possibile fare direttamente sull’hardware: attivare i motori, ottenere lo stato di un bottone, accendere LED, scattare foto e girare video;

2. telegram consente di gestire l’interazione utente attraverso una chat Telegram; 3. whatdoyousee permette di ottenere informazioni su una foto scattata

precedente-mente.

(58)

- express.js consente di semplificare la realizzazione dell’interfaccia HTTP; - fs e path permettono di gestire file e riferirsi ad essi con un path nel file system; - node-uuid viene utilizzato per generare RFC4122[75] UUID;

- child_process offre funzionalità per eseguire programmi esterni.

- node-telegram-bot-api; implementa in modo semplificato l’integrazione con Tele-gram;

- cognitive-services facilità l’utilizzo dei Microsoft Recognition Service. Al momento dell’avvio dell’applicativo vengono, svolte le seguenti attività:

1. lettura del filerpi-service.json, orpi-service-dev.jsonse viene eseguito con

il parametro -dev. Le informazioni contenuti in questo file, tabella 3.2, saranno

utilizzate per la configurazione del servizio;

2. creazione un task per l’integrazione con Telegram, utilizzo bot di node-telegram-bot; 3. avvio del server HTTP attraversoexpress.jsper gestire le richieste REST.

Tabella 3.2 Valori contenuti in rpi-service.json

Nome Tipo Descrizione

telegram_key string chiave del servizio Telegram

vision_url string URL del servizio Microsoft Compter Vision

vision_key string chiave per accedere al servizio Microsoft Computer Vision port int porta di ascolto del webservice

rover_cmd string comando che offre le funzionalità del rover photo_cmd string comando che permette di acquisire foto video_cmd string comando che permette di acquisire video vconv_cmd string path del software vconv

temp_path string directory temporanea per il salvataggio immagini e video Nella parte successiva, viene definita l’API che sarà disponibile sull’interfaccia HTTP attraverso metodi GET su risorse esposte.

(59)

3.4 rpi-service.js 43

3.4.1 REST API

Le API permettono di passare dei parametri attraverso la query string del metodo GET . Le interfacce che permettono di interagire con l’hardware Rpi3 sono le seguenti sei:

1. /rpi/motor/[action]

Viene eseguito in modo asincrono, attraverso la funzione child_process.exec,

il comando definito dal valore dirover_cmd, contenuto nel file di configurazione,

seguito dal parametromotore dall’azione specificata daaction.

rover_cmdnel sistema di produzione saràrpi-rover.exementre in quello di test

saràsimcmd.bat.

Il valore cheactionpuò assumere è uno dei seguenti:

• forwardattiva i motori per far muovere il rover avanti,

• backwardattiva i motori per far muovere il rover indietro,

• leftfa girare il rover a sinistra,

• rightfa girare il rover a destra,

• stopferma i motori.

Al termine dell’esecuzione del comando, verrà richiamata la funzione contenuta nella callback, che si occuperà di aggiornare l’output del comando oppure il messaggio di errore se non è stato possibile eseguirlo.

Il risultato restituito è l’output del comando della precedente esecuzione conclusa e non quella eseguita dalla chiamata in modo asincrono.

Il codice scritto per implementare questa API e le successive utilizza uno stile di programmazione chiamato Continuation Passing Style[76].

2. /rpi/led/[id]/[action]

Anche questa chiamata fa eseguire, in modo asincrono, il comandorover_cmd

uti-lizzato nella precedente interfaccia, con la differenza che sarà seguito dai parametri:

led,iddel LED,action. L’actionpotrà avere uno di questi due valori:

• onillumina il led;

(60)

L’output, come nel caso precedente, sarà restituito al termine dell’esecuzione del comando.

3. /rpi/button/[id]

Ritorna l’output della precedente esecuzione che ha ottenuto lo stato del bottone individuato daid:

1 se il bottoneidè stato premuto; 0 altrimenti.

4. /rpi/distance

In modo asincronorover_cmdviene eseguito con il parametrouds. In questo caso

l’output che l’interfaccia restituisce è il risultato della distanza in centimetri.

5. /rpi/photo

Permette di scattare una foto e salvarla in formato JPEG nella directory temporanea definita nel file di configurazione. Questo metodo non restituisce direttamente la foto in formato binario ma semplicemente una stringa identificativa di tipo UUID, generata dalla funzioneuuid.v4(). Questa interfaccia può prendere i seguenti parametri:

• widthlunghezza della foto in pixel,

• heightaltezza dell’immagine in pixel,

• qualitylivello di compressione, che può assumere un valore da 1 a 100, dove 1

la qualità più bassa e 100 la più alta.

Il comando che verrà eseguito sarà costruito utilizzando il valorephoto_cmd,

conte-nuto nel file di configurazione, i parametri ricevuti dall’interfaccia e l’identificativo UUID.

photo_cmdnel sistema di produzione saràraspistillmentre in quello di test sarà simcmd.bat photo.

6. /rpi/video

E’ simile alla precendente interfaccia con la differenza che gira un video e lo converte in formato H264[59]. Questa interfaccia può prendere i seguenti parametri:

(61)

3.4 rpi-service.js 45

• heightaltezza dell’immagine in pixel,

• timedurata in secondi del filmato.

In modo simile a come è implementato nell’interfaccia precedente, la funzione

video_cmdcostruisce il comando con i parametri passati e con l’identificativo UUID

generato dalla funzioneuuid.v4().

video_cmdnel sistema di produzione sarà raspividmentre in quello di test sarà simcmd.bat video.

Il file video ottenuto è uno stream video H264 ( MPEG 4 AVC ), che, per poterlo inviare a Telegram e visualizzarlo attraverso un lettore multimediale, sarà necessario convertire in un file MP4[77].

Per eseguire tale conversione, sarà utilizzato il softwareavconv[78], la cui posizione

è specificata nel valore divconv_cmddel file di configurazione.

Come nell’interfaccia precedente, restituisce un UUID che identifica un video in formato MP4.

Le interfacce che possono essere utilizzate per le funzionalità Telegram sono le seguenti: 1. /telegram/listchat

Restituisce le chat attive su Telegram. Ogni chat, identificata da un valore di tipo numerico intero, viene popolata dalbot, un oggetto di tipoTelegramBot, creato in

fase di inizializzazione all’avvio dirpi-service.js.

L’output è quindi un array di interi in formato JSON, dove ogni numero identifica una chat.

2. /telegram/broadcast

Viene inviato a tutte le chat attive il messaggio contenuto nel parametrotext. Per

svolgere questa operazione, viene invocata la funzioneSendMessagge delbotsu

tutte le chat attive. 3. /telegram/[idchat]

Restituisce le informazioni in formato JSON della chat identificata daidchat.

4. /telegram/[idchat]/next

(62)

5. /telegram/[idchat]/text

Permette di inviare alla chat, identificata daidchat, un messaggio con il testo

conte-nuto nel parametrotext, invocando la funzioneSendMessaggedelbotsulla chat

identificata daidchat.

6. /telegram/[idchat]/video

Invia alla chat, identificata daidchat, un video, presente nella directory temporanea,

identificato dal parametroidvideo. In Telegram, quando verrà mostrato il video,

sarà visualizzato con un commento testuale contenuto nel parametrotext.

7. /telegram/[idchat]/photo

Invia aidchatun’immagine, presente nella directory temporanea, identificata dal

pa-rametroidphoto. In Telegram, quando verrà mostrata l’immagine, sarà visualizzato

con un commento testuale contenuto nel parametrotext.

Infine è presente un’ interfaccia che offre la funzionalità "cognitiva" di guardare:

/whatdoyousee

Richiede al servizio Microsoft Computer Vision l’elaborazione di un’immagine , pre-sente nella directory temporanea, identificata dal parametroidphoto. Il risultato

viene restituito come output.

3.5 fsc-rover

Fsc-rover è composto dai sequenti tre componenti:

1. fsc-context: la parte dichiarativa di MLCodache definisce la Knowledge Base del sistema;

2. fsc-ctx: contiene il codice inF#delle strutture dati e delle funzioni di utilità che

verranno utilizzate dal modulo principale;

3. fsc-rover: il codice inF#Codache implementa la Business Logic del sistema.

3.5.1 fsc-context

Nel sorgente C.19fsc-context.P, codice Datalog, vengono definite una serie di fatti e di

regole, che consentono di modellare il contesto in cui opererà il sistema. Il contesto di questo applicativo definisce:

(63)

3.5 fsc-rover 47

1. la modalità di interazione remota tra l’utente e il rover; 2. l’ambiente su cui il rover opera;

3. il controllo automatico, le operazioni che il rover dovrà effettuare in autonomia al verificarsi di certe condizioni nell’ambiente.

Modalità di interazione remota.

Il software dovrà permettere agli utenti di interagire attraverso una serie di comandi semplici da scrivere in una chat ed avere la possibilità di richiamare le funzionalità di

rpi-service.js.

Per questo motivo nel sistema sono previsti due tipi di comando: 1. UsrCmd: comandi utilizzati dall’utente;

2. SysCmd: comandi che il sistema richiamerà surpi-service.js.

Ad ogniSysCmdpuò essere associata una descrizioneDesc. Per ogni utente che accede al

Bot di Telegram viene attivata una chat, identificata con un numeroIdChat. In questa chat IdChatl’utente può lanciare unUsrCmd. Ad ogniUsrCmdpuò essere associato un comando

di sistemaSysCmd.

usrcmd(UsrCmd,SysCmd)associa unUsrCmdad unSysCmd.

cmddesc(SysCmd,Desc)associa una descrizioneDescin linguaggio naturale aSysCmd.

Questa descrizione verrà mostrata all’utente alla chiamata del comandohelp. request(IdChat,UsrCmd)definisce una richiesta dove:

• IdChatè il numero identificativo della chat;

• UsrCmdè il comando utente.

result(SysCmd,Out)definisce l’associazione tra il comandoSysCmde il risultato della

sua esecuzione. Le variabili di questo fatto sono le seguenti: • SysCmdè un comando di sistema;

(64)

response(IdChat,Out)

:- request(Id,UserCmd),usrcmd(UserCmd,SysCmd),result(SysCmd,Out)

permette di associare ad una chat utente, identificata daIdChat, una rispostaOut. Il

corpo della regola definisceOutcome il risultato dellaSysCmdassociata aUserCmd

dellaIdChat.

usrcmddesc(UsrCmd,Desc)

:-usrcmd(UsrCmd,SysCmd),cmddesc(SysCmd,Desc)

consente allaUsrCmddi ottenere una descrizione Desc. Nel corpo della regola, la DescdellaSysCmdviene associata allaUserCmd.

Ambiente.

Il sistema può rilevare, nell’ambiente in cui opera, oggetti Obja cui associa un valore Valuedi rilevazione. Inoltre è possibile associare ad alcuniObjunSysCmd, il cui output

saràValuecheObjavrà nel contesto. La rilevazione sarà positiva sull’oggetto se il valore

associato sarà dentro un certo intervallo di confidenza traMineMax, estremi inclusi. objcmd(Obj,SysCmd)lega un oggettoObj, rappresentato da una stringa, ad un comando

SysCmd. Questo fatto sarà utilizzato per ottenere ilValueassociato all’Obj. recognition(Obj,Value)assegna un valore numericoValuead un oggettoObj. confidence(Obj,Min,Max)rappresenta l’intervallo numerico di confidenza per

deter-minare se è stato individuato o meno l’oggetto. Le variabili di questo fatto sono le seguenti:

• Objidentifica l’oggetto;

• Minvalore minimo dell’intervallo;

• Maxvalore massimo dell’intervallo. detected(Obj)

:-recognition(Obj,Value),confidence(Obj,Min,Max),Value>Min,Value<Max :-recognition(Obj,Value),confidence(Obj,Min,Max),Value=Min

:-recognition(Obj,Value),confidence(Obj,Min,Max),Value=Max

permettono di determinare se Obj è rilevato nel contesto: per esserlo, il Value

Riferimenti

Documenti correlati

tamente l’attenzione, non è altro che la vostra capacità di collocare tali dettagli in uno spazio interiore e immaginario senza prendere in prestito nulla dal reale, cui tutti

a)con la legge 326/2003 è stata eliminata per gli Amministratori, dipendenti e rappresentanti di società, associazioni ed enti con personalità giuridica la

legati attorno alla vita e dei leoni danzanti. La gente raccoglieva il letame celebrando gioiosamente a gran voce. Ben presto, il letame sulla strada fu raccolto del

The new Nationality Code, which has been adopted by the Greek Parliament at the end of 2004, does not even slightly move in the direction of adopting specific rules for

In addition, housing wealth effects were also estiiiiat(‘d for different age and wealth groups, as well as for positive and negative wealtli gains. The observations

Le banche popolari attuano politiche di gestione della dimensione e della qualità del patrimonio in funzione alle disposizioni fissate dalla normativa di Vigilanza, riflessa

gA (el procedere alla raccolta delle opere il Comitato ha incontrato ostacoli insormontabili: la gelosa, diffidente oculatezza con cui alcuni possessori