# Robotica educativa/Le basi dell'informatica

Robotica educativa

## Introduzione

* PrerequisitiRobotica educativa/Prerequisiti
* Etica della roboticaRobotica educativa/Etica della robotica

## Robotica con Arduino

* Le basi dell'informaticaRobotica educativa/Le basi dell'informatica
* Le basi dell'elettronicaRobotica educativa/Le basi dell'elettronica

## Primi passi nella robotica

* Invio di un SOSRobotica educativa/Invio di un SOS
* Che tempo che faRobotica educativa/Temperatura e umidità
* TermostatoRobotica educativa/Termostato
* Misurazione della distanzaRobotica educativa/Misurazione della distanza
* Sensore di parcheggioRobotica educativa/Sensore di parcheggio
* Gestione di un servomotoreRobotica educativa/Servomotore
* TelepassRobotica educativa/Telepass
* Dal computer ad ArduinoRobotica educativa/Dal computer ad Arduino
* Musica maestro!Robotica educativa/Musica maestro

## Ora che abbiamo un'idea...

Modifica il sommario
«L'informatica è la scienza che risolve problemi. Talvolta con l'utilizzo del computer.»
Non è nota la paternità di questa definizione, ma fa comprendere quanto spesso fuorviante sia il suo approccio. Pertanto, per informatica, più che un approccio alla macchina, si preferisce intendere un approccio al problema.
Se si utilizzerà, in seguito, un elaboratore elettronico, o meno, dipende dal problema stesso e dall'approccio. Sovente, anche problemi complessi possono avere soluzioni molto semplici, pertanto — prima di digitare sulla tastiera — la domanda da porsi è: qual è la soluzione migliore per risolvere questo problema? Mi occorre un elaboratore elettronico? Se la risposta è sì, si inizierà il lavoro con le idee molto chiare e il tempo sarà stato sempre ben speso.

## Il linguaggio C++

