Questo scenario prevede un robot in free casual roaming: un robot che deve navigare casualmente in un’area evitando gli ostacoli, integrando quindi due componenti principali: movimento e collision avoidance.
5.2.1
Algoritmo
Data l’autonomia del robot in questione, risulta che una iniziale soluzione semplificata LeJOS a questo primo case study non necessita di coordinazio- ne ReSpecT. Si sceglie di utilizzare il package Behavior di LeJOS NXJ, API che consente di specificare in termini di comportamento il funzionamento del robot.
Il modello di controllo orientato al comportamento permette l’incap- sulamento di ciascun behavior1 in una struttura facilmente comprensibile. Questo approccio garantisce una pi`u facile manutenzione del codice, la sua riutilizzabilit`a, la separazione di compiti indipendenti in moduli.
I concetti fondamentali del behavior programming implementato in LeJOS NXJ sono molto semplici:
• solo un behavior pu`o essere attivo e avere il controllo del robot in un determinato istante di tempo
• ciascun behavior ha una priorit`a predefinita
1behavior, letteralmente comportamento, indica un insieme di azioni orientate al rag-
giungimento di uno scopo prestabilito, come ad esempio: muoversi, evitare gli ostacoli, monitorare il proprio stato, ecc.
5.2. CASE STUDY: FREE CASUAL ROAMING 33
• ciascun behavior `e capace di stabilire se `e il momento di assumere il controllo
• il behavior attivo in un determinato istante di tempo `e quello con prio- rit`a maggiore fra tutti i behavior che potrebbero assumere il controllo L’API Behavior `e composta di una sola interfaccia a di una sola classe. L’interfaccia Behavior definisce tre metodi publici che ne riassumono il fun- zionamento. Ciascun compito che il robot deve eseguire pu`o essere definito in una classe individuale di tipo Behavior. Una volta che sono stati creati, i vari behavior sono passati ad un Arbitrator che regola la loro esecuzione.
La struttura dell’API `e la seguente: • lejos.subsumption.Behavior
– boolean takeControl()
Ritorna un valore booleano che indica se questo behavior pu`o diventare attivo.
– void action()
Viene eseguito quando un behavior `e attivo. Di conseguenza un behavior `e attivo per tutto il tempo che questo metodo `e in ese- cuzione. Il metodo finisce l’esecuzione quando il compito ad esso assegnato finisce o quando viene invocato il metodo suppress(), lasciando comunque il robot in uno stato safe per il prossimo behavior.
– void suppress()
Termina immediatamente l’esecuzione del codice del metodo action() • lejos.subsumption.Arbitrator
– public Arbitrator(Behavior[] behaviors, boolean returnWhenInactive)
Costruttore di un Arbitrator.
behaviors: la priorit`a di un behavior `e il suo indice nell’array
returnWhenInactive: se true, il programma esce quando non
c’`e nessun behavior che vuole assumere il controllo. Altrimenti il programma rimane in esecuzione finch´e viene fermato attraverso la pressione dei pulsanti Enter/Escape del NXT
– public void start()
34 CAPITOLO 5. CASE STUDIES CON LEJOS
L’utilizzo della classe Arbitrator `e di facile comprensione. Quando un og- getto Arbitrator viene creato, gli viene passato un array di oggetti Behavior. Successivamente viene invocato il suo metodo start() che fa partire il suo processo di arbitraggio, decidendo quale behavior diventer`a attivo. Infatti, l’Arbitrator invoca il metodo takeControl() di ciascun oggetto Behavior, a cominciare dall’oggetto con il pi`u grande indice nell’array e scalando in ordi- ne decrescente fino a trovare un behavior che vuole assumere il controllo. Se la priorit`a di quest’ultimo `e maggiore di quella del behavior correntemente attivo, allora il behavior attivo viene soppresso e viene invocato il metodo action() del nuovo behavior. Come risultato si ha che tra eventuali behavior che vogliono il controllo, solo quello con priorit`a maggiore diventer`a attivo. Fatte queste premesse, l’implementazione risulta di facile attuazione. Per prima cosa si implementano i due behavior relativi a movimento e collision avoidance. 6 p u b l i c c l a s s M o v e m e n t i m p l e m e n t s B e h a v i o r { 7 p r i v a t e b o o l e a n s u p p r e s s e d = f a l s e; 8 9 p u b l i c b o o l e a n t a k e C o n t r o l () { 10 r e t u r n tr u e; 11 } 12 13 p u b l i c v o i d s u p p r e s s () { 14 s u p p r e s s e d = t r u e; 15 } 16 17 p u b l i c v o i d a c t i o n () { 18 s u p p r e s s e d = f a l s e; 19 20 // m u o v e il r o b o t a v a n t i 21 M o t o r . A . f o r w a r d () ; 22 M o t o r . C . f o r w a r d () ; 23 24 // a v a n z a f i n c h `e non v i e n e s o p r e s s o 25 // ( o s s i a f i n c h `e non v i e n e r i l e v a t o un o s t a c o l o ) 26 w h i l e (! s u p p r e s s e d ) 27 T h r e a d . y i e l d () ; 28 29 // a r r e s t a il r o b o t 30 M o t o r . A . s t o p () ; 31 M o t o r . C . s t o p () ; 32 } 33 }
La classe Movement rappresenta un behavior che ha il compito di muo- vere il robot in avanti finch´e l’esecuzione di questo behavior viene ferma- ta. Tale evento avviene nel caso della rilevazione di un ostacolo, compito assegnato alla classe CollisionAvoidance di seguito.
5.2. CASE STUDY: FREE CASUAL ROAMING 35 6 p u b l i c c l a s s C o l l i s i o n A v o i d a n c e i m p l e m e n t s B e h a v i o r { 7 p r i v a t e T o u c h S e n s o r t o u c h ; 8 p r i v a t e U l t r a s o n i c S e n s o r s o n a r ; 9 p r i v a t e b o o l e a n s u p p r e s s e d = f a l s e; 10 11 p u b l i c C o l l i s i o n A v o i d a n c e ( U l t r a s o n i c S e n s o r sonar , T o u c h S e n s o r t o u c h ) { 12 t h i s. s o n a r = s o n a r ; 13 t h i s. t o u c h = t o u c h ; 14 } 15 16 p u b l i c b o o l e a n t a k e C o n t r o l () { 17 r e t u r n t o u c h . i s P r e s s e d () || s o n a r . g e t D i s t a n c e () < 25; 18 } 19 20 p u b l i c v o i d s u p p r e s s () { 21 s u p p r e s s e d = t r u e; 22 } 23 24 p u b l i c v o i d a c t i o n () { 25 s u p p r e s s e d = f a l s e; 26 27 // gi r a il r o b o t a 180◦ 28 M o t o r . A . r o t a t e ( -180 , t r u e) ; 29 M o t o r . C . r o t a t e ( -360 , t r u e) ; 30 31 // a s p e t t a di f i n i r e la r o t a z i o n e o e s s e r e s o p r e s s o 32 w h i l e ( M o t o r . C . i s M o v i n g () && ! s u p p r e s s e d ) 33 T h r e a d . y i e l d () ; 34 35 // a r r e s t a il r o b o t 36 M o t o r . A . s t o p () ; 37 M o t o r . C . s t o p () ; 38 } 39 }
Finalmente la classe principale RoamingRobot che raggruppa il tutto.
9 p u b l i c c l a s s R o a m i n g R o b o t { 10 p u b l i c s t a t i c vo i d ma i n ( S t r i n g [] a r g s ) { 11 // a l l o c a z i o n e dei s e n s o r i di t a t t o e u l t r a s o n i c o 12 U l t r a s o n i c S e n s o r s o n a r = new U l t r a s o n i c S e n s o r ( S e n s o r P o r t . S1 ) ; 13 T o u c h S e n s o r t o u c h = new T o u c h S e n s o r ( S e n s o r P o r t . S2 ) ; 14 15 // c r e a z i o n e dei b e h a v i o r e i n s e r i m e n t o in un a r r a y 16 B e h a v i o r b1 = new M o v e m e n t () ; 17 B e h a v i o r b2 = new C o l l i s i o n A v o i d a n c e ( sonar , t o u c h ) ; 18 B e h a v i o r [] b A r r a y = { b1 , b2 }; 19 20 // c r e a z i o n e del A r b i t r a t o r ed e s e c u z i o n e 21 A r b i t r a t o r a r b y = new A r b i t r a t o r ( b A r r a y ) ; 22 a r b y . s t a r t () ;
36 CAPITOLO 5. CASE STUDIES CON LEJOS
23 }
24 }
5.2.2
Risultati
Per quanto riguarda questo case study, per la natura stessa dello scenario, l’approccio pi`u conveniente (facendo uso di LeJOS) `e quello di sviluppare un firmware autonomo sul NXT. La programmazione orientata al comporta- mento `e principalmente utilizzata per robot autonomi che lavorano in modo indipendente. Ovviamente, se si dovessero coordinare tra di loro pi`u robot in free casual roaming, questa soluzione diventa inefficiente, in quanto non permette la comunicazione diretta tra device diversi, ma garantisce sola- mente il funzionamento del robot come singola entit`a nell’ambiente, non inserito in un sistema pi`u esteso. Infatti, per poter implementare la coordi- nazione bisognerebbe sviluppare altri behavior. Sapendo che i vari behavior sono ordinati in base alla precedenza, chi potrebbe garantire che un robot abbia precedenza su un altro?
Quindi la soluzione migliore per questo case study specifico implica l’u- tilizzo delle API Behavior. Tale scelta `e giustificata dalla ricerca della solu- zione pi`u semplice, pi`u potente e specifica possibile, anche se `e leggermente pi`u dispendiosa in termini di tempo. Altrettanto importante `e lo sviluppo di codice facilmente mantenibile e riutilizzabile, obiettivo pi`u facile da rag- giungere vista la modularit`a dei singoli behavior che possono essere aggiunti e rimossi arbitrariamente in quanto essenzialmente indipendenti.
D’altra parte, se dovessimo coordinare pi`u robot in free roaming, lo scenario cambia e la soluzione migliore implica l’utilizzo di ReSpecT, in un’applicazione che integra un piano in esecuzione sul NXT con un modulo eseguito su PC e dotato delle funzionalit`a garantite da ReSpecT.