Comportamento Esploratore (giallo)

thymioII-yellow.jpg

Thymio Esploratore

Con questo comportamento di base selezionabile con il colore giallo Thymio II esplora l'ambiente evitando gli ostacoli.

Questo è il file ASEBA .aesl contente il codice scritto in linguaggio ASEBA, per generare questo comportamento.


Dichiarazione delle variabili

L'elenco variabili utilizzato deve essere dichiarato all'inizio del codice. Il simbolo # in una linea significa che esso e il resto della linea sono osservazioni che saranno ignorate dal compilatore; non influenzerà il comportamento del robot, è lì solo per noi umani. Mettere più di un # in fila serve solo a evidenziare meglio il commento e permette di riconoscerlo più facilmente.

In questa parte del codice, vediamo la parola chiave var prima di ogni variabile. Questo indica al compilatore che la parola seguente è una variabile. Le variabili di Thymio sono globali (sono accessibili da qualsiasi parte del codice), quindi devono avere dei nomi univoci e trasparenti, cioè che richiamino in qualche modo il loro significato ed uso! Se si sceglie variabili denominate temp1, temp2, temp3, ecc…, non sarà così facile ricordare come vengano utilizzate, senza mettere dei commenti nella sezione di dichiarazione.

Le variabili possono essere inizializzate ad un valore specifico, come speed che è sulla linea 9, con la dichiarazione speed var = 200. Se una variabile non è inizializzata, il suo valore è indefinito (può contenere qualsiasi cosa).

Alla riga 12, possiamo vedere che la variabile led viene dichiarato come var led[8]. Questo significa semplicemente che led non è una singola variabile, ma un array contenente 8 valori. Sarà possibile accedere a questi valori nel codice tramite led[0], led[1], led[2] fino a led[7]. Gli array sono indicizzati da 0 alla loro dimensione massima, meno uno.

Infine, la matrice var weight_braitenberg [] = [1,2,3,2,1] mostra un altro modo per dichiarare un array. Le parentesi quadre indicano che weight_braitenberg è un array, ma non se ne dà la dimensione; poi l'istruzione = [1,2,3,2,1] riempie l'array con 5 elementi di valore 1, 2, 3, 2, 1.

Questi nomi delle variabili sono probabilmente oscuri per il momento, ma si chiariranno esplorando le diverse parti del codice. Potete saperne di più sulle variabili dalla documentazione di riferimento del linguaggio ASEBA.

Impostazione del Timer

Mentre il Thymio esplora, si vuole mostrare sia una luminosità sia un'animazione dei led a cerchio, quindi è necessario aggiornare le luci a intervalli regolari. Per fare ciò, il codice precedente predispone timer0 con un intervallo di tempo di 20 ms (millisecondi, 1 secondo = 1000 ms), il che significa che ogni 20 ms l'evento timer0 verrà attivato. Thymio ha due timer, lo 0 e l'1. Questi temporizzatori possono essere configurati per periodi compresi tra 1 e 32767 ms. Possono essere impostati in modo indipendente e possono ciascuno attivare un evento, timer0 e timer1. Questo è particolarmente utile se si desidera eseguire una certa azione ad intervalli di tempo regolari.

Se si fosse invece scritto timer.period[1] = 100, avrebbe significato che l'evento timer1 sarebbe stato attivato ogni 100 ms. È possibile saperne di più sull'utilizzo del timer consultando la documentazione di riferimento per l'interfaccia di programmazione.

Gestione dell' evento Timer

La prima riga che non sia un commento è onevent timer0. Questo significa che ogni volta che l'evento timer0 viene attivato, il robot farà ciò che è scritto nel blocco che segue. In questo caso, questa parte del codice verrà eseguito ogni 20 ms come è stato impostato nella parte precedente.

Questo blocco di codice può essere scomposto in due parti, la prima inizia con il commento # Led ring animation (animazione dell'anello di Led) e la seconda con # Body color pulse (impulso di colore del corpo del robot).

Animazione dell'anello di Led

In poche parole, questa parte fa in modo che le luci LED ad anello poste sulla parte superiore del robot ruotino come mostrato nel video.

Ora, tuffiamoci nel codice. Sulla linea 23 c'è: call math.fill (led, 0). Questa è una chiamata a una funzione nativa (quelle disponibili si possono trovare in basso a sinistra della finestra ASEBA Studio). Queste sono le sequenze predeterminate di comandi che sono già memorizzate nella memoria di Thymio. Questa funzione è legata alla matematica in quanto ha il prefisso math.. In particolare, questa funzione riempie la matrice led con gli zeri, ed è un modo efficace per inizializzare un array per calcoli matematici successivi. Troverete anche tutte le funzioni native qui con relativa descrizione.

Proseguendo nel codice, vediamo che la variabile led_state viene modificata. L'istruzione led_state = (led_state + 2) & 0xff è complessa, quindi dovremo esaminarla nel dettaglio. L'espressione led_state + 2 è tra parentesi, il che significa che questa operazione verrà eseguita per prima, in modo che il contenuto della variabile led_state venga incrementato di 2, e il risultato venga memorizzato temporaneamente. Poi c'è l'istruzione & 0xff. Questa è una istruzione di maschera. 0xFF è un numero scritto in esadecimale, è uguale a 15 * 16 + 15 = 255 che è rappresentato internamente da 8 consecutivi bit a 1. Il segno & è l'operatore logico AND. Si applica l'operatore logico AND bit per bit tra il risultato del calcolo precedente e la costante & 0xFF, ottendo il valore uno solo se entrambi i bit esaminati sono a uno. In pratica, eseguendo & 0xFF equivale a considerare solo i primi otto bit consecutivi della variabile led_state incrementata di 2, "mascherando" gli altri e limitando automaticamente il numero massimo rappresentabile come risultato a 255. Questo in pratica è equivalente a verificare se la variabile led_state+2 è superiore a 255, e se è più grande, sottrarre 256. Poi il risultato finale è memorizzato nella variabile led_state. Similmente, l'istruzione led_state = (led_state + 2) & 0xff permette al valore di led_state di essere incrementato da 2 e fa in modo che il valore risultante rimanga tra 0 e 255. La variabile crescerà ogni volta che l'evento timer0 è attivato fino a quando non supera i 255, poi si torna a zero e si torna a crescere.

La riga successiva (28) imposta la variabile fixed a led_state diviso per 32. Poichè il linguaggio ASEBA non supporta numeri decimali, fixed varierà tra 0 (quando led_state è compreso tra 0 e 31) e 7 (ove led_state è compreso tra 224 e 255), vale a dire vi è un arrotondamento al valore intero del risultato della divisione. Questo verrà utilizzato per impostare un led ad un livello fisso di luminosità durante il tempo in cui si verificano i 32 eventi timer0 . Sapendo che l'evento timer0 si verifica ogni 20 millisecondi, la variabile fixed rimarrà la stesso per 32 * 20 = 640 millisecondi.

Le tre righe successive potranno impostare la luminosità di tre led, il fixed , quello precedente (fixed-1) e quello successivo (fisso + 1). L'idea è di impostare il led fisso (fixed) a piena luminosità, aumentando la luminosità del led successivo e riducendo la luminosità del led precedente. Facciamo un esempio:

Cercle_led.svg

Led 6 è il fixed uno, completamente illuminato. Il precedente, il 5, si accende anche mentre il 7 è spento. Led 5 sarà poi sempre meno luminosa, mentre il 7 diventerà più luminosa. Una volta che il 7 è completamente illuminato, il prossimo, led 0, diventerà più luminoso, mentre il 6 lentamente si spegne, ecc …

Si andrà quindi lungo il cerchio dei led, illuminandoli come descritto. Possiamo vedere gli indici della matrice led qui:

led[fixed]
led[(fixed - 1) & 0x7]
led[(fixed + 1) & 0x7]

L'istruzione & 0x07 è un'altra operazione di mascheramento. Essa assicura che il risultato di (fixed - 1) e (fixed + 1) non lascino mai i valori da 0 a 7. Infatti, se fixed = 0, poi (fixed - 1) = -1, ma il led successivo in questo caso è 7, non -1. L'operazione maschera correggerà questo riportando il risultato a 7 e farà in modo che i led si accendano e si spengano con continuità.

L'ultima riga della parte dell'animazione del cerchio di led (32) è call leds.circle(led [0], …). Questo imposterà il valore di luminosità di ogni LED. Infatti, finora, abbiamo manipolato solo la matrice di variabili led[], ora dobbiamo fare il in modo che il robot effettivamente modifichi la luminosità dei led!

Impulso di colore del corpo

Questa parte del codice farà illuminare il corpo del Thymio di impulso di un colore giallo.

La linea 33 è, come per i led cerchio, un incremento della variabile led_pulse. Sarà sufficiente aggiungere 1 alla variabile ogni volta che l'evento timer0 viene attivato.