Come tra umani, tra umani e macchine esistono molteplici linguaggi. Alcuni orientati agli umani (quindi facili da imparare e utilizzare, come il BASIC), altri orientati alla macchina (come l'Assembler, il C e il C++).
Dovendo programmare un microprocessore, utilizzeremo il linguaggio C++, pensato per scrivere sistemi operativi. I primi passi sono un po' complicati, ma poi è tutta discesa, poiché i comandi sono davvero pochi.
Per quel che riguarda uno studio approfondito del C e del C++ si rimanda ai seguenti testi:
Risorse
* C
* Dal C al C++
la conoscenza approfondita di tali linguaggi va ben oltre quanto richiesto per la programmazione di Arduino, poiché ogni dispositivo fornisce librerie con istruzione ad alto livello, facili da comprendere.

## Il linguaggio C++ per Arduino

Nel caso del microcontrollore Arduino vengono forniti comandi aggiuntivi e librerie, che arricchiranno il vocabolario della macchina, senza che lo sforzo ricada su di noi.
Arduino, quando si crea un nuovo progetto, presenta il codice suddiviso in due parti (funzioni):
* il setup che contiene l'inizializzazione del programma;
* il loop il quale contiene il programma vero e proprio che verrà eseguito ciclicamente fino allo spegnimento o al reset.
Il tutto si presenta così:
Le funzioni sono di tipo void perché non restituiscono nulla come risultato. E nemmeno hanno argomenti in ingresso (i quali andrebbero dichiarati tra le parentesi tonde.
Arduino, invece, ha un set di istruzioni, pensate per la gestione di sensori e attuatori, con i quali si interfaccerà.

## Gestione di ingressi/uscite

Gli ingressi (e le uscite) di Arduino possono essere digitali o analogici. Nel setup si definisce quale uso si farà di ciascun pin connesso a componenti esterni attraverso la funzione pinMode(pin, mode), dove:
* pin è il numero del pin:
** da 0 a 13 per i pin digitali;
** da A0 ad A5 per i pin analogici (questi possono essere trattati come pin digitali, ma non il viceversa);
* mode è la modalità con cui verrà utilizzato. Le costanti possibili sono:
** INPUT per gli ingressi
** OUTPUT per le uscite
** INPUT_PULLUP per ingressi che necessitano di una resistenza, cosiddetta di pull-up.

### Ingressi e uscite numeriche

Per accendere e spegnere un LED con un pulsante, occorre un ingresso (il pulsante) e un'uscita (il LED). Assumendo che il pulsante sia connesso al pin 7 e il LED al pin 13 si scriverà:

### Ingressi e uscite analogiche

Arduino Uno ha una risoluzione in ingresso di 10 bit. Questo significa che distingue $2^{10}=1024$ differenti livelli di tensione. Essendo alimentato con una tensione massima di $5~{\text{V}}$ può distinguere valori di tensioni pari a $V_{MIN}={\frac {5~{\text{V}}}{1024}}=4,88~{\text{mV}}$.
Le uscite analogiche, invece, hanno un range di 8 bit, pertanto i livelli saranno $2^{8}=256$ (compreso lo 0). Possono essere utilizzate per pilotare dispositivi con modulazione PWM (modulazione a larghezza di impulsi) così da variare – tramite un potenziometro – la luminosità di un LED o la potenza di un motore.
Attenzione: spesso si passerà il valore letto in ingresso in uscita. Siccome l'uscita ha due bit in meno, questo andrà diviso per quattro, come nel codice che segue:
Non tutte le uscite supportano questa funzione. Quelle possibili sono le 3, 5, 6, 9, 10 e 11. Si riconoscono per via del segno tilde (~) sulla scheda.
Infine, sui pin 5 e 6 la frequenza di lavoro è di circa 980 Hz. Sempre a proposito di questi due pin, i loro output PWM avranno un ciclo utile più alto di quello atteso, a causa dell’interazione con le funzioni millis e delay, che condividono lo stesso timer interno usato per generare queste uscite PWM. Questo si noterà in particolare con impostazioni basse del ciclo utile (comprese tra 0 e 10) e potrebbe risultare in un valore di 0 che non spegne completamente l’output sui pin 5 e 6.

## Gestione avanzata di ingressi/uscite

Esistono diversi comandi che consentono una gestione avanzata e, allo stesso tempo semplice, di ingressi uscite. Di seguito vengono elencati i principali:
pulseIn legge un impulso (sia esso HIGH o LOW) su un pin. Se il valore è settato su HIGH, attende che il pin vada nello stato HIGH e, nel frattempo, misura il tempo trascorso. Funziona sugli impulsi di lunghezza compresa tra 10 microsecondi e 3 minuti (per valori così alti, si consiglia l'utilizzo di variabili del tipo unsigned long).
Può essere usato con due modalità: con e senza timeout, parametro opzionale che interrompe la funzione in caso di tempistiche eccessivamente lunghe. Restituisce la durata dell’impulso (in microsecondi) oppure 0 se nessun impulso è partito prima del timeout.
tone genera un’onda quadra alla frequenza specificata, può essere specificata anche una durata, altrimenti il segnale prosegue fino all'esecuzione del comando noTone (utile in contesti di emergenza).
Il pin può essere connesso ad un buzzer piezoelettrico o altro speaker per riprodurre suoni. Può essere generato solo un suono alla volta. Se un tono è già in riproduzione su un pin differente, la chiamata a tone non avrà alcun effetto. Se il tono è in riproduzione sullo stesso pin, la chiamata ne imposterà una frequenza differente.
Non è possibile generare toni inferioni a 31Hz. Per riprodurre toni differenti su pin multipli, occorre eseguire noTone su un pin prima di eseguire tone su un altro pin.

## Gestione del tempo

Sostanzialmente ci sono due tipologie di funzioni da conoscere:
* delay e delayMicrosecond, le quali fermano l'attività del microcontrollore per i millisecondi e microsecondi stabiliti (rispettivamente);
* millis e micros, che invece restituiscono il tempo trascorso dall'accensione, rispettivamente in millisecondi e microsecondi. A causa dei numeri elevati che devono gestire, queste perdono il conteggio dopo circa 70 minuti e 50 giorni.
Ecco alcuni esempi:
Con millis è possibile generare un'attesa con il seguente frammento di codice:

## Gli interrupt

Alcune operazioni svolte dal microcontrollore richiedono tempo. Altre, come delay, lo mettono in attesa. Per forzare la sua attività al verificarsi di un evento (come un allarme che deve bloccare un ciclo di lavorazione) esistono gli interrupt.
Gli interrupt consentono di svolgere alcune attività importanti in sottofondo e sono abilitati per impostazione predefinita. Alcune funzioni sono disabilitate e le comunicazioni in arrivo possono essere ignorate. Tuttavia, gli interrupt possono alterare leggermente la tempistica del codice e possono essere disabilitati per sezioni di codice particolarmente critiche.
Il loro utilizzo è molto semplice:
Il primo parametro di attachInterrupt è il numero di interrupt. Normalmente si usa digitalPinToInterrupt(pin) per trasformare un pin numerico in un interrupt specifico. Per esempio, se ci si collega al pin 3, si utilizza digitalPinToInterrupt(3) come primo parametro di attachInterrupt.
Sulle schede Arduino Uno (le più diffuse) è possibile utilizzare come interrupt i pin 2 e 3.

### Utilizzo degli interrupt

Gli interrupt sono utili per far sì che le cose avvengano automaticamente nei microcontrollori e possono contribuire a risolvere i problemi di temporizzazione. L'uso di un interrupt può essere utile per la lettura di un trasduttore girevole o per il monitoraggio di un ingresso da parte dell'utente.
Se si volesse garantire che un programma rilevi sempre gli impulsi di un trasduttore rotante, così da non perdere mai un impulso, diventerebbe molto difficile scrivere un programma che faccia qualsiasi altra cosa, perché il programma dovrebbe eseguire costantemente il controllo delle linee del trasduttore per rilevare gli impulsi quando si presentano. Anche altri sensori presentano una dinamica simile, come, per esempio, il sensore sonoro che vuole rilevare un clic o il sensore a infrarossi che cerca di rilevare la caduta di una moneta. In tutte queste situazioni, l'uso di un interrupt può consentire al microcontrollore di svolgere altre operazioni senza perdere il segnale di ingresso.

### Le routine degli interrupt

Gli interrupt sono funzioni speciali che hanno alcune limitazioni particolari, che la maggior parte delle altre funzioni non ha. Un interrupt non può ricevere parametri e non dovrebbe restituire nulla.
In generale, gli interrupt dovrebbero essere più corti e veloci possibile. Se lo script utilizza più istruzioni per le operazioni, è possibile eseguirne solo una alla volta; gli altri interrupt verranno eseguiti dopo il termine di quello corrente, in un ordine che dipende dalla loro priorità. millis si basa sugli interrupt per il conteggio, quindi non si incrementerà mai all'interno di un'istruzione per le operazioni. Poiché delay richiede gli interrupt per funzionare, non funzionerà se richiamato all'interno di un interrupt. micros funziona inizialmente, ma inizierà a comportarsi in modo irregolare dopo $1-2~{\text{ms}}$. delayMicroseconds non utilizza alcun contatore, quindi funzionerà normalmente.
In genere le variabili globali vengono utilizzate per passare i dati tra l'interrupt e il programma principale. Per assicurarsi che le variabili condivise tra l'interrupt e il programma principale vengano aggiornate correttamente, occorre dichiararle come volatili.

### Parametri

La funzione per dichiarare l'interrupt si presenta così:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode)
dove:
* pin è il pin di Arduino (il 2 o il 3);
* ISR è la funzione da chiamare quando si verifica un interrupt; questa funzione non deve accettare alcun parametro e non deve restituire nulla. Questa funzione, talvolta viene definita routine di servizio dell'interrupt;
* mode definisce quando l'interrupt deve essere attivato. Come valori ammessi vengono predisposte quattro costanti:
** LOW per attivare l'interrupt quando il pin è a livello basso;
** CHANGE per attivare l'interrupt quando il pin cambia stato;
** RISING per attivare l'interrupt quando il pin passa da livello basso a livello alto;
** FALLING per quando il pin passa da livello alto a livello basso.

### Un esempio completo
## Comunicazioni con altri dispositivi
### La porta seriale

La porta seriale è il più facile e comodo metodo per ricevere (e inviare) dati dalla scheda Arduino a un'altra macchina, sia essa il computer, sia essa un'altra scheda Arduino.
Tipicamente si ha a disposizione una scheda Arduino Uno. Questa ha una porta seriale i cui pin dedicati sono due:
* 0, per la ricezione;
* 1, per la trasmissione.
Attenzione: questi pin sono connessi alla porta USB, dalla quale Arduino viene programmato. Pertanto, se si desidera utilizzarli con apparati esterni, all'atto della programmazione, andranno scollegati per evitare effetti indesiderati.
Se, invece, si ha a disposizione un Arduino Mega, allora si avranno quattro porte seriali. La prima come per Arduino Uno (il che rende i codici compatibili), le altre tre per altri dispositivi.
Sempre in tema di precauzioni: Arduino lavora con tensioni di $5~{\text{V}}$ o $3,3~{\text{V}}$, a seconda delle schede. Pertanto, la porta seriale di Arduino non deve mai essere connessa direttamente alla porta seriale RS232, che opera con livelli di tensione di $\pm 12~{\text{V}}$ che danneggerebbero la scheda Arduino.

### Comunicazione tramite porta seriale

È possibile utilizzare la comunicazione seriale con i pin Tx/Rx rispettando la logica TTL ($5~{\text{V}}$). Per eseguire una comunicazione seriale con un dispositivo esterno TTL (come un'altra scheda Arduino) è sufficiente collegare il pin Tx al pin Rx del proprio dispositivo e il pin Rx al pin Tx. Da non dimenticare che anche le messe a terra delle schede devono essere connesse, diversamente mancherebbe un riferimento di $0~{\text{V}}$.