UNIVERSITA’ POLITECNICA DELLE MARCHE Facoltà di Ingegneria Corso di laurea in Ingegneria Informatica e dell’Automazione SIMULAZIONE MULTI-AGENTE MEDIANTE LA PIATTAFORMA “MASON” RELATORE : Prof. Aldo Franco DRAGONI Candidato Mirko BUDANO Matr. 1024576 Anno Accademico 2008-2009 Indice: 1. INTRODUZIONE E OBIETTIVI ………………………………..4 2. SISTEMI MULTI-AGENTE ……………………………………..6 3. PIATTAFORMA DI SIMULAZIONE MASON ………………..9 3.1. Caratteristiche ………………………………………………...10 3.2. Architettura …………………………………………………...11 3.2.1. Livello “Modello”…………………………………………13 3.2.2. Livello “Visualizzazione”…………………………………14 3.2.3. Livello “Utilità”…………………………………………..17 3.3. Utilizzo di MASON in ECLIPSE ……………………………18 3.3.1. Prerequisiti………………………………………………..18 3.3.2. Installare MASON in ECLIPSE …………………………..19 3.3.3. Creare un nuovo progetto ………………………………...20 3.3.4. Importare un modello MASON …………………………...22 3.3.5. Avviare il modello………………………………………...22 4. IMPLEMENTAZIONE DELLA SIMULAZIONE MULTI-AGENTE …………………………………………………24 4.1. Descrizione della simulazione ……………………………….24 4.2. Realizzazione del modello …………………………………...30 4.2.1. Model3D.java …………………………………………….30 4.2.2. Orologio.java ……………………………………………..36 4.2.3. Person.java ……………………………………………….37 4.2.4. MovePerson.java …………………………………………40 4.2.5. Variatore Parametri.java ………………………………...42 4.2.6. ViewParametri.java ………………………………………44 4.2.7. Assistente Virtuale.java …………………………………..46 2 4.3. Realizzazione della parte grafica ……………………………47 4.3.1. Model3DWithUI.java …………………………………….47 4.3.2. Altre classi grafiche ………………………………………54 4.4. Librerie Java3D ……………………………………………...56 4.4.1. Scene Graph………………………………………………57 4.4.2. Shape3D…………………………………………………...60 4.4.3. Grouping shapes ………………………………………….62 4.4.4. Luci direzionali……………………………………………63 4.4.5. Classe Loader …………………………………………….65 5. CONCLUSIONI …………………………………………………...67 6. RIFERIMENTI …………………………………………………...68 7. APPENDICE : LIBRERIE DEL MASON ………………………70 8. INDICE DELLE FIGURE ……………………………………….75 3 1. INTRODUZIONE E OBIETTIVI L’obiettivo di questa tesi è la realizzazione di una simulazione multiagente 3D con l’utilizzo della piattaforma “MASON”. Mason è l’acronimo di “Multi-Agent Simulator Of Neighborhoods”. Mason è stato sviluppato alla George Mason University mediante un progetto di collaborazione tra il “Department of Computer Science’s Evolutionary Computation Laboratory” e il “ Center for Social Complexity”. La simulazione multi-agente esposta in questa tesi modella un appartamento in 3D composto da vari ambienti, in cui sono inseriti dei sensori che rilevano i parametri ambientali. All’interno dell’ambiente si muove un anziano che ha su di esso dei sensori che rilevano i parametri vitali e il verificarsi di situazioni particolari come ad esempio la sua caduta. L’anziano si muove secondo traiettorie predefinite ed esegue delle azioni durante la giornata. Inoltre nell’ambiente è stato inserito anche un assistente virtuale che interagisce con l’anziano e gli fornisce supporto durante la sua attività quotidiana, ad esempio ricordandogli di prendere le medicine o di chiudere i rubinetti rimasti aperti. I parametri ambientali e vitali vengono visualizzati su una finestra apposita la quale viene aggiornata periodicamente oppure su richiesta dell’utente premendo il pulsante predisposto a tale scopo. L’obiettivo di una simulazione è di riprodurre il comportamento di un sistema reale. In questo contesto, le simulazioni sono perciò un modello di tali sistemi che consentono all’utente di controllare degli ambienti per fare sperimentazioni. 4 L’obiettivo della mia simulazione è di monitorare la vita dell’anziano attuando una forma di ambient assisted living. L’assisted living è rivolto a quegli anziani che non possono vivere in maniera totalmente indipendente ma non hanno bisogno di cure mediche 24 ore su 24. Si introduce quindi il concetto di “casa intelligente” infatti i servizi di assisted living forniti nella mia simulazione riguardano il supporto alla vita quotidiana attraverso l’assistente virtuale che interagisce con l’anziano. Quindi l’assisted living è una filosofia di cure e servizi che promuove l’indipendenza e la dignità dell’anziano stesso. Nel seguito della tesi verranno esposte le caratteristiche, l’architettura e il funzionamento del Mason ed inoltre verrà spiegata in maniera più approfondita l’implementazione della simulazione sviluppata. 5 2. SISTEMI MULTI-AGENTE Un sistema multi-agente (MAS) è un sistema composto da più agenti intelligenti che interagiscono. Un agente è un’entità virtuale che vive in un ambiente, lo percepisce, agisce in esso e ha un comportamento autonomo conseguente alla sua conoscenza, alle sue interazioni e alla sua finalità. Ogni agente singolarmente valuta la situazione e prende le decisioni sulla base di una serie di regole. I sistemi multi-agente possono essere utilizzati per risolvere problemi che sono difficili o impossibili da risolvere per un singolo agente o per un sistema monolitico. Gli agenti hanno importanti caratteristiche: • Autonomia: gli agenti sono almeno parzialmente autonomi. • Punto di vista locale: un agente non ha una completa visione del sistema o il sistema è troppo complesso per un agente per rendere pratico l’uso di tali conoscenze. • Decentralizzazione: non c’è nessun controllo agente. Tipicamente i sistemi multi-agente si riferiscono ad agenti software. Tuttavia gli agenti potrebbero anche essere robot, umani o gruppi di umani. Inoltre i sistemi multi-agente possono avere una propria organizzazione e comportamenti complessi anche quando le strategie individuali dei singoli agenti sono semplici. Gli agenti possono condividere le loro conoscenze con una qualsiasi lingua concordata, entro i limiti del protocollo di comunicazione utilizzato. Un esempio è il linguaggio di comunicazione della FIPA (ACL). 6 Molti sistemi multi-agente sono implementati nei computer tramite delle simulazioni attraverso l’utilizzo di un sistema basato sul time step, un esempio di questo è la piattaforma Mason come vedremo nel corso di questa tesi. Un altro paradigma comunemente utilizzato nei sistemi MAS è il “feromone”, dove ogni componente fornisce le informazioni agli altri componenti nelle vicinanze. Questi feromoni potrebbero evaporare cioè il loro valore diminuisce con il passare del tempo. La caratteristica principale che si ottiene quando si sviluppa un sistema multi-agente è la flessibilità, dal momento che un MAS può essere aggiunto, modificato e ristrutturato senza la necessità di riscrivere in maniera dettagliata l’applicazione. Lo studio dei sistemi multi-agente riguarda lo sviluppo e l’analisi di sofisticati problemi di intelligenza artificiale e il controllo delle architetture per realizzare tali sistemi. I sistemi multi-agente ad hoc sono spesso creati da zero ma esistono anche dei framework che hanno attuato delle norme comuni e che sono molto utili in quanto consentono di risparmiare tempo, semplificare lo sviluppo e standardizzare i MAS stessi. I toolkit per i sistemi multi-agente hanno l’obiettivo di evitare che il progettista debba partire ogni volta da zero. In particolare evitare che il progettista debba sviluppare le parti generali di un MAS generico. Toolkit diversi hanno esigenze o preferenze progettuali diverse. Esistono 2 tipologie di modelli: Modelli “forti”: il toolkit ha una definizione rigida di agente e il progettista deve solo definire i particolari strettamente dipendenti dall’applicazione. 7 Modelli “deboli”: il toolkit ha una definizione lasca di agente ed è il progettista a definire le caratteristiche degli agenti. Un esempio è il Mason che fornisce solo le librerie di base minime a cui un programmatore java può aggiungere delle funzionalità specifiche per la sua applicazione. In generale maggiore è la flessibilità del modello di agente adottato, minore è la possibilità di un semplice sviluppo grafico del MAS. La programmazione ad agenti è strettamente basata su quella ad oggetti in quanto un agente può essere definito in modo naturale come un oggetto, o meglio come una classe che incapsula le funzionalità implementate dall’agente i cui metodi e proprietà pubblici definiscono i servizi che esso mette a disposizione degli altri agenti. Si può usare un qualunque linguaggio ad oggetti ma la natura distribuita di un’applicazione multi-agente e l’eterogeneità a livello hardware e di sistema operativo che si può incontrare in una rete di computer fanno preferire il linguaggio che per definizione è nato per programmare in ambienti con tali caratteristiche: Java. I sistemi MAS sono utilizzati nel mondo reale per applicazioni grafiche come i giochi per computer. Inoltre sono utilizzati anche nei film, per il coordinamento dei sistemi di difesa, trasporto, logistica e in molti altri campi. 8 3. PIATTAFORMA DI SIMULAZIONE MASON Mason è un toolkit di simulazione single-process e discrete-event scritto in Java e disegnato con un alto livello di modularità e flessibilità per essere applicato ad una vasta gamma di simulazioni multi-agente. Il sistema di simulazione è open-source e gratuito. Mason non deriva da altri toolkit ma si basa su principi primi. La filosofia progettuale che sta alla base del Mason è quella di costruire delle librerie minime, veloci e ortogonali a cui un programmatore java esperto può facilmente aggiungere delle nuove funzioni specifiche per un determinato dominio di applicazione. Per questo è stata aggiunta la visualizzazione grafica e altre facilitazioni utili per diverse simulazioni. Le librerie sono destinate ai ricercatori che spesso eseguono simulazioni con un gran numero di agenti e interazioni ed è per questo che Mason è veloce, portatile, in grado di garantire risultati replicabili indipendentemente dalla piattaforma utilizzata. Il modello Mason può essere fornito di un interfaccia grafica che ne permette la visualizzazione sia in 2D che in 3D. Attualmente però Mason non fornisce strumenti di alto livello per programmatori inesperti né funzioni specifiche che quindi devono essere aggiunte dal programmatore in base alle sue esigenze. Mason ha un architettura e delle caratteristiche inusuali per un sistema di simulazione multi-agente. Il dominio di applicazione comprende la robotica , intelligenza artificiale, le scienze sociali e altre scienze. 9 3.1 Caratteristiche Mason è stato realizzato per avere un sistema di simulazione semplice e utilizzabile per simulare una vasta gamma di modelli multi-agente. Le caratteristiche del Mason sono le seguenti: Basato sul Java. Ha un piccolo core ed è veloce (soprattutto quando viene eseguito senza visualizzazione). Alto livello di modularità e flessibilità. Il modello è indipendente dalla visualizzazione che può essere aggiunta, rimossa o modificata in ogni momento. I modelli possono essere “checkpointed”, recuperati e trasportati dinamicamente su altre piattaforme con o senza visualizzazione. Portatile e produce risultati identici indipendentemente dalla piattaforma utilizzata. Le visualizzazioni sono in 2D e 3D. Supporto efficiente per moltissimi agenti. Le librerie Mason possono essere facilmente incluse in altre librerie. Ci sono tre obiettivi progettuali che non sono stati utilizzati esplicitamente per realizzare Mason. In primo luogo Mason non viene utilizzato per effettuare singole simulazioni in rete su più processori. In secondo luogo Mason è stato realizzato con un core semplice e piccolo quindi non ha fornito funzioni speciali per agenti sociali e simulatori di robotica. 10 In terzo luogo anche se Mason è stato progettato per avere un uso ragionevolmente efficiente della memoria, essa non rappresenta una priorità. 3.2 Architettura Mason è scritto in Java per trarre vantaggio dalla sua portabilità, dalle definizioni di tipo rigide (che garantiscono la replicabilità dei risultati) e dalla serializzazione degli oggetti (per salvare e caricare la simulazione). Il toolkit Mason è scritto in maniera modulare con un architettura stratificata come mostrata in figura 3.1. Figura 3.1 ( Architettura Mason ) Le Utilities sono delle strutture di utilità che possono essere utilizzate per qualsiasi scopo. 11 Il Simulation Model è una collezione di classi che consiste di uno schedule a eventi discreti (rappresenta il tempo) , un generatore di numeri casuali altamente efficiente e una serie di field (campi) che rappresentano lo spazio. Questo codice da solo è sufficiente per scrivere delle simulazioni di base avviabili da linea di comando. Il Visualization e GUI Tools invece permette la visualizzazione dei field del modello e il controllo da parte dell’utente della simulazione. Il livello modello e il livello visualizzazione sono perfettamente separati tra di loro infatti a runtime agisce una suite di strumenti che consente di prelevare e manipolare il modello mantenendolo indipendente dalla visualizzazione. Questo ci consente di trattare il modello come un’entità “selfcontained”. Noi in ogni momento possiamo separare il modello dalla visualizzazione , fare un checkpoint del modello su disco, passare ad un'altra piattaforma e riprendere la simulazione da dove era stata interrotta ottenendo esattamente gli stessi risultati. La figura 3.2 mostra questa procedura. Figura 3.2 ( procedura del checkpointing) 12 3.2.1 Livello “Modello” Il modello Mason è interamente contenuto in una sottoclasse di SimState. SimState è la superclasse astratta per realizzare il modello Mason. Il modello può essere completamente indipendente dalla visualizzazione grafica. Il livello modello consiste di due parti: fields e discrete-event schedule. I fields memorizzano degli oggetti arbitrari e li allocano nella loro posizione spaziale. Gli oggetti sono liberi di appartenere a più fields. L’uso dei fields è facoltativo e il programmatore può decidere di aggiungerne degli altri, specifici per le sue esigenze. Mason fornisce diversi tipi di field: Array di oggetti 2D o 3D, int o double , delimitati o toroidali e con un layout esagonale, triangolare o quadrato. Reti sparse in 2D o 3D, delimitate o toroidali con un layout esagonale, triangolare o quadrato. Spazi continui in 2D o 3D. Spazi discreti in 2D o 3D. Grafici. Lo schedule invece rappresenta il tempo e permette agli agenti di eseguire le loro azioni nel futuro. Nel Mason il termine agente indica un’entità computazionale che può essere programmata per eseguire delle azioni e che può manipolare l’ambiente. Questo però non implica che l’agente sia fisicamente contenuto nell’ambiente stesso. Mason non programma gli eventi da inviare ad un agente ma è l’agente stesso che programma le sue attività. La pianificazione di 13 un’agente per eseguire diverse funzioni può essere facilmente effettuata con una apposita classe. Una simulazione di base tipicamente consiste di uno o piu fields, uno schedule e degli oggetti ausiliari definiti dall’utente. Il modello è self-contained quindi può essere salvato su disco, caricato su un'altra piattaforma ed eseguito con gli stessi risultati. Inoltre il modello non contiene nessuna visualizzazione e può essere lanciato anche senza. 3.2.2 Livello “Visualizzazione” La simulazione Mason può operare con o senza un’interfaccia grafica (GUI) e può commutare tra due modelli durante la simulazione stessa. Per fare ciò il modello è completamente separato dalla visualizzazione. Quando opera senza visualizzazione il modello viene eseguito come una normale applicazione java. Invece quando opera con visualizzazione il modello è mantenuto nella propria “sandbox” (buca nella sabbia) ed è eseguito per conto proprio senza che la GUI possa modificare le informazioni del modello. Gli oggetti del livello visualizzazione possono esaminare gli oggetti del livello modello solo con il permesso di un gatekeeper wrapper chiamato GUIState. Questa classe consente di staccare il modello dalla visualizzazione. Dato che alcuni oggetti della visualizzazione hanno bisogno di essere programmati (in particolare le finestre che devono essere aggiornate per riflettere i cambiamenti del modello) allora la GUIState fornisce un proprio mini-schedule ausiliario tenuto in sintonia con lo schedule del modello. 14 Lo schedule del modello e quello ausiliario sono separati attraverso un controller che ha il compito di far partire la simulazione grafica. Mason realizza la visualizzazione attraverso uno o più display ovvero delle finestre grafiche che forniscono una vista in 2D o 3D dei field del modello. I displays hanno molte relazioni con i fields, inoltre i display3D possono visualizzare anche fields 2D. La GUI non visualizza e manipola il modello direttamente ma attraverso dei “fields portrayals” (ritratti) che agiscono come delegati per gli oggetti e i fields del modello. I fields portrayal rappresentano graficamente i fields del modello chiamando dei simple portrayal che sono responsabili del disegno e del controllo degli oggetti memorizzati nei fields. Gli oggetti possono anche fornire un proprio simple portrayal specifico che esegue il disegno per quel tipo di oggetto. Ci sono vari tipi di fields portrayals che sono, a turno, attaccati ad un display e provvedono a disegnare e manipolare l’ambiente grafico sulla base dei loro fields object deleganti. Mason inoltre fornisce anche una console che facilità l’utente nelle operazioni di start/pause/stop della simulazione ed inoltre consente di salvare e caricare i modelli serializzati, mostrare e nascondere i displays e visualizzare gli ispettori. Mason realizza la visualizzazione sia in 2D ( usando AWT e java2D) che in 3D (usando le librerie Java3D). La figura 3.3 mostra schematicamente i componenti del Mason e le relazioni che intercorrono tra di essi. 15 Figura 3.3 ( Componenti del Mason) 16 3.2.3 Livello “Utilità” Il livello Utilità contiene delle classi che possono essere utilizzate per qualsiasi scopo. Ad esempio le classi di utilità comprendono delle “bag”, vettori immutabili in 2D o 3D , un’implementazione molto efficiente di un generatore di numeri casuali e tante altre classi utili. Le “bag” sono dei contenitori che hanno la stessa struttura degli arraylist ma sono molto più veloci. Le bag forniscono dei metodi per aggiungere o rimuovere degli elementi, per scorrere tutti gli elementi contenuti in essa e per accedere direttamente ad ogni elemento tramite un indice. 17 3.3 Utilizzo di Mason in Eclipse Per sviluppare la mia simulazione multi-agente ho utilizzato come ambiente di programmazione Eclipse. Eclipse è un ambiente di sviluppo integrato potente e largamente utilizzato ed è una piattaforma conveniente per sviluppare il modello Mason. Eclipse è gratis, disponibile per windows, linux e per mac, fornisce un editor per scrivere programmi java, display grafici del programma, una gerarchia dei package ed anche un debugger. Usare Eclipse è conveniente in quanto fornisce degli aiuti durante la scrittura del codice e nel caso di errori sintattici indica i modi possibili per risolverli. 3.3.1 Prerequisiti Per poter utilizzare la piattaforma Mason è necessario eseguire dei passi preliminari. Innanzitutto bisogna scaricare dal sito http://www.cs.gmu.edu/~eclab/projects/mason/ il della Mason programma in formato compresso e decomprimerlo. Una volta decompresso si ottiene una cartella che contiene le librerie necessarie per eseguire le simulazioni. Il passo successivo è scaricare delle librerie opzionali ovvero JFreeChart, iText e Java Media Framework. Per l’installazione seguire le indicazioni contenute nel file readme. Per eseguire simulazioni 3D è necessario installare il Java3D framework dal sito della Sun e copiare i file .jar nella cartella del Mason. 18 Dopo aver eseguito queste operazioni la fase successiva è configurare Eclipse per l’utilizzo del Mason. 3.3.2 Installare Mason in Eclipse Per installare Mason in Eclipse bisogna seguire i seguenti passi: Lanciare Eclipse, appena viene eseguito chiederà la directory da utilizzare come workspace. Dopo aver lanciato Eclipse bisogna creare un progetto che contiene il MASON. • Selezionare File New Project. Selezionare Java Project e cliccare su Next. • Nella finestra che compare indicare come nome del progetto “MASON” , cliccare su Create new project in workspace, e Create separate source and output folders. Poi cliccare su Finish per chiudere la finestra. • Espandere il progetto MASON cliccando sul + alla sua sinistra, cliccare con il tasto destro del mouse su “src” e selezionare Import File system Next. Selezionare la cartella MASON ,cliccare su OK e selezionare le caselle corrispondenti a ec e sim come mostrato nella figura 3.4. 19 Figura 3.4 (Installazione Mason in Eclipse) 3.3.3 Creare un nuovo progetto Questo passo viene eseguito se si vuole creare un modello Mason dall’inizio. Le operazioni da eseguire sono: Selezionare File New Project. Poi selezionare Java Project e cliccare su Next. Nella nuova finestra indicare il nome del progetto e selezionare Create separate source and output folders. Cliccare su Next per visualizzare la finestra con i Java settings. 20 Cliccare su Projects e selezionare Add. Cliccare sulla casella che indica il progetto MASON creato precedentemente e premere il tasto Finish come indicato nella figura 3.5. Figura 3.5 (Creazione di un nuovo progetto) Creare un nuovo package in cui inserire le classi che verranno create. A questo punto siamo in grado di iniziare a scrivere il nostro modello di simulazione MASON. 21 3.3.4 Importare un modello Mason Questo passo viene eseguito se si vuole importare un modello Mason già esistente. Le operazioni da eseguire sono le seguenti : Selezionare File New Project. Poi selezionare Java Project e cliccare su Next. Nella nuova finestra indicare il nome del progetto e selezionare Create separate source and output folders. Cliccare su Next per visualizzare la finestra con i Java settings. Cliccare su Projects e selezionare Add. Cliccare sulla casella che indica il progetto MASON creato precedentemente e premere il tasto Finish. Creare un nuovo package. Cliccare con il tasto destro del mouse sul package e selezionare Import File system. Nella finestra che compare selezionare la cartella che contiene il modello da importare e indicare i file da importare. A questo punto il modello è stato importato e la simulazione può essere avviata. 3.3.5 Avviare il modello Per eseguire il modello bisogna seguire i seguenti passi: Selezionare Run Run. Nella finestra che si apre selezionare “Run configuration”. A questo punto selezionare Java Application , cliccare su New e indicare il nome del package e il nome della classe che contiene il metodo main. Poi cliccare su Run come indicato nella figura 3.6. 22 Figura 3.6. (Avviare un progetto) Una volta configurato è possibile riavviare il programma cliccando su Run Run Last Launched on nel menù Eclipse. 23 4. IMPLEMENTAZIONE DELLA SIMULAZIONE MULTI-AGENTE 4.1 Descrizione della simulazione La simulazione multi-agente esposta in questa tesi modella un appartamento in 3D composto da varie stanze. All’interno dell’ambiente si muove un anziano il quale ha dei sensori che rilevano i parametri vitali e il verificarsi di situazioni particolari come ad esempio la sua caduta. In ogni ambiente è presente un sensore che rileva i parametri ambientali ed un assistente virtuale che interagisce con l’anziano e gli fornisce supporto durante la sua attività quotidiana, ad esempio ricordandogli di prendere le medicine o di chiudere i rubinetti rimasti aperti. Nella figura 4.1. è rappresentato il sensore ambientale e l’assistente virtuale. Figura 4.1 (Assistente virtuale e sensore) I parametri ambientali e vitali vengono visualizzati su una finestra apposita la quale viene aggiornata periodicamente oppure su richiesta dell’utente premendo il pulsante predisposto a tale scopo. 24 L’obiettivo della simulazione è monitorare la vita dell’anziano tramite i sensori per eventualmente intervenire in caso di necessità. La figura 4.1 mostra una panoramica dell’appartamento in cui vive l’anziano. Come si nota dalla figura sottostante l’appartamento è composto da una cucina, da una camera da letto, da un bagno e da un salotto. Figura 4.2 (Panoramica della casa) L’anziano si muove secondo delle traiettorie predefinite ed esegue delle azioni nell’arco della giornata. La giornata dell’anziano inizia alle 8:00 recandosi in cucina per fare colazione. Una panoramica della cucina è mostrata in figura 4.3. Dopo la colazione alle 8:30 l’anziano si avvia verso il bagno per svolgere i suoi bisogni fisiologici. Durante il percorso l’anziano cade e l’assistente virtuale gli chiede se ha bisogno di aiuto. Una panoramica del bagno è mostrata in figura 4.4. 25 Figura 4.3 (Panoramica della cucina) Figura 4.4 (Panoramica del bagno) Dopo essere andato in bagno l’anziano si reca in camera per leggersi un libro. La panoramica della camera è mostrata in figura 4.5. Dopo una fase di lettura l’anziano va in salotto a guardare la tv. Una panoramica del salotto è mostrata in figura 4.6. 26 Figura 4.5 (Panoramica della camera) Figura 4.6 (Panoramica del salotto) 27 Alle ore 10:00 il figlio fa visita all’anziano e per passare il tempo giocano a scacchi. Una panoramica della partita a scacchi e mostrata in figura 4.7. Alle ore 11:00 il figlio lascia la casa e l’anziano torna a sedersi sul divano a guardare la tv. Alle ore 12:00 l’anziano si reca in cucina e si mette a cucinare, terminata la preparazione si mette a tavola e subito dopo lava i piatti. Dopo aver eseguito queste azioni l’anziano torna in salotto e si sdraia sul divano per riposarsi. Il riposo va avanti finchè l’anziano non sente nuovamente un bisogno fisico, quindi si reca in bagno. Durante il tragitto l’anziano cade e l’assistente virtuale gli chiede se ha bisogno di aiuto. Dopo essere andato in bagno torna sul divano a guardare la tv. Alle ore 17:00 l’assistente virtuale gli ricorda di prendersi le medicine quindi l’anziano si alza, provvede a prendere le medicine e poi torna a sedere sul divano. Alle ore 18:00 squilla il telefono e l’assistente virtuale lo informa che c’è il figlio in linea, quindi l’anziano risponde. Alle ore 19:00 l’assistente virtuale fa una panoramica dei parametri vitali dell’anziano. Alle ore 20:00 l’anziano inizia a prepararsi la cena, terminata la preparazione si mette a tavola e dopo la cena lava i piatti. Dopo aver lavato i piatti torna sul divano a guardare la tv. Resta a guardare la tv fino alle 23:00 , poi va in camera, chiude le finestra e si mette a dormire fino alla mattina. 28 Figura 4.7 (Anziano con il figlio) 29 4.2 Realizzazione del modello Il modello è interamente contenuto in una sottoclasse di SimState. SimState è la superclasse astratta per la realizzazione del modello Mason. Il livello modello consiste di due parti: fields e discrete-event schedule. I fields memorizzano degli oggetti arbitrari e li allocano nella loro posizione spaziale. Lo schedule invece rappresenta il tempo e permette agli agenti di eseguire le loro azioni nel futuro. Mason non programma gli eventi da inviare ad un agente ma è l’agente stesso che programma le sue attività. La pianificazione di un’agente per eseguire le diverse funzioni può essere facilmente effettuata con una apposita classe che estende Steppable. Una simulazione di base tipicamente consiste di uno o piu fields, uno schedule e degli oggetti ausiliari definiti dall’utente. La classe principale che ho utilizzato per la creazione del modello è Model3D.java. Le altre classi necessarie per la realizzazione della simulazione sono MovePerson.java, la classe Orologio.java, VariatoreParametri.java , Person.java, ViewParametri e AssistenteVituale.java. Nel seguito verrà esposta la struttura e le funzioni di ognuna delle classi sopra citate. 4.2.1 Model3D.java Model3D.java è una sottoclasse di sim.engine.SimState che è la classe di base per modellare una simulazione Mason. 30 SimState ha 2 variabili fondamentali: • random: è un generatore di numeri casuali che utilizza l’algoritmo ec.util.MersenneTwisterFast. Tale algoritmo è molto efficiente in quanto utilizza una matrice di ricorrenza lineare su campo binario. • Sim.engine.schedule: è la rappresentazione del tempo. Consente agli agenti di eseguire le loro azioni nel futuro. Il codice della classe Model3D.java è il seguente: import sim.engine.*; import sim.util.*; public class Model3D extends SimState { static final long serialVersionUID=1; double width = 60; double height = 60; double length = 60; public House house; Person p; public Model3D(long seed){ super(seed); } public void start(){ super.start(); house = new House(this,width,height,length); house.setHouse(); //creo orologio che simula lo scorrimento del tempo Orologio orologio=new Orologio(1); house.setObjectLocation(orologio, new Double3D(0,15,-55)); schedule.scheduleRepeating(0,0,orologio,1); //creo la persona che si muove nell'ambiente p=new Person(orologio); 31 house.setObjectLocation(p,new Double3D(50,Y,-30)); schedule.scheduleRepeating(Schedule.EPOCH,1,p,1); //creo ospite Ospite ospite=new Ospite(orologio); schedule.scheduleRepeating(Schedule.EPOCH, 1,ospite); //creo i vari sensori ambientali SensoriAmbientali sensAmb1=new SensoriAmbientali(house) house.setObjectLocation(sensAmb1,new Double3D(-30,8,50.6)); … //creo il sensore vitale posizionato addosso alla persona SensoriVitali sensVitali=new SensoriVitali(p); //creo il sensore per il gas SensoreGas sGas=new SensoreGas(this); //creo un agente che fa variare tutti i parametri adeguatamente nell'arco della giornata VariatoreParametri var= new VariatoreParametri( this,orologio,house,p); schedule.scheduleRepeating(Schedule.EPOCH,1,var,1); //creo un coordinatore che mi interroga i sensori e mi fornisce i valori delle misurazioni ViewParametri vP=new ViewParametri(orologio,sensAmb1, sensVitali, sGas); schedule.scheduleRepeating(0,1,vP,1); } public static void main(String[] args){ doLoop(Model3D.class, args); System.exit(0); } } Il costruttore di Model3D.java prende come parametro un numero casuale che dipende dall’orologio interno del sistema. Il metodo start ( ) viene chiamato quando inizia la simulazione e si occupa di : Creare il field. 32 Inizializzare il field per creare i componenti dell’ambiente domestico. Creare l’orologio e sincronizzarlo con lo schedule del modello Mason. Creare l’anziano, collocarlo nella posizione iniziale e avviare il suo comportamento che è predefinito e dipende dal valore dell’orologio. Creare i sensori ambientali e collocarli all’interno della casa. Creare i sensori vitali. Creare la classe VariatoreParametri che fa variare i parametri vitali e ambientali in modo casuale per ottenere un andamento realistico. Creare la classe ViewParametri che visualizza periodicamente in una finestra sia i parametri vitali che quelli ambientali. Il field che ho utilizzato per rappresentare lo spazio è la classe House.java che estende la classe Continuous3D. La struttura della classe House è la seguente: import sim.field.continuous.Continuous3D; import sim.util.Double3D; public class House extends Continuous3D { //costruttore public House(Model3D model,double w, double h, double l){ super(1,w,h,l); this.model=model; } //metodo che mi imposta i componenti dentro casa public void setHouse(){ … 33 … } } Sim.field.continuous.Continuous3D rappresenta uno spazio continuo tridimensionale. Il costruttore ha 4 parametri: Livello di discretizzazione : deve essere più grande della dimensione massima di ogni oggetto che si prevede di mettere in Continuous3D per essere sicuri che la ricerca degli oggetti sia efficiente all’interno dello spazio 3D. Larghezza Altezza Lunghezza Inoltre tale classe prevede diversi metodi. Quelli che ho usato nella mia simulazione sono: setObjectLocation (Object obj, Double3D location): si occupa di collocare l’oggetto obj nella posizione location. getObjectLocation (Object obj): ritorna la posizione attuale dell’oggetto obj. getObjectsWithinDistance(Double3D position,Double distance) ritorna una bag che contiene tutti gli oggetti che si trovano entro la distanza distance rispetto al punto position. Sim.engine.schedule invece rappresenta il tempo e consente agli agenti di eseguire delle azioni nel futuro. Si possono pianificare eventi che si verificano una sola volta oppure più volte in un intervallo di tempo. In questo caso lo schedule fornisce 34 un oggetto di tipo Stoppable su cui è possibile chiamare il metodo stop( ) che consente di cancellare tutte le ripetizioni future dell’evento. Lo schedule è di tipo discrete-event cioè il tempo è discreto ed è composto da time step. Ad ogni time step lo schedule chiama tutti gli eventi in programma in quel momento. Possono essere programmati anche eventi multipli nello stesso tempo. Gli eventi programmati per lo stesso momento sono classificati in base al loro ordering definito da un numero intero. Gli agenti che hanno un ordinamento più basso vengono eseguiti prima degli altri. Se gli agenti previsti per lo stesso tempo hanno anche lo stesso ordinamento allora la loro esecuzione è determinata in maniera casuale. È possibile ottenere il numero di volte che il metodo step ( ) è stato chiamato utilizzando il metodo getStep( ) . Lo schedule fornisce diversi metodi ma il metodo principale che ho utilizzato nella mia simulazione è schedule.scheduleRepeating ( double time, int ordering, Steppable agent, double interval). Questo metodo consente all’agente di eseguire le sue azioni a partire dall’istante di tempo definito da time con un ordinamento pari a ordering. Il valore di interval invece definisce la frequenza di esecuzione delle azioni, ad esempio se vale 1 significa che agent esegue le sue azioni ogni time step . Il valore normalmente utilizzato per time è Schedule.EPOCH che rappresenta il primo tempo utile per la schedulazione. Nella piattaforma Mason un agente è un oggetto che implementa l’interfaccia Steppable. Tale interfaccia prevede un solo metodo ovvero step( ) che definisce il comportamento dell’agente nel corso del tempo. Tale metodo viene chiamato automaticamente dallo schedule. 35 Nel modello inoltre vengono creati anche i sensori vitali e i sensori ambientali. La loro funzione è quella di fornire i valori delle rilevazioni effettuate nel momento in cui vengono interrogati. I parametri vitali sono contenuti nella classe Person.java mentre i parametri ambientali sono contenuti nella classe House.java . Tali parametri vengono fatti variare dalla classe VariatoreParametri.java e vengono visualizzati tramite la classe ViewParametri.java. Queste classi saranno esposte in maniera più approfondita nel seguito. 4.2.2 Orologio.java La classe Orologio.java è un agente che implementa l’interfaccia Steppable. Il metodo step( ) viene eseguito ad ogni time step e consente all’orologio di rimanere sincronizzato con lo schedule del modello Mason. Ogni time step l’orologio viene incrementato di un secondo. Quando il valore di steps raggiunge circa il valore 86000 significa che la giornata è finita e quindi la simulazione viene interrotta. L’orologio è un componente fondamentale del modello perché sincronizza le varie classi . Il codice di tale classe è il seguente: import sim.engine.*; import sim.portrayal.DrawInfo2D; import sim.portrayal3d.SimplePortrayal3D; public class Orologio extends SimplePortrayal3D implements Steppable { public int ore=8; public int minuti; public int secondi; public int steps; public int n; 36 public Orologio(int n){ this.n=n; } public void step(SimState state){ steps++; secondi++; if(secondi==60){ minuti++; secondi=0; if(minuti==60){ ore++; minuti=0; if(ore==24){ ore=0; } } } if(steps==86000){ ((Model3D)state).schedule.reset(); ((Model3D)state).finish(); } } //metodo che mi disegna l'orologio public TransformGroup getModel(Object obj, TransformGroup j3dModel) { … } } 4.2.3 Person.java La classe Person.java è un agente che implementa l’interfaccia Steppable. Il metodo principale di tale classe è step( ) che consente all’agente ovvero all’anziano di eseguire delle azioni nel corso della giornata in base al tempo che scorre. Le azioni eseguite dipendono dal 37 valore corrente dell’orologio che è sincronizzato con lo schedule del modello Mason. La classe Person.java estende anche la classe SimplePortrayal3D che consente di disegnare l’anziano utilizzando le funzionalità del Java3D come vedremo nel seguito di questa tesi. La classe Person.java tra le classi della simulazione è quella più lunga in quanto definisce tutti i comportamenti dell’anziano nell’arco della giornata. Il codice di tale classe è: import sim.engine.*; import sim.util.*; import sim.portrayal3d.SimplePortrayal3D; public class Person extends SimplePortrayal3D implements Steppable { static final long serialVersionUID=1; public static final int move=0; public static final int sit=1; public static final int disteso=2; public static final int caduto=3; //variabili istanza … … //metodo step public void step(SimState state){ model=(Model3D)state; this.loc=model.house.getObjectLocation(this); //alle 8 si alza e va in cucina if((orologio.ore==8)&&(orologio.minuti==0)&&( orologio.secondi==0||orologio.secondi==1)) { Double3D[] newLoc ={new Double3D(40,model.Y,-20), new Double3D(43,model.Y,0), new Double3D(43,model.Y,38), new Double3D(38,model.Y+1,38), null}; comp=move; finalComp=sit; 38 mp=new MovePerson(this); mp.setMovement(newLoc,finalComp); s=model.schedule.scheduleRepeating(orologio.n* orologio.steps,mp,1); } //alle 8:30 si alza dal tavolo e cade if((orologio.ore==8)&&(orologio.minuti==30)&& (orologio.secondi==0)){ Double3D[] newLoc ={new Double3D(43,model.Y,0), new Double3D(43,model.Y,-9), new Double3D(43,model.Y-3.5,-10), null}; comp=move; finalComp=caduto; mp.setMovement(newLoc,finalComp); s=model.schedule.scheduleRepeating(orologio.n* orologio.steps,mp,1); } //esegue le altre azioni della giornata … … } //metodo che mi disegna omino public TransformGroup getModel(Object obj, TransformGroup j3dModel){ … } //metodo che mi imposta la rotazione dell'omino public Transform3D setTransform(){ … } //metodo che mi aggiunge dei componenti aggiuntivi in base al tempo che scorre public TransformGroup setComponent(){ … } 39 In base al valore dell’orologio l’anziano esegue delle azioni quindi il metodo step( ) è una sequenza di if come mostrato in breve dal codice sovrastante. Gli altri metodi della classe sono : getModel(Object obj, TransformGroup j3dModel) : viene eseguito ogni time step per caricare il disegno dell’anziano in base all’azione che sta svolgendo. setTransform( ): viene utilizzato per eseguire la rotazione dell’anziano durante il suo movimento in base alla traiettoria seguita. setComponent( ): aggiunge dei componenti aggiuntivi alla scena grafica in base al valore dell’orologio. Nel metodo step( ) vengono definite le traiettorie che l’anziano segue nel corso della giornata. Il movimento vero e proprio viene eseguito dalla classe MovePerson.java che varrà esposta in seguito. 4.2.4 MovePerson.java La classe MovePerson.java consente all’anziano di muoversi da un punto all’altro della casa. Il codice di tale classe è il seguente: import sim.util.*; import sim.engine.*; public class MovePerson implements Steppable { //variabili istanza … … //costruttore public MovePerson(Person p){ this.p=p; } 40 //imposta le caratteristiche del movimento da eseguire public void setMovement(Double3D[] newLoc,int c){ … } //metodo step public void step(SimState state){ Model3D model=(Model3D)state; if(newLoc[i]!=null){ moveTo(); double newx=loc.x+xdir; double newz=loc.z+zdir; loc=new Double3D(newx,newLoc[i].y,newz); model.house.setObjectLocation(p,loc); if(Math.abs(loc.x-newLoc[i].x)<0.3 &&Math.abs(loc.z-newLoc[i].z)<0.3) { model.house.setObjectLocation(p,newLoc[i]); i++; } } if(i==n) { p.setComportamento(comp); p.s.stop(); } } //metodo che in base ai punti da raggiungere effettua lo spostamento public void moveTo(){ … } } Il costruttore prende come argomento un oggetto di tipo Person in modo da collogarsi con l’anziano. Il metodo setMovement(Double3D [ ] newLoc, int c) imposta il movimento da eseguire infatti ha 2 parametri: Double3D [ ] newLoc : è un vettore di punti 3D che definisce la traiettoria seguita dall’anziano. 41 int c : è un intero che definisce il comportamento dell’anziano quando raggiunge il punto finale di newLoc . Può assumere diversi valori a seconda che l’anziano stia in piedi , seduto, disteso oppure caduto per terra. Il metodo step( ) consente all’anziano di eseguire dei piccoli movimenti per raggiungere il prossimo punto previsto dal vettore della traiettoria. Una volta che l’anziano ha raggiunto il punto finale il movimento viene interrotto dal metodo p.s.stop( ) e viene impostato il suo comportamento finale che può essere in piedi , seduto, caduto o disteso. Il metodo moveTo( ) determina le direzioni del movimento in base al prossimo punto da raggiungere. 4.2.5 VariatoreParametri.java La classe VariatoreParametri.java si occupa di far variare i parametri vitali e ambientali nell’arco della giornata nel modo più realistico possibile. I parametri da far variare sono : Temperatura dell’ambiente Umidità Luminosità Temperatura corporea Pressione arteriosa Frequenza cardiaca Il codice della classe è : import sim.engine.SimState; import sim.engine.Steppable; public class VariatoreParametri implements Steppable { //variabili istanza … 42 //costruttore public VariatoreParametri(Model3D m,Orologio clock,House house,Person p){ this.model=m; this.orologio=clock; this.house=house; this.p=p; } //metodo step public void step(SimState state) { double x; //variazione temperatura ambientale if(orologio.ore<15){ if((orologio.minuti==0 || orologio.minuti==30)&&(orologio.secondi==0)){ x=house.getTemperatura()+0.2+(model.random. nextDouble()*0.2-0.1); house.setTemperatura(x); } } else { if((orologio.minuti==0 || orologio.minuti==30)&&(orologio.secondi==0)){ x=house.getTemperatura()+0.2+(model.random. nextDouble()*0.2-0.1); house.setTemperatura(x); } } //variazione umidità … //variazione luminosità … //variazione temperatura corporea … //variazione pressione … //variazione frequenza cardiaca … } 43 Il metodo step( ) si occupa di far variare i parametri a intervalli di tempo regolari. Ho scelto di farli variare casualmente ogni mezz’ora. 4.2.6 ViewParametri.java La classe ViewParametri.java interroga periodicamente i sensori ambientali e vitali e visualizza i risultati delle rilevazioni su un’apposita finestra. Il codice della classe è il seguente: import java.awt.*; import javax.swing.*; import sim.engine.*; import sim.util.Double3D; public class ViewParametri implements Steppable , ActionListener { //variabili istanza … //costruttore che crea la finestra e la posiziona public ViewParametri(Orologio o, Sensori Ambientali sA, SensoriVitali sV,SensoreGas sG) { … … } //metodo step public void step(SimState state){ … } public void actionPerformed(ActionEvent e){ … } } 44 Il costruttore inizializza le variabili di istanza e crea la finestra di visualizzazione dei parametri. Il metodo step( ) si occupa di interrogare periodicamente i sensori vitali e ambientali per aggiornare la finestra. Il metodo actionPerformed (ActionEvent e) consente di interrogare e aggiornare la finestra di visualizzazione quando viene premuto l’apposito pulsante collocato sulla finestra stessa. La finestra di visualizzazione è mostrata in figura 4.8. Figura 4.8 ( Finestra di visualizzazione) 45 4.2.7 AssistenteVirtuale.java La classe AssistenteVirtuale.java si occupa di gestire la visualizzazione dell’assistente virtuale e di fornire supporto all’anziano durante la sua attività quotidiana. L’assistente virtuale si occupa di: Fornire un messaggio di buongiorno all’anziano in cui lo informa che i suoi parametri vitali sono nella norma. Nel caso della caduta dell’anziano gli chiede se ha bisogno di aiuto. Ricordare all’anziano di prendersi le medicine. Far notare all’anziano eventuali rubinetti rimasti aperti. Rispondere al telefono e mettere in comunicazione l’anziano con il chiamante. Fornire all’anziano un riepilogo dei suoi parametri vitali. Queste funzioni vengono eseguite tramite una voce sintetizzata realizzata utilizzando un apposito software adatto allo scopo. La riproduzione dell’audio viene attuata utilizzando un’apposita classe Suono.java che carica e riproduce un suono in formato .wav. 46 4.3 Realizzazione della parte grafica La simulazione Mason può operare con o senza un’interfaccia grafica (GUI). Per fare ciò il modello è separato dalla visualizzazione. Nella mia simulazione la visualizzazione grafica è fondamentale. Gli oggetti del livello visualizzazione possono esaminare gli oggetti del livello modello solo con il permesso di un gatekeeper wrapper chiamato GUIState. Questa classe consente di staccare il modello dalla visualizzazione. 4.3.1 Model3DWithUI.java La classe principale che ho utilizzato per la gestione grafica della simulazione è Model3DWithUI.java. Tale classe estende GUIState. Il codice della classe Model3DWithUI.java è il seguente: import sim.engine.*; import sim.display.*; import sim.display3d.Display3D; import sim.portrayal3d.continuous.ContinuousPortrayal3D; import javax.media.j3d.*; import javax.swing.*; import javax.vecmath.*; import com.sun.j3d.loaders.*; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.image.TextureLoader; public class Model3DWithUI extends GUIState { public Display3D display; public JFrame displayFrame; ContinuousPortrayal3D housePortrayal=new ContinuousPortrayal3D(); public static void main(String[] args) { Model3DWithUI m=new Model3DWithUI(); Console c=new Console(m); 47 c.setVisible(true); } //costruttori public Model3DWithUI() { super(new Model3D(System.currentTimeMillis())); } public Model3DWithUI(SimState state) { super(state); } public static String getName() { return "Prova: Casa"; } //metodo quit public void quit() { super.quit(); if (displayFrame!=null) displayFrame.dispose(); displayFrame = null; // let gc display = null; // let gc } //metodo init che inizializza la simulazione public void init(Controller c){ super.init(c); Model3D m=(Model3D)state; // make the display display = new Display3D(750,750,this,1); display.attach(housePortrayal,"house"); float scale =(float) Math.max(Math.max(m.width,m.height), m.length); display.scale(1f/scale); //creo e registro il frame del display3D con la console displayFrame = display.createFrame(); c.registerFrame(displayFrame); displayFrame.setVisible(true); } public void start() { super.start(); 48 setupPortrayals(); } public void load(SimState state) { super.load(state); setupPortrayals(); } //metodo setupPortrayal public void setupPortrayals() { display.destroySceneGraph(); Model3D m=(Model3D)state; housePortrayal.setField(m.house); display.reset(); display.createSceneGraph(); display.root.addChild(createScene()); display.root.addChild(creaPavimento()); } //carica la scena grafica dal file public BranchGroup createScene() { //Crea la radice del branch graph BranchGroup objRoot=new BranchGroup(); … … return objRoot; } public BranchGroup creaPavimento(){ … } } Dopo aver messo il codice relativo alla classe procedo alla spiegazione di esso. Sim.Display.GUIState è la superclasse astratta per la costruzione e la gestione della grafica. Si occupa di controllare il modello e di gestire un mini-schedule ausiliario associato a quello del modello stesso. 49 Tale classe prevede 2 costruttori, uno prende come parametro una SimState e l’altro crea la SimState al volo. Il metodo main crea una Console che ha come parametro un’istanza della classe GUIState. La Console è un controller che consente all’utente di manipolare lo schedule e sta alla base della simulazione grafica. I suoi principali compiti sono: Riproduzione, arresto e pausa della simulazione. Visualizzazione del time corrente. Controllo del generatore di numeri casuali. Salvataggio e caricamento della simulazione. Visualizzazione dei display. Una rappresentazione della console è mostrata in figura 4.9. Figura 4.9 (Console del mason) 50 Il metodo init (Controller c) viene utilizzato per inizializzare la simulazione. Tale metodo è chiamato quando la GUI viene avviata per la prima volta. Si occupa di : Creare il display3D. Creare il frame che conterrà il display. Registrare il frame con la console. Attaccare il portrayal3D con il display3D. Sim.display3d.Display3D visualizza e manipola gli oggetti portrayal3D consentendo all’utente di ruotarli, ingrandirli, modificare le sequenza di aggiornamento, scattare delle fotografie e filmati della simulazione. Display3D è Steppable infatti ad ogni time step viene aggiornato e ridisegnato. Il costruttore prende 4 parametri: Double width: larghezza della regione. Double height: altezza della regione. GUIState simulation: è la simulazione da visualizzare. Long interval: intervallo di visualizzazione del display. Il display3D può essere collocato in un JFrame che si ottiene chiamando l’apposita funzione display.createFrame( ) fornita dal display3D stesso. Una volta creato il frame deve essere registrato con la console per consentirle di gestire la visualizzazione e l’aggiornamento all’interno del frame stesso. La registrazione viene effettuata utilizzando il metodo c.registerFrame( displayFrame). Il display3D utilizza le librerie Java3D che verranno esposte nel prossimo paragrafo. I fields portrayals sono classi responsabili del disegno lasciando all’utente la manipolazione degli oggetti conservati al loro interno. 51 Il portrayal3D che ho utilizzato nella mia simulazione è sim.portrayal3d.continuous.ContinuousPortrayal3D che è il portrayal di default per il campo Continuous3D. Per attaccare il display3D con il portrayal3D si utilizza il metodo display.attach(housePortrayal,"house"). Una rappresentazione del display3D è fornita in figura 4.10. Figura 4.10 (Visualizzazione del display3D) Il metodo quit( ) è chiamato quando console viene chiusa e si occupa di chiudere il display e il relativo frame associato. 52 Il metodo start( ) viene chiamato quando si preme il pulsante play della console. Il metodo load( ) invece viene chiamato quando la simulazione è caricata da un file di controllo. In genere questi 2 metodi fanno la stessa cosa quindi si utilizza il metodo setupPortrayals( ) che esegue le operazioni necessarie. Tale metodo svolge varie operazioni: display.destroySceneGraph( ): rimuove dalla scena tutto il contenuto precedente. housePortrayal.setField( m.house): indica che il portrayal deve raffigurare il field del modello ovvero m.house. Questa operazione va eseguita dopo aver distrutto la scena grafica perché potrebbe tentare di modificare gli oggetti che Java3D ha in comune con gli oggetti della scena grafica e che non possono essere modificati. display.reset ( ) e display.createSceneGraph( ): consentono al display3D di ricostruirsi dopo aver distrutto la scena grafica. Quando si verifica il reset del display lui si registra automaticamente con la GUIState per essere continuamente aggiornato ad ogni step. Il metodo createScene( ) si occupa di creare la struttura di base della casa cioè le mura. Infine il metodo creaPavimento( ) si occupa di disegnare il pavimento della casa caricandolo da una texture. 53 4.3.2 Altre classi grafiche Gli altri componenti della casa vengono disegnati a parte ognuno in una classe apposita. Le varie classi vengono definite per distinguere le tipologie di oggetti contenuti nella casa e per effettuare il disegno su misura. I componenti della casa sono aggiunti al field house e collocati nella posizione idonea. Le varie classi utilizzate sono: Armadio.java : disegna l’armadio e lo colloca nella camera. Bagno.java : effettua il disegno dei sanitari del bagno. Cucina.java : effettua il disegno dei componenti della cucina che comprende il frigorifero, i fornelli, il lavandino e i mobili. Divano.java : disegna il divano e lo colloca in salotto. Door.java : disegna le porte e le colloca nelle posizioni idonee. Finestra.java : disegna le finestre e le colloca nelle posizioni idonee. Letto.java : disegna il letto e lo colloca nella camera. Sedia.java : disegna le sedie e le colloca nelle posizioni idonee all’interno della casa. Tavolo.java : disegna i tavoli e li colloca nelle giuste posizioni. Telefono.java : disegna il mobile con il telefono sopra e lo colloca nel salotto. Tv.java : disegna il televisore lcd e lo colloca nel salotto. Ognuna delle classi sopra citate estende la classe SimplePortrayal3D che non fornisce un disegno di default ma è il programmatore che decide come disegnare quel determinato componente. Il disegno di ogni componente avviene utilizzando la classe loader di java3D che consente di caricare un file .obj che contiene la realizzazione grafica dell’oggetto da disegnare. La classe loader verrà 54 esposta in maniera più approfondita nel paragrafo successivo relativo alle librerie java3D. Un esempio di come avviene il caricamento della grafica è mostrato nel codice seguente: import javax.media.j3d.BranchGroup; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import sim.portrayal3d.SimplePortrayal3D; import com.sun.j3d.loaders.Scene; import com.sun.j3d.loaders.objectfile.ObjectFile; public class Bagno extends SimplePortrayal3D { public TransformGroup getModel(Object obj, TransformGroup j3dModel) { if(j3dModel==null){ j3dModel = new TransformGroup(); TransformGroup tG1=new TransformGroup(); Transform3D t3d=new Transform3D(); t3d.setScale(20.0); tG1.setTransform(t3d); j3dModel.addChild(tG1); ObjectFile f=new ObjectFile(ObjectFile.RESIZE); try { Scene s=f.load("bagno.obj"); BranchGroup b=s.getSceneGroup(); tG1.addChild(b); b.compile(); } catch (Exception e) {System.out.println(e);} } return j3dModel; } } 55 4.4 Librerie Java3D Java3D è un interfaccia di programmazione grafica in 3D per la costruzione di applicazioni e applet Java. Java3D è una libreria per l'interfacciamento ad un sistema tridimensionale grafico e sonoro. Basato sulla portabilità del java. Essa fornisce agli sviluppatori di alto livello costrutti per creare e manipolare la geometria 3D . Le schede 3D producono oggi grafica interattiva paragonabile agli effetti speciali cinematografici. Java è uno standard di sviluppo consolidato, potente e stabile. Il livello più basso del Java3D si basa sulle librerie come Direct3D, OpenGL, QuickDraw3D, e XGL…. Java 3D introduce alcuni concetti non comunemente considerati come parte dell’ambiente grafico 3D come ad esempio il suono spaziale. Java 3D è stato progettato con diversi obiettivi in mente : Raggiungere elevate prestazioni: il rendering è gestito automaticamente. Il programmatore decide solo “cosa” disegnare mentre Java3D decide “come” disegnarlo. Integrazione con Java : core e portabilità Fornire una serie di funzioni interessanti per creare mondi 3D. Fornire un elevato livello di programmazione object-oriented che consente agli sviluppatori di implementare sofisticate applicazioni e applet rapidamente. Forza industriale: non solo semplici applet3D ma anche applicazioni molto più complesse. Questo permette a java3D di ospitare una vasta gamma di formati di file. 56 Java3D supporta un ampio range di applicazioni: Simulazione 3D. Sistemi CAD/CAM. Visualizzazione Scientifica. Desktop 3D. Videogame. Ecc.. 4.4.1 Scene Graph L’applicazione costruisce i singoli elementi grafici come oggetti distinti e poi li collega insieme in una struttura chiamata scene graph. La scena grafica contiene una descrizione completa di tutta la scena, ciò include la geometria dei dati, gli attributi e tutte le altre informazioni utili. Una scena grafica è un albero che contiene i dati di scena. I children sono le forme, le luci, suoni ecc…. I parents sono gruppi di children e altri parents. Questo definisce un raggruppamento gerarchico di forme. Il programmatore decide “cosa disegnare” mentre java3D decide “come” disegnarlo per ottimizzare il rendering. Un albero si compone di nodi e archi. I nodi sono oggetti java3D invece gli archi rappresentano due tipi di relazioni tra oggetti: relazione padre-figlio oppure reference. Terminologia della scene graph : 1. Node : elementi della scena grafica. Le sottoclassi costruiscono una scena grafica. Leaf node: nodi senza figli (forme, luci, suoni, ecc…) 57 Group nodes: nodi con figli (branch , transform , switches , ecc…) 2. Node Component : insieme di attributi di un nodo Geometria della forma; Colore; Suoni; I node component sono collegati alla scena grafica tramite reference. Class Hierarchy java.lang.Object javax.media.j3d.SceneGraphObject javax.media.j3d.Node javax.media.j3d.Group javax.media.j3d.Leaf javax.media.j3d.NodeComponent Terminologia dell’universo : Virtual Universe : raccolta di scene grafiche. In genere uno per ogni applicazione. Locale : posizione in cui l’universo mette la scena grafica. In genere uno per ogni universo. Branch Graph : una scena grafica. In genere diverse scene grafiche per ogni locale. Normalmente le scene grafiche sono divise in due tipi di branch graph: 1. Content Branch : (forme , luci , ecc..) in genere più content branch per locale. 2. View Branch : visualizzazione delle informazioni. In genere uno per ogni universo. Tale divisione è facoltativa infatti content e view possono appartenere anche allo stesso ramo. 58 SimpleUniverse è un oggetto contenente un virtualUniverse, un locale e una view branch graph. La procedura di creazione di un simpleUniverse è: 1. Creare un oggetto Canvas3D. 2. Creare un oggetto SimpleUniverse e collegarlo al canvas3D. 3. Personalizzare l’oggetto simple universe. 4. Costruire uno o più content branch graph. 5. Compilarli. 6. Collegarli al locale del simple universe. L’aggiunta di un branch graph nel locale ( o nel simple universe) li rende dei nodi live (drawable) Rimuovere il branch graph dal locale invece ha l’effetto contrario. Gli oggetti vivi possono essere renderizzati e i loro parametri non più modificabili. Per rendere un parametro modificabile anche quando l'oggetto è vivo, la corrispondente capability deve essere impostata su “modificabile” prima che l'oggetto stesso diventi vivo. Il metodo isLive( ) restituisce true se il nodo è live, false altrimenti. Il metodo compile( ) di branchGroup compila il branch ottimizzando il rendering. Quando si invoca tale metodo java3D converte l’intero branch graph in una rappresentazione interna molto più efficiente. Le capacità possono essere cambiate solo se il nodo è live, inoltre tali capacità vengono anche ereditate. 59 4.4.2 Shape3D Shape3D è descritto da una geometria (forma) e da un aspetto (appearance : colore, trasparenza, ecc). Java3D fornisce anche altri tipi di geometria tra cui raster geometry e text geometry . Shape3D estende la classe Leaf. java.lang.Object javax.media.j3d.SceneGraphObject javax.media.j3d.Node javax.media.j3d.Leaf javax.media.j3d.Shape3D I metodi di Shape3D sono: Shape3D( ) Shape3D(Geometry geometry, Appearance appearance) void setGeometry( Geometry geometry ) void setAppearance( Appearance appearance ) Costruire una shape è come collegare un insieme di coordinate 3D. Una rappresentazione degli assi cartesiani del java3D è fornita nella figura 4.11. Y X Z Figura 4.11 (Assi cartesiani in Java3D) 60 Il vertice descrive un angolo di un poligono e contiene diverse informazioni tra cui la coordinata 3D , colore , superfici normali e coordinate di texture. La coordinata 3D è necessaria mentre le altre sono facoltative. I diversi tipi di geometria sono: GeometryArray consente di costruire punti, linee, triangoli e quadrilateri. GeometryStripArray consente il riuso dei vertici per migliorare le prestazioni. IndexedGeometryArray indicizza i vertici per poterli riutilizzare a piacimento tutte le volte che si vuole. GeometryInfo permette di definire dei poligoni arbitrari. L’aspetto di una figura 3D definisce come effettuare il render della geometria ovvero il colore, trasparenza, spessore delle linee e altro. Tali caratteristiche sono incapsulate nella classe Appearance . Gli attributi sono distinti in : Material: controlla l’ambiente, emissione, il colore speculare e il fattore di lucentezza. ColoringAttributes: controlla il colore intrinseco della figura. TransparencyAttributes: controlla il valore e le modalità di trasparenza. PointAttributes: gestisce le dimensioni del punto e l’antialiasing. LineAttributes: gestisce il rendering delle linee. PolygonAttributes: gestisce il rendering dei poligoni. Texture: gestisce la texture dell’immagini e le modalità di rendering. 61 4.4.3 Grouping shapes Una scena grafica è una gerarchia di gruppi. Java3D ha diversi tipi di gruppi. Ogni gruppo gestisce una lista di nodi figli. Tutti i gruppi condividono gli attributi ereditati dalla classe Group. È possibile aggiungere, inserire, rimuovere e ottenere i children in un gruppo. I children sono implicitamente numerati a partire da zero. Un gruppo può avere qualsiasi numero di children. Java3D ordina le figure per migliorare l'efficienza. La gerarchia è la seguente: java.lang.Object javax.media.j3d.SceneGraphObject javax.media.j3d.Node javax.media.j3d.Group javax.media.j3d.BranchGroup javax.media.j3d.OrderedGroup javax.media.j3d.DecalGroup javax.media.j3d.SharedGroup javax.media.j3d.Switch javax.media.j3d.TransformGroup I grouping node di java3D sono: BranchGroup estende Group e crea un branch graph. Il branch graph può essere aggiunto ad un locale, può essere compilato, può essere un child di un altro nodo e può eventualmente distaccarsi dalla madre. Quando un branchGroup viene aggiunto ad un locale diventa vivo. TransformGroup estende group e consente di costruire un nuovo sistema di coordinate. La trasformazione è descritta tramite una Transform3D definita internamente come una matrice 4x4. È possibile impostare direttamente la matrice ma 62 in genere si preferisce usare i metodi messi a disposizione dalla classe. Le operazioni che consente di eseguire sono: o Traslazione: sposta il sistema di coordinate e le sue forme. o Rotazione: orienta il sistema di coordinate e le sue forme. È possibile ruotare lungo l’asse X,Y,Z oppure lungo un asse arbitrario. o Scaling: aumenta o riduce le proporzioni del sistema di coordinate. OrderedGroup estende Group e consente di eseguire il render dei children in ordine. Switch estende Group e consente di selezionare zero, uno o più children di cui fare il render. SharedGroup estende Group e crea un gruppo di forme che possono essere condivise. Non viene aggiunto direttamente alla scena grafica ma è referenziato da uno o più leaf group. 4.4.4 Luci direzionali Java3D illumina gli oggetti in base ad una combinazione delle proprietà degli oggetti e delle luci dell’universo virtuale. Java3D usa un modello di illuminazione che approssima il modello fisico reale. L’equazione del modello di illuminazione dipende da tre vettori: La normale alla superficie (N) La direzione della luce (L) La direzione dell’osservatore (E) 63 Figura 4.12 (Modello di illuminazione) Ovviamente nell’equazione entrano in gioco anche le proprietà dell’oggetto. Anche se il modello di illuminazione è basato su quello fisico alcuni fenomeni fisici non vengono modellati. L’API java3D fornisce diverse classi per le luci, ogni classe deriva dalla classe astratta Light. Le varie classi sono: AmbientLight: fornisce una luce della stessa intensità in tutte le direzioni e in tutte le posizioni. DirectionalLight: approssima sorgenti di luce distanti (ad esempio il sole) e illumina in una sola direzione con la stessa intensità in maniera indipendente dalla distanza. PointLight: è una sorgente di luce puntiforme che si diffonde in tutte le direzioni e la cui intensità diminuisce con la distanza. SpotLight: è una sottoclasse di PointLight e aggiunge il concetto di direzione e concentrazione della luce. In genere conviene usare due luci direzionali per illuminare l’ambiente perché sono più semplici da usare rispetto alle altre. Nella mia simulazione infatti ho usato 2 luci direzionali. Il codice relativo è: //Aggiunge una luce direzionale DirectionalLight lightD1=new DirectionalLight(); lightD1.setColor(new Color3f(1.0f,1.0f,0.9f)); lightD1.setDirection(new Vector3f(1.0f,1.0f,1.0f)); 64 lightD1.setInfluencingBounds(bounds); objRoot.addChild(lightD1); //Aggiunge un'altra luce direzionale DirectionalLight lightD2=new DirectionalLight(); lightD2.setColor(new Color3f(1.0f,1.0f,1.0f)); lightD2.setDirection(new Vector3f(-1.0f,-1.0f,-1.0f)); lightD2.setInfluencingBounds(bounds); objRoot.addChild(lightD2); 4.4.5 Classe loader La realizzazione di forme 3D utilizzando le classi di base è molto complessa in quanto bisogna definire tutti i possibili vertici, le superfici, le normali alle superfici ed un'altra serie di attributi fondamentali. Per modellare l’ambiente grafico della mia simulazione ho utilizzato la classe loader che legge un modello da un file e ne crea la sua rappresentazione java3D. Il package com.sun.j3d.loaders fornisce gli strumenti per caricare contenuti 3D creati con altre applicazioni (3DStudio, Blender, Art of Illusion, ecc…). Poiché esistono moltissimi formati 3D (obj, vrml,3ds, ecc…) e possono sempre essere inventati di nuovi allora java3D mette a disposizione un’interfaccia generica per la creazione di caricatori di file. Le operazioni da svolgere per caricare un file utilizzando un loader sono semplici: Trovare un loader compatibile con il formato del file. Caricare il file e assegnare il risultato ad un oggetto Scene. Inserire lo scene nello scene graph. Nella mia simulazione 3D ho utilizzato dei file in formato .obj realizzati con l’applicazione Art of Illusion. 65 Art of Illusion è un programma open source per la modellazione, il rendering, il texturing, il ray tracing di immagini ed animazioni tridimensionali. Lo scopo principale di Art of Illusion è quello di costituire un potente strumento di modellazione 3D con un'interfaccia grafica che apporta miglioramenti a quelle presenti in altri programmi di computer grafica. 66 5. CONCLUSIONI Il progetto che ho sviluppato mi ha consentito di estendere le mie conoscenze nell’area dell’intelligenza artificiale, in quella della grafica tridimensionale e ha approfondito notevolmente le mie competenze con il linguaggio di programmazione java e con la simulazione multi-agente mediante la piattaforma Mason. L’obiettivo della mia simulazione è quello di monitorare la vita dell’anziano attuando quindi una forma di ambient assisted living. Nella realtà questo obiettivo può essere realizzato utilizzando gli strumenti tecnologici che io ho rappresentato graficamente nella mia simulazione cioè sensori ambientali, sensori vitali e un’assistente virtuale autonomo con voce sintetizzata. Nel mio progetto comunque gli agenti non sono completamente autonomi in quanto le azioni compiute dall’anziano sono predefinite e anche il supporto fornito dall’assistente virtuale è deciso a priori. Quindi spero che il mio lavoro possa essere un punto di partenza per realizzare delle simulazioni autonome in cui gli agenti decidono le azioni da compiere in base alle loro capacità decisionali. Inoltre spero anche che il mio lavoro con il Mason possa essere di aiuto ad altri studenti che cercano di utilizzare questa piattaforma di simulazione multi-agente non semplice da capire per programmatori inesperti. Infine vorrei ringraziare il prof. Dragoni che mi ha dato la possibilità di svolgere attività di tirocinio presso il DIIGA. 67 6. RIFERIMENTI [1] George Mason University, Department of Computer Science, Washington, MASON Multi-agent Simulation Toolkit http://www.cs.gmu.edu/ ~eclab/ projects/mason/. [2] Sean Luke. ECJ 11: A Java evolutionary computation library. http://cs.gmu.edu/_eclab/projects/ecj/, 2004. [3] Evolutionary Computation Laboratory Department of Computer http://cs.gmu.edu/~eclab/. [4] Center for Social Complexity http://socialcomplexity.gmu.edu. [5] Steve Lytinen (http://condor.depaul.edu/~slytinen/) e Steve Railsback (Lang, Railsback & Associates): How to Set Up MASON in Eclipse. [6] Liviu Panait and Sean Luke. A pheromone-based utility model for collaborative foraging. In Proceedings of the Third International Joint Conference on Autonomous Agents and Multi Agent Systems (AAMAS-2004), 2004. [7] E. Bonabeau, M. Dorigo, and G. Theraulaz. Swarm Intelligence: From Natural to Artificial Systems. Santa Fe Institute Studies in the Sciences of Complexity. Oxford University Press, 1999. [8] The Java 3D API Specification. Version 1.2, April 2000. http://java.sun.com/products/java-media/3D/forDevelopers/ J3D_1_2_API/j3dguide/index.html. [9] Henry A. Sowizral, David R. Nadeau : Introduction to Programming with Java 3D. [10] Burattini E. , Cordeschi R. Intelligenza Artificiale: manuale per le discipline della comunicazione. Ottobre 2001. 68 [11] Deitel H.M., Deitel P.J. : Java Fondamenti di programmazione , terza edizione, ottobre 2005. [12] Deitel H.M., Deitel P.J. : Java Tecniche avanzate di programmazione , terza edizione. [13] Mason’s documentation and tutorial http://www.cs.gmu.edu/~eclab/projects/mason/docs/ [14] Sean Luke, Claudio Cioffi-Revilla, Liviu Panait, and Keith Sullivan. MASON: A New Multi-Agent Simulation Toolkit. 2004. Proceedings of the 2004 SwarmFest Workshop. [15] Claudio Cioffi-Revilla, Sean Paus, Sean Luke, James Olds, and Jason Thomas. Computational Mnemonic Agent-Based Structure Simulation and Sociality: A Model. 2004. In Conference on Colective Intentionality IV. [16] Sean Luke, Claudio Cioffi-Revilla, Liviu Panait, Keith Sullivan, and Gabriel Balan. MASON: A Multi-Agent Simulation Environment. 2005. In Simulation. 69 7. APPENDICE : LIBRERIE DEL MASON La piattaforma di simulazione Mason offre molte librerie che hanno diverse relazioni tra di loro. Uno schema generale sull’organizzazione del Mason è esposto nella figura 7.1. Figura 7.1 ( Schema generale dei componenti Mason) 70 Una rappresentazione dei componenti del modello e le relazioni con l’interfaccia grafica sono mostrate in figura 7.2. Figura 7.2 (Relazioni tra modello e GUI) 71 Una panoramica dei fields offerti dalle librerie del Mason è mostrata in figura 7.3. Figura 7.3 ( Fields del Mason) 72 Una panoramica dei fields portrayal3D offerti dalle librerie Mason è mostrata in figura 7.4. Figura 7.4 ( Fields portrayals3D) 73 Infine una panoramica dei simple portrayal3D è mostrata in figura 7.5. Figura 7.5 ( Simple portrayals3D) 74 8. INDICE DELLE FIGURE 3.1 Architettura del Mason 11 3.2 Procedura del checkpointing 12 3.3 Componenti del Mason 16 3.4 Installazione di Mason in Eclipse 20 3.5 Creazione di un nuovo progetto 21 3.6 Avviare un progetto 23 4.1 Assistente virtuale e sensore 24 4.2 Panoramica della casa 25 4.3 Panoramica della cucina 26 4.4 Panoramica del bagno 26 4.5 Panoramica della camera 27 4.6 Panoramica del salotto 27 4.7 Anziano con il figlio 29 4.8 Finestra di visualizzazione 45 4.9 Console del mason 50 4.10 Visualizzazione del display3D 52 4.11 Assi cartesiani in java3D 60 4.12 Modello di illuminazione 64 7.1 Schema generale dei componenti Mason 70 7.2 Relazioni tra modello e GUI 71 7.3 Fields del Mason 72 7.4 Fields portrayals3D 73 7.5 Simple portrayal3D 74 75