Da VPL 1.3 a VPL 1.4 - Che cosa è cambiato con gli eventi?

Questa pagina illustra un importante cambiamento tra la versione 1.3 e la versione 1.4 del VPL: la gestione degli eventi. In VPL 1.3, alcuni eventi (bottoni, prossimità e sensori del terreno) sono verificati continuamente per tutto il tempo che sono veri, mentre in VPL 1.4, scattano solo una volta, quando diventano veri.

Motivazione

Far scattare continuamente un evento non è molto pulito e non è consistente con gli eventi clap e tap, e a volte confondono l'utente nell'interpretazione del meccanismo che c'è dietro la gestione degli eventi. Lo si può facilmente vedere con il seguente semplice programma:

music13.png

Con questo codice nella versione 1.4, fin tanto che il bottone centrale viene toccato, la musica viene avviata. Questo significa che la musica viene riavviata continuamente fino a che il bottone viene rilasciato. Quindi l'evento del bottone non è generato dalla transizione da bottone non toccato a bottone toccato, ma è verificato per tutto il tempo che rimane toccato. Solo appena prima quando il bottone viene rilasciato la musica può essere eseguita interamente.

Nella versione 1.4, lo stesso codice ha un altro effetto:

v14-music.png

In questa versione l'evento si verifica solo quando il bottone viene toccato e la musica può essere eseguita senza essere riavviata.

Eventi impliciti e codice esplicito

Consideriamo un altro esempio in cui si potrebbe pensare che sia conveniente avere un evento sensibile allo stato e non alla transizione di stato:

v13grount-obstacle.png

Con questo codice, fino a che la base vede il terreno il robot avanza, quando incontra un ostacolo si ferma. Se l'ostacolo sparisce il robot riparte perché fino a quando il robot è sul terreno, il primo evento viene attivato anche se vi è un ostacolo. Se vi è un ostacolo questo codice dice di andare avanti e di fermarsi ed è l'ultimo comando eseguito che controlla che cosa il robot fa. Questo comportamento che dipende dall'ordine con cui vengono eseguite le linee di codice è considerato una "situazione di corsa" (race condition) che rende meno chiaro il codice e non è una buona pratica perchè può portare ad una corsa critica, anche se a volte è comoda.

In VPL 1.4 questo codice :

v14-ground-obstacle.png

… genera ad un comportamento differente: quando avviato Thymio va avanti, se incontra un ostacolo si ferma come nella versione 1.3, ma se l'ostacolo sparisce il robot non riparte perché il primo evento che è sulla variazione di stato e non sullo stato non viene più attivato. Per far ripartire il Thymio occorre riattivare l'evento ad esempio sollevando e rimettendo sul terreno il Thymio. L'evento che è sensibile alla variazione di stato si riattiva e il Thymio avanza. Questo comportamento è consistente perché nel codice non c'è scritto che il robot debba ripartire se l'ostacolo sparisce. Se è questo che si vuole, occorre aggiungere un evento che dice esplicitamente che se l'ostacolo sparisce (transizione) il Thymio riparte:

v14-ground-obstacle-ok.png

Nuove funzionalità della versione 1.4

Il modo in cui la versione 1.4 gestisce gli eventi consente di scrivere più facilmente programmi che nella versione 1.3 richiedevano l'utilizzo degli stati o erano addirittura impossibili da scrivere in VPL.
Il programma della musica visto prima è un esempio, quello che se segue è un altro esempio:

v14-toggle-color.png

Questo codice in modalità avanzata sembra logico: toccando il bottone centrale si vuole cambiare il colore da rosso a verde e viceversa, usando un solo stato interno. In realtà con la versione 1.3 il comportamento sarà che il colore cambierà in continuazione per tutto il tempo che il tasto viene premuto. Per avere il comportamento richiesto sarebbe stato necessario utilizzare un altro stato, per ricordare il passaggio a bottone non premuto e solo in questo caso consentire la variazione di colore, rendendo il codice più lungo e più complesso.

Ecco un altro esempio:

v14-arret-2emeligne.png

