Linguaggio Aseba
Questa documentazione è anche disponibile in Aseba Studio nell'item di menu Help->Language. Quando si utilizzano termini tecnici, questi sono collegati ai corrispondenti articoli di Wikipedia, in Italiano dove disponibili, oppure in Inglese. Si consiglia di leggere prima la pagina relativa ai concetti di base di Aseba. Questa documentazione presenta il linguaggio com'è a partire dalla versione 1.2 di Aseba. Per versioni più vecchie leggere questa pagina.
Il linguaggio di Aseba assomiglia a quello di Matlab (un linguaggio comune di programmazione scientifica); questa somiglianza consente agli sviluppatori con una conoscenza precedente di qualche linguaggio di scripting di trovarsi velocemente a proprio agio con Aseba e quindi abbassare la curva di apprendimento. Semanticamente, è un semplice linguaggio di programmazione imperativo con un singolo tipo di dato (intero a 16 bit con segno ) e vettori (array). Questa semplicità consente agli sviluppatori di programmare nuovi comportamenti di Thymio senza una precedente conoscenza di un sistema dei tipi, essendo gli interi il più naturale tipo di variabile e molto indicato per programmare robot basati su micro-controllori.
Commenti
I commenti consento di aggiungere nel codice delle informazioni testuali che vengono ignorate dal compilatore. I commenti sono molto utili per annotare il codice con informazioni comprensibili dall'essere umano o per disabilitare temporaneamente dei pezzi di codice. I commenti iniziano con # e terminano alla fine della linea.
Esempio
# Questo è un commento
var b # un altro commento
Sono anche possibili commenti su più linee. Essi iniziano con #* e terminano con *#.
Esempio:
#*
Questo è un commento
su più linee
*#
var b # semplice commento
Scalari
I valori scalari sono utilizzati in Aseba per rappresentare in numeri. Essi possono essere utilizzati in qualsiasi espressione, come l'inizializzazione di variabili, espressioni matematiche o condizioni logiche.
Notazione
Gli scalari possono essere rappresentati utilizzando varie basi. Il modo più naturale è il sistema numerico decimale, usando cifre da 0 a 9. I numeri negativi sono dichiarati utilizzando il segno meno - di fronte al numero.
Esempio:
i = 42
i = 31415
i = -7
Possono essere anche utilizzati numeri binari e esadecimali. I numeri binari sono prefissati da 0b, mentre i numeri esadecimali sono prefissati da 0x.
Esempio
# notazione binaria
i = 0b110 # i = 6
i = 0b11111111 # i = 255
# notazione esadecimale
i = 0x10 # i = 16
i = 0xff # i = 255
Nella notazione binaria, i valori sono compresi tra 0b0000000000000000 e 0b1111111111111111, mentre in esadecimale sono compresi tra 0x0 e 0xffff. Valori decimali superiori a 32767 in decimale sono interpretati come numeri negativi.
Variabili
Le variabili si riferiscono sia singoli valori scalari o vettori di valori scalari. I valori sono compresi tra -32768 e 32767, che è l'intervallo di validità per gli interi a 16 bit con segno. E' necessario dichiarare tutte le variabili definite dall'utente, utilizzando la parola chiave var all'inizio di uno script Aseba, prima di fare qualsiasi elaborazione.
Il nome delle variabili è definito secondo queste semplici regole:
- Il nome può solo contenere caratteri alfabetici maiuscoli o minuscoli ed i caratteri '_' o '.'
- Il nome deve iniziare con un carattere alfabetico valido, oppure con '_'
- Il nome è sensibile alle maiuscole o minuscole: una variabile con nome "foo" è differente da un'altra chiamata "Foo"
- Il nome non può coincidere con una parola chiave Aseba (vedere l'elenco delle parole chiave riservate)
Le Variabili possono essere inizializzate nella dichiarazioni, utilizzando il simbolo di assegnazione in combinazione con qualsiasi espressione matematica valida.
Una variabile non precedentemente inizializzata può contenere qualsiasi valore. Non si deve mai assumere che una variabile non inizializzata abbia valore zero.
Esempio:
var a
var b = 0
var c = 2*a + b # attenzione: 'a' non viene inizializzata
Parole chiave riservate
Le seguenti parole chiave non possono essere utilizzate come nomi validi per variabili, perché sono già utilizzate dal linguaggio Aseba.
Parole chiave | |||
---|---|---|---|
abs | call | callsub | do |
else | elseif | emit | end |
for | if | in | onevent |
return | step | sub | then |
var | when | while |
Costanti
In Aseba Studio si possono definire delle costanti utilizzando il pannello "Costanti" ma non possono essere definite direttamente nel codice. Una costante rappresenta un valore numerico che può essere utilizzato in tutti i punti del codice dove si può utilizzare un numero.
Diversamente da una variabile, una costante non può essere modificata durante l'esecuzione. Le costanti sono utili quando si vuole facilmente cambiare il comportamento tra differenti esecuzioni, come ad esempio quando si vuole adattare un valore di soglia condiviso da diversi nodi Aseba. Una costante non può avere lo stesso nome di una variabile, altrimenti viene rilevato un errore dal compilatore.
Esempio:
# assumiamo l'esistenza di una costante di nome THRESHOLD
var i = 600
if i > THRESHOLD then
i = THRESHOLD - 1
end
Vettori
I vettori (Array in inglese) rappresentano aree contigue di memoria, indirizzate da una singola unità logica. La dimensione di un vettore è fissa e deve essere specificata nella dichiarazione. I vettori possono essere dichiarati usando le solite parentesi quadre []. Il numero tra parentesi quadre specifica il numero di elementi che devono essere assegnati al vettore e che ne rappresenta la dimensione. Può essere una espressione costante, comprese operazioni matematiche tra scalari e costanti. Utilizzando il costruttore del vettore (vedi sotto) è possibile definire una assegnazione opzionale dei valori del vettore. facendo così, non è necessario definire la dimensione del vettore.
Esempio:
var a[10] # vettore di 10 elementi
var b[3] = [2, 3, 4] # inizializzazione
var c[] = [3, 1, 4, 1, 5] # dimensione implicita di 5 elementi
var d[3*FOO-1] # dimensione definita utilizzando una espressione costante (FOO è dichiarata come costante)
I vettori possono essere acceduti in vari modi:
- Un singolo elemento è acceduto utilizzando le parentesi quadre con un singolo valore. L'indice di un vettore parte da zero e arriva fino alla dimensione meno uno. Qualsiasi espressione può essere utilizzata come indice comprese espressioni matematiche che includono altre variabili.
- un sottoinsieme di elementi può essere acceduto specificando le parentesi quadre e due espressioni costanti separate da due punti ':'.
- Se si omettono le parentesi quadre, si accede all'intero vettore.
Esempio:
var foo[5] = [1,2,3,4,5]
var i = 1
var a
var b[3]
var c[5]
var d[5]
a = foo[0] # copia il primo elemento di 'foo' in 'a'
a = foo[2*i-2] # idem
b = foo[1:3] # prendi il secondo, terzo e quarto elemento di 'foo' e copiali in 'b'
b = foo[1:2*2-1] # idem
c = foo # copia i 5 elementi del vettore 'foo' nel vettore 'c'
d = c * foo # moltiplica gli elementi dei vettori 'foo' e 'c' elemento per elemento e copia il risultato in 'd'
Una variabile scalare è considerata essere equivalente a un vettore di dimensione 1, quindi il codice seguente è legale:
var a[1] = [7]
var b = 0
b = a
Costruttori di vettori
I costruttori di vettori sono un modo per costruire vettori partendo da variabili, altri vettori, scalari, o anche espressioni complesse. Sono utili in molti casi, per esempio quando si inizializzano altri vettori, o come operandi in espressioni, funzioni ed eventi. Un costruttore di un vettore è fatto utilizzando le parentesi quadre che racchiudono diverse espressioni separate da , (virgola). la dimensione di un costruttore di un vettore è pari alla somma delle dimensioni dei singoli elementi, e deve coincidere con la dimensione del vettore in cui il risultato è memorizzato.
Esempio:
var a[5] = [1,2,3,4,5] # costruttore per inizializzare un vettore
var b[3] = [a[1:2],0] # il vettore b viene inizializzato a [2,3,0]
a = a + [1,1,1,1,1] # aggiungi 1 a ciascun elemento del vettore a
a = [b[1]+2,a[0:3]] # il vettore a conterrà [5,2,3,4,5]
Espressioni e assegnazioni
Le espressioni consentono di effettuare calcoli matematici e sono scritte usando la normale notazione matematica infissa. Le assegnazioni utilizzano la parola chiave = e assegnano il risultato del calcolo di una espressione ad una variabile scalare, un elemento di un vettore o un intero vettore, a seconda della dimensione dell'operando. Aseba fornisce vari operatori. Fare riferimento alla tabella seguente per una breve descrizione e per conoscere la precedenza di ciascun operatore. Per eseguire le espressioni in un ordine diverso da quello stabilito dalla precedenza degli operatori si possono usare le parentesi.
Precedenza | Operatore | Descrizione | Associatività | Numero argomenti |
---|---|---|---|---|
1 | () | raggruppa in sottoespressioni | unaria | |
[] | Indice di un vettore | unaria | ||
- | Meno unrio | unaria | ||
~ | NOT binario | unaria | ||
abs | valore assoluto | unaria | ||
2 | * / | moltiplicazione e divisione | binaria | |
% | Modulo | binaria | ||
3 | + - | Addizione, sottrazione | binaria | |
4 | << >> | scorrimento a destra, scorrimento a sinistra | binaria | |
5 | & | AND binaria | associativa a sinstra | binaria |
6 | ^ | or esclusiva binaria (xor) | associativa a sinistra | binaria |
7 | | | Or binaria | associativa a sinistra | binaria |
8 | == != < <= > >= | Condizione † | binaria | |
9 | not | not logico † | unria | |
10 | and | and logico † | binaria | |
11 | or | or logico † | binaria | |
12 | = | Assegnazione | binaria | |
|= ^= &= | Assegnazione con or, xor, and | binaria | ||
*= /= | Assegnazione con prodotto e quoziente | binaria | ||
%= | Assegnazione con modulo | binaria | ||
+= -= | Assegnazione con somma e differenza | binaria | ||
<<= >>= | Assegnazione by left / right shift | binaria | ||
++ -- | incremento e decremento ‡ | unaria |
Note
† Disponibile solo nelle strutture if, when, e while
‡ Disponibile solo associato ad una variabile, come a-- or a[i]++, non in una espressione.
La versione con assegnazione dell'operatore binario funziona applicando l'operatore ad una variabile e memorizzando il risultato nella variabile stessa. Per esempio A *= 2 è equivalente a scrivere A = A * 2. Queste forme abbreviate hanno lo scopo di rendere il codice più compatto.
Esempio:
a = 1 + 1
# Risultato: a = 2
a *= 3
# Risultato: a = 6
a++
# Risultato: a = 7
b = b + d[0]
b = (a - 7) % 5
c[a] = d[a]
c[0:1] = d[2:3] * [3,2]
Uso
Le espressioni matematiche sono strumenti di tipo generale. Come tali possono essere usate in una grande varietà di situazioni. Eccone alcune:
- Sulla parte destra di una assegnazione
- Come indice quando si accede ad un elemento di un vettore
- All'interno di chiamate di funzioni
- Come argomenti quando si emette un evento
Controllo di flusso
Condizioni
Aseba fornisce due tipi di condizionali: if e when. Questi consistono nella verifica di una condizione e in un blocco di codice. Il test consiste in un confronti opzionalmente raggruppati usando and (congiunzione logica), or (disgiunzione logica), e not (negazione logica) operatori e parentesi.
Un confronto è fatto da un operatore e due operandi, e può essere vero o falso. Gli operandi possono essere espressioni arbitrarie. La seguente tabella elenca gli operatori di confronto.
Operatore | Funzione di verità |
---|---|
== | vero se i due operandi sono uguali |
!= | vero se i due operandi sono differenti |
> | vero se il primo operando è strettamente maggiore del secondo |
>= | vero se il primo operando è maggiore o uguale al secondo |
< | vero se il primo operando è strettamente minore del secondo |
<= | vero se il primo operando è minore o uguale al secondo |
Sia if che when eseguono differenti blocchi di codice a seconda se la condizione è vera o falsa; ma when esegue il blocco corrispondente a vero solo se l'ultima valutazione del codice era falsa e quella corrente è vera. Questo consente l'esecuzione del codice solo quando qualcosa cambia. Il condizionale if esegue un primo blocco di codice se la condizione è vera. Si può aggiungere un secondo blocco di codice da eseguire quando la condizione è falsa tramite la parola chiave else. E' possibile concatenare ulteriori condizionali if usando la parola chiave elseif.
Esempio:
if a - b > c[0] then
c[0] = a
elseif a > 0 then
b = a
else
b = 0
end
if a < 2 and a > 2 then
b = 1
else
b = 0
end
when a > b do
leds[0] = 1
end
Il blocco when viene eseguito solo quando a diventa maggiore di b.
Loop
Due costrutti consentono la creazione di iterazioni ad anello (loop) while e for.
Una iterazione ad anello con while esegue ripetutamente un blocco di codice fintanto che la condizione specificata sia vera. La condizione è della stessa forma di quella usata da if.
Esempio:
while i < 10 do
v = v + i * i
i = i + 1
end
Una iterazione ad anello con for consente ad una variabile di iterare su un intervallo di interi, con una dimensione del passo di incremento specificabile con step. Il passo di incremento può anche essere negativo. In questo caso la variabile si decrementa della quantità specificata andando dal valore maggiore al valore minore indicato dopo la parola chiave in.
Esempio:
for i in 1:10 do
v = v + i * i
end
# ad ogni iterazione la variabile i viene incrementata di 1 e si andrà da 1 a 10
for i in 30:1 step -3 do
v = v - i * i
end
# ad ogni iterazione la variabile i viene decrementata di 3 e si andrà da 30 a 1
Il valore della variabile che controlla il loop è indefinito dopo l'esecuzione della fine del loop. Potrà essere solitamente valorizzata all'ultimo valore incrementato del passo, ma può prendere anche altri valori a causa delle ottimizzazioni del codice, ad esempio nei loop di un solo elemento.
Blocchi
Sottoprogrammi
Quando volete eseguire la stessa sequenza di codice in due o tre posti nel programma, è possibile scrivere il codice in comune in un sottoprogramma (subroutine) e quindi richiamare questo sottoprogramma da posti diversi. E' possibile definire un sottoprogramma usando la parola chiave sub seguita dal nome del sottoprogramma. Potete chiamare il sottoprogramma usando la parola chiave callsub, seguita dal nome del sottoprogramma. I sottoprogrammi devono essere definiti prima di essere chiamati. I sottoprogrammi non possono avere argomenti né essere ricorsivi, cioè non possono richiamare se stessi né direttamente, né indirettamente .
I sottoprogrammi possono accedere a qualsiasi variabile (in Aseba tutte le variabili sono globali).
Esempio:
var v = 0
sub toto
v = 1
onevent test
callsub toto
Eventi
Aseba ha una architettura basata su eventi, cioè gli eventi possono scatenare l'esecuzione di codice in maniera asincrona.
Gli eventi possono essere esterni, per esempio eventi definiti dall'utente in arrivo da un altro nodo Aseba, o interni, per esempio emessi da un sensore che fornisca un dato aggiornato.
Il ricevimento di una notifica di un evento fa eseguire, se definito, il blocco di codice che inizia con la parola chiave onevent seguita dal nome dell'evento.Il codice in cima al programma è eseguito quando il programma è avviato o riavviato.
Per consentire l'esecuzione del codice relativo ad un nuovo evento gli script non devono bloccarsi e non devono contenere iterazioni ad anello infinite. Per esempio nel contesto della robotica spesso si ricorre ad una iterazione ad anello infinita all'interno della quale vengono eseguite tutte le elaborazioni legate ai valori dei sensori. Nel linguaggio Aseba invece il codice viene eseguito se specificato per un dato evento. Se l'evento si realizza allora verrà richiamato il sottoprogramma relativo.
Esempio:
var run = 0
onevent start
run = 1
onevent stop
run = 0
onevent ir_sensors
if run == 1 then
emit sensors_values proximity_sensors_values
end
Direttiva Return
E' possibile uscire da una subroutine e sospendere l'esecuzione di uno script attivato da un evento con la direttiva return.
Esempio:
var v = 0
sub toto
if v == 0 then
return
end
v = 1
onevent test
callsub toto
return
v = 2
Invio di eventi esterni
Il programma può anche emettere un evento utilizzando la parola chiave emit, seguita dal nome dell'evento e dagli argomenti dell'evento stesso (se previsti). Se viene fornita una variabile questa deve avere una dimensione corrispondente a quella specificata negli argomenti dell'evento che deve essere emesso. Invece di una variabile, in situazioni più complesse è anche possibile utilizzare come argomenti di un evento costruttori di vettori ed espressioni matematiche. Gli eventi consentono al programma di causare l'esecuzione di codice su un altro nodo o di comunicare con un programma esterno.
onevent ir_sensors
emit sensors_values proximity_sensors_values
Funzioni native
Il linguaggio di script Aseba è stato progettato per essere semplice e consentire una rapida comprensione anche per sviluppatori inesperti e per realizzare la macchina virtuale efficientemente su un micro-controllore. Per eseguire calcoli complessi o che fanno uso intenso di risorse, forniamo funzioni native realizzate in codice nativo per maggior efficienza.
Per esempio una funzione nativa è il modo naturale di realizzare un prodotto scalare.
Le funzioni native sono sicure poiché specificano e verificano la dimensione dei loro argomenti, che possono essere costanti, variabili, celle di vettori, costruttori di vettori ed espressioni. Nel caso di vettori, potete accedere all'intero vettore, un singolo elemento, o un sotto-insieme del vettore. Le funzioni native accettano i loro argomenti per referenza (reference) e possono modificare il loro contenuto, ma non restituiscono alcun valore. Si possono richiamare le funzioni native per mezzo della parola chiave call.
Esempio:
var a[3] = 1, 2, 3
var b[3] = 2, 3, 4
var c[5] = 5, 10, 15
var d
call math.dot(d, a, b, 3)
call math.dot(d, a, c[0:2], 3)
call math.dot(a[0], c[0:2], 3)
Cosa leggere ora?
Potresti essere interessato a leggere: