Capitolo 1
Navigazione autonoma
1.1 Veicolo autonomo
Questa tesi affronta una parte di un progetto più ampio riguardante la costruzione
di un veicolo autonomo. Il problema che si intende risolvere con questo progetto è
quello della navigazione autonoma.
Un veicolo equipaggiato con diversi sensori nel nostro caso telecamere, an-
tenna GPS, profondimetro LASER, piattaforma inerziale INS, encoder di posizione
sulle ruote, ecc. si troverà in questo scenario tipico: inizialmente le informazio-
ni dell'ambiente circostante saranno sconosciute o solo parzialmente note; il suo
compito sarà quello di andare dalla propria posizione iniziale ad una prefissata
posizione finale, evitando gli ostacoli, presenti all'interno dell'ambiente e rilevati
durante la navigazione, e cercando di minimizzare la distanza percorsa.
Elaborando i dati in ingresso attraverso diversi approcci e tecniche, il veicolo
deve essere in grado di costruire e aggiornare un modello virtuale dell'ambiente
circostante; noto questo modello deve calcolare una traiettoria all'interno dell'am-
biente in modo da minimizzare i rischi di collisione e allo stesso tempo la lunghezza
del percorso.
1.2 Organizzazione del progetto
Il progetto è stato portato avanti da una quarantina persone coordinate dal dot-
torando Luca Burelli, durante il corso di Controllo dei Processi tenuto dal Prof.
Ruggero Frezza in due trimestri dell'anno accademico, da gennaio 2005 a giugno
18 Navigazione autonoma
Figura 1.1: L'auto utilizzata per il progetto: una Range Rover del 1990; sono visi-
bili i sensori sul tetto: le telecamere, il LIDAR (profondimetro LASER) e l'antenna
GPS. Nel retro dell'auto sono posizionati i computer e i sistemi di alimentazione.
2005. Il lavoro è stato suddiviso tra 12 team, in modo da affrontare l'intero progetto
in modo organico e su più fronti.
La presente tesi si basa sul lavoro compiuto in parte durante il corso da un
gruppo di 4 persone (Nicola Barbon, Alessio Basso, Matteo Di Giovinazzo e Fran-
cesco Tartaggia) coordinato da me, e portato poi a termine da solo, seguendo gli
obiettivi prefissati per l'interfaccia grafica e la telemetria del sistema.
1.3 Analisi del progetto
Affrontare il problema dell'interfaccia uomo-macchina per un sistema così com-
plesso, come quello del progetto di un veicolo autonomo, richiede un buon lavoro
di analisi e progettazione.
Dato che nel corso di laurea che mi appresto a terminare, non esiste, almeno
al Vecchio Ordinamento, un corso di Ingegneria del Software, secondo me indi-
spensabile per uno studente di Ingegneria Informatica, per quanto mi riguarda ho
dovuto raccogliere un po' di documentazione per poter affrontare proficuamente
1.3 Analisi del progetto 19
l'impresa di scrivere un software da zero, coordinando nella prima parte il lavoro
tra più persone e progettando al meglio l'architettura dell'applicazione.
La suddivisione del lavoro ha obbligato tutti i gruppi ad una progettazione
e discussione prima teorica, poi implementativa delle soluzioni ai sottoproblemi
specifici. Poiché i requisiti e gli obiettivi dell'applicazione di telemetria sono stati
fissati man mano che si è stabilita l'organizzazione dell'intero progetto, è stato
necessario un continuo feedback con tutti i team.
Per questo motivo molte specifiche sono cambiate in corso d'opera: in un
software come questo infatti, le specifiche non possono essere congelate, visto
che il modo con cui l'applicazione viene usata influenza un ripensamento e una
riprogettazione costanti.
In definitiva gli scopi dell'interfaccia uomo-macchina sono quelli di rendere pos-
sibile il controllo remoto del sistema. Questo significa, nella parte di sviluppo e
testing, la necessità di avere sotto mano tutti i segnali che arrivano ed escono da
un modulo software, per verificare costantemente come procede il lavoro di imple-
mentazione degli studi teorici e per capire dove e come migliorare il funzionamento
dell'applicazione.
Nel momento in cui l'applicazione viene messa in opera, dopo il cosiddetto
deployment, l'interfaccia grafica uomo-macchina deve permettere il monitoraggio
del sistema tramite una vista unica su tutti i moduli software che compongono il
progetto. Inoltre alcuni aspetti devono poter essere manovrabili da remoto, come
ad esempio l'accensione o lo spegnimento di emergenza o ancora la gestione degli
allarmi non risolvibili automaticamente dal sistema software.
Per tutti questi aspetti la scelta, molto ben ponderata, dell'architettura soft-
ware, su cui tutti i moduli software si sono appoggiati, è stata decisiva. Il capitolo 2
è dedicato all'illustrazione di questo argomento, partendo da un confronto tra le
possibili soluzioni e tra i costi in termini di tempo e semplicità di utilizzo, fino
ad approfondire i dettagli anche implementativi del lavoro svolto dal gruppo di
sviluppo software [34] per personalizzare ed estendere al meglio l'architettura di
Ice, il middleware scelto per questo scopo.
Ogni gruppo poi ha avuto parte attiva nello stabilire i protocolli ad alto livello,
ossia le interfacce, tra differenti sottosistemi. L'interfaccia grafica era perciò vin-
colata a conoscere e seguire queste specifiche decise durante il lavoro sul progetto.
Il capitolo 3 ne parla, passando velocemente in rassegna il lavoro dei vari gruppi e
soffermandosi sulle specifiche utili alla telemetria.
20 Navigazione autonoma
Di ogni cellula, di questo essere vivente che sarà l'applicazione distribuita, che
darà vita al veicolo autonomo, sono schematizzati in tabelle i dati che necessitano
di essere monitorati in telemetria e lo stato della realizzazione, implementazione in
codice e integrazione nell'architettura software. Purtroppo per alcuni sistemi non è
stata ancora stabilita l'interfaccia di alto livello per richiedere i dati da visualizzare,
per altri invece sono stati effettuati test approfonditi.
Per realizzare l'interfaccia grafica si è scelto di privilegiare la modularità e
la progettazione del design, utilizzando un linguaggio orientato agli oggetti come
Java. La programmazione object-oriented ha influenzato pesantemente tutto il
progetto: lo scopo era quello di aumentare la qualità del software, visto che co-
munque per quanto riguarda le prestazioni, ora come ora non sono la parte più
problematica per la buona riuscita di dello sviluppo di un'applicazione.
Il fatto di dover lavorare assieme ad altri team, di dover consegnare il progetto
svolto ad altre persone, in modo che possano utilizzarlo ed estenderlo in maniera
semplice e immediata, ci ha convinto nella scelta di utilizzare una piattaforma
software, su cui appoggiare la nostra applicazione.
Nel capitolo 4 viene così descritta la scelta tra varie piattaforme per costruire
applicazioni desktop, soffermandoci poi su quella su cui abbiamo optato, NetBeans
Platform, per costruire l'interfaccia uomo-macchina.
Una esaustiva descrizione di tutto il codice prodotto e organizzato in moduli
software è trattata nel capitolo 5, corredato da numerose screenshot.
Per spiegare al meglio l'architettura software, in tutta la tesi si fa uso dei dia-
grammi UML1. Questi schemi grafici permettono di riassumere in un'unica figura
le entità coinvolte, classi o interfacce, ma soprattutto le relazioni che intercorrono
tra di loro.
Implementazioni, realizzazioni, usi tra una classe e un'altra permettono di chia-
rire il motivo di scelte architetturali, di comprendere in modo immediato alcune
logiche di programmazione ad oggetti.
Per questo motivo e per maggiore approfondimento, nell'appendice A, sono
raccolti alcuni esempi di design pattern, i costrutti fondamentali nella progettazione
odierna di software object-oriented.
1Unified Modeling Language
1.4 Struttura del codice 21
1.4 Struttura del codice
In figura 1.2 si può vedere come è stato organizzato tutto il codice prodotto dai
vari team.
software
bin
include . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .File icelogger.h e altri include
navlib
interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interfacce Slice
lib
share
config. . . . . . . . . . . . . . . . . . . . . . . . . .file di configurazione navnet_*.xml
servers . . . . . . . . . . . .file di configurazione per ogni sottosistema
scripts . . . . . . . . . contiene lo script launcher.py per avviare il sistema
src
cells . . . . . Implementazioni delle Cells (per dettagli vedi figura 3.2)
hostmon . . . . . . . . . . . . . . . . . Applicazione Hostmon, vedi sezione 2.12
navlib . . . . . . . . . . . . . .Libreria Navlib, base dell'architettura software
tools
gui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Interfaccia grafica
kim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Simulatore del veicolo
Figura 1.2: Struttura del repository CVS dei sorgenti
Il tutto è stato gestito con il tool di versionamento CVS2, per mantenere tutte
le modifiche progressive dei diversi gruppi di lavoro.
2Concurrent Versioning System
Capitolo 2
Architettura software del sistema
2.1 Il progetto come applicazione distribuita
L'applicazione nel suo insieme è costituita da più agenti software. Questi sottosi-
stemi devono scambiare informazioni per poter collaborare all'elaborazione: i dati
fluiranno tra i vari componenti, per esempio dai sensori di input, ai sistemi di
integrazione e agli attuatori.
Per motivi di prestazioni, dovranno perciò essere distribuiti su diversi computer.
Inoltre per motivi di organizzazione del lavoro gli stessi sottosistemi saranno affidati
a differenti team di sviluppo.
Una buona architettura di sistema richiede perciò che questi sottosistemi siano
altamente disaccoppiati, separati e rendano accessibile a tutti solamente una inter-
faccia di alto livello. Esistono molti pacchetti software, chiamati middleware, che
aiutano a raggiungere questi obiettivi, nascondendo i dettagli della comunicazione
di rete dal codice specifico dell'applicazione.
Un middleware è un software che si frappone tra applicazioni eterogenee, re-
sidenti su macchine diverse, probabilmente scritte in linguaggi diversi, e serve ad
offrire un layer che garantisce la trasparenza di rete e di idioma.
I middleware permettono di richiedere un'operazione ad un oggetto residente
in un altra macchina, come se la chiamata fosse locale; questo avviene codificando
la richiesta e spedendola attraverso la rete al destinatario, che esegue l'operazione
e rispedisce i risultati indietro seguendo il medesimo meccanismo. Alle due appli-
cazioni coinvolte nella comunicazione sembrerà di stare sulla stessa macchina e di
parlare lo stesso linguaggio.
24 Architettura software del sistema
2.2 Panoramica dei middleware esistenti
Fin dalla metà degli anni Novanta l'industria del software ha utilizzato middleware
che permettessero agli sviluppatori di creare delle architetture software distribute.
Un importante passo fu compiuto con i middleware object-oriented come DCOM e
CORBA, queste librerie software resero possibile la progettazione e la realizzazione
di applicazioni distribuite, senza la necessità di essere esperti nelle comunicazioni
via rete.
La piattaforma middleware si prende carico di ogni aspetto, come per esempio
del marshalling e unmarshalling (la codifica e decodifica dei dati per la trasmis-
sione), del mapping degli indirizzi logici degli oggetti in indirizzi fisici di rete, della
conversione dei dati in accordo con l'architettura nativa dei client o dei server e
della gestione on-demand dell'esecuzione dei server.
CORBA, uno dei middleware più famosi, è una specifica pubblicata nel 1991,
primo tentativo di standardizzare l'architettura di sistemi distribuiti compresi i
protocolli di comunicazione e le interfacce.
DCOM invece è un middleware proprietario di Microsoft, derivato dall'archi-
tettura COM e ActiveX, paradigma di programmazione per componenti, utilizzato
in C++ e Visual BASIC.
Per molte ragioni però, né DCOM, né CORBA catturarono la maggior parte
del mercato:
• DCOM infatti come soluzione proprietaria non può essere utilizzata in am-
bienti di rete eterogenei con diversi sistemi operativi.
• DCOM non permette all'applicazione di ospitare un grande numero di og-
getti. Ciò è dovuto al sovraccarico causato dal meccanismo della garbage
collection distribuita.
• CORBA anche se appoggiata da numerose aziende non ha una compatibi-
lità completa tra le varie implementazioni, minando così alla base la sua
interoperabilità.
• La complessità dei due framework fa in modo che il raggiungimento di un
buon livello di conoscenza, adeguato per progettare e realizzare un'applica-
zione distribuita, richieda molto tempo.
• Essendo sia DCOM che CORBA estremamente complessi è quasi impossibile
2.3 La scelta di Ice 25
trovare un'implementazione completa di tutta la specifica, che abbia anche
buone prestazioni.
Contemporaneamente al declino di DCOM e CORBA, l'uno surclassato dall'ar-
chitettura .NET di Microsoft, l'altra stagnante e abbandonata alla sua complessi-
tà dalle aziende, si sono fatte avanti nella comunità del software per applicazioni
distribuite altre soluzioni, maggiormente standardizzate come SOAP1 ed i web
service, sull'onda dell'XML Hype [6].
Nonostante molta pubblicità, molte pubblicazioni e l'idea intrigante di utiliz-
zare il World Wide Web, ormai onnipresente, come infrastruttura di rete, i web
service non hanno saputo mantenere la promessa di diventare la lingua franca delle
applicazioni distribuite su Internet.
Più che una piattaforma object-oriented sono un'architettura service-oriented,
con prestazioni inadeguate per applicazioni anche non realtime: il parsing del-
l'XML aggiunge pesante carico alla CPU del sistema, aumenta la latenza e abbassa
il throughput aumentando la banda necessaria alla comunicazione. Inoltre soffre
intrinsecamente di problemi di sicurezza.
2.3 La scelta di Ice
Una soluzione è venuta da ZeroC Inc.2 che ha sviluppato Ice (Internet Communi-
cation Engine) un middleware che si ispira direttamente a CORBA. Gli obiettivi
principali perseguiti nel design di Ice sono stati:
• fornire una piattaforma middleware object-oriented utilizzabile in ambienti
eterogenei;
• fornire una serie di caratteristiche che permettano lo sviluppo di applicazioni
realistiche nei campi più disparati;
• evitare la complessità non necessaria (contrariamente alla specifica di CORBA
per esempio) rendendo la piattaforma facile da imparare e semplice da uti-
lizzare;
• fornire un'implementazione efficiente in termini di banda utilizzata, uso della
memoria e carico di lavoro della CPU;
1Simple Object Access Protocol
2http://www.zeroc.com/
26 Architettura software del sistema
• fornire un'implementazione sicura, che ne permetta l'utilizzo anche in reti
pubbliche.
In un primo momento assieme al team di sviluppo software abbiamo realiz-
zato alcuni esperimenti preliminari con un'implementazione di CORBA chiamata
TAO3.
Figura 2.1: Screenshot dell'applicazione web nsbrowser realizzata con JSP su
Jakarta Tomcat 5.5.9
Perciò per testare CORBA, prima ancora di scegliere la piattaforma NetBeans
per lo sviluppo della GUI per il progetto, abbiamo realizzato un browser del servizio
dei nomi di CORBA con due tecnologie diverse, la prima come applicazione web
(vedi figura 2.1), la seconda come applicazione desktop (vedi figura 2.2), entrambe
basate su Java.
Il nameservice browser era una parte indispensabile della configurazione e del
monitoraggio dell'intera applicazione distribuita. Nel suo sviluppo sono venute
alla luce, la complessità dell'approccio di CORBA, molto astratto, poco adatto
alle nostre necessità.
Anche se le promesse di CORBA sono quelle di rendere trasparente tutto lo
strato di basso livello, è risultato comunque necessario un certo sforzo di pro-
grammazione per usare queste funzionalità, per esempio per tutte le condizioni di
3http://www.cs.wustl.edu/~schmidt/TAO.html
2.4 L'architettura di Ice 27
Figura 2.2: Screenshot dell'applicazione desktop realizzata con Java Swing
errore trovate passando da applicazioni omogenee nello stesso host, ad applicazioni
eterogenee su host diversi.
Quindi anche se presenta importanti caratteristiche come la latenza garantita,
se utilizzato in un sistema operativo realtime, i problemi riscontrati erano incom-
patibili con il nostro modello di sviluppo. Assieme a queste ultime conclusioni e
alla valutazione generale precedente, abbiamo scelto Ice come middleware per il
nostro progetto.
2.4 L'architettura di Ice
2.4.1 Introduzione
Ice è una piattaforma middleware orientata agli oggetti. Fondamentalmente, que-
sto significa che Ice fornisce strumenti, API4, librerie per costruire applicazioni
client-server object-oriented. Le applicazioni Ice sono utilizzabili in ambienti ete-
rogenei: client e server possono essere scritti in diversi linguaggi di programma-
zione, possono essere eseguiti in diversi sistemi operativi e diverse architetture di
processore e possono comunicare attraverso varie tecnologie di networking. Il co-
dice sorgente per queste applicazioni è portabile indipendentemente dall'ambiente
di esecuzione.
4Application Programming Interface
28 Architettura software del sistema
2.4.2 Terminologia
Client e Server
I termini client e server non denotano parti di una applicazione, ma i ruoli che
sono interpretati da diverse parti dell'applicazione durante una richiesta:
• i client sono entità attive, richiedono un servizio ai server;
• i server sono entità passive, forniscono un servizio in risposta alle richieste
dei client.
Spesso i server non sono server puri, nel senso di non richiedere mai un servizio e
rispondere solamente alle richieste, al contrario i server di frequente agiscono come
server davanti ai client e come client con altri server per soddisfare le richieste.
Analogamente anche i client non si comportano sempre come client puri. Que-
sta inversione di ruoli è comune in molti sistemi, così che i sistemi client-server
sono più giustamente chiamati sistemi peer-to-peer.
Oggetti Ice
Un oggetto Ice è un concetto, una astrazione. Ecco alcune caratteristiche che ne
specificano la definizione:
• Un oggetto Ice è un'entità nell'ambiente locale o remoto che può rispondere
alle richieste dei client.
• Un singolo oggetto Ice può essere istanziato in un singolo server o in maniera
ridondante in più server. Resta sempre un singolo oggetto Ice anche se ha
istanze simultanee.
• Ogni oggetto Ice ha una o più interfacce, di cui una principale, che ne de-
termina il tipo. Una interfaccia è una collezione di operazioni che sono rese
disponibili da un oggetto. I client possono effettuare richieste invocando
operazioni.
• Una operazione o funzione ha zero o più parametri e un valore di ritorno.
Ogni parametro e valore di ritorno ha un suo specifico tipo di dato. I pa-
rametri oltre a questo possiedono una direzione: i parametri di input sono
inizializzati dal client e passati al server, viceversa quelli di output sono
inizializzati dal server e passati al client.
2.4 L'architettura di Ice 29
• Ogni oggetto Ice ha una sua univoca identità per distinguere l'oggetto da altri
oggetti. Non occorre che le identità degli oggetti siano globalmente univoche,
è sufficiente che non collidano i nomi nel dominio di interesse dell'applicazione
distribuita.
I proxy
Il proxy è un ambasciatore, un delegato nello spazio di indirizzamento locale al
client, che rappresenta un oggetto Ice di solito remoto rispetto al client.
I client che vogliono contattare un oggetto Ice, devono possedere un proxy
all'oggetto in questione. Quando un client invoca una operazione sul proxy di un
oggetto, lo strato software di runtime di Ice:
1. localizza l'oggetto Ice;
2. attiva il server che contiene l'oggetto Ice se non è stato avviato;
3. attiva l'oggetto Ice messo a disposizione del server;
4. trasmette gli eventuali parametri di input all'oggetto Ice;
5. aspetta che l'operazione sia completata;
6. restituisce gli eventuali parametri di output e il valore di ritorno al client
oppure lancia un'eccezione nel caso di errore.
Rappresentazione di un proxy tramite stringa
Un proxy contiene tutte le informazioni necessarie perché questa sequenza di passi
possa essere portata a termine. In particolare contiene:
• l'identità dell'oggetto che identifica quale particolare oggetto nel server è il
destinatario della richiesta, completo di categoria;
• le informazioni sull'indirizzo di rete che permette alla parte di runtime lato
client di contattare il corretto server, in gergo endpoint.
Un proxy può essere rappresentato con una stringa, come ad esempio la stringa
Nav/GpsInsSensor:tcp navbox01 -p 10000
30 Architettura software del sistema
è la rappresentazione leggibile del proxy. Lo strato di runtime di Ice provvederà a
convertire il proxy nella sua rappresentazione in stringa e viceversa.
Per un client è sufficiente conoscere queste informazioni per poter reperire
l'oggetto Ice tramite il suo proxy, oltre al tipo di oggetto per poter invocarne
un'operazione.
Proxy diretti e indiretti
Nei proxy diretti la rappresentazione in formato stringa del proxy contiene anche le
informazioni di indirizzamento attraverso la rete del server che contiene l'oggetto
in questione (come nell'esempio fatto sopra). In quelli indiretti, oltre all'identità
dell'oggetto, la stringa contiene il nome simbolico dell'object adapter, che è l'agente
software che si occupa di aprire connessione sugli endpoint specificati, in attesa
delle richieste dei client. Eccone un esempio:
GpsSensor@GpsInsAdapter
Lo strato di runtime si occuperà di reperire le informazioni necessarie da un servi-
zio di naming, come un locator registry di IcePack (vedi sezione 2.8), per risalire
all'attuale endpoint dell'object adapter in modo che il clienti possa contattarlo.
Ovviamente utilizzando i proxy indiretti meccanismo molto simile al Domain
Name Service (DNS) che regge l'infrastruttura dei nomi di dominio su Internet
le informazioni sugli oggetti a disposizione dei client non perderanno validità anche
se i server associati verranno spostati da un host all'altro.
I servant
Poiché gli oggetti Ice sono entità concettuali, le richieste dovranno essere indirizzate
verso una entità concreta che si occupi dell'elaborazione lato server, fornendo la
logica che sta dietro all'invocazione di una specifica operazione. Insomma dovrà
esserci del codice scritto in un linguaggio di programmazione nel server su un host
specifico, che onori la richiesta del client.
La parte server che fornisce questo è il servant o server propriamente detto:
incarna cioè uno o più oggetti Ice, fornendo la logica applicativa per eseguire le
operazioni di cui sono interfaccia. Il servant è perciò una esecuzione della classe
scritta dallo sviluppatore e registrata presso lo strato di runtime come server di uno
o più oggetti Ice. Le funzioni implementate quindi corrispondono alle operazioni
sull'interfaccia dell'oggetto Ice.