processing
guida introduttiva alla programmazione visuale
processing
guida introduttiva alla programmazione visuale
alberto cecchi
1
valerio belloni ...
processing
guida introduttiva alla programmazione visuale
indice:
prima parte:
seconda parte:
terza parte:
quarta parte:
quinta parte:
This work is licensed under the Creative Commons AttributionNoncommercial-Share Alike 3.0 Unported License. To view a copy
of this license, visit http://creativecommons.org/licenses/by-ncsa/3.0/ or send a letter to Creative Commons, 171 Second Street,
Suite 300, San Francisco, California, 94105, USA.
2
p.3
p.34
p.48
p.54
p.60
processing
guida introduttiva alla programmazione visuale
Processing
Programmare per l’arte
Prima Parte
Possiamo dire che Processing è un software grafico che si occupa di
Immagini, Forme, Movimenti, Suoni e Interazioni.
Processing è allo stesso tempo un linguaggio di programmazione, un
ambiente di sviluppo nonché un metodo di insegnamento della
programmazione.
Processing è stato inventato da Casey Reas e Ben Fry al fine di
insegnare agli studenti nel settore dell’arte e della grafica la
programmazione software.
Oggi Processing è utilizzato da studenti, artisti, designers e
ricercatori per imparare, sperimentare e produrre. Processing
rappresenta in pieno il proverbio di Confucio:
“se ascolto dimentico, se vedo ricordo, se faccio capisco”
Processing, in quanto linguaggio di programmazione, è un
linguaggio testuale (si scrivono le istruzioni) pensato per produrre e
modificare immagini. Processing è il giusto compromesso tra
semplicità (nell’uso) e complessita dei risultati che si possono
raggiungere. Sono sufficienti pochi minuti di corso affinchè uno
studente possa scrivere le prime righe di codice ed osservare dei
risultati.
Utenti avanzati possono invece realizzare progetti anche molto
complessi scrivendo direttamente delle librerie che possono anche
migliorare ed aumentare le funzionalità del software stesso.
I lavori fatti in Processing possono essere facilmente esportati nel
web e questo aspetto ha facilitato la distribuzione del software e
della sua conoscenza.
Il sito ufficiale di Processing è
www.processing.org, all’interno del sito è presente anche un forum
con migliaia di iscritti che discutono assiduamente riguardo le
problematiche tecniche e creative.
Processing facilita l’insegnamento della grafica digitale, delle tecniche
di interazione come ad esempio disegno vettoriale e raster, image
3
processing
guida introduttiva alla programmazione visuale
processing, gestione degli eventi del mouse e della tastiera e
comunicazione nelle reti di computer.
Le librerie estendono le funzionalità di base anche alla generazione
dei suoni, alla comunicazione dei dati (input/output) alle
funzionalità tridimensionali ed esportazioni file in vari formati.
Il linguaggio Processing non è molto diverso da tanti altri linguaggi
di programmazione. Processing è stato progettato raffinando e
rivedendo questi linguaggi che lo hanno preceduto. Questo aspetto è
molto importante, infatti possiamo vedere Processing come uno
strumento per avvicinarsi alla programmazione. Chi impara a
programmare in Processing avrà il futuro molto facilitato qualora
volesse imparare a programmare anche in altri linguaggi.
L’aspetto principale che differenzia Processing da altri linguaggi di
programmazione riguarda la sua versatilità per tutto ciò che è legato
alla grafica, al disegno, all’animazione e alle interazioni live.
Installare e Aprire Processing
Processing è appunto Open Source e completamente gratuito. Per
Scaricarlo è sufficiente andare all’indirizzo www.processing.org/
download dove si trovano le versioni per Linux, OSX e Windows.
L’ambiente di sviluppo di Processing (Processing Development
Environment PDE) è composto da un semplice editor testuale dove
vengono scritte le istruzioni. PDE è anche l’estensione dei file di
lavoro prodotti in Processing.
Poi troviamo un’area messaggi, una console testuale e una toolbar
dalla quale possono essere effettuate le operazioni più comuni
(nuovo, apri, salva, esporta…). Sempre nella Toolbar in alto sono
presenti i due tipici pulsanti degli ambienti di programmazione (Stop
e Run).
Ecco la lista completa dei pulsanti presenti nella Toolbar:
RUN
STOP
NEW
OPEN
SAVE
EXPORT
4
processing
guida introduttiva alla programmazione visuale
Quando si lancia un programma (Run) il risultato compare in una
finestra che si apre automaticamente (display window).
Ogni programma scritto con Processing (attraverso l’editor testuale)
si chiama Sketch. All’interno dell’editor testuale sono presenti le due
tipiche funzionalità Taglia e Incolla (Cut and Paste) e Cerca e
Sostituisci (Search and Replace).
L’area messaggi, in basso ci dice ad esempio se una volta lanciato il
programma ci sono errori. In pratica l’area messaggi è il mezzo che
Processing usa per comunicare con noi, scrivendoci in quell’area
qualunque tipo di messaggio riguardo il suo comportamento (ad
esempio se si scrive uno Sketch errato sarà l’area messaggi ad
avvertirci).
L’area della conosole testuale (sotto l’area messaggi) ci scrive dei
messaggi in forma più estesa e dettagliata della message window).
Questa area ha anche la funzione di controllo durante le operazioni
di programmazione. Ad esempio quando si vuole controllare una
fare intermedia della programmazione, possiamo far comparire in
questa finestra i dati desiderati (più avanti sarà tutto più chiaro).
I menu di Processing sono solo 6:
Processing
File
Edit
Sketch
Tools
Help
Questa breve lista dei menù all’interno dei quali troviamo pochi
comandi, rende l’idea della semplicità dell’ambiente di sviluppo
Processing. Vedremo i comandi all’interno dei menù più avanti.
Quando si crea un nuovo Sketch (programma) Processing crea
automaticamente anche una specifica cartella che avrà lo stesso
nome dello sketch (come spiegato prima il file dove è scritto il
programma ha l’estensione .pde).
Processing è un ambiente in grado di gestire file multimediali
pertanto se all’interno del nostro progetto per esempio aggiungiamo
un suono o un’immagine questi file andranno a collocarsi
automaticamente dentro la cartella data, all’interno della cartella
dello Sketch. Processing permette di lavorare secondo la logica
“drag and drop” pertanto per aggiungere un’immagine al nostro
programma è sufficiente prendere il file e trascinarlo sopra l’editor
testuale dove stiamo scrivendo il nostro Sketch.
5
processing
guida introduttiva alla programmazione visuale
La cartella dello Sketch che a sua volta conterrà anche la cartella data
con tutti i file multimediali aggiunti si troverà in una directory del
computer che possiamo decidere dal menù File/Preferences.
Programmare in Processing
Abbiamo detto che programmare in Processing è molto semplice
pertanto il modo migliore per capire questo concetto è iniziare a
scrivere qualche semplice programma cercando di comprenderne il
senso.
//Creiamo una finestra 320 x 240 pixel//
size(320, 240);
background(255);
Abbiamo scritto tre righe nella finestra testuale dell’ambiente di
sviluppo di Processing.
La prima riga potrebbe sembrare semplice e tutti i programmatori
giovani o inesperti o egoisti o masochisti tendono a trascurare
questo tipo di istruzione che invece è determinante.
Ogni volta che scriviamo un programma dobbiamo aggiungere dei
commenti che possano essere letti dai programmatori ma che non
vengano interpretati come istruzioni dal programma stesso. I
commenti sono importanti perchè attraverso i commenti il
programmatore dichiara le operazioni che compie in modo che
potrà rileggerli in futuro oppure in modo che altri programmatori
che apriranno il programma leggendo i commenti possano capire
come ha ragionato il programmatore precedente.
Commentare un programma significa comunicare con se stessi (nel
futuro) e con gli altri. Non commentare un programma significa non
comunicare ne con se stessi (quando un anno dopo aprirete un
programma fatto e non commentato non ricorderete quali
ragionaventi avrete fatto e vi dispererete) ne con altre persone alle
quali per lavoro o per divertimento volete lasciare in eredità il vostro
lavoro. Un programma non commentato è spazzatura.
Questo aspetto così centrale della programmazione risulta ancor più
centrale quando ci riferiamo ad un programma Open Source come
Processing. Processing non costa nulla perchè delle persone buone
d’animo hanno lavorato a lungo e hanno deciso di larsciarci in
eredità gratuita il loro lavoro. Un programmatore che non scrive i
commenti sui programmi realizzati in processing contravviene alla
6
processing
guida introduttiva alla programmazione visuale
filosofia Open Source perchè i suoi programmi saranno
difficilmente interpretabili da altri programmatori.
La stesso giudizio però vale anche per i programmatori che lavorano
in ambiti commerciali. Un programmatore che non commenta i
propri software danneggia economicamente il suo datore di lavoro e
tutto l’ambiente nel quale lavora.
Torniamo quindi alla nostra prima riga di programma scritta in
Processing
//Creiamo una finestra 320 x 240 pixel//
I due slash “//” indicano esattamente l’inizio e la fine di un
commento del programmatore. Questo commento è molto semplice
agli occhi di un programmatore esperto potrebbe sempbrare inutile
ma in realtà quanto più diffusamnte è documentato un software
tanto più facile sarà la sua lettura e correzione in futuro.
Per scrivere dei commenti che siano più lunghi di una riga
Processing ci permette di utilizzare anche la seguente forma:
/* I commenti sono molto importanti
possiamo scriverli anche in più righe
il software non interpreta queste istruzioni
*/
Vediamo invece ora la prima istruzione (o funzione) vera e propria:
size(320, 240);
Possiamo notare in questa istruzione tre elementi importanti:
- Il comando “size”
- I parametri (320, 240)
- Il simbolo che chiude l’istruzione “;”
Il comando “size” stabilisce che deve essere creata una finestra.
Questa è la tipica istruzione con cui si inizia a programmare in
Processing. Con “size” si stabiliscono le dimensioni della finestra
sulla quale poi compariranno i risultati del nostro programma.
Le dimensioni che abbiamo stabilito in questo caso sono 320 pixel
in larghezza (asse X) e 240 pixel in altezza (asse Y).
Con “;” invece diciamo a Processing è terminata l’istruzione.
Da notare la seguente istruzione:
7
processing
guida introduttiva alla programmazione visuale
//size(320, 240);
Poichè la riga inizia con “//” Processing interpreterà tutto ciò che
segue come un commento e quindi quando si lancerà il programma
non verrà effettuata nessuna azione. A volte i programmatori
disordinati tendono a commentare molto le istruzioni durante il
processo produttivo. Questa operazione se non documentata è un
operazione che genera solo confusione. Pertanto quando si
commenta un’istruzione è bene spiegare, attraverso un ulteriore
commento il motivo per il quale sono presenti delle istruzioni
commentate.
Rispetto ai paramentri è importante notare che ad esempio nel caso
di “size” debbono essere 2 e la loro posizione è obbligatoria. Al
primo posto si mette il valore delle X e al secondo posto (dopo la
virgola) si mette il valore delle Y.
Infine da notare un aspetto molto impor tante della
programmazione, la convenzione di chiudere l’istruzione con “;”
potrebbe sembrare inutile e noiosa. Potrebbe anche essere così, ma
comunque è dobbiamo capire che qualora non mettessimo quel
dettaglio “;” il nostro programma non funzionerà. I linguaggi di
programmazione usano una sintassi molto più rigida della sintassi
che si usa quando si parla o quando si scrive una mail. Quando
scriviamo una mail ad un amico e ci dimentichiamo una virgola nel
contenuto del nostro messaggio esso arriverà a destinazione
uguamente. Se invece facciamo un errore quando scriviamo
l’indirizzo mail il messaggio non arriverà mai al destinatario.
Scrivere un’istruzione in Processing è come scrivere un indirizzo
mail, se non metti la chiocciola o sbagli anche solo un puntino non
funzionerà nulla.
Gli aspetti formali della programmazione sono importanti e non
possono essere tralasciati. Un altro aspetto formale che non
possiamo tralasciare in Processing è che i comandi sono “case
sensitive”. “Size” e “size”non sono la stessa cosa, il comando “size”
deve essere scritto con tutte le lettere minuscole, se non lo facciamo
Processing non interpreta il comando. “Size” per Processing non
significa nulla.
Torniamo ora alla terza riga del nostro breve programma:
background(255);
8
processing
guida introduttiva alla programmazione visuale
Possiamo facilmente distiguere il comando “background” il
parametro tra parentesi e il termine della riga di istruzione “;”.
Il comando specifico “background” indica a Processing il colore che
dovrà avere lo sfondo della finestra che abbiamo appena creato. 255
indica il colore bianco.
Una volta terminato di scrivere il nostro programma in tre righe lo
potremo lanciare cliccando sul pulsante RUN. Potremo
interrompere l’esecuzione del nostro programma cliccando sul
pulsante STOP.
Numeri e Variabili
Abbiamo creato il nostro primo breve programma in Processing.
Abbiamo compreso alcuni principi base della programmazione.
Questi principi sono pressochè universali nella programmazione e
comprenderli in processing ci permetterà poi di applicarli a
praticamente qualunque altro linguaggio di programmazione.
Nel nostro primo programma abbiamo visto che i comandi possono
avere dei parametri e che questi parametri si esprimono in numeri.
Nella programmazione è normale però esprimere i numeri anche
attraverso delle variabili.
Queste due espressioni producono lo stesso risultato:
//senza variabili
background(0);
//con variabili
int X = 0;
background (X);
Nel secondo caso abbiamo fatto due operazioni. Con la prima
operazione abbiamo detto al programma di attivare l’uso di una
variabile che abbiamo chiamato “X” e abbiamo assegnato un valore
a questa variabile “0”.
Il risultato è che “background” avrà un valore pari a zero, proprio
come nel primo esempio.
Le variabili sono molto utili nella programmazione proprio perchè
sono “variabili” e quindi il loro valore può cambiare in base a degli
9
processing
guida introduttiva alla programmazione visuale
eventi , oppure possono cambiare in base a delle operazioni
matematiche.
Le variabili sono molto utili anche perchè memorizzano dei valori e
permettono di riutilizzarli quando serviranno in futuro.
Esistono diversi tipi di variabili; nel nostro esempio “int” indica una
variabile che può assumere un valore numerico intero (senza valori
dopo la virgola). “float” è un altro tipo di variabile numerica che può
invece contenere anche valori dopo la “virgola”.
Importante: come in quasi tutti i linguaggi legati all’informatica la
virgola che noi utilizziamo nei numeri per indicare i valori decimali,
deve essere sostituita dal punto “.”.
Nei linguaggi di programmazione 10.5 equivale al 10,5 nella
notazione che utilizziamo in Italia.
Da notare che non è possibile fare operazioni matematiche
mescolando due variabili di tipo diverso (una “int” e l’altra “float”).
Nel linguaggio comune della programmazione l’istruzione:
int X = 0;
viene detta inizializzazione o dichiarazione di una variabile. Questo
tipo di istruzioni generalmente vengono messe all’inizio dei
programmi e comunque debbono essere posizionate sempre prima
che si utilizzi la variabile stessa.
La seguente sequenza non funzionerebbe:
background (X);
int X = 10;
Se vogliamo utilizzare la variabile “X” prima la dobbiamo
inizializzare “int X = 10;”.
Una volta che la variabile è stata inizializzata è possibile utilizzarla
tutte le volte che si desidera. Inoltre dopo l’inizializzazione la
variabile può essere “manipolata”.
Nell’esempio seguente osserviamo che:
int X = 10;
X = 6;
background (X);
la variabile “X” è stata prima inizializzata poi successivamente è
stato assegnato un nuovo valore alla variabile “X = 6;”.
10
processing
guida introduttiva alla programmazione visuale
Pertanto il valore finale di “background (X);” sarà 6.
Ovviamente per brevità sarebbe stato più intelligente scrivere:
int X = 6;
background (X);
il risultato sarebbe stato identico.
Il nome delle variabili
Abbiamo visto quindi che le variabili hanno un nome. Ho utilizzato
“x” e come primo passagio potrebbe essere anche corretto ma
quandi si scrive un programma più complesso è invece consigliabile
dare un nome “sensato” alle variabili.
Il lungo discorso che ho fatto nelle pagine precedenti riguardo i
commenti vale anche per le variabili.
Ipotizziamo ad esempio di voler disegnare un cerchio attraverso un
programma e ipotizziamo che questo cerchio cambierà di
dimensione durante l’esecuizone del programma stesso.
Potremmo assegnare a questa variabile semplicemente una lettera
“X” oppure “C”, ma se immaginiamo che il nostro programma sarà
abbastanza complesso allora sarà sicuramente meglio utilizzare un
nome della variabile più esteso.
Possiamo chiamare la variabile che gestirà il nostro cerchio ad
esempio “cerchio”. In questo modo quando riapriremo il
programma in futuro oppure qualcun’altro aprirà il nostro
programma il nome della variabile permetterà facilmente di
comprendere di che variabile si tratta e per che cosa viene utilizzata.
Pertanto quando dichiarerò la mia variabile all’inizio del programma
scriverò
int cerchio = 10;
anzichè
int X = 10;
Il termine cerchio ci aiuterà molto in futuro quando il nostro
programma andrà progressivamente coplicandosi. Ma in realtà un
buon programmatore dovrebbe precedere la dichiarazione della
variabile con un commento che spiega a cosa serve quella variabile.
Ad esempio:
11
processing
guida introduttiva alla programmazione visuale
// ecco la variabile che gestisce
// il raggio del cerchio
int cerchio = 10;
Il nome delle variabili è sempre meglio che sia “parlante”. Alcuni
nomi però sono inibiti e non possono essere utilizzati per le
variabili.
Ad esempio non posso nominare una variabile “int” perchè facendo
questo complicherei molto la vita a Processing che potrebbe fare
confusione. Infatti “int” è anche un termine assegnato ad un
comando.
Di seguito una lista dei nomi di variabili che non possiamo usare in
Processing:
abstract
assert
boolean
break
byte
case
catch
char
class
const
continue
default
do
double
else
enum
extends
false
final
finally
float
for
goto
if
implements
import
init
instanceof
int
interface
long
native
new
null
package
private
protected
public
return
setup
short
start
static
12
processing
guida introduttiva alla programmazione visuale
stop
strictfp
super
switch
synchronizedthis
throw
throws
transient
true
try
update
void
volatile
while
Questo aspetto è comune a praticamente tutti i linguaggi di
programmazione. Un consiglio che posso dare ai programmatori
italiani è proprio quello di dare un nome in italiano alle variabili.
Poichè i comandi tipicamente sono in inglese si eviterà facilmente di
utilizzare un nome vietato.
Esiste poi una lista di variabili che gestisce autonomamente
Processing. Quando ad esempio abbiamo generato la finestra:
size(320, 240);
Processing ha automaticamente immagazzinato in un due variabili
“width” e “height” questi valori. Se in futuro vorremo utilizzare
questi valori potremo utilizzarli richiamando direttamente le
variabili.
Variabili e calcoli matematici
Le variabili normalmente vengono utilizzate anche per effettuare
calcoli matematici. Le operazioni di base che si effettuano sono più
“+”, meno ”-“, per ”*” e diviso “/”.
Normalmente il risultato di un’operazione matematica viene
memorizzato nelle variabili.
Ad esempio:
int x = 2 + 3;
trasferisce il risultato della somma “2+3” nella variabile X al
momento della sua inizializzazione “int”.
Oppure:
int x = 4;
13
processing
int
int
int
int
y
s
d
m
guida introduttiva alla programmazione visuale
=
=
=
=
6;
x + y;
s / 2;
(x * y)-2;
dichiara il valore delle variabili “x” e “y”, poi viene sommato e il
risultato è memorizzato nella varibile “s” (da cui avremo s = 10). In
“d” invece memorizziamo il risultato di della somma precedente
dividendola per 2 (da cui otterremo d = 5).
Infine nella quinta riga abbiamo una vera e propria espressione.
Trasferiamo nella variabile “m” il risultato della moltiplicazione di
“x” per “y” e successivamente, fuori dalle parentesi, sottraiamo 2 (da
cui otteniamo m = 22).
Da notare che il risultato di un calcolo matematico deve sempre
essere associato a una variabile. Infatti se nella terza riga scriviamo
solo:
x + y;
otterremo un errore quando manderemo in RUN il nostro sketch.
L’uso delle parentesi cosi come nella matematica serve per dare la
priorità ai calcoli. Inoltre moltiplicazione e sottrazione hanno la
priorità su addizione e sottrazione.
Le variabili posso essere utilizzate molte volte all’interno della stessa
espressione. A volte siamo costretti a compiere diverse operazioni
ma non ci interessato i risultati intermedi bensì solo il risultato
finale.
Nel seguente programma:
int
int
int
s =
x
y
s
s
=
=
=
/
4;
6;
x + y;
2;
dopo avere calcolato “x+y” e memorizzato il risultato in “s”
utilizziamo nuovamente “s” nella riga successiva per memorizzare il
valore “s” della riga precedente diviso per 2. Operando in questo
modo abbiamo “risparmiato” una variabile però abbiamo perso il
risultato temporaneo della somma “x + y”. Quando Processing
14
processing
guida introduttiva alla programmazione visuale
eseguirà la quarta riga trasferirà in “s” il risultato della nuova
operazione (“s/2”) e il precedente valore di “s” sarà perso.
Iniziare a disegnare
Le operazioni matematiche che si possono effettuare in Processing
sono molte di più delle quattro operazioni di base, ma stiamo
procedendo secondo un livello di difficoltà progressivo. Abbiamo
capito come si scrive un’istruzione in Processing e abbiamo capito
l’importanza della sintassi. Inoltre abbiamo introdotto il concetto di
variabile nella programmazione. Questi primi elementi ci
permettono di iniziare a scrivere un programma leggermente più
complesso.
Per fare questo però ci avvarremo dell’aspetto maggiormente
potente in Processing, cioè le funnzionalità grafiche.
Credo che comprendere una formula matematica sia molto più
semplice se il risultato di questa formula viene tradotto in una
dimensione grafica.
Prima quindi di addentrarci nei meandri della programmazione e
dell’uso intensivo della matematica iniziamo quindi ad osservare le
funzionalità grafiche di Processing. La conoscenza delle funzionalità
grafiche faciliterà molto lo sviluppo di formule matematiche più
complesse.
Abbiamo iniziato la nostra programmazione scrivendo tre righe:
//Creiamo una finestra 320 x 240 pixel//
size(320, 240);
background(255);
che, abbiamo visto cliccando su RUN, generano una finestra di
sfondo bianco della dimensione di 320 pixel di larghezza e 240 pixel
di altezza.
Per disegnare qualche cosa dentro questa finestra è necessario prima
di tutto comprendere il concetto di coordinate. L’asse delle X scorre
in orizzontale mentre l’asse delle Y scorre in verticale.
L’angolo in alto a sinistra della nostra finestra ha le coordinate (0, 0).
L’angolo in basso a destra ha coordinate (320, 240). L’angolo in alto
a destra ha coordinate (320, 0) mentre l’angolo in basso a sinistra ha
coordinate (0, 240).
figura 2
disegno delle coordinate
15
processing
guida introduttiva alla programmazione visuale
L’istruzione grafica piùsemplice di Processing permette di generare
un punto nello schermo. Questa è la sua sintassi:
point(X, Y);
questo comando grafico ha due parametri, “X” ed “Y” che indicano
le coordnate della finestra nella quale verrà disegnato il punto.
Se ad esempio decidessimo di disegnare il punto esattamente al
centro della finestra che abbiamo appena creato sarà sufficiente
aggiungere una quarta riga:
//Creiamo una finestra 320 x 240 pixel//
size(320, 240);
background(255);
point(160, 120);
Dividendo per due la larghezza e l’altezza della finestra ottengo le
coordinate “X,Y” del punto centrale della finestra.
Per comprendere meglio il funzionamento del sistema delle
coordinate è sufficiente cambiare i valori “X,Y” del comando point.
Da notare che questi valori debbono necessariamente rimanere
all’interno dell’intervallo della finestra stessa.
Per generare più punti nella finestra aggiungo più volte la stessa
istruzione cambiando le coordinate.
Mantenendo fisso uno dei due valori delle coordinate si ottengono
dei punti lungo l’asse verticale o orizzontale a seconda del valore
tenuto fisso.
size(320, 240);
background(255);
//Creiamo tre punti sull’asse verticale
//tenendo il valore “X” stabile
point(160, 60);
point(160, 120);
point(160, 180);
L’aspetto centrale di Processing in quanto strumento didattico è
proprio la facilità con la quale possiamo visualizzare dei principi
matematici e statistici. Le coordinate X,Y le ritroviamo in infiniti
sistemi e rappresentazioni. Manipolare in Processing i valori del
16
processing
guida introduttiva alla programmazione visuale
comando “point” permette di comprendere immediatamente in
modo visivo il funzionamento delle coordinate.
Questa guida può essere letta anche come un’introduzione ai
principi della matematica, della programmazione e degli algoritmi,
possiamo vedere Processing come lo strumento più veloce per
comprendere questi principi.
Una volta compreso il principio delle coordinate sarà molto
semplice con processing disegnare tutte le forme geometriche di
base.
Ad esempio questa è la sintassi del comando per disegnare una linea:
line(x1, y1, x2, y2);
Con questo comando viene eseguita una linea che come estremi due
punti individuati con “X1,Y1” e “X2,Y2”.
size(320, 240);
background(255);
//Creiamo una linea diagonale
//che attraversa la finestra
//dall’angolo in alto a sinistra
//all’angolo in basso a destra
line(0, 0, 320, 240);
Per fare una linea in senso orizzontale il parametro Y dei due punti
dovrà rimanere costante. Il seguente comando genera una linea che
attraversa la finestra orizzontalmente alla sua metà.
line(0, 120, 320, 120);
Per disegnare diverse linee è sufficiente mettere un’istruzione dopo
l’altra nello stesso Sketch. Per disegnare diverse linee con dei punti
in comune è sufficiente scrivere più istruzioni dove ogni linea ha due
coordinate uguali alla linea successiva.
//figura composta da due linee
//che hanno un punto in comune
//100,120
line(0, 120, 100, 120);
17
processing
guida introduttiva alla programmazione visuale
line(100, 120, 80, 220);
Unendo delle linee possiamo disegnare triangoli, quadrilateri,
rettangoli e linee spezzate.
//triangolo prodotto
//disegnando 3 linee
line(0, 120, 100, 120);
line(100, 120, 80, 220);
line(80,220,0, 120);
Ovviamente però Processing prevede le istruzioni per disegnare
direttamente Triangoli, Quadrilateri, Rettangoli ed Ellissi.
triangle
quad
rect
ellipse
Ecco spiegato di seguito il funzionamento di ogni istruzione:
triangle (X1, Y1, X2, Y2, X3, Y3);
Attraverso i tre punti vengono disegnati i tre lati del triangolo.
quad (X1, Y1, X2, Y2, X3, Y3, X4, Y4);
Attraverso i quattro punti vengono definiti i quattro lati del
quadrilatero. Il quadrilatero che ne deriva può avere anche tutti i lati
diversi e non avere lati paralleli.
Importante però quando si disegna un quadrilatero è di seguire un
ordine dei lati.
Se ad esempio scrivete questa istruzione
quad (1, 1, 50, 10, 100, 100, 130, 100);
succede che anzichè generare un quadrilatero genererete due
trinagoli. Ciò succede perchè nel passaggio dal secondo punto al
terzo e dal terzo al quarto Processing segue l’ordine dei punti e
quindi i lati del quadrilatero si incrocieranno.
18
processing
guida introduttiva alla programmazione visuale
Scambiando il terzo punto con il quarto otterremo invece un
quadrilatero:
quad (1, 1, 50, 10, 130, 100, 100, 100);
Per quanto riguarda il rettangolo Processing ragiona in modo
leggermente diverso, ecco la sintassi:
rect(x, y, width, height)
si individua con i parametri “X,Y” l’angolo in alto a sinistra del
rettangolo e successivamente si dichiara la larghezza e l’altezza del
rettangolo. Ovviamente se “width” e “height” hanno lo stesso
valore succede che il rettangolo diventa un quadrato.
Infine ecco l’istruzione per generare ellissi e cerchi:
ellipse (X, Y, width, height);
Con “X, Y” si stabilisce il centro dell’ellisse mentre con “width,
height” si stabiliscono larghezza e altezza dell’ellisse. Se i due
parametri “width, height”sono uguali si ottiene un cerchio perfetto.
Abbiamo quindi visto come si disegnano le figure geometriche di
base con Processing. Gli esempi descritti sopra fanno sempre
riferimento a delle forme “stabili” legate cioè a dei numeri “fissi”.
Volendo effettuare dei disegni più complessi e dinamici potremmo
associare le nostre forme a delle variabili.
Inoltre le forme che abbiamo disegnato fanno sempre riferimento
ad un contesto “neutrale”dove il colore di sfondo è sempre bianco e
le figure sono bianche bordate di nero.
Ad esempio il seguente Sketch
size(320, 240);
background(255);
//Creiamo un quadrilatero
quad (1, 1, 50, 10, 130, 100, 100, 100);
//mettiamo sopra al quadrilatero un cerchio
ellipse (20,20, 50, 50);
19
processing
guida introduttiva alla programmazione visuale
produrrà graficamente il quadrilatero che conosciamo e
successivamente sopra di esso un cerchio le cui coordinate del
centro sono “20, 20” ed il cui raggio è 50. Il cerchio come possiamo
vedere ha uno sfondo bianco pertano si sovrappone, coprendolo in
parte, al quadrilatero.
Questo comportamento ci spiega due aspetti di Processing.
Prima di tutto dobbiamo capire che Processing come tutti i linguaggi
di programmazione esegue i comandi leggendoli in sequenza. La
sequenza di esecuzione diventa sempre più importante e strategica
quando si complica lo Sketch.
Inoltre le figure grafiche hanno un riempimento e non sono
trasparenti. Per vedere meglio questo riempimento possiamo
cambiare il colore della finestra.
background(0);
Canbiando il valore di background da 255 (bianco) a 0 (nero)
vediamo ancora maglio che le forme geometriche create hanno un
colore di riempimento.
I numeri compresi tra 0 e 255 rappresentano tutte le gradazioni che
vanno dal nero al bianco, cioè sono dei grigi sempre meno intensi
che alla fine 255 diventa un bianco.
Questa modalità di classificazione dei colori vale anche per il colore
di riempimento delle forme.
Quando questo colore non viene dichiarato Processing stabilisce
autonomamente un colore (questo in informatica viene definito
valore di default).
Per vedere ad esempio quale è il colore di default delle finestre è
sufficiente cancellare l’istruzione background dal nostro sketch.
Mandando in run Processing vediamo che la finestra assume un
colore di sfondo grigio.
I comandi hanno valori di default diversi infatti le forme
geometriche che abbiamo creato hanno un valore di default per il
riempimento che è il bianco (255).
Per cambiare il valore di default per il riempimento delle forme
geometriche si utilizza l’istruzione:
fill ();
questa istruzione deve precedere il comando per la generazione della
forma geometrica.
Il seguente sketch
20
processing
guida introduttiva alla programmazione visuale
size(320, 240);
fill (80);
//Creiamo un quadrilatero
quad (1, 1, 50, 10, 130, 100, 100, 100);
//mettiamo sopra al quadrilatero un cerchio
ellipse (20,20, 50, 50);
genera quindi una finestra con un colore di sfondo di default (grigio)
e delle forme geometriche con un colore di sfondo stabilito dal
valore tra parentesi del comando “fill”. 80 indica un grigio scuro.
Il valore fill funziona per tutte le forme geometriche che verranno
generate dopo di esso. Possiamo infatti vedere che sia il quadrilatero
che il cerchio hanno lo stesso riempimento. Qualora volessimo
generare forme geometriche con valori di sfondo diversi dobbiamo
semplicemente mettere dei nuovi comandi fill
size(320, 240);
//Creiamo un quadrilatero
fill (80);
quad (1, 1, 50, 10, 130, 100, 100, 100);
//mettiamo sopra al quadrilatero un cerchio
fill (250);
ellipse (20,20, 50, 50);
Il fill valido è sempre l’ultimo e vale nello sketch finchè non ne
dichiariamo uno nuovo. Il cerchio dello sketch qui sopra è pressochè
bianco (250) il quadrilatero e grigio scuro (80) e se creassimo una
nuoma forma geometrica dopo il cerchio senza specificare un nuovo
fill esso sarebbe 250.
Le forme grafiche hanno altri valori di default. Ad esempio
disegnando le forme geometriche notiamo che il bordo della forma
ha un colore e uno spessore. Il cerchio che abbiamo creato nel
precedente Sketch ha il bordo nero, questo colore è di default e può
essere cambiato mettendo, sempre prima dell’istruzione che genera
la forma geometrica , l’istruzione:
stroke (255);
21
processing
guida introduttiva alla programmazione visuale
in questo caso il cerchio avrà un bordo bianco (255) e qualora sia
bianco anche il riempimento ovviamente non avremo percezione del
bordo stesso.
Un modo più corretto per fare scomparire il bordo da una forma
geometrica è l’apposito comando
nostroke (0);
così come possiamo fare scomparire il riempimento con
noFill (0);
Inoltre possiamo anche decidere lo spessore del bordo delle forme
geometriche (e delle linee) attraverso l’istruzione
strokeWeight(4);
dove il valore tra parentesi indica lo spessore del bordo espresso in
pixel. Da notare un aspetto importante: la “W” di Weight è
maiuscola e come ho spiegato nelle prime pagine i comandi sono
“case sensitive” pertanto dobbiamo scriverli tenendo presenti le
maiuscole e le minuscole.
In generale su questo aspetto però l’ambiente di sviluppo di
Processing ci aiuta poichè se per errore digitiamo un comando
errato (es: strokeweight) vediamo che Processing non modifica il
colore del comando stesso lasciandolo nero. Quando invece
digitiamo un comando che per Processing significa qualche cosa (es:
strokeWeight) succede che immediatamente il testo viene cambiato
di colore e diventa marrone.
Da notare infine che in molti linguaggi di programmazione si segue
questa convenzione, la prima parola di un comando si scrive in
minuscolo la seconda parola (attacata) inizia sempre con una
maiuscola, lo stesso vale per l’eventuali terza o quarta parola.
Diversi altri parametri permettono di intervenire sulle forme
geometriche ma per ora abbiamo visto quelli essenziali e possiamo
procedere oltre nel nostro percorso di addestramento alla
programmazione.
In seguito scopriremo come gestire i colori (per ora abbiamo visto
solamente come gestire i grigi, e come gestire ad esempio le
trasparenze nonchè le curve e tante altre cose ...).
22
processing
guida introduttiva alla programmazione visuale
Ora però è necessario un nuovo salto nella modalità di lavoro.
Programmare veramente
La programmazione che abbiamo visto fino ad ora è composta da
una serie di comandi messi in sequenza. Processing elabora le
istruzioni una dopo l’altra partendo dalla prima riga e terminando
all’ultima. In pratica Processing legge i programmi che abbiamo
fatto fino ad ora come noi leggiamo i contenuti di un libro.
Abbiamo visto anche il concetto di variabile. Le variabili sono utili
perchè invece di utilizzare sempre i numeri possiamo sostituirli con
delle entità il cui stato varia con lo scorrere del programma.
I disegni che abbiamo fatto fino ad ora sono molto semplici e
sopratutto sono statici. Infatti tutte le istruzioni che abbiamo scritto
vengono elaborate sequenzialmente ma ad una velocità tale percui
quando premiamo il tasto RUN davanti a noi compare una figura
apparentemente statica.
Processing è un’applicazione che si presta bene per fare lavori di tipo
statico (immagini fisse) ma si presta molto bene anche per fare
animazioni.
Inoltre anche nell’elaborazione di immagini statiche potrebbe
succedere che vogliamo produrre molte volte una figura ad intervalli
regolari oppure di dimensioni progressivamene crescenti.
Questa tipologia di problematiche: animazioni e ripetizioni
(iterazioni) possono essere risolte in modo veloce attraverso delle
apposite istruzioni.
Partiamo da un caso molto semplice: all’interno della nostra finestra
vogliamo disegnare dei punti ad intervalli regolari sull’asse
orizzontale, uno ogni 40 pixel.
Disegniamo ora questi punti utilizzando il metodo più semplice che
abbiamo visto.
size(320, 240);
background(255);
//Creiamo sette punti
//sull’asse orizzontale
//tenendo il valore “Y” stabile
point(40, 120);
point(80, 120);
point(120, 120);
point(160, 120);
23
processing
guida introduttiva alla programmazione visuale
point(200, 120);
point(240, 120);
point(280, 120);
Abbiamo visto già nelle pagine precedenti tutte le istruzioni che
permettono di generare questo nuovo Sketch. Premendo RUN
vediamo sette punti a intervalli rogolari che attraversano lo schermo
in senso orizzontale.
Ora introduciamo l’uso delle variabili. Stabiliamo una variabile che
chiamiamo “intervallo” e che ha il valore di 40, successivamente
sostituiamo i valori delle coordinate X dei punti con le variabili.
size(320, 240);
background(255);
// dichiaro la variabile
int intervallo = 40;
//Creiamo sette punti
//sull’asse orizzontale
//tenendo il valore “Y” stabile
point(intervallo, 120);
point(intervallo*2, 120);
point(intervallo*3, 120);
point(intervallo*4, 120);
point(intervallo*5, 120);
point(intervallo*6, 120);
point(intervallo*7, 120);
Abbiamo moltiplicato l’intervallo per dei valori progressivamente
maggiori ottenendo esattamente lo stesso risultato del precedente
Sketch.
Il coefficiente di moltiplicazione che applichiamo
all’invervallo stabilisce la distribuzione dei punti.
Proviamo quindi a trasformare in variabile anche questo
coefficiente, chiamandola coefficiente.
size(320, 240);
background(255);
// dichiaro la variabile
int intervallo = 40;
// dichiaro la variabile
// coefficiente
int coefficiente = 1;
24
processing
guida introduttiva alla programmazione visuale
//Creiamo sette punti
//sull’asse orizzontale
//tenendo il valore “Y” stabile
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
Leggendo con attenzione lo Sketch appena scritto vediamo che esso
è diventato molto più lungo. Infatti per poter incrementare ogni
volta il coefficiente è stata aggiunta l’apposita istruzione
“coefficiente = coefficiente + 1;”. Comunque un primo vantaggio
possiamo coglierlo dal fatto che osservando con attenzione lo sketch
vediamo che le istruzioni sono sempre uguali. Infatti le due righe di
istruzione:
point(intervallo*coefficiente, 120);
coefficiente = coefficiente + 1;
si ripetono sette volte generando i sette punti. Per velocizzare
l’operazione di scrittura dello sketch potremmo scriverlo facendo
“copia” e “incolla” delle due righe fino a ripeterle sette volte.
La logica della programmazione informatica sta esattamente in
questi passaggi:
- concepire tutti i passaggi che portano al risultato
(abbiamo scritto nel primo Sketch tutte le istruzioni che portavano
al risultato desiderato)
- concepire questi passaggi in modo che siano ripetitivi
(abbiamo scritto nel terzo Sketch istruzioni ripetitive che portano al
risultato desiderato)
25
processing
guida introduttiva alla programmazione visuale
- trasformare i passaggi da ripetitivi a ricorsivi
(ora trasformeremo le operazioni ripetitive in ricorsive scrivendo un
“ciclo”):
size(320, 240);
background(255);
// dichiaro la variabile
int intervallo = 40;
// dichiaro la variabile
// coefficiente
int coefficiente = 1;
//Creiamo sette punti
//sull’asse orizzontale
//tenendo il valore “Y” stabile
for (coefficiente = 1; coefficiente
coefficiente = coefficiente+1) {
point(intervallo*coefficiente, 120);
}
<
8;
L’unico elemento nuovo nello Sketch precedente è esattamente
l’istruzione “for” che ha la seguente sintassi:
for (coefficiente = 1; coefficiente
coefficiente = coefficiente+1) {
point(intervallo*coefficiente, 120);
}
<
8;
I principi di ricorsività vengono stabiliti tra parentesi dopo avere
scritto l’istruzione “for”. Tra parentesi troviamo tre elementi
separati da “;”.
Il primo elemento “coefficiente = 1” stabilisce il valore di partenza
del ciclo.
Il secondo elemento “coefficiente < 8” stabilisce il valore di
interruzione del ciclo.
Il terzo elemento stabilisce l’aggiornamento del valore che avverrà
ricorsivamente (l’incremento della variabile) che nel nostro caso è
“coefficiente = coefficiente+1”.
In seguito all’istruzione “for” tra le parentesi graffe vengono messe
le operazioni da compiere durante tutta la durata del ciclo “point
(intervallo*coefficiente, 120)”.
26
processing
guida introduttiva alla programmazione visuale
Leggiamo come se fosse scritta in lingua italiana l’istruzione “for”del
nostro ciclo:
Incrementa il coefficiente di una unità e finchè il suo valore è
minore di 7 disegna un punto.
Attraverso le istruzioni di tipo “for” possiamo quindi ripetere
un’operazione finchè non si verifichi una condizione di interruzione.
Abbiamo quindi sintetizzato il nostro sketch, da notare che ora,
qualora volessimo disegnare 100 punti invece di 7 la lunghezza dello
sketch sarebbe sempre la stessa mentre invece nella modalità
precendente avremmo dovuto scrivere 100 righe di codice, una per
punto.
Il seguente Sketch disegna 100 punti, con un intervallo tra un punto
e l’altro di 3 pixel:
size(320, 240);
background(255);
// dichiaro la variabile
int intervallo = 3;
// dichiaro la variabile
// coefficiente
int coefficiente = 1;
//Creiamo sette punti
//sull’asse orizzontale
//tenendo il valore “Y” stabile
for (coefficiente = 1; coefficiente < 101;
coefficiente = coefficiente+1) {
point(intervallo*coefficiente, 120);
}
Per fare questa semplice modifica abbiamo solamente modificato la
variabile “int intervallo = 3;” ed abbiamo cambiato il valore di
interruzione del ciclo “for” con “coefficiente < 100”.
La verifica di interruzione del ciclo ”for” avviene attraverso un
simbolo comunemente conosciuto: “<”.
In processing è possibile anche controllare se un valore è maggiore
“>” oppure se un valore è uguale “==”.
Nel caso di uguale (come in molti linguaggi di programmazione) si
utilizza due volte il
simbolo “=” per evitare che il programma compia un’operazione
sulla variabile.
Pertanto quando scriviamo:
27
processing
guida introduttiva alla programmazione visuale
X = 5 trasferiamo il valore “5” nella variabile “X”
Mentre se scriviamo
X == 5 controlliamo se il valore di X è uguale (==) a 5.
La programmazione in Processing ci permette quindi di evitare di
scrivere infinite operazioni descrivendole una ad una. Attraverso i
cicli “for” possiamo ripetere delle operazioni infinite volte
cambiando ogni volta l’operazione grazie all’uso delle variabili.
Le condizioni
Un’altra istruzione (oltre al ciclo “for”) è determinante nel processo
di apprendimento della programmazione. Questa istruzione è “if ”.
Continuiamo a lavorare nel nostro precedente Sketch e
modifichiamolo decidendo che i nostri punti devono diventare delle
linee quando il valore del “coefficiente” supera la soglia di 90
(elimino i commenti per risparmiare “carta” visto che sono presenti
nello Sketch precedenti).
size(320, 240);
background(255);
int intervallo = 3;
int coefficiente = 1;
for (coefficiente = 1; coefficiente < 101;
coefficiente = coefficiente+1) {
if (coefficiente > 90) {
line (intervallo*coefficiente, 120,
intervallo*coefficiente, 130);
}
point(intervallo*coefficiente, 120);
}
Abbiamo aggiunto l’istruzione “if ”:
if (coefficiente > 90) {
line (intervallo*coefficiente, 120,
intervallo*coefficiente, 130);
}
28
processing
guida introduttiva alla programmazione visuale
che controlla se il coefficiente è maggiore di 90 e qualora lo sia
disegna una linea verticale lunga 10 pixel (notare il valore della
coordinata Y che è prima 120 poi 130). Mandando in RUN lo sketch
completo vediamo che Processing disegna 90 punti e poi inizia a
disegnare delle linee.
La gestione delle condizioni nella programmazione è determinante,
infatti ogni volta che verifichiamo se una condizione si verifica
automaticamente creiamo un bivio nel percorso possibile che può
compiere il programma.
Quando al mattino usciamo di casa controlliamo se piove e qualora
stia piovendo prendiamo l’ombrello. In quel momento compiamo
un’operazione di tipo “if ”.
Quando all’interno di un programma ad esempio vogliamo gestire le
possibili interazioni con l’utente che lo userà dobbiamo farlo
attraverso delle operazioni “if ”. Tutti i software che producono delle
interazioni con l’utente lo fanno ragiornando attraverso dei comandi
di tipo “if ”.
I cicli “for” insieme ai controlli “if ” sono due elementi centrali della
logica di programmazione (in processing e praticamente in
qualunque altro linguaggio di programmazione).
Il controllo “if ” permette anche di gestire la condizione negativa
(detta “else” ossia altrimenti). Pertanto possiamo decidere anche di
cambiare il nosro sketch così come segue:
size(320, 240);
background(255);
int intervallo = 3;
int coefficiente = 1;
for (coefficiente = 1; coefficiente < 101;
coefficiente = coefficiente+1) {
if (coefficiente > 90) {
line (intervallo*coefficiente, 120,
intervallo*coefficiente, 130);
}
else {
point(intervallo*coefficiente, 120);
}
}
Oltre al controllo precedente (“if coefficiente > 90”) abbiamo
aggiunto la verifica della condizione negativa “else”. In questi
passaggi è importante seguire anche l’uso delle parentesi poichè se
29
processing
guida introduttiva alla programmazione visuale
utilizzate in modo errato producono degli errori in fase di
esecuzione.
Rispetto all’uso delle parentesi vale sempre una regola semplice: le
parentesi aperte debbono essere tante quante le parentesi chiuse.
Inoltre le parentesi sono sempre legate, quindi se si apre una
parentesi tonda si deve chiudere la parentesi tonda. Quando si apre
una graffa si deve chiudere la graffa.
Inoltre le parentesi possono essere nidificate, messe cioè una dentro
l’altra.
Nello Sketch sopra ad esempio abbiamo messo dentro alle parentesi
del ciclo “for” (che quindi inglobano il resto delle istruzioni) le
parentesi relative ad “if ” e ad “else”. Possiamo dire che abbiamo
messo due piccole scatole (“if ” e “else”) dentro una scatola più
grande (“for”).
Programmare le animazioni
Le istruzioni che abbiamo visto fino ad ora ci hanno permesso di
capire i principi base della programmazione. Per generare delle
forme grafiche è sufficiente scrivere le specifiche istruzioni. Le
forme grafiche hanno sempre delle coordinate e dei valori (colore,
spessore...) che possono essere espressi in numeri o attraverso delle
variabili.
L’esecuzione delle istruzioni da parte di Processing procede
linearmente a meno che, attraverso le istruzioni for non realizziamo
dei cicli.
Nel caso in cui volessimo però realizzare delle animazioni dobbiamo
ragionare in modo diverso.
Un’animazione è composta da fotogrammi (immagini fisse)
successivi. L’esecuzione dei fotogrammi ad una velocità sufficiente
genera un effetto di animazione nel nostro cervello.
Processing è un software che ci permette di disegnare attrvaerso le
istruzioni grafiche e ci permette anche di disegnare in movimento.
Riconfiguriamo ora lo Sketch realizzato precedentemente dandoci
un nuovo obiettivo. Produrre attraverso un’animazione dei punti
successivi che compaiono progressivamente.
Per ottenere questo nuovo effetto dobbiamo utilizzare le istruzioni
che permettono di gestire le funzioni:
// configuro i parametri
// di esecuzione
void setup () {
30
processing
guida introduttiva alla programmazione visuale
size (320,240);
background (255);
}
int intervallo = 0;
// definisco la funzione
// dentro la funzione
// metto le istruzioni ricorsive
void draw (){
frameRate (1);
point(intervallo, 120);
intervallo = intervallo + 10;
}
Le funzioni utilizzate in questo nuovo Sketch sono due:
void setup () {}
void draw () {}
Con “void setup” vengono definite tutte quelle parti del programma
che rimarranno effettive durante la sua esecuzione. Le istruzioni
interne alla funzione “void setup” vengono eseguite una sola volta.
Infatti dentro le parentesi “{}” sono state messe le due istruzioni
tipiche di ogni Sketch per la definizione della finestra e del suo
colore di sfondo. Inoltre è stata anche messa l’inizializzazione della
variabile “intervallo” che è necessaria un’unica volta.
Con “void draw”viene invece definita la funzione ricorsiva che verrà
eseguita ricorsivamente senza sosta. “frameRate (1);” stabilisce la
velocità dell’animazione che ho impostato ad 1 fotogramma al
secondo in modo al fine di cogliere bene gli effetti dello Sketch. Poi
metto l’istruzione per disegnare il punto e l’istruzione per spostare
di intervalli regolari il punto stesso (intervallo = intervallo + 10).
Quando verrà mandato in RUN lo Sketch si otterrà un’animazione
alla velocità di un frame al secondo dove compare un nuovo punto
ogni frame. Questo punto (grazie al contatore) avrà ad ogni frame
una coordinata Y incrementata di 10.
Mandando in RUN lo Sketch così come è stato configurato succede
che i punti creati nel fotogramma precedente rimangono persistenti
nel video pertanto ad ogni fotogramma avremo un punto in più.
Qualora invece volessimo avere un effetto di spostamento del punto
dovremmo ad ogni nuovo frame cancellare il punto creato nel
fotogramma precedente. Per fare questo è sufficiente spostare
31
processing
guida introduttiva alla programmazione visuale
l’istruzione “background (255);”dalla funzione “setup” alla funzione
“draw”.
Mandando nuovamente in RUN lo Sketch modificato notiamo che il
punto del frame precedente scompare ed abbiamo un effetto di
movimento (anche se molto a scatti e lento).
Per velocizzare il movimento è sufficiente modificare i parametri
frameRate (lo impostiamo a 5 poi a 15). Per dare maggiore fluidità è
sufficiente abbassare l’incremento costante della variabile
“intervallo”; anzichè 10 mettiamo 3 poi 1.
Continuando a modificare questi due parametri possiamo capire
sempre meglio il loro uso. Da ricordare che nel cinema e nella
televisione si lavora all’incirca ad una frequenza di 25 fotogrammi al
secondo.
Processing ha un valore di default del “frameRate” di 60. Pertanto se
all’interno della funzione “draw” non dichiariamo una velocità
questo valore sarà automaticamente impostato a 60 (molto veloce).
Da notare infine che, mandando in esecuzione lo Sketch, il punto si
sposta progressivamente da sinistra a destra finchè non scompare. In
realtà, pur scomparendo il punto Processing continua ad elaborare
lo Sketch incrementando il valore “intervallo” anche oltre la
dimensione della finestra dichiarata in “size”. Questo aspetto dovrà
essere tenuto presente quando verranno programmati degli Sketch
sempre più complessi poichè in termini di elaborazione essi
impegnano il computer pur non generando alcun effetto visibile.
Farsi in casa una funzione
I processi base della programmazione sono stati introdotti. Le
funzioni sono molto importanti poichè permettono di eseguire in
modo ricorsivo delle operazioni.
La programmazione in Processing permette anche di definire delle
funzioni da richiamare quando se ne ha bisogno.
Ad esempio possiamo definire una funzione che disegna due punti
che si muovono da sinistra a destra.
Costruisco una funzione come segue:
void punti () {
// con il controllo if
// faccio in modo di ripartire
// ogni volta che esco dallo schermo
if (intervallo > 320) {
intervallo = 10;
32
processing
guida introduttiva alla programmazione visuale
}
intervallo = intervallo + 10;
point (intervallo, 120);
point (intervallo +1, 118);
}
dopo l’istruzione che introduce le funzioni (void) viede dato un
nome alla funzione stessa. In questo caso “punti”. Poi per vedere
l’effetto in modo continuativo utilizzo anche una istruzione if che
praticamente controlla se i punti hanno superato la dimensione dello
schermo “if (intervallo > 320)”. In caso affermativo riporto la
variabile “intervallo” al suo valore di partenza (intervallo = 10;) e
quindi i punti riappariranno nello schemo a sinistra in modo infinito.
Le due istruzioni “point” definiscono la posizione dei due punti che
scorreranno in senso orizzontale (infatti come coordinata X hanno
una variabile mentre come coordinata Y hanno un numero fisso).
L’utilità delle funzioni definite sta nel fatto che possono essere
richiamate quando sono necessarie. Pertanto una volta definite
potranno essere utilizzate molte volte.
Di seguito uno sketch che richiama la funzione “punti” (tolgo i
commenti ricorsivi dallo Sketch per brevità).
int intervallo = 10;
void setup () {
size (320,240);
}
void draw (){
frameRate (15);
background (255);
punti ();
}
void punti () {
if (intervallo > 320) {
intervallo = 10;
}
intervallo = intervallo + 10;
point (intervallo, 120);
point (intervallo +1, 118);
33
processing
guida introduttiva alla programmazione visuale
}
Leggendo il contenuto della funzione “void draw ()” vediamo il
richiamo alla funzione creata “punti ();”. Per richiamare una
funzione creata è sufficiente quindi scrivere il nome della funzione e
mettere le due parentesi tonde e la virgola.
Il flusso di esecuzione dello Sketch salterà quindi alla funzione
“punti” e la scorrerà come se fosse un sottoprogramma. Terminata
la funzione Processing tornerà a leggere l’istruzione subito dopo il
richiamo. Da ricordare che tutte le istruzioni della funzione “void
draw ()” sono eseguite da processing in modo infinito.
E’ comunque possibile interrompere questo ciclo infinito attraverso
l’istruzione “noLoop ();” sia in un punto specifico durante
l’esecuzione della funzione “draw” sia come caratteristica generale
dello sketch mettendo l’istruzione nell’area “setup”.
Volendo far ripartire il loop infinito di “draw” è invece sufficiente
mettere l’istruzione “loop ();” nel punto desiderato.
Variabili, funzioni, interazioni (if) e cicli rapresentano la base della
programmazione. Chi ha letto e compreso tutto ciò che è scritto
nelle pagine precedenti può tranquillamente dire in giro che conosce
i rudimenti della programmazione.
34
processing
guida introduttiva alla programmazione visuale
Seconda Parte
I colori
Molte istruzioni sono state volontariamente tralasciate nella prima
parte del testo perchè l’intento era far comprendere i principi base e
successivamente incrementare la conoscenza intorno ad essi.
Ad esempio nella Prima parte ho descritto il metodo utilizzato in
Processing per definire il bianco, il nero e tutte le tonalità di grigio
che stanno in mezzo.
Traducendo in termini informatici e matematici la modalità di
classificazione utilizzata da Processing per le scale di grigio possiamo
dire che vengono utilizzati 8 bit. Infatti 8 bit permettono di ottenere
28 (256) combinazioni diverse (da 0 a 255).
Il criterio che processing utilizza per i colori è praticamente lo stesso
solamente che applica la scala ai tre colori primari utilizzati per
classificare i colori negli schermi (anche quelli televisivi). Questi
colori sono Il Rosso il Verde (Green) e il Blu, il metodo viene infatti
chiamato RGB.
Processing utilizza 8 bit per classificare ognuno dei tre colori primari
del metodo RGB.
Vediamo prima di tutto un semplice Sketch per capire meglio il
metodo:
size (320, 240);
fill(255, 255, 255);
ellipse (50, 50, 20, 20);
Lo Sketch produce un cerchio (ellipse) di colore bianco poichè nella
istruzione “fill” sono stati impostati i parametri RGB al massimo
valore (255, 255, 255). Ne consegue che se impostiamo tutti e tre i
parametri al mimimo otteniamo il nero (0, 0, 0). Questo metodo è
anche detto additivo.
I tre numeri hanno una posizione fissa, il primo indica il Rosso, il
secondo il Verde e il tezo il Blu. Di seguito una breve tabella con
alcuni esempi di colore ottenuti attraverso il metodo RGB:
(255, 0, 0) = Rosso
(0, 255, 0) = Verde
(0, 0, 255) = Blu
35
processing
guida introduttiva alla programmazione visuale
(255, 255, 0) = Giallo
(150, 150, 150) = Grigio
(250, 200, 200) = Rosa
Le combinazioni possibili prodotte da 24 bit sono circa 16 milioni
di colori.
Il metodo RGB può essere applicato in sostituzione del metodo a 8
bit. Ad esempio per tornare allo Sketch precedente potremmo
stabilire di voler disegnare un cerchio bianco con bordo rosso. Per
fare questo utilizziamo un’istruzione che abbiamo già visto “stroke”
però in questo caso dichiariamo i 3 colori primari.
size (320, 240);
fill(255, 255, 255);
stroke (255, 0, 0);
ellipse (50, 50, 20, 20);
Inoltre aggiungendo l’istruzione background possiamo anche
stabilire il colore di sfondo della finestra. Ad esempio se allo sketch
precedente aggiungiamo l’istruzione “background (0, 0, 0)” dopo
l’istruzione “size”, otteniamo uno sfondo verde.
Trasparenza
Processing permette anche di gestire un quarto parametro per
gestire i colori. Anche questo quarto parametro viene gestito con
uno spettro di 8 bit, esso è la trasparenza (anche detto canale alpha).
Vediamo uno Sketch:
size (320, 240);
fill(0, 0, 255, 200);
ellipse (50, 50, 20, 20);
fill(255, 0, 0, 100);
ellipse (40, 40, 20, 20);
fill(255, 0, 255, 50);
ellipse (20, 20, 50, 50);
Il precedente Sketch produce tre cerchi con colori diversi e gradi di
riempimento diversi (il quarto parametro dell’istruzione “fill”).
36
processing
guida introduttiva alla programmazione visuale
Quando il canale Apha è impostato a 0 la figura risulta
completamente trasparente mentre quando il canale è impostato a
255 la figura risulta essere piena.
Il grado di trasparenza è particolarmente utile quando si hanno delle
figure sovrapposte e si vuole lasciare trasparire le figure sottostanti.
Eseguendo il precedente Sketch possiamo notare che i tre cerchi
sono sovrapposti secondo l’ordine definito nella scrittura dello
Sketch: il primo cerchio risulta essere più in fondo e vicino allo
sfondo, mentre l’ultimo cerchio risulta essere più in superficie e
quindi sopra i due cerchi scritti precedentemente.
Il grado di trasparenza è applicabile anche ai grigi. Ecco una tabella
esplicativa delle possibili situazioni, riportata all’istruzione “fill” ma
estensibile a “background”:
fill (100); = riempimento grigio
fill (100, 50); = riempimento grigio con un alto livello di trasparenza
fill (255, 0, 0); = riempimento con metodo RGB
fill (255, 0, 0, 120); = riempimento con metodo RGB e un medio
livello di trasparenza
Un’ultima cosa interessante sui colori riguarda le variabili. E’
possibile definire delle variabili di tipo colore e successivamente
richiamare il colore direttamente scrivendo il nome della variabile.
color rosso = color(255, 0, 0);
fill(rosso);
Ad esempio nelle due righe sopra ho definito il colore rosso e
successivamente lo richiamo all’interno di un parametro fill.
Questà opportunità permette di gestire colori particolari dei quali
magari si è già provata in passato la combinazione. In questo modo
mettendo all’inizio dello Sketch il codice del colore sarà più facile in
seguito nello Sketch richiamarlo.
Nei semplici Sketch questo tipo di funzionalità potrebbero sembrare
inutili, ma quando si inizia a scrivere degli Sketch lunghi centinaia di
righe ci si accorge dell’utilità di queste funzioni (nonchè dei
commenti “//”).
Il caso
Quando si realizza arte con il computer i colori sono ovviamente
determinanti. Designare senza colori è molto più difficile e
limitativo. Mentre alcuni tipi di disegni possono essere facilmente
37
processing
guida introduttiva alla programmazione visuale
riprodotti anche in scale di grigio, altri tipi di rappresentazione
necessitano dei colori. Se ben usata, l’opzione dei colori permette di
ottenere dei risultati e delle rappresentazioni visive molto più
efficaci.
C’è un altro aspetto concettuale che riguarda la programmazione che
è altrettanto determinante: la casualità (random).
Generare dei numeri a caso attraverso il computer permette di
ottenere delle forme visuali molto più credibili che non utilizzando
delle rigide formule trigonometriche.
Le numerazioni casuali sono molto utili ad esempio quando si vuole
simulare un movimento di un “soggetto” organico oppure quando si
vuole disporre in modo naturale degli oggetti.
Ad esempio vuolendo simulare una distesa d’erba potremmo in
teoria decidere di mettere un filo ogni 4 pixel ma questa disposizione
così “rigida” e costante darebbe immediatamente un effetto estetico
di artificialità all’immagine risultante. Se invece disponiamo i fili
d’erba in modo casuale entro un certo intervallo (tra 1 e 6 pixel)
otteniamo un effetto naturale nella distribuzione dell’erba stessa.
Inoltre la casualità è molto importante anche quando si vogliono
gestire dei giochi. Tutti gli eventi a partire da un lancio di moneta o
di dado possono essere gestiti attraverso la generazione di un evento
casuale nel computer.
La casualità ha quindi uno spazio importante nella generazione di
immagini e nella gestione delle animazioni fatte con Processing e
con qualunque altro software.
Da notare inoltre che la casualità in quanto tale non è gestibile dai
computer. Infatti i computer ragionano in base a regole molto rigide
e cicliche e quando gli si chiede di generare un numero casuale essi
hanno difficoltà e quindi vanno alla ricerca di eventi da misurare.
Il movimento del mouse è un tipico evento misurato dal computer
che poi rielaborato più volte produce un numero casuale.
Questo aspetto così complesso per il computer è completamente
invisibile agli utenti ma è emblematico di quanto sia ritenuto
importante il fattore casuale nella programmazione. Nonostante il
computer non sia “geneticamente” in grado di produrre eventi
casuali, gli si chiede di gestirli perchè attraverso questa casualità si
possono simulare infiniti eventi.
Modifichiamo quindi l’ultimo Sketch della prima parte utilizzando
un fattore casuale:
int intervallo = 10;
void setup () {
38
processing
guida introduttiva alla programmazione visuale
size (320,240);
}
void draw (){
frameRate (5);
background (255);
punti ();
}
void punti () {
if (intervallo > 320) {
intervallo = 10;
}
intervallo = intervallo + int (random (20));
point (intervallo, 120);
point (intervallo +1, 118);
}
Nella funzione “void punti” ho corretto la linea che calcola il salto
che i punti devono compiere ad ogni nuovo frame:
intervallo = intervallo + int (random (20));
Precedentemente il valore di incremento era “10” mentre ora il
valore di incremento (che definisce lo spostamento dei punti) sarà
un valore casuale compreso tra zero e 20 (int (random (20)); ).
“random (20); genera un numero casuale con virgola (di tipo
“float”) compreso tra 0 e 20. L’istruzione “int ()” serve ad
arrotondare i numeri con decimali in numeri interi.
Questa istruzione “int” è necessaria in quanto Processing non
permette di mescolare numeri con virgola (di tipo float) con numeri
interi (di tipo int).
Mandando in RUN lo Sketch vediamo che ora i punti si spostano
sempre da sinistra a destra ma procedendo in modo irregolare a
volte hanno delle accelerazioni mentre altre volte procedono
lentamente. Questo andamento è casuale e lanciando più volte lo
Sketch si otterranno sempre risultati diversi.
Osservando i punti compiere questo tipo di movimenti abbiamo un
effetto di movimento che suscita molta più curiosità, la sensazione
che dona questo tipo di movimento è più organica e “viva” che non
il movimento rettilineo uniforme del precedente Sketch. Per
modificare l’effetto degli scatti possiamo agire su diversi parametri.
Aumentando il valore di random (20) otteniamo scatti sempre più
39
processing
guida introduttiva alla programmazione visuale
variegati, mentre otteniamo scatti meno evidenti mettendo dei valori
più bassi.
Inoltre, aumentando il “framerate” otteniamo maggiore velocità
dell’animazione con più fluidità nel movimento dei punti.
Interveniamo nuovamente sullo Sketch al fine di aumentare l’effetto
organico del movimento:
int intervallo = 10;
void setup () {
size (320,240);
}
void draw (){
frameRate (10);
background (255);
punti ();
}
void punti () {
if (intervallo > 320) {
intervallo = 10;
}
intervallo = intervallo + int (random
(5));
point (intervallo, int (random (118,
121)));
point (intervallo +1, int (random (116,
119)));
}
Ora, analizzando la funzione “void punti” vediamo che ho inserito
un fattore di casualità anche nello spostamento sulla coordinata Y.
Pertanto i punti si sposteranno anche leggermente in alto o in basso
durante il loro consueto movimento verso destra.
Analizzando l’istruzione vediamo che tra parentesi questa volta ci
sono due parametri “int (random (116, 119))”. Quando l’istruzione
random contiene due parametri significa che è stato definito un
parametro inferiore e un parametro superiore dell’intervallo casuale.
Nello Sketch precedente, il valore di Y 120 per il primo punto, ora
invece sarà un valore casuale compreso tra 118 e 121.
40
processing
guida introduttiva alla programmazione visuale
Mandando in RUN questo ultimo Sketch vediamo che i due punti
spostandosi leggermente anche in alto e in basso avranno un effetto
ancor più organico. Sembreranno volare come due mosche.
Più avanti affronteremo ancor più approfonditamente questo
concetto. Per il momento l’utilizzo della funzione “random” sarà
molto utile perchè ci permetterà di osservare degli esempi più
complessi e variegati, a volte dai comportamenti inattesi (perchè
casuali).
Curve
Abbiamo già esplorato le forme grafiche di base di Processing
(point, line, rect, triangle, quad, ellipse). Osservando i cicli e le
funzioni abbiamo capito che possiamo assegnare le coordinate di
queste forme geometriche a delle variabili anche casuali.
Processing permette anche di generare delle curve secondo un
metodo detto di Bezier.
In pratica possono essere dichiarate, oltre ai due punti di inizio e
fine della curva, anche le tangenti ai due punti.
Vediamo un esempio scrivendo il seguente Sketch e mandandolo in
RUN:
size (320, 240);
noFill ();
bezier(10, 20, 100, 5, 280, 155, 10, 175);
Il punto di inizio e di fine della curva sono la prima e la quarta
coordinata dell’istruzione. La seconda e la terza coordinata indicano
invece le tangenti.
Per capire meglio cosa siano le tangenti consiglio di aggiungere due
istruzioni in grado di visualizzarle:
size (320, 240);
noFill ();
bezier(10, 20, 100, 5, 280, 155, 10, 175);
line (10,20, 100,5);
line (10,175, 280,155);
Grazie alle due linee appena disegnate possiamo ora vedere le
tangenti. Da notare che la curva risultante dalle nostra istruzioni
tende ad essere più accentuata verso il basso.
41
processing
guida introduttiva alla programmazione visuale
Osservando la tangente più in basso comprendiamo il motivo. La
tangente è molto più “lunga” pertanto essa “attrae” molto di più la
curva.
Semplificando possiamo vedere la curva di Bezier come se fosse un
elastico: con la prima e la quarta coordinata vengono fissati
(inchiodati) i punti di inizio e fine dell’elastico. Attraverso la seconda
e terza coordinata si “attrae” l’elastico. Quanto più lontane sono le
coordinate di attrazione tanto più l’elastico sarà teso e quindi la
curva sarà più accentuata.
Per avere prova della desrcizione appena effettuata scrivete la
seguente istruzione:
bezier(10, 20, 10, 20, 10, 175, 10, 175);
Il punti di tiraggio dell’elastico sono ora gli stessi dei punti di
terminazione dell’elastico stesso. Ne risulta che la curva di Bezier è
una linea retta (perchè il “tirante” non è attivo avendo le stesse
coordinate del punto).
Attraverso questo metodo possiamo disegnare praticamente
qualunque tipo di cur va. Questa funzionalità risulterà
particolarmente utile quando vorremo generare delle forme
organiche che molto difficilmente hanno spigoli e angoli netti.
Lo Sketch di seguito ci mostra il variare di una curva di bezier al
variare delle coordinate delle tangenti:
int contatore = 10;
void setup () {
size (320,240);
}
void draw (){
frameRate (10);
background (255);
//incremento il contatore
contatore = contatore + 1;
// definisco la curva di bezier
// associando le tangenti
// a un contatore per osservare
// il cambiamento della curva
bezier (10,10, contatore, 10,
200, 60,200);
}
42
contatore,
processing
guida introduttiva alla programmazione visuale
Osservando infine il risultato delle nostre curve notiamo che esse
hanno sempre un effetto di scalettatura. Questo effetto (detto
aliasing) può essere eliminato attraverso l’istruzione “smooth ();” da
mettere all’inizio dello Sketch.
L’effetto sarà di una curva molto più “morbida”. In termini
e l a b o r a t iv i q u e s t a g r a d e vo l e f u n z i o n a l i t à e s t e t i c a d i
ammorbidimento aumenterà l’impegno del computer. Ovviamente il
fenomeno avverrà quando avremo disegnato molte curve e avremo
delle animazioni molto veloci.
Complichiamo ulteriormente il nostro lavoro introducendo anche
un fattore di casualità nella generazione della curva. Questo esercizio
è utile perchè viene formulato in modo nuovo uno Sketch
contenente solo funzionalità già viste.
Lo Sketch mandato in RUN genera una curva di bezier che nel
tempo si espande verso destra o verso sinistra seguendo la casualità:
int contatore = 10;
// la variabile casuale
float ai = 1;
void setup () {
size (320,240);
smooth ();
}
void draw (){
frameRate (10);
background (255);
// genero un numero casuale
ai = random (1);
// controllo il numero “estratto”
if (ai > 0.5) {
contatore = contatore + 2;
bezier (100,10, contatore, 10, contatore,
200, 120,200);
}
else {
contatore = contatore - 2;
bezier (100,10, contatore, 10, contatore,
200, 120,200);
}
}
43
processing
guida introduttiva alla programmazione visuale
La variabile “ai” è legata alla generazione di un numero casuale (con
decimali e quindi di tipo float) compreso tra 0 e 1. La probalità che
questo numero sia superiore o inferiore a 0.5 è del 50%.
Tendenzialmente quindi avremo una curva che si muove
c a s u a l m e n t e ve r s o d e s t r a e ve r s o s i n i s t r a ch e p e r ò
probabilisticamente tende ad essere stabile (cioè tende a ritornare
alla sua posizione di partenza. Modificando l’istruzione “if (ai >
0.5)” ad esempio in “if (ai > 0.4)” altereremo probabilisticamente
rapporto e quindi la curva tenderà a modificarsi verso una direzione.
I vettori
Quando nella programmazione si parla di vettori non ci si riferisce a
delle forme grafiche bensì a dei contenitori. Abbiamo già visto nella
prima parte il tipo di contenitori più diffusi nella programmazione:
le variabili.
I vettori sono delle variabili concatenate in sequenza. Il termine
inglese per definire i vettori è Array e questi sono alcuni esempi di
istruzioni:
int[] vettore;
float [] vettore2;
Nel primo caso abbiamo la dichiarazione di un vettore che conterrà
dei valori interi mentre nel secondo caso abbiamo la dichiarazione di
un vettore che conterrà dei valori con virgola.
Una volta dichiarato il tipo di vettore è necessario inizializzarlo:
vettore = new int[50];
vettore2 = new float[150];
Nel primo caso abbiamo inizializzato un vettore che conterrà un
massimo di 50 valori diversi mentre nel secondo caso abbiamo
inizializzato un vettore che ne conterrà 150.
Queste dimensioni sono normali in molti tipi di programmi e questo
è proprio il motivo per il quale si usano i vettori anziche le variabili.
Nel caso in cui si vogliano immagazzinare 50 informazioni usando le
variabili sarebbe necessario inizializzare 50 diverse variabili. I vettori
sono quindi il modo più elegante e rapido per organizzare i dati
all’interno di un programma. Troviamo i vettori praticamente in tutti
i linguaggi di programmazione.
44
processing
guida introduttiva alla programmazione visuale
Vediamo ora uno Sketch che utilizza i vettori:
size (320, 240);
smooth ();
noFill ();
int[] curva = new int[10];
// ciclo per riempire l'array
for (int cicli = 0; cicli < 10; cicli = cicli +1) {
curva[cicli] = int (random (200));
}
// ciclo di lettura dell'array
for (int cicli = 0; cicli < curva.length; cicli =
cicli +1) {
bezier(curva[cicli], 0, curva[cicli], 100, 200,
240, 240, 240);
}
// secondo ciclo di lettura dell'array
for (int cicli = 0; cicli < curva.length; cicli =
cicli +1) {
ellipse (curva[cicli], 5, 10, 10);
}
Nella quarta riga osserviamo l’struzione di inizializzazione dell’array:
“int[ ] curva = new int[10];” che sarà quindi composto da numeri
interi e si chiamerà “curva”.
Subito dopo leggiamo un ciclo “for” che ha la funzione di riempire
l’array. Il ciclo compie 10 “giri” e mette in ogni casella dell’array un
valore casuale compreso tra 0 e 200 (“curva[cicli] = int (random
(200))”).
Successsivamente abbiamo due altri cicli. Con il primo ciclo
vengono disegnate 10 curve i cui parametri sono letti dall’array
precedentemente creato ( “bezier(curva[cicli], 0, curva[cicli], 100,
200, 240, 240, 240)”).
Da notare che il parametro di chiusura del ciclo “for” viene stabilito
attraverso un controllo della lunghezza dell’array (“cicli <
curva.length”). Curva.lenght dichiara infatti la lunghezza dell’array
che avevamo chiamato “curva”.
Il secondo ciclo di lettura dell’array è simile al primo con la
differenza che vengono disegnati dei cerchi in corrispondenza del
termine superiore delle curve create precedentemente.
Questo secondo ciclo è stato creato appositamente per dimostrare
l’utilità di un array. Infatti nel secondo ciclo è stato riletto tutto il
45
processing
guida introduttiva alla programmazione visuale
contenuto memorizzato nell’array e che volendo potrebbe essere
ulteriormente letto per funzioni future.
L’array quindi ci permette di immagazzinare grandi quantità di dati
evitando di dover creare numerose variabili. Inoltre grazie alla loro
sequenzialità gli array facilitano l’accesso per la lettura e la scrittura
attraverso i cicli.
Il seguente Sketch compie le stesse funzioni del precedente in
modalità “continuous” generando un effetto di animazione.
In questo caso il vettore viene riempito e svuotato automaticamente
ad ogni nuovo ciclo automatico di “void draw”.
int[] curva = new int[10];
void setup () {
size (320, 240);
smooth ();
noFill ();
frameRate (10);
}
void draw () {
// azzero lo schermo
background (255);
// ciclo per riempire l'array
for (int cicli = 0; cicli < 10; cicli = cicli +1) {
curva[cicli] = int (random (200));
}
// ciclo di lettura dell'array
for (int cicli = 0; cicli < curva.length; cicli =
cicli +1) {
bezier(curva[cicli], 0, curva[cicli], 100, 200,
240, 240, 240);
}
// secondo ciclo di lettura dell'array
for (int cicli = 0; cicli < curva.length; cicli =
cicli +1) {
ellipse (curva[cicli], 5, 10, 10);
}
}
Notiamo nello Sketch precedente che ad ogni inizio di ciclo viene
pulito lo schermo attraverso l’istruzione “background (255);”. Se
togliamo questa istruzione vedremo che le curve si sovrapporranno
progressivamente andando a formare dopo diversi secondi un intero
spicchio nero. Le ultime sezioni bianche che rimangono sono i
46
processing
guida introduttiva alla programmazione visuale
numeri compresi tra zero e 200 che non sono mai stati generati.
Probabilisticamente potrebbero passare anche diversi minuti senza
che la funzione random generi un numero.
47
processing
guida introduttiva alla programmazione visuale
Terza Parte
Il testo
Processing, come tutti i linguaggi di programmazione, permette di
gestire il testo. I due comandi più importanti sono:
char ();
String ();
Qesti due comandi sono in realtà due nuove tipi di variabili. La
variabile di tipo “char” può contenere un unico carattere mentre la
variabile di tipo “String” può contenere intere parole o frasi.
Per assegnare un carattere a una variabile si scrive:
char carattere = 'F';
In questo modo la lettera “F” viene memorizzata nella variabile
“carattere”.
Per assegnare una parole o una frase a una variabile si scrive:
String testolungo = “manuale di Processing”;
Da notare che “String” inizia con la lettera grande mentre “char”
inizia con la lettera piccola. Da ricordare che i comandi di
Processing debbono essere scritti tenendo conto anche di maiuscole
e minuscole.
Inoltre da notare che l’istruzione Char richiede gli apici (‘) per
evidenziare il carattere mentre l’istruzione String richiede le
virgolette (“). String può contenere anche testi lunghi un inico
carattere.
Nell’informatica esiste una tabella di corrispondenza tra i caratteri e i
numeri. Praticamente ogni lettera dell’alfabeto è stata classificata con
un numero in modo sequenziale. Questa tabella di corrispondenza si
chiama ASCII e ad esempio la lettera A corrisponde al numero 65.
La lettera B corrisponde al numero 66 e così via.
Questa tabella di corrispondenza è indispensabile poichè senza di
essa il computer (che ragiona per numeri) non potrebbe elaborare i
testi. Le variabili di tipo “char”, essendo lunghe un unico carattere,
possono essere ricondotte ai numeri e viceversa.
Se ad esempio scriviamo:
48
processing
guida introduttiva alla programmazione visuale
char carattere = ‘F’;
int numero = carattere;
La variabile “carattere” viene riempita con il valore “F”, poi con la
seconda istruzione la variabile “numero” viene riempita con il
numero corrispondente alla lettera F (70) secondo il codice ASCII.
Questa operazione di conversione bidirezionale dei numeri in lettere
e delle lettere in numeri è possibile solamente attraverso l’istruzione
“char”. Con l’istruzione “String” essendo essa potenzialmente
associata a testi più lunghi di una lettera ciò non è possibile.
Attraverso l’espressione “char ()” possiamo richiamare direttabente
il codice ASCII del carattere. Ad esempio se scriviamo:
char lettera = char(70);
Otteniamo che la variabile “lettera” viene associata con la lettera
“F” (avente come codice ASCII il numero 70).
L’istruzione “String” permette di fare operazioni sul testo. Se ad
esempio associamo due variabili a due diverse parole,
successivamente possiamo attaccare (sommare) le due parole.
String prima = “Manuale di “;
String seconda = “Processing”;
String somma = prima + seconda;
La variabile “somma” avrà come risultato “Manuale di Processing”.
Da notare che dopo l’espressione “Manuale di” è stato lasciato
appositamente uno spazio in modo che esso risulta presente nella
somma delle due variabili.
Il modo più velore per vedere il risultato di queste operazioni sule
variabili testuali (ma anche per quelle numeriche) è l’uso
dell’istruzione “println(somma);” Questa istruzione “println” mostra
un valore nella finestra della console. La stessa finestra dell’ambiente
di sviluppo dove ci appaiono gli errori. Questa finestra è utile quindi
anche quando si sta lavorando ad un programma e si voglieno
controllare dei valori intermedi e temporanei di alcune variabili.
Caratteri sullo schermo
Processing utilizza i font che sono stati precedentemente dichiarati.
A differenza dei normali programmi di scrittura, dove troviamo il
menù a tendoina con tutti i font disponibili, Processing, essendo un
49
processing
guida introduttiva alla programmazione visuale
ambiente di sviluppo permette di utilizzare qualunque font che sia
stato precedentemente impostato.
Infatti Processing utilizza solamente tipi di carattere in formato
VLW. Quando all’interno di uno Sketch sviluppato in Processing
intendiamo utilizzare un font dobbiamo prima di tutto importare il
font stesso attraverso il “Menù Tool” comando “Create Font”.
Dando questo comando si apre una finestra nella quale compare la
lista dei caratteri installati nel proprio computer. Si seleziona il
carattere e la relativa dimensione che si vuole importare e cliccando
su OK verrà automaticamente creato un file che poi potrà essere
richiamato all’interno dello Sketch.
Se ad esempio vogliamo utilizzare il font Courier nella dimensione
12 all’interno del nostro Sketch dopo avere generato il file dovremo
richiamare un file di questo nome: “Courier-12.vlw”.
Ecco uno Sketch:
size (320, 240);
background (255);
// Inizializzo la variabile
PFont carattere;
// Carico il font nello Sketch
carattere = loadFont("Courier-12.vlw");
// Stabilisco il font che sto per usare
textFont(carattere);
fill(0);
// Scrivo il testo
text("Manuale di Processing", 30, 100);
Con “PFont” viene inizializzata una variabile che conterrà il nome
del font stesso. Con “carattere = loadFont("Courier-12.vlw");”
carico nello Sketch il font che intendo utilizzare e ovvimente potrei
carirarne anche più di uno.
Poi successivamente, quando starò per utilizzare il font, dichiaro il
suo uso con “textFont(carattere);” e con “fill (0);” stabilisco che il
carattere sarà di colore nero.
Con l’istruzione “text” dichiariamo il testo che vogliamo scrivere
(potremmo in alernativa mettere il nome di una variabile String) in
seguito troviamo le coordinate X,Y dove comparirà il testo.
Nel seguente Sketch abbiamo la situazione del precedente con
l’unica differenza che attraverso l’istruzione “textSize(18);” il testo
avrà una dimensione diversa da quella importata.
50
processing
guida introduttiva alla programmazione visuale
size (320, 240);
background (255);
PFont carattere;
carattere = loadFont("Courier-12.vlw");
textFont(carattere);
textSize(18);
fill(0);
text("Manuale di Processing", 30, 100);
Questa operazione di ingrandimento rappresenta un degradamento
della qualità del carattere che risulterà sgranato tanto più sarà stato
ingrandito. Infatti atttaverso l’azione di importazione del carattere
abbiamo importato delle immagini bitmap (pixel per pixel) del font.
Qualitativamente è quindi consigliabile importare i caratteri in tutte
le dimensioni che si vorranno utilizzare.
Il seguente Sketch è invece un semplice esempio di animazione di un
testo. Si tratta all’incirca della somma dello Sketch precedente e dell
Sketch utilizzato nelle pagine precedenti per animare un punto
facendolo scorrere da sinistra a destra:
void setup () {
size (320, 240);
}
int intervallo = 0;
void draw (){
background (255);
PFont carattere;
carattere = loadFont("Courier-12.vlw");
frameRate (10);
textFont(carattere);
textSize(12);
fill(0);
text("ciao a tutti", intervallo, 120);
intervallo = intervallo + 1;
}
Lavorare con le Stringhe
Processing permette di lavorare con le stringhe attraverso delle
apposite istruzioni.
Se ad esempio abbiamo la variabile “testolungo” associata ad una
string:
51
processing
guida introduttiva alla programmazione visuale
String testolungo = “manuale di Processing”;
Possiamo misurare la lunghezza della stringa attraverso l’istruzione
lunghezza = testolungo.length ();
Dove lunghezza sarà una variabile di tipo “int” e in questo caso
restituirà il numero “21”, ossia la lunghezza del testo “manuale di
Processing” inclusi gli spazi tra una parola e l’altra.
Mentre con la linea di comando:
char iniziale = (testolungo.charAt(0));
Trasferisce il primo carattere (indicato con la posizione 0) della
variabile “testolungo” nella variabile iniziale. Pertanto charAt(1)
restituirà la “a” di “manuale” mentre il numero 6 ci darà la lettera
“e”. Il numero 20 la lettera “g” di “Processing”.
Attraverso l’istruzione substring (); possiamo invece prendere delle
parti di una scringa ed associarle ad un’altra variabile (oppore
stamparle...).
string pezzo = testolungo.substring(2,6);
Con questa linea di istruzione abbiamo trasferito in una nuova
variabile “pezzo” tutte le lettere comprese tra la posizione 2 e la
posizione 6 esclusa della variabile “testolungo”. In pratica abbiamo
trasferito “nual” nella variabile pezzo.
Il seguente Sketch produce una linea la cui lunghezza è inversamente
legata alla lunghezza di un testo associato ad una variabile di tipo
“String”.
size (320, 240);
String
testolungo
=
"Manuale
Processing" ;
// misuro la lunghezza di testolungo
int lunghezza = testolungo.length ();
// memorizzo il primo carattere
// nella variabile “iniziale”
char iniziale = (testolungo.charAt(0));
//produco una linea
//usando la lunghezza
line (lunghezza, lunghezza, 100, 100);
52
di
processing
guida introduttiva alla programmazione visuale
Notiamo che il primo punto della linea è legato alla variabile
“lunghezza” che abbiamo utilizzato per misurale la lunghezza del
testo “manuale di Processing”.
Aggiungesto altre parole al testo “manuale di Processing” e
mandando in RUN lo Sketch vediamo che la linea tende
progressivamente ad accorciarsi.
53
processing
guida introduttiva alla programmazione visuale
Quarta Parte
Grafica e Movimenti più complessi
Processing è un software specializzato per la grafica e le animazioni.
Tutte le istruzioni che abbiamo visto fino a questo punto ci hanno
permesso di comprendere i principi fondamentali della
computergrafica bidimensionale. Le forme che abbiamo disegnato
fino ad ora sono relativamente semplici.
Abbiamo visto con le curve di Bezier come sia possibile disegnare
qualunque tipo di curva utilizzando 4 paramentri.
Vediamo ora prima di tutto come animare le forme grafiche. In
realtà abbiamo già visto come sia possibile, attraverso l’uso dei
contatori e la pulizia dello schermo , animare curve e punti.
Processing ci viene incontro in queste funzionalità di animazioni
attraverso tre funzioni di animazione:
translate ();
rotate ();
scale ();
Attraverso queste tre semplici istruzioni possiamo applicare degli
effetti graficamente complessi a tutte le immagini presenti all’interno
del nostro Sketch.
Sappiamo che scrivendo queste due istruzioni:
size (320, 240);
line(10, 20, 100, 120);
otteniamo una linea che attraverso lo schermo. Attraverso
l’istruzione “translate();” abbiamo la possibilità di traslare la linea
sulle coordinate X e Y.
Infatti se scriviamo:
size (320, 240);
translate(100, 0);
line(10, 20, 100, 120);
succede che la linea, a differenza del precedente Sketch, avrà delle
cordinate traslate di 100 pixel sull’asse delle X. Le nuove coordinate
della linea saranno: (110, 20, 200, 120). I due valori X dei due punti
sono stati incrementati di 100 pixel.
54
processing
guida introduttiva alla programmazione visuale
Ecco il risultato aritmetico dell’istruzione:
line (10 + 100, 20 + 0, 100 + 100, 120 + 0);
Ovviamente possiamo traslare sia le coordinate X che le Y, ecco un
esempio:
size (320, 240);
translate(100, 25);
line(10, 20, 100, 120);
La linea disegnata sullo schermo avrà le seguenti coordinate:
line (110, 45, 200, 145);
L’istruzione traslate è attiva per tutte le forme grafiche che appaino
successivamente ad essa. Pertanto se tracciamo due linee dopo
l’istruzione traslate otteniamo che tutte e due le linee saranno
traslate.
size (320, 240);
translate(100, 25);
line (10, 20, 100, 120);
line (20, 40, 200, 100);
Mandando in RUN lo Sketch vediamo che sia la prima che la
seconda linea risultano traslate. Inoltre le traslazioni si sommano,
pertanto se vogliamo ulteriormente traslare una linea dopo una
prima traslazione sarà sufficiente inserire la nuova traslazione.
size (320, 240);
translate(100, 25);
line (10, 20, 100, 120);
translate(80, 15);
line (20, 40, 200, 100);
La seconda linea del precedente Sketch è traslata nelle sue
coordinate di 180 (100+80) pixel sull’asse “X” e 40 pixel sull’asse
“Y” (25+15). Mentre la prima linea risulta traslata solamente dei
valori del primo comando traslate.
55
processing
guida introduttiva alla programmazione visuale
Per ripristinare le condizioni originarie è sufficiente mettere in
negativo i valori di traslate. Nel sequente Sketch le coordinate della
seconda linea sono “normali”.
size (320, 240);
translate(100, 25);
line (10, 20, 100, 120);
translate(-100, -25);
line (20, 40, 200, 100);
Poichè la seconda istruzione “traslate” sottrae esattamente i valori
della prima istruzione, la seconda linea avrà le coordinate:
line (20, 40, 200, 100);
Proprio come indicato nello Sketch stesso.
Rotazione
I principi della traslazione valgono anche nel caso della rotazione.
Essi quindi sono validi finchè non intervenga un nuovo valore che si
somma al precedente.
Per capire l’unità di misura dela rotazione dobbiamo capire il
concetto di radiante. Normalmente misuriamo i giri in gradi, quindi
un giro completo è di 360 gradi mentre un giro di 180 gradi è mezzo
giro. Una ruotazione ad angolo retto è una ruotazione di 90 gradi.
I radianti sono legati alla costante matematica detta “Pi greco” “PI”
o “π”. Il pi greco misura il rapporto tra una qualunque circonferenza
di un cerchio e il suo relativo diametro. Questo rapporto è costante e
viene sintetizzato in 3.14 anche se i decimali dopo la virgola sono
infiniti.
La corrispondenza tra i gradi e i radianti è molto semplice:
- due radianti (2 * π) sono 360 gradi
- un radiante (π) è 180 gradi
- mezzo radiante (π/2) è 90 gradi
In processing π si scrive PI. Il seguente Sketch mostra la ruotazione
di una stessa linea di 90 gradi:
size (240, 240);
line(0, 0, 100, 0);
rotate(PI/2);
line(0, 0, 100, 0);
56
processing
guida introduttiva alla programmazione visuale
Mandando in RUN lo Sketch lediamo una linea in alto orizzontale
(la prima linea dello Sketch) e una seconda linea verticale che è la
seconda linea dello Sketch. La seconda linea ha subito quindi una
rotazione di 90 gradi in senso orario.
Le dimensione dello schermo questa volta sono state impostate a
(240, 240) al fine di facilitare la comprensione dei gradi.
Osserviamo infatti una rotazione di 45 gradi:
size (240, 240);
line(0, 0, 240, 0);
rotate(PI/4);
line(0, 0, 240, 0);
Vediamo che la seconda linea in questo caso è ruotata di 45 gradi e
grazie al fatto che la finestra è quadrata possiamo osservare che essa
traccia una pate della diagonale della finestra stessa.
Di seguito vediamo tre linee. La prima non subisce alcuna
ruotazione mentre la seconda subisce una ruotazione di 45 gradi
(PI/4) e la terza ruota di 90 gradi (PI/4 + PI/4 = PI/2).
size (240, 240);
line(0, 0, 240, 0);
rotate(PI/4);
line(0, 0, 240, 0);
rotate(PI/4);
line(0, 0, 240, 0);
La funzione di ruotazione funziona quindi come la funzione di
traslazione. Per eliminare il suo effetto è sufficiente riproporre il
valore in negativo:
size (240, 240);
line(0, 0, 240, 0);
rotate(PI/4);
line(0, 0, 240, 0);
rotate(- PI/4);
strokeWeight (5);
line(0, 0, 200, 0);
In questo caso la terza linea sembra scomparire mentre in realtà essa
è perfettamente sovrapposta alla prima linea. Per questo motivo ho
57
processing
guida introduttiva alla programmazione visuale
aumentato lo spessore della linea “strokeWeight (5);” inoltre ho
leggermente accorciato la lua lunghezza in modo che si possa
cogliere anche la prima linea.
Infine per comprendere completamente il tipo di ruotazione che
avviene mandiamo in RUN il seguente Sketch
size (240, 240);
ellipse (100, 0, 20, 20);
rotate(PI/4);
ellipse (100, 0, 20, 20);
Vediamo anche in questo caso che il cerchio si sposta. Mentre se il
cerchio ruotasse su se stesso non dovremmo vedere alcuno
spostamento. In effetti con il comando rotate così come con il
comando translate ciò che ruota non è l’oggetto bensì la finestra con
tutto ciò che è disegnato al suo interno. Questa ruotazione fa perno
sulla coordinata (0,0) dello schermo.
Scala
Per ingrandire o rimpiccolire un oggetto si utilizza l’istruzione scale
();.
Il seguente Sketch mostra due cerchi dove il secondo cerchio è stato
raddoppiato nelle sue dimensioni:
size (240, 240);
ellipse (100, 100, 20, 20);
scale (2);
ellipse (100, 100, 20, 20);
Le coordinate del cerchio cambiano proprio perchè è la finestra che
si raddoppia nella sua dimensione con tutti i suoi contenuti.
Il seguente Sketch mostra tre cerchi. Il terzo cerchio ha le stesse
proporzioni del primo ma ho modificato il riempimento e
ridimensionato il raggio.
size (240, 240);
ellipse (100, 100, 20, 20);
scale (2);
ellipse (100, 100, 20, 20);
scale (0.5);
fill (100,20);
58
processing
guida introduttiva alla programmazione visuale
ellipse (100, 100, 10, 10);
Vediamo che attraverso l’istruzione “scale (0.5);” è stato diviso per
due il precedente rapporto di ingrandimento “scale(2)”. In questo
modo il rapporto finale è 0.5*2 cioè 1.
Quest’ultimo Sketch ci mostra tre cerchio scalati ogni volta per due.
Il terzo cerchio sarà quindi 4 volte (2*2) più grande del primo.
size (240, 240);
ellipse (50, 50, 20, 20);
scale (2);
ellipse (50, 50, 20, 20);
scale (2);
ellipse (50, 50, 20, 20);
Da notare che anche la distanza tra il secondo e il terzo cerchio è
doppia rispetto alla distanza tra il primo e il secondo cerchio.
Infine notiamo che le tre funzionalità di modifica delle forme
grafiche possono ovviamente essere utilizzate in modo combinato.
size (240, 240);
ellipse (50, 50, 20, 20);
scale (2);
ellipse (50, 50, 20, 20);
translate (20, 0);
ellipse (50, 50, 20, 20);
Nel precedente Sketch i cerchio risulterà traslato di 20 pixel sull’asse
delle X e ingrandito di due volte. Il secondo cerchio ha invece subito
solamente l’ingrandimento ma non la traslazione.
59
processing
guida introduttiva alla programmazione visuale
Quinta parte
Arduino
Arduino è una piattaforma open source per lo sviluppo e la
progettazione di oggetti interattivi.
Lo scopo principale di questa scheda è quella di dare la possibilità a
sviluppatori e artisti di progettare prototipi letteralmente “giocando”
con l’elettronica e sperimentando con sensori, attuatori e controller
elettronici.
Questa particolare ricerca nell’interazione tra il calcolatore e il
mondo fisico è nota come “Physical Computing” ed era fino a pochi
anni fa una disciplina conosciuta e utilizzata solo in campo
ingegneristico, che richiedeva una conoscenza avanzata
dell’elettrotecnica e del software.
Questo livello di complessità ha tenuto per anni lontani gli ideatori,
gli obbisti e gli artisti dalle infinite possibilità che l’elettronica può
aprire nel mondo del design e dell’arte in generale.
Lo scopo degli sviluppatori di Arduino è quello di fornire uno
strumento semplice che permetta a chiunque di iniziare a costruire
progetti interattivi in modo immediato ed economico.
Grazie a questa semplicità di utilizzo e alla crescente diffusione, oggi
Arduino oltre a risolvere numerosi problemi nello sviluppo e nella
realizzazione di oggetti interattivi, è alla base di una nuova filosofia
che cresce e si alimenta dal mondo dell’open source e dalla
condivisione di conoscenze tipica della rete.
Nel mondo anglosassone questo “modo di procedere” nello
sviluppo è noto come “Tinkering”, una forma di deriva creativa
guidata dall’immaginazione e dalla curiosità.
Mentre il percorso di sviluppo ingegneristico classico presuppone
una progettazione che procede in modo razionale dal punto A al
punto B, il Tinkering presuppone il perdersi in questo percorso e
scoprire un nuovo punto C.
Tinkering significa in pratica trovare risultati curiosi provando e
sbagliando procedimenti ignoti.
60
processing
guida introduttiva alla programmazione visuale
Costruire senza le istruzioni, giocando con i fallimenti, non
preoccupandosi del modo giusto o sbagliato di fare le cose.
Uno dei modi migliori di utilizzare questo processo creativo è
riutilizzare tecnologie esistenti, smontare vecchi apparecchi
elettronici e usarne parti interessanti sfruttandole per utilizzi lontani
da quelli per cui erano state progettate.
Questo approccio spontaneo e casuale è alla base di alcune nuove
forme d’arte come il Circuit Bending: un genere musicale suonato
con vecchi strumenti giocattolo elettronici, smontati e modificati per
creare suoni completamente diversi da quelli pensati dal costruttore
originario.
Arduino insomma rappresenta oggi una nuova ottica con cui
guardare la tencologia che ci circonda, sviluppare nuove funzioni per
strumenti vecchi ed esplorare nuove possibilità senza il bisogno di
perdersi in anni di studi ma semplicemente giocando con ciò che già
abbiamo a portata di mano sfruttando l’istinto di ogni bambino...
smontare i giocattoli per vedere cosa c’è dentro.
L’Hardware:
Arduino è una scheda composta principalmente da un processore e
una serie di ingressi e uscite sia digitali che analogici, alimentabile sia
via USB che tramite un alimentatore esterno.
61
processing
guida introduttiva alla programmazione visuale
Il Software:
Il processore di Arduino è programmabile attraverso un ambiente di
sviluppo(IDE) basato su Processing.
Tutto il software necessario all’utilizzo di Arduino oltre a svariati
esempi di codice è scaricabile gratuitamente dal sito www.arduino.cc
Una volta scritto il programma nell’editor principale (proprio come
un programma in Processing) va controllata la sua correttezza,
premendo verify, se il codice è scritto correttamente apparirà il
messaggio Done compiling, a questo punto é possibile caricare il
programma nel processore di Arduino.
Premendo il bottone reset su Arduino si hanno 6 secondi per
premere Upload to I/O board nella parte alte dell’IDE.
Questo procedimento invia il programma alla scheda, lo salva nella
sua memoria e lo esegue automaticamente.
62
processing
guida introduttiva alla programmazione visuale
La BreadBoard
Prima che il vostro circuito funzioni perfettamente ci sarà bisogno di
vari tentativi e saldare diversi tentativi su una piastra è un lavoro
lungo e dispendioso.
L’equivalente elettronico dello schizzo iniziale di un progetto fatto
su un foglio di carta è la BreadBoard.
Si tratta in pratica di una piastra di plastica piena di fori ognuno dei
quali contiene un contatto.
Quando si mette un componente in uno di questi fori si crea un
contatto elettrico con tutti gli altri fori della stessa colonna verticale.
Le due coppie di linee di fori in alto e in basso della Breadboard
(solitamente colorate di rosso e blu e con il segno+ e -) sono invece
collegate in orizzontale e sono usate per portare l’alimentazione in
tutta la piastra.
63
processing
guida introduttiva alla programmazione visuale
L’Interazione
L’utilizzo piu’ frequente di Arduino è lo sviluppo di oggetti
interattivi.
Il funzionamento base che accomuna questo dipo di dispositivi
segue uno schema molto semplice:
Le informazioni che il dispositivo legge dal mondo esterno
attraverso dei sensori vengono elaborate dal programma all’interno
del processore, questo deciderà il comportamento del dispositivo
che interagirà di consegueza con il mondo esterno attraverso degli
attuatori.
Sensori e attuatori sono componenti elettronici, i primi “leggono”
delle informazioni dal mondo fisico e le trasformano in segnali
interpretabili dal processore, i secondi convertono i segnali del
processore in azioni fisiche.
Per semplificare queste definizioni con un esempio, nel corpo
umano, gli occhi sono dei sensori che convertono la luce in
immagini, il cervello (nel nostro caso il processore) elabora le
immagini e manda segnali ai muscoli (attuatori).
64
processing
guida introduttiva alla programmazione visuale
Un primo esempio pratico
Vediamo con un esempio pratico come lo schema precedente di
interazione possa trovare un applicazione con Arduino.
Costruiamo un semplice dispositivo che accende un LED (lightemitting diode) quando viene premuto un bottone.
In questo caso il bottone rappresenta il sensore e il LED l’attuatore.
Iniziamo costruendo il semplice circuito illustrato nella seguente
figura.
65
processing
guida introduttiva alla programmazione visuale
N.B.
il LED va inserito con il contatto piu’ corto nel pin GND e con
quello piu’ lungo nel pin 13.
Scriviamo poi nell’IDE il seguente programma:
// primo esempio di interazione con Arduino
const int buttonPin = 7;
// numero del pin del bottone
const int ledPin = 13;
// numero del pin del LED
int buttonState = 0;
// variabile che legge il bottone
void setup() {
// inizializza il pin del LED come output
pinMode(ledPin, OUTPUT);
// inizializza il pin del bottone come input
pinMode(buttonPin, INPUT);
}
void loop(){
// legge lo stato del bottone
buttonState = digitalRead(buttonPin);
// controlla se il bottone e’ premuto
// se e’ premuto e’ LOW
if (buttonState == LOW) {
// accende il LED
digitalWrite(ledPin, HIGH);
66
processing
guida introduttiva alla programmazione visuale
}
else {
// spegne il LED
digitalWrite(ledPin, LOW);
}
}
Carichiamo il codice nella scheda e vediamo che il LED si illumina quando
il pulsante viene premuto.
Questo avviene perchè la funzione
digitalRead();
legge se un voltaggio passa nel pin precedentemente dichiarato,
se il voltaggio è inferiore a 2.5V (bottone premuto) allora la
funzione ritornerà un valore LOW e di conseguenza accenderà il
LED con la funzione:
digitalWrite(ledPin, HIGH);
mentre se passerà un voltaggio superiore allora ritornerà un valore
HIGH (che corrisponde al bottone non premuto).
Proprio come in un programma in Processing dobbiamo
inizialmente dichiarare variabili e costanti, anche nel programmare
Arduino è necessario dichiarare come i pin della scheda verranno
utilizzati.
all’interno della funzione
void setup();
dobbiamo configurare se il comportamento di un determinato pin
sarà di INPUT o di OUTPUT.
Nel nostro precedente esempio con il codice
pinMode(ledPin, OUTPUT);
abbiamo dichiarato che il pin 13 verrà utilizzato come Output
mentre con
67
processing
guida introduttiva alla programmazione visuale
pinMode(buttonPin, INPUT);
dichiariamo che il pin 7 si comporterà come INPUT.
La funzione
digitalRead(pin);
legge il valore HIGH o quello LOW da uno specifico pin digitale
mentre quella
analogRead(pin);
legge un valore intero da 0 a 1023 da uno dei pin da 0 a 5.
La funzione
digitalWrite(pin, valore);
manda in output un valore HIGH o uno LOW ad uno specifico pin.
Mentre la funzione
analogWrite(pin, valore);
manda un valore analogico da 0 a 255 ad uno dei pin 9, 10 o 11
(nei modelli di Arduino più nuovi, quelli con il processore ATmega
168 si possono utilizzare i pin 3, 5, 6, 9, 10 e 11).
In questo caso ad un valore di 0 corrisponde 0 volts mentre ad un
valore di 255 corrisponde un voltaggio di 5V.
68
processing
guida introduttiva alla programmazione visuale
Questo manuale è scritto sotto licenza Creative Commons e gli
autori accettano volentieri proposte di nuove parti da aggiungere ad
esso. Chi volesse proporsi può scrivere a:
Alberto Cecchi:
[email protected]
Valerio Belloni:
[email protected]
processing
guida introduttiva alla programmazione visuale
ver. 0.9
oct. 2009
69
Scarica

processing - Code Computer