Accanto troviamo un altro test condizionale, ma questa volta in due parti. Questo test è comunemente nella forma di:

if … then … else … end

Analizziamolo nel dettaglio. Esso è fatto da quattro parole chiave:

  • if:** testiamo la variabile (in questo caso la domanda è:led_pulse è maggiore di 0?)
  • then:** se la condizione è vera (se led_pulse è maggiore di 0), eseguiamo il seguente codice (call leds.top(led_pulse,led_pulse,0))
  • else:** se la condizione è falsa (se led_pulse è minore o uguale a 0), eseguiamo il seguente codice (call leds.top(-led_pulse,-led_pulse,0))
  • end:** questa è semplicemente la fine del test.

Facciamo un esempio. Diciamo che, all'inizio, led_pulse è uguale a 0. Poi, verrà incrementato sulla linea 33 e diventerà 1. La prova if led_pulse>0 sarà vero, così i led di Thymio all'inizio saranno impostati (1, 1, 0). Il prossimo test sulla linea 36 sarà falso poichè led_pulse non è più grande di 32, che dovrà quindi rimanere invariato. Infine, se la prima condizione è vera (linea 36), la condizione else non sarà eseguita.

Ciò continua così 32 volte di fila, poi quando led_pulse è uguale a 33, la seconda condizione (linea 39), sarà vera. led_pulse sarà quindi impostato a -32. La prossima volta che l'evento timer0 viene attivato, la prima condizione (linea 37) sarà falsa, così il codice della sezione else verrà eseguito. Sarà sufficiente impostare la dei led luminosità uguale a -led_pulse per renderli luminosi sempre meno ogni volta che il timer0 timer viene attivato.

Gestione dell'evento buttons

Questa parte farà andare più veloce il robot quando si tocca il pulsante avanti, più lento quando il pulsante indietro viene toccato e lo ferma quando il pulsante centrale viene toccato.

Troviamo la linea onevent buttons. Ciò significa che ogni volta che si preme un tasto qualsiasi, Questa parte di codice che gestisce l'evento viene attivata.

Nel codice, possiamo vedere tre blocchi simili. La struttura si basa sull'utilizzo di when … do … end. Questa struttura è simile a if … then … end con una sola eccezione. Il while stato eseguito il codice solo se il valore precedente era falso e il valore corrente è vero. Esso consente di definire un'azione da eseguire solo nel momento qualcosa è cambiato rispetto a prima!

Il primo blocco di when … do … end sarà eseguito solo quando si tocca il pulsante avanti, il secondo blocco quando il pulsante indietro viene toccato e l'ultimo quando il pulsante centrale viene toccato.

Nel primo blocco, la velocità del robot viene aumentata aggiungendo 50. speed+=50 è equivalente a speed=speed+50, solo più breve da scrivere. Nel secondo blocco la velocità diminuisce sottraendo 50 e in ultimo, il robot può essere disattivato semplicemente impostando la velocità a 0 (e anche la velocità di riferimento a 0).

Potete vedere due chiamate a funzioni native sulle linee 48 e 53. Questi saranno semplicemente limitare la variabile speed. La linea 48 call math.min(speed, speed, 500) memorizzerà il minimo (ovvero più piccolo) di velocità e 500 nella variabile speed (il primo argomento della chiamata math.min ).

Gestione dell'evento prox

Questa parte è l'algoritmo di evitamento ostacoli utilizzato da Thymio. Esso è basato sul veicolo Braitenberg. Esso contiene anche una seconda parte che è il rilevamento bordo della tabella.

Algoritmo Braitenberg di evitamento ostacoli

Questa parte è divisa in due piú piccole. La prima viene eseguita se la velocità di Thymio è maggiore di 0 (ad esempio se si sta andando avanti) e la seconda se la sua velocità è inferiore a 0 (ad esempio, se si sta andando indietro). Questo introduce un altro tipo di test condizionale, ancora abbastanza vicino al tradizionale if … then … end.

if … then … ElseIf … then … end

L'unica differenza sta nel elseif. Questo significa semplicemente che ci sono più di due possibilità. Fino ad ora, abbiamo provato qualcosa dicendo: // Se non è questo, è quello //. Ora, diremmo // Se non è questo, potrebbe essere che.. // oppure potrebbe essere…. Il che comporta che la seconda situazione non si verifica necessariamente se non si verifica la prima, ma è condizionata da una ulteriore verifica.