Questo codice consente di avviare il robot con il tasto avanti e di arrestarsi alla second linea scura sul terreno. Nella versione 1.3 sarebbe stato necessario riconoscere esplicitamente lo spazio chiaro tra le linee scure e utilizzare un'altra variabile di stato.

Un caso d'uso passando dalla versione 1.3 alla versione 1.4: seguire una linea e arrestarsi davanti a un ostacolo.

Quando si inizia a combinare i comportamenti compaiono differenze importanti tra la versione 1.3 e la versione 1.4. Prendiamo come esempio un robot che segue una linea e si ferma quando incontra un ostacolo.

Con la versione 1.3, si poteva scrivere il codice seguente:

v13-line-following.png

Questo programma fa in modo che il robot segua la linea nera sul terreno e si fermi se trova un oggetto di fronte.
Quando il robot si ferma, tuttavia, gli eventi di inseguimento della linea sono ancora attivi, ma le loro azioni sono cancellate dall'ultima linea che controlla che non vi siano ostacoli e invia l'ultimo comando ai motori. Appena l'ostacolo sparisce il robot riprende la sua corsa.

Nella versione 1.4 con lo stesso codice il robot non ripartirà quando l'ostacolo viene rimosso, perché l'evento di ostacolo rimosso non è gestito. Occorre aggiungere una riga per gestire esplicitamente questo evento:

v14-following-nomemory.png

Tuttavia questo programma ha ancora un comportamento diverso rispetto alla versione 1.3: quando il robot riparte dopo che l'ostacolo è sparito, non sa in che stato si trovava quando si è fermato e quindi non sa se proseguire o girare e in quale direzione.
Il programma seguente risolve il problema nel seguente modo: se il robot seguendo la linea vede solo bianco gira a sinistra per ritornare sulla linea. Quando l'ostacolo sparisce, per ripristinare il comportamento di inseguimento della linea fa lo stesso ma nella direzione opposta. Questo riporta velocemente Thymio sul percorso.

Se si vuole che il robot riparta nello stesso stato in cui si trovava quando era partito occorre memorizzare questa situazione e riutilizzare queste informazioni quando il robot riparte, per esempio in questo modo:

v14-following-memory.png

Questa soluzione può generare problemi complicati. Per esempio in questo esempio: se il robot che insegue la linea incontra un ostacolo, si ferma. L'arresto non è istantaneo, perché è necessario un po' di tempo per fermarsi. Se durante questo tempo il robot supera il confine tra linea nera e terreno chiaro, si genererà un altro evento gestito dall'inseguimento di linea e il robot ripartirà. Siccome l'ostatolo è già presente l'evento di incontro dell'ostacolo è già avvenuto e il robot non si fermerà, urtando l'ostacolo.

Un simile problema può avvenire se il robot, una volta arrestato di fronte ad un ostacolo viene spinto da un altro robot o da qualcuno e durane questo movimento supera il bordo della linea sul terreno. Proseguirà urtando l'ostacolo.

Questo significa che nella versione 1.4 occorre pensare più attentamente alla sequenza degli eventi che nella versione 1.3. Alcune soluzioni sono più chiare che altre. Ad esempio il problema dell'inseguimento della linea e dell'arresto di fronte ad un ostacolo può essere risolto più elegantemente dal seguente programma, che contiene anche l'ordine di stop e start:

v14-following-startstop.png

Questo programma ricorda la presenza di un ostacolo e blocca il comportamento di inseguimento della linea fino a che l'ostacolo viene rimosso o viene richiesto esplicitamente al robot di proseguire.

Questa gestione degli stati aggiunge complessità ma permette di essere più precisi nella definizione del comportamento. Per esempio se si vuole che il robot diventi rosso per un secondo quando l'ostacolo sparisce, nella versione 1.3 è necessario aggiungere degli stati per memorizzare la transizione, quindi questo codice non funziona nella versione 1.3 perché il timer è riavviato in continuazione:

v13-red-nobstacle-nowork.png

Il codice nella versione 1.4 che usa lo stesso numero di elementi funziona come atteso:

v14-red-onesec.png
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License