Il robot verificherà la prima condizione sulla linea 65 if speed> 0 then e se speed non è maggiore di 0, verificherà la seconda condizione di riga 76 elseif speed <0 e se speed non è minore di 0 allora il robot non esegue alcun codice (il robot è fermo).

Nel caso in cui Thymio sta andando avanti, la sua velocità è adattata secondo i valori dei suoi sensori di prossimità frontale. Questo è il concetto del veicolo Braitenberg:

Vengono utilizzati i valori dei sensori di prossimità, dopo aver attraversato un processo matematico di "pesatura", per modificare direttamente la velocità di ciascuna ruota di Thymio

Braitenberg.png

Come si può vedere nella figura, più vicino Thymio arriva a un ostacolo, più grande diventa il valore del sensore di prossimità su quel lato, minore la velocità della ruota sul lato opposto dovrà essere. Poichè Thymio utilizza un comando differenziale per avanzare (le due ruote sono azionate indipendentemente), se la velocità della ruota sinistra diventa più piccola, il robot girerà a sinistra ed evitare l'ostacolo alla sua destra!

Questo è esattamente ciò che le linee da 66 a 69 fanno.

Vengono calcolati due coefficienti utilizzando una somma ponderata dei sensori di prossimità orizzontali, temp_braitenberg e temp_braitenberg_turn. Uno di essi si occuperà di rallentare il robot in caso di un ostacolo frontale, l'altra farà girare il robot in caso di un ostacolo ai lati.

Le velocità di riferimento delle due ruote sono adattate con questi coefficienti. Le funzioni utilizzate per calcolare i coefficienti sono funzioni native della libreria matematica.

Nel secondo caso (da riga 76 a 80), quando Thymio sta andando indietro, i soli sensori in grado di rilevare un ostacolo sono quelle posteriori. Ci sono solo due sensori sul retro del Thymio, che guardano direttamente all'indietro, quindi evitare ostacolo non sarà efficace come per i movimenti in avanti. Il concetto applicato è esattamente lo stesso che per la modalità di avanzamento.

Nelle righe 82-85, troverete quattro call (chiamate) in fila. Ognuno di essi utilizza una funzione nativa della libreria matematica. Queste sono funzioni limite. Prendiamo la prima. La funzione vedrà quale valore tra motor.left.target e vmax è il più piccolo e salverà il risultato in motor.left.target. Ciò significa che se motor.left.target diventa più grande rispetto alla velocità massima che Thymio può raggiungere, motor.left.target è impostata su vmax . In questo modo, è possibile garantire che motor.left.target non superi mai vmax (che significa velocità massima). Le altre tre chiamate sono qui per lo stesso motivo, per limitare la velocità delle ruote sinistra e destra per un valore superiore o inferiore.

Riconoscimento del bordo del tavolo

Qui, l'idea è di fermare Thymio se raggiunge il bordo del tavolo.

Troviamo un altro semplice if … then … else … end test condizionale. Il test è sulle variabili prox.ground.reflected [0] e prox.ground.reflected [1]. Se mettete il vostro Thymio su un tavolo e guardare i valori di queste variabili in ASEBA, dovreste trovare un valore tra 300 e 1000. Ora, se si prende il robot e si solleva dal tavolo, questi sensori devono indicare circa 0. Sapendo ciò, si basta verificare se i sensori di prossimità terra rilevano valori più piccoli di una certa soglia. Se è così, il robot non è su un tavolo, deve fermarsi (ed i led inferiori vengono illuminati in rosso grazie alle linee di codice call leds.bottom.left (32,0,0) e call leds.bottom.right(32,0,0)). In caso contrario, il robot è su un tavolo, dobbiamo solo spegnere il led e lasciamo la velocità gestita dall'algoritmo Braitenberg. Si noti che i sensori di terra sono nella parte anteriore della Thymio, ciò non aiuta quando il robot sta andando indietro!

Thymio_IR_Ground_en.png

Una piccola nota riguardante i sensori di terra. Si può vedere che ci sono tre valori diversi per i sensori di terra: prox.ground.ambiant, prox.ground.reflected e prox.ground.delta . Il primo misura la luce ambiente senza emettere alcun impulso infrarossi (IR), il secondo misurare l'impulso infrarossi riflesso e l'ultimo fa la differenza tra i primi due. In questo modo, si può avere un valore dell'impulso infrarossi riflesso senza l'inquinamento della luce ambiente.

Questo è tutto!

Buon divertimento con il tuo Thymio!

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License