Una Introduzione ad Arduino

Transcript

Una Introduzione ad Arduino
Introduzione
La Testa Robotica
Una Introduzione ad
Arduino
Prof. Michele Scarpiniti
Dipartimento di Ingegneria dell’Informazione, Elettronica e Telecomunicazioni
“Sapienza” Università di Roma
http://ispac.diet.uniroma1.it/scarpiniti/index.htm
[email protected]
M. Scarpiniti
Una Introduzione ad Arduino
1 / 69
Introduzione
La Testa Robotica
1
Introduzione
Introduzione
L’IDE
Gli esempi
2
La Testa Robotica
L’hardware
Il software
Il funzionamento
M. Scarpiniti
Una Introduzione ad Arduino
2 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Introduzione
Introduzione
M. Scarpiniti
Una Introduzione ad Arduino
3 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Introduzione
L’obiettivo di queste slides è di introdurre ed illustrare il funzionamento della
scheda Arduino attraverso semplici esempi.
Si vedrà, in particolare, l’applicazione di Arduino nel controllare una testa
robotica in grado di localizzare una sorgente in movimento all’interno di una
stanza attraverso una coppia di microfoni (orecchi) e una coppia di webcam
(occhi).
Maggiori informazioni su Arduino e accessori possono essere reperite al link
http://www.arduino.com/ da cui è anche possibile scaricare l’ambiente
grafico (IDE) per la programmazione del dispositivo.
M. Scarpiniti
Una Introduzione ad Arduino
4 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Arduino in sintesi
Arduino è una piccola scheda
equipaggiata con un microcontrollore e
una circuiteria di contorno, utile per
creare rapidamente prototipi. Con
Arduino si possono realizzare in maniera
relativamente rapida e semplice, piccoli
dispositivi per il controllo di sensori e
attuatori.
Completamente italiano, il progetto di
Arduino è stato sviluppato presso
l’Interaction Design Institute, un istituto
di formazione post-dottorale con sede a
Ivrea, fondato da Olivetti e Telecom
Italia.
M. Scarpiniti
Una Introduzione ad Arduino
5 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
La storia di Arduino
Il nome della scheda deriva da quello di un bar di Ivrea frequentato da alcuni dei
fondatori del progetto. Il progetto ha preso avvio in Italia ad Ivrea, nel 2005,
con lo scopo di rendere disponibile, a progetti di Interaction design realizzati da
studenti, un device per il controllo che fosse più economico rispetto ad altri sistemi
di prototipazione disponibili all’epoca.
I progettisti sono riusciti nell’intento di creare una piattaforma di semplice utilizzo
ma che, al tempo stesso, permettesse una significativa riduzione dei costi rispetto
a molti prodotti disponibili sul mercato. A ottobre 2008 erano già stati venduti più
di 50.000 esemplari di Arduino in tutto il mondo.
A partire dal 2015, per via di alcune
scelte dei creatori del progetto, il
marchio Arduino è disponibile solo sul
mercato americano. Nel resto del
mondo, le stesse schede vengono
commercializzate con il nuovo marchio
Genuino.
M. Scarpiniti
Una Introduzione ad Arduino
6 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Arduino UNO (Genuino UNO)
La scheda più comune e diffusa della famiglia Arduino è senz’altro Arduino UNO
(ovvero Genuino UNO, in Europa), equipaggiato di un micro-controllore ATmega328P della Atmel. E’ poi presente una porta USB per interagire con il PC e
caricare il software e vari connettori per l’I/O, in particolare:
1
14 connettori per l’I/O digitale (numerati da 0 a 13);
2
6 connettori specificamente dedicati a ingressi di segnali analogici (collegati
quindi ad una ADC).
M. Scarpiniti
Una Introduzione ad Arduino
7 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Arduino UNO: specifiche tecniche
Le specifiche tecniche di Arduino UNO sono riportate nella seguente tabella.
Microcontrollore
Operating Voltage
Input Voltage (recommended)
Input Voltage (limit)
Digital I/O Pins
PWM Digital I/O Pins
Analog Input Pins
DC Current per I/O Pin
DC Current for 3.3V Pin
Flash Memory
SRAM
EEPROM
Clock Speed
Length
Width
Weight
M. Scarpiniti
Una Introduzione ad Arduino
ATmega328P
5V
7-12 V
6-20 V
14 (of which 6 provide PWM output)
6
6
20 mA
50 mA
32 KB of which 0.5 KB used by bootloader
2 KB
1 KB
16 MHz
68.6 mm
53.4 mm
25 g
8 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Arduino UNO: l’anatomia della scheda
Descriviamo nello specifico le varie parti e i vari componenti della scheda Arduino UNO.
M. Scarpiniti
1
Pin digitali: per leggere da sensori e scrivere su attuatori;
2
LED pin 13: utile per il debugging ;
3
LED accensione: indica se la scheda è accesa;
4
Microcontrollore ATmega: il cuore della scheda;
5
Ingressi analogici: per leggere valori analogici;
6
Pin alimentazione GND e 5V: per fornire l’alimentazione a ai
dispositivi collegati;
7
Connettore alimentazione: per alimentare la scheda se non
connessa tramite porta USB. Accetta tensioni nell’intervallo
7-12 V;
8
LED di TX e RX: indicano la comunicazione tra la scheda e
il computer;
9
Porta USB: per collegare la scheda al computer;
10
Tasto di Reset: per resettare il microcontrollore.
Una Introduzione ad Arduino
9 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Altre schede della famiglia Arduino
Esistono diverse varianti alla scheda Arduino/Genuino UNO. Le più diffuse
sono elencate nella seguente tabella.
Entry Level
Enhanced Features
Internet of Things
Genuino UNO, Genuino 101, Genuino MICRO
Genuino MEGA, Genuino ZERO, Genuino Yùn
Genuino MKR1000
In particolare, l’ultima scheda è stata progettata per offrire una soluzione
pratica e conveniente per coloro i quali cercano di aggiungere ai loro progetti
la connettività Wi-Fi con il minimo sforzo.
M. Scarpiniti
Una Introduzione ad Arduino
10 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
L’IDE di Arduino
L’ambiente di sviluppo integrato (IDE) di Arduino è un’applicazione multi-piattaforma
scritta in Java, che include un editore di testo dotato di syntax highlighting, il controllo delle parentesi e indentazione automatica. L’editor è inoltre in grado di
compilare e lanciare il programma eseguibile in una sola passata e con un solo
click. La sintassi è C-like, ma molto più intuitiva.
L’IDE è utilizzata per scrivere i codici
sorgenti che contengono tutte le
istruzioni necessarie affinché il computer
possa controllare tutte le funzionalità di
Arduino. Tali codici sono chiamati
sketch. L’IDE si occupa anche di
trasferire tali istruzioni sulla scheda
(upload) in modo tale che Arduino
funzioni anche se non più connesso al
calcolatore.
M. Scarpiniti
Una Introduzione ad Arduino
11 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
L’IDE di Arduino: il Monitor Seriale
L’IDE di Arduino mette a disposizione uno strumento molto comodo, chiamato monitor seriale. Il monitor seriale è uno strumento che permette
di leggere i dati che Arduino comunica tramite la porta seriale (COM) al
computer e consente anche di stampare alcuni messaggi utili per testare il
corretto funzionamento dell’applicazione. L’interfaccia del monitor seriale è
rappresentata di seguito.
M. Scarpiniti
Una Introduzione ad Arduino
12 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Le funzioni principali dell’IDE di Arduino
Quando si apre l’IDE per scrivere un nuovo sketch, sul prompt compaiono le definizioni di due funzioni da editare, che risultano fondamentali per il corretto
funzionamento del dispositivo
void setup () {
// put your setup code here , to run once :
}
void loop () {
// put your main code here , to run repeatedly :
}
Tali funzioni si occupano delle inizializzazioni di tutte le variabili e della definizione
dei compiti che la scheda dovrà ripetere durante l’intero funzionamento.
Eventuali altre funzioni, da utilizzare all’interno di loop(), possono essere
definite a seguire.
M. Scarpiniti
Una Introduzione ad Arduino
13 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
La funzione setup()
La funzione setup() viene chiamata all’inizio del programma e viene utilizzata per inizializzare tutte le variabili, i vari pin e per linkare tutte le librerie
necessarie.
Questa funzione viene eseguita una sola volta, all’avvio dell’applicazione.
Segue un esempio:
int buttonPin = 3;
void setup ()
{
Serial . begin (9600) ;
pinMode ( buttonPin , INPUT ) ;
}
In questo esempio, si crea una variabile buttonPin, che rappresenta il
terzo pin digitale, impostandola come un input e abilitando la
comunicazione seriale a 9600 b/s. L’intento è dunque, di leggere il livello
di tensione (basso o alto) dal pin 3.
M. Scarpiniti
Una Introduzione ad Arduino
14 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
La funzione loop()
La funzione loop(), chiamata subito dopo la setup(), è iterata costantemente per tutta la durata dell’applicazione, eseguendo ad ogni ciclo le
istruzioni presenti nel suo blocco. Tale funzione è dunque utilizzata per la
descrizione dei compiti che la scheda dovrà compiere. Segue un esempio:
void loop ()
{
if ( digitalRead ( buttonPin ) == HIGH )
Serial . println ( ’H ’) ;
else
Serial . println ( ’L ’) ;
delay (1000) ;
}
In tale esempio, si legge la tensione dal pin 3, impostato precedentemente,
e se la tensione è alta si scrive H nel monitor seriale, altrimenti L. Dopo
ogni lettura del pin si attende un secondo.
M. Scarpiniti
Una Introduzione ad Arduino
15 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Le funzioni principali
Nelle funzioni precedenti sono state utilizzate alcune funzioni fondamentali,
di seguito descritte.
Serial.begin(speed): setta la velocità di trasmissione tramite la
porta seriale al valore indicato;
pinMode(pin, mode): configura il comportamento (INPUT o
OUTPUT) del pin indicato;
digitalRead(pin): legge il valore digitale (HIGH o LOW) dal pin
indicato;
Serial.println(’stringa’): stampa un valore o una stringa sul
monitor seriale, andando poi a capo;
delay(ms): mette in pausa il programma per un numero di
millisecondi specificato.
M. Scarpiniti
Una Introduzione ad Arduino
16 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Le librerie principali
Molte funzionalità utili nelle applicazioni, sono raccolte in librerie di funzioni
disponibili nell’IDE. Un esempio è la libreria Serial utilizzata precedentemente, che consente la comunicazione seriale, oppure la Servo che implementa
i metodi per la gestione dei servomeccanismi.
Per utilizzare nell’IDE una certa libreria, la si deve includere con la direttiva
# include < Libreria .h >
Ad esempio, se volessi utilizzare la libreria Servo:
# include < Servo .h >
void setup () {
// il mio codice
}
void loop () {
// il mio codice
}
M. Scarpiniti
Una Introduzione ad Arduino
17 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Le librerie principali
Anche se esistono alcune librerie specifiche solo per alcuni modelli di Arduino, è disponibile
un insieme di librerie standard funzionanti su tutti i dispositivi. Nello specifico
Libreria
EEPROM
Ethernet
Firmata
GSM
LiquidCrystal
SD
Serial
Servo
SPI
SoftwareSerial
Stepper
TFT
WiFi
Wire
M. Scarpiniti
Descrizione
Lettura e scrittura su supporti permanenti
Per utilizzare una scheda di rete opzionale
Per comunicare attraverso un protocollo seriale standard
Per utilizzare una scheda GSM opzionale
Per il controllo di display a cristalli liquidi (LCD)
Lettura e scrittura su SD card
Per le comunicazioni seriali con PC e serial monitor
Per il controllo dei servo-motori
Per comunicare attraverso il bus Serial Peripheral Interface (SPI)
Per le comunicazioni seriali verso i pin digitali
Per il controllo di motorini passo-passo
Per comandare schermi TFT
Per la connessione wireless attraverso un’apposita scheda
Per ricevere/inviare dati dalle interfacce TWI/I2C
Una Introduzione ad Arduino
18 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
La libreria Serial
La libreria Serial è fondamentale per qualsiasi applicazione, poiché abilita la comunicazione da e verso computer ed inoltre abilita l’utilizzo del monitor seriale. Non è possibile
immaginare di lavorare senza.
Per questo motivo, tale libreria è predefinita nell’IDE di Arduino e non è necessaria
includerla manualmente con la direttiva #include.
Tale libreria include 21 funzioni. Oltre la begin(), le più importanti sono:
available(): restituisce il numero di byte disponibili nel buffer di lettura (che ne
può contenere fino a 64);
end(): termina la comunicazione seriale;
peek(): restituisce il byte (o carattere) seriale successivo , senza rimuoverlo dal
buffer;
print(), println(): stampa un valore (o una stringa) sulla porta seriale o
monitor seriale. Il secondo comando manda a capo;
read(): legge i dati dalla connessione seriale;
setTimeout(): configura il tempo massimo (in millisecondi) di attesa per la
comunicazione seriale;
write(): scrive dati binari alla porta seriale.
M. Scarpiniti
Una Introduzione ad Arduino
19 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
La libreria Serial
Tale libreria (Serial) è quindi utilizzata per la comunicazione tra la scheda
Arduino e il computer o altri dispositivi. Tutte le schede Arduino hanno
almeno una porta seriale (anche nota come UART o USART). La comunicazione avviene sul pin digitale 0 (RX, per la trasmissione) e sul pin digitale
1 (TX, trasmissione) e con il computer tramite la porta USB. Quindi, se si
utilizzano le funzioni di tale libreria, non è possibile utilizzare i pin 0 e 1 per
l’ingresso o l’uscita digitale da eventuali sensori/attuatori.
È anche possibile utilizzare l’ambiente monitor seriale, incorporato in
Arduino, per comunicare con la scheda. Facendo clic sul pulsante del
monitor seriale nella barra degli strumenti e selezionando la stessa velocità
di trasmissione utilizzata nella chiamata di Serial.begin(), si aprirà una
finestra in cui è possibile stampare (scrivere) valori ricevuti (trasmessi)
dalla scheda.
M. Scarpiniti
Una Introduzione ad Arduino
20 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
La modulazione PWM
La modulazione a larghezza di impulso (Pulse Width Modulation o PWM) può
essere usata in Arduino per ottenere valori analogici a partire da segnali digitali.
Un segnale PWM è, in effetti, un’onda quadra che varia da 0 V a 5 V, con frequenza
costante, ma in cui è variabile la frazione di tempo in cui il segnale è attivo a 5 V
(detto dutycycle), che può variare tra lo 0 e il 100 %.
La modulazione PWM è implementata in Arduino tramite la funzione
analogWrite ( pin , dutyCycle )
dove dutyCycle è un valore tra 0 e 255, e pin è
uno dei pin PWM (3, 5, 6, 9, 10 o 11). Il comando
analogWrite non fornisce alcun controllo sulla frequenza. Il valore della tensione di uscita del pin sarà
una frazione dei 5 V, proporzionale al dutycycle: è
quindi possibile far variare con continuità una tensione
da 0 a 5 V.
M. Scarpiniti
Una Introduzione ad Arduino
21 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Alcuni semplici esempi
L’IDE di Arduino mette a disposizione un certo numero di esempi molto
utili per chi è alle prime armi. Infatti, attraverso questi esempi, è possibile imparare l’utilizzo delle funzioni e delle librerie principali. Tali esempi
sono suddivisi per categoria (analogico, digitale, comunicazione, controllo,
sensori, display, USB, ecc.) e sono accessibili dal menù File => Esempi.
Alcuni di questi esempi sono descritti approfonditamente nel testo “Genuino
Projects Book”, che è venduto insieme allo starter kit, che contiene, oltre
alla scheda Genuino UNO, numerosi altri componenti per implementare gli
esempi proposti.
E’ comunque possibile trovare numerosi altri esempi in rete oppure nei tanti
testi dedicati alla scheda, facilmente reperibili in commercio.
M. Scarpiniti
Una Introduzione ad Arduino
22 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Far lampeggiare un LED
Il primo classico esempio consiste nel far lampeggiare un LED. Si collega un LED
rosso, con in serie un resistore, tra il pin digitale 13 e il pin GND, come schematicamente indicato nelle figure seguenti. Si programma quindi la scheda per inviare
alternativamente una tensione alta (5 V) e una bassa (0 V) al pin 13.
Il resistore R serve per limitare il valore della corrente che scorre nel LED, per non
bruciarlo ed il suo valore è calcolato come
R=
V − VLED
5 − 1.7
≡
= 220 Ω,
I
15 · 10−3
in cui I è la corrente (di solito intorno ai 15 ÷ 20 mA) e VLED = 1.7 V per il LED
rosso.
M. Scarpiniti
Una Introduzione ad Arduino
23 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Far lampeggiare un LED
Lo sketch di Arduino che fa lampeggiare il LED è il seguente.
void setup () {
pinMode (13 , OUTPUT ) ;
output
}
// pin digitale 13 impostato come
Si inizializza, cioè, il pin digitale 13 come uscita.
void loop () {
digitalWrite (13 , HIGH ) ;
delay (1000) ;
digitalWrite (13 , LOW ) ;
delay (1000) ;
}
//
//
//
//
si
si
si
si
accende il LED
aspetta 1 secondo
spegne il LED
apsetta 1 secondo
Si ripete ciclicamente: si invia tensione alta in uscita al pin 13 (LED acceso), si
aspetta 1 secondo, si invia tensione bassa (LED spento), si aspetta 1 secondo e
cosı̀ via finché non si stacca la scheda. Quindi ogni secondo il LED si accende e si
spegne.
M. Scarpiniti
Una Introduzione ad Arduino
24 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Far sfumare l’intensità di un LED
Si vuol far variare con continuità l’intensità in un LED, aumentandola gradualmente
fino ad un valore massimo e poi diminuendola fino a spegnere il LED e poi di nuovo
aumentandola. A tal proposito si utilizza la modulazione PWM. Il LED sarà dunque
collegato ad un pin analogico (il pin 9), controllato con un dutycycle variabile da
0 a 255 e di nuovo a 0, attraverso la funzione analogWrite(pin, dutyCycle).
Anche in questo caso il resistore R1 è determinato come nel caso precedente.
M. Scarpiniti
Una Introduzione ad Arduino
25 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Far sfumare l’intensità di un LED
Lo sketch di Arduino inizia con la definizione di tre variabile che indicano il numero
del pin a cui collegare il LED, il valore della luminosità iniziale del LED e di quanto
far aumentare la luminosità dopo un certo intervallo temporale. Si sceglie il pin
numero 9 che è uno di quelli abilitati alla modulazione PWM, con cui si farà variare
l’intensità.
int led = 9;
int brightness = 0;
int fadeAmount = 5;
// il pin PWM del LED
// luminosità del LED
// variazione della luminosità del LED
La funzione setup() imposta semplicemente il pin a cui è collegato il LED (il
numero 9) come un pin di uscita.
void setup () {
pinMode ( led , OUTPUT ) ;
}
M. Scarpiniti
Una Introduzione ad Arduino
// il pin 9 è impostato come output
26 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Far sfumare l’intensità di un LED
La funzione loop() imposta inizialmente il valore di luminosità iniziale (pari a zero)
e quindi il LED risulta spento. Si aumenta quindi l’intensità del valore prestabilito fadeAmount, si aspetta per 30 millisecondi e si reimposta la nuova luminosità
con analogWrite(). Se nel frattempo si è raggiunta la luminosità massima,
cioè l’onda quadra è diventata una costante con dutycycle pari a 255, la variabile
fadeAmount viene impostata negativa in modo da diminuire gradualmente l’intensità. Viceversa, quando il dutycycle è divenuto nullo, la variabile fadeAmount
viene reimpostata positiva per aumentare l’intensità e cosı̀ via.
void loop () {
analogWrite ( led , brightness ) ;
// impostare la luminosità
brightness = brightness + fadeAmount ;
luminosità
// cambio di
if ( brightness == 0 || brightness == 255) {
// raggiunto
il limite massimo si inverte la luminosità
fadeAmount = - fadeAmount ;
}
delay (30) ; // aspetta 30 millisecondi
}
M. Scarpiniti
Una Introduzione ad Arduino
27 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Rilevatore di vibrazione
Il prossimo esempio, consiste in un rilevatore di vibrazione attraverso un sensore
piezoelettrico. Se il sensore piezoelettrico vibra, produce una tensione ai suoi capi
che può essere letta attraverso un pin di ingresso analogico della scheda. Il sensore
è collegato ai pin GND e A0 (il primo ingresso analogico disponibile). Si collegherà in
seguito un LED al pin digitale 13, che si accende se il sensore rileva una vibrazione
sufficientemente grande.
Per proteggere il sensore piezoelettrico da tensioni e correnti eccessive, viene
inserito in parallelo un resistore da 1 MΩ.
M. Scarpiniti
Una Introduzione ad Arduino
28 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Rilevatore di vibrazione
Lo sketch di Arduino inizia con la definizione di tre costanti che indicano il numero
del pin a cui collegare il LED, il numero del pin analogico a cui collegare il sensore
e la soglia per determinare se c’è stata una vibrazione consistente. Si dichiarano
poi una variabile per leggere il valore del sensore e una variabile che indica lo stato
del LED, inizializzata a LOW.
const int ledPin = 13;
// LED colleg . al pin digitale 13
const int knockSensor = A0 ; // piezo colleg . al pin analogico 0
const int threshold = 100; // soglia
int sensorReading = 0;
int ledState = LOW ;
// valore del piezo
La funzione setup() imposta semplicemente il pin a cui è collegato il LED (il
numero 13) come un pin di uscita e inizializza una comunicazione seriale a 9600
baud.
void setup () {
pinMode ( ledPin , OUTPUT ) ;
Serial . begin (9600) ;
}
M. Scarpiniti
Una Introduzione ad Arduino
// pin del LED impostato OUTPUT
// si utilizza la porta seriale
29 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Rilevatore di vibrazione
La funzione loop() legge inizialmente il valore di tensione generato dal sensore,
attraverso la funzione analogRead() che restituisce un intero compreso tra 0 e
1023. Se questo valore supera il valore di soglia threshold, lo stato del LED viene
cambiato in HIGH e quindi acceso tramite digitalWrite(), mentre nel monitor
seriale viene stampato un messaggio. Si attenono poi 100 millisecondi per evitare
problemi di sincronizzazione e il programma termina.
void loop () {
sensorReading = analogRead ( knockSensor ) ;
del sensore
// legge il valore
if ( sensorReading >= threshold ) { // se supera la
ledState = ! ledState ;
// stato del LED
digitalWrite ( ledPin , ledState ) ; // accende il
Serial . println ( " Knock ! " ) ; // stampa " Knock !"
seriale
}
delay (100) ; // aspetta 100 millisecondi
soglia
è HIGH
LED
sul monitor
}
M. Scarpiniti
Una Introduzione ad Arduino
30 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Utilizzo di un accelerometro
Nel prossimo esempio si vuole leggere i dati relativi alle accelerazioni nelle tre
direzioni x, y e z attraverso un accelerometro della famiglia ADXL3xx (prodotti
principalmente da SparkFun e Adafruit), che è un sensore analogico.
Lo schema di collegamento è rappresentato nelle seguenti figure, anche se è possibile
avere configurazioni differenti per sensori di diversi produttori (attenzione ai valori
di alimentazione).
L’accelerometro della famiglia ADXL3xx è collegato a tutti i pin analogici A0-A5,
secondo il seguente schema
ADXL3xx Pin
Arduino Pin Analogico
M. Scarpiniti
Self-Test
0
Una Introduzione ad Arduino
z-axis
1
y-axis
2
x-axis
3
Ground
4
VDD
5
31 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Utilizzo di un accelerometro
Si dichiarano tutti e 5 i pin da utilizzare. Poiché si vuole utilizzare i pin A4 e A5
come alimentazione, li si dichiarerà come pin digitali (rispettivamente il 18 e 19).
const
const
const
const
const
int
int
int
int
int
groundpin = 18;
powerpin = 19;
xpin = A3 ;
ypin = A2 ;
zpin = A1 ;
//
//
//
//
//
pin A4 -- Ground
pin A5 -- VDD
x - axis
y - axis
z - axis
A questo punto, si inizializza una comunicazione seriale a 9600 baud, si impostano
i pin 18 e 19 come uscite, settandole a livello LOW (Ground) e HIGH (VDD).
void setup () {
Serial . begin (9600) ;
// Non necessario se si utilizzano i pin 5 V e Gnd :
pinMode ( groundpin , OUTPUT ) ;
pinMode ( powerpin , OUTPUT ) ;
digitalWrite ( groundpin , LOW ) ;
digitalWrite ( powerpin , HIGH ) ;
}
Se per l’alimentazione si utilizzano i pin 5V e Gnd è possibile commentare le
righe precedenti e la dichiarazione dei pin 18 e 19.
M. Scarpiniti
Una Introduzione ad Arduino
32 / 69
Introduzione
La Testa Robotica
Introduzione
L’IDE
Gli esempi
Utilizzo di un accelerometro
Nella funzione loop() si legge semplicemente i valori dei tre pin A1, A2 e A3 attraverso al funzione analogRead(), stampando il valore sul monitor seriale insieme
ad una tablatura per incolonnare i risultati. Si attendono quindi 100 millisecondi
e si ricomincia a leggere e stampare i nuovi valori finché non si spegne la scheda.
void loop () {
Serial . print ( analogRead ( xpin ) ) ;
Serial . print ( " \ t " ) ;
Serial . print ( analogRead ( ypin ) ) ;
Serial . print ( " \ t " ) ;
Serial . print ( analogRead ( zpin ) ) ;
Serial . println () ;
// Stampa del valore lungo x
// Stampa di una tablatura
// Stampa del valore lungo y
// Stampa del valore lungo z
delay (100) ;
// Si attendono 100 millisecondi prima della
prossima lettura
}
Si osservi che non si è utilizzato il pin di self-test.
M. Scarpiniti
Una Introduzione ad Arduino
33 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La Testa Robotica
La Testa Robotica
M. Scarpiniti
Una Introduzione ad Arduino
34 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La testa robotica: Bender
L’applicazione principale consiste nel costruire una testa robotica in grado
di seguire una sorgente sonora in movimento all’interno di un ambiente.
La testa robotica, denominata Bender, ha dimensione di 21 x 16 x 13
cm ed è equipaggiata con due microfoni, che fungono da orecchi, e due
webcam, che fungono da occhi. E’
poi presente un algoritmo di localizzazione binaurale, basato sulle registrazioni dei due microfoni e un algoritmo di face detection, basato una sola
webcam, che viene utilizzato per correggere gli errori dovuti al riverbero
dell’ambiente.
M. Scarpiniti
Una Introduzione ad Arduino
35 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La testa robotica: Bender
Più in dettaglio, i microfoni utilizzati sono due AKG-c562cm, che sono
microfoni a condensatore con eccellenti caratteristiche di radiazione, come
messo in evidenza dalla figura seguente a sinistra.
Le webcam utilizzate sono due comuni webcam a bassa risoluzione 640 x
480.
I movimenti sono controllati da tre servomotori, precisamente un servomotore digitale (pan del collo), un micro-servomotore digitale (tilt degli occhi)
e un micro-servomotore analogico (pan degli occhi).
M. Scarpiniti
Una Introduzione ad Arduino
36 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La testa robotica: Bender
I tre servomotori devono essere alimentati con una alimentazione in continua di 5 V. Poiché tali attuatori non assorbono troppa corrente, è possibile
alimentarli direttamente tramite la scheda Arduino, utilizzano i pin di alimentazione 5V e GND. Tali pin sono collegati alle linee di alimentazione
della breadboard ai cui verranno successivamente collegate le alimentazioni dei servomotori. Nel caso sia richiesta molta corrente da parte di un
attuatore, sarà necessario utilizzare un alimentatore esterno.
I servomotori possiedono un terzo cavo (di
colore giallo) per il loro controllo.
Si
utilizzeranno a tal proposito i pin:
3: per il pan del collo;
5: per il pan degli occhi;
6: per il tilt degli occhi.
M. Scarpiniti
Una Introduzione ad Arduino
37 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La libreria Servo
Per utilizzare i servomotori, è necessario utilizzare alcune funzioni contenute nella
libreria Servo, già presente nella distribuzione installata dell’IDE di Arduino.
Per creare un oggetto di tale classe, si dichiara una variabile di tipo Servo:
Servo myservo ;
Le sei funzioni della libreria sono elencate di seguito:
attach(pin): collega la variabile myservo al pin indicato;
read(): legge l’angolo corrente del servomotore;
write(angle): sposta il servomotore all’angolo indicato. Valore compreso
tra 0 e 180, dove 90 indica la posizione centrale di riposo;
writeMicroseconds(us): invia al servomotore un valore in microsecondi
con un conseguente spostamento del dispositivo. Di solito è un valore
compreso tra 1000 e 2000 µs, con valore centrale pari a 1500 µs, ma può
dipendere dal particolare servomotore;
attached(): verifica se la variabile myservo è collegata a qualche pin;
detach(): scollega la variabile myservo dal pin in cui era collegata.
M. Scarpiniti
Una Introduzione ad Arduino
38 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Lo sketch in Arduino
Lo sketch Arduino per utilizzare la testa robotica è il seguente:
# include < Servo .h >
Servo eyepan ;
Servo eyetilt ;
Servo neckpan ;
Si dichiarano quindi le tre variabili eyepan, eyetilt e neckpan che descrivono i
tre servomotori.
void setup () {
eyepan . attach (5) ;
eyetilt . attach (6) ;
neckpan . attach (3) ;
eyepan . w r i t e M i c r o s e c o n d s (1280) ;
eyetilt . w r i t e M i c r o s e c o n d s (1680) ;
neckpan . w r i t e M i c r o s e c o n d s (1475) ;
Serial . begin (9600) ;
}
La funzione setup(), collega le tre variabili ai pin 3, 5 e 6, inizializzando la
posizione dei servomotori. Si apre poi una comunicazione seriale a 9600 baud.
M. Scarpiniti
Una Introduzione ad Arduino
39 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Lo sketch in Arduino
Viene quindi creato un buffer di sei elementi di tipo carattere:
char buf []={0 ,0 ,0 ,0 ,0 ,0};
Non appena sono disponibili 6 byte, vengono memorizzati nel buffer appena creato.
La funzione readBytes() restituisce caratteri. Questi caratteri sono convertiti in
numeri interi con la funzione convert() e quindi passati al writeMicroseconds()
che fa spostare i servomotori quanto specificato.
void loop () {
if ( Serial . available () >5) {
int num = Serial . readBytes ( buf ,6) ;
if ( num ==6) {
int * val = convert ( buf ) ;
eyepan . w r i t e M i c r o s e c o n d s ( val [0]) ;
eyetilt . w r i t e M i c r o s e c o n d s ( val [1]) ;
neckpan . w r i t e M i c r o s e c o n d s ( val [2]) ;
}
}
}
Si noti che i 6 caratteri, cioè 6 byte, equivalgono a 3 interi (un intero è 2 byte).
M. Scarpiniti
Una Introduzione ad Arduino
40 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Lo sketch in Arduino
La conversione dai 6 caratteri e ai 3 interi è effettuata con la seguente funzione.
int * convert ( char arr []) {
void * vpt = arr ;
int * pt = ( int *) vpt ;
return pt ;
}
In pratica si dichiara un puntatore all’array di caratteri e si esegue un’operazione di
casting (conversione di tipo) verso il tipo intero:
int * pt = ( int *) vpt ;
Alla fine si restituisce tale puntatore.
M. Scarpiniti
Una Introduzione ad Arduino
41 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Il driver della testa robotica consiste in un file di header, denominato BenderWin.h,
che contiene alcune funzioni per la gestione della stessa, come, ad esempio, l’inizializzazione, la connessione, la lettura e l’invio della posizione e la limitazione
dell’escursione massima consentita dei servomotori. Nelle applicazioni che utilizzeranno la testa robotica, si dovrà includere il file BenderWin.h. Tale file è scritto
per il sistema operativo Windows, ma è disponibile anche la versione BENDER.h per
Mac OS e Linux.
Le funzioni implementate sono le seguenti:
void
void
bool
int
bool
void
Serial ( char * portName ) ;
Serial () ;
IsConnected () ;
ReadData ( char * buffer , unsigned int nbChar ) ;
WriteData ( uint16_t * buffer , unsigned int nbChar ) ;
constrain ( uint16_t & eyepan , uint16_t & eyetilt , uint16_t &
neckpan ) ;
void sendAngles ( uint16_t eyepan , uint16_t eyetilt , uint16_t
neckpan ) ;
double map ( double x , double a , double b , double c , double d ) ;
void c o m p u t e A n d S e n d A n g l e s ( double x0 , double y0 , double z0 ) ;
M. Scarpiniti
Una Introduzione ad Arduino
42 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Si inizia con l’inclusione di tutte le librerie necessarie e la definizione di una variabile
ARDUINO WAIT TIME impostata a 2 secondi.
# include < windows .h >
# include < stdlib .h >
# include < stdio .h >
# include < stdint .h >
# include < tchar .h >
# include < string >
# include < unistd .h >
# include < fcntl .h >
# include < math .h >
# define A R D U I N O _ W A I T _ T I M E 2000
Si passa quindi alla dichiarazione di alcune variabili utili per la gestione della
comunicazione con la testa robotica.
HANDLE hSerial ;
bool connected ;
COMSTAT status ;
DWORD errors ;
M. Scarpiniti
//
//
//
//
//
HANDLE è un tipo di dato trasparente
usato come PUNTATORE ad una risorsa
Stato della connessione
Informazione sulla connessione
Mantiene traccia dell ’ ultimo errore
Una Introduzione ad Arduino
43 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La prima funzione Serial(portName), crea una connessione attraverso la porta
indicata da portName.
void Serial ( char * portName )
{
connected = false ;
// Non ancora connessi
hSerial = CreateFile ( portName ,
// Crea una connessione
GENERIC_READ | GENERIC_WRITE , // Tipo di connessione
0,
// Condivisioni
NULL ,
// Non può generare processi figli
OPEN_EXISTING ,
// Apre la risorsa solo se esiste
FILE_ATTRIBUTE_NORMAL , // Attributi base
NULL ) ; // Eventuale handle se non esiste la risorsa
La funzione CreateFile(), definita in windows.h, ha il compito di creare la
connessione seriale
M. Scarpiniti
Una Introduzione ad Arduino
44 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
A questo punto si verifica la connessione. Se non si è trovata la porta indicata attraverso la funzione GetLastError(), viene stampato il relativo messaggio di errore,
altrimenti c’è stato un errore generico e si stampa semplicemente “ERRORE!!!”.
if ( hSerial == I N V A L I D _ H A N D L E _ V A L U E ) // Verifica la connessione
{
// Se si è riscontrato un errore
if ( GetLastError () == E R R O R _ F I L E _ N O T _ F O U N D )
printf ( " ERRORE : la porta % s non è disponibile .\ n " ,
portName ) ;
else
printf ( " ERRORE !!! " ) ;
}
M. Scarpiniti
Una Introduzione ad Arduino
45 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Altrimenti, se non ci sono stati errori di connessione, si inizializzano i parametri
della comunicazione seriale e se c’è effettivamente comunicazione (verificato tramite
la funzione GetCommState()) tali parametri vengono impostati.
else
{
// Se connesso si impostano i parametri
DCB d cb Se r ia lP ar a ms = {0};
if (! GetCommState ( hSerial , & d cb S er ia l Pa ra ms ) ) // Stato
corrente
printf ( " Non si sono letti i parametri attuali ! " ) ;
else
{
// Parametri per la scheda Arduino
d cb Se ri a lP ar am s . BaudRate = CBR_9600 ;
d cb Se ri a lP ar am s . ByteSize =8;
d cb Se ri a lP ar am s . StopBits = ONESTOPBIT ;
d cb Se ri a lP ar am s . Parity = NOPARITY ;
In particolare vengono impostati il rate di trasmissione (BaudRate), quanti bit da
trasmettere per byte (ByteSize), il numero di stop bits (StopBits) e se c’è il
controllo di parità (Parity).
M. Scarpiniti
Una Introduzione ad Arduino
46 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Con la funzione SetCommState() si settano i parametri sulla scheda. Se c’è stato
un errore si stampa un messaggio di errore, altrimenti si imposta lo stato della
connessione (true) e si attendono due secondi prima di fare altro.
// Verifica dell ’ applicazione dei parametri
if (! SetCommState ( hSerial , & dc b Se ri al P ar am s ) )
{
printf ( " ATTENZIONE : non sono stati impostati i
parametri della Porta Seriale " ) ;
}
else
{
connected = true ; // Se tutto è andato bene
Sleep ( A R D U I N O _ W A I T _ T I M E ) ; // Attende 2 s prima
di resettare Arduino
}
}
}
}
M. Scarpiniti
Una Introduzione ad Arduino
47 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La funzione Serial() (senza argomenti) si occupa di disconnettere la scheda, se
precedentemente era connessa.
void Serial ()
{
if ( connected )
// Se era connessa
{
connected = false ;
// Ora è disconnessa
CloseHandle ( hSerial ) ; // L ’ handle viene chiuso
}
}
La funzione CloseHandle(), definita in windows.h, si occupa di chiudere
l’handel relativo ad un certo numero di oggetti, tra cui le connessioni seriali.
Accetta come argomento di ingresso l’handle relativo alla risorsa da chiudere.
M. Scarpiniti
Una Introduzione ad Arduino
48 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La funzione ReadData() legge un numero nbChar di caratteri, salvandoli nel vettore buffer. Dopo aver verificato lo stato della comunicazione, se sono arrivati
un certo numero di caratteri maggiori di quelli da leggere, si pone la variabile di
appoggio toRead al valore desiderato nbChar.
int ReadData ( char * buffer , unsigned int nbChar )
{
DWORD bytesRead ;
// Numero di byte letti
unsigned int toRead ; // Numero di byte da leggere
Clea rCommErr or ( hSerial , & errors , & status ) ;
porta seriale
// Stato della
if ( status . cbInQue >0) // Se è stato letto qualcosa
{
if ( status . cbInQue > nbChar ) // Se sono arrivati
sufficienti dati
{
toRead = nbChar ;
}
M. Scarpiniti
Una Introduzione ad Arduino
49 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Altrimenti si pone la variabile di appoggio toRead al numero di caratteri correntemente letti e li si legge con la funzione ReadFile().
else
{
toRead = status . cbInQue ;
}
// Cerca di leggere il numero di dati richiesto
if ( ReadFile ( hSerial , buffer , toRead , & bytesRead , NULL )
&& bytesRead != 0)
{
return bytesRead ;
}
}
return -1;
// Se non è stato letto nulla
}
M. Scarpiniti
Una Introduzione ad Arduino
50 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La funzione WriteData() invia alla porta seriale un buffer di dati lungo nbChar.
A tal proposito, utilizza la funzione WriteFile() e se c’è stato un errore nella
scrittura dei dati, si chiude la comunicazione con la funzione ClearCommError().
Ritorna un valore booleano a seconda dell’esito della scrittura dei dati.
bool WriteData ( uint16_t * buffer , unsigned int nbChar )
{
DWORD bytesSend ;
// Cerca di scrivere il buffer sulla porta seriale
if (! WriteFile ( hSerial , ( void *) buffer , nbChar , & bytesSend ,
0) )
{
Clea rCommErr or ( hSerial , & errors , & status ) ; // Status
della porta seriale
return false ;
}
else
return true ;
}
M. Scarpiniti
Una Introduzione ad Arduino
51 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La funzione IsConnected() verifica semplicemente lo stato della connessione.
bool IsConnected ()
{
// Ritorna semplicemente lo stato della connessione
return connected ;
}
La funzione map(), associa al valore x, il seguente valore y :
y=
(x − a) (d − c)
+ c.
b−a
Tale valore serve a mappare gli angoli di rotazione dei servomotori all’interno di un
intervallo massimo di escursione, al fine di evitare danni meccanici.
double map ( double x , double a , double b , double c , double
return (( x - a ) *( d - c ) /( b - a ) ) + c ;
}
M. Scarpiniti
Una Introduzione ad Arduino
d){
52 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La funzione constrain() vincola la massima escursione che i servomotori potranno compiere, in modo da evitare angoli pericolosi che potrebbero danneggiare i
dispositivi.
void constrain ( uint16_t eyepan , uint16_t eyetilt , uint16_t
neckpan ) {
eyepan = eyepan <950?950:( eyepan >1610?1610: eyepan ) ;
eyetilt = eyetilt <1370?1370:( eyetilt >1970?1970: eyetilt ) ;
neckpan = neckpan <750?750:( neckpan >2200?2200: neckpan ) ;
}
Tali limiti corrispondono a:
pan dell’occhio: [950 − −160] µs ≈ 70◦ ;
tilt dell’occhio: [1370 − −1970] µs ≈ 70◦ ;
pan del collo: [750 − −2200] µs ≈ 160◦ .
M. Scarpiniti
Una Introduzione ad Arduino
53 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
La funzione sendAngles invia i dati relativi agli angoli dei tre servomotori attraverso la connessione seriale. Tale funzione, dopo aver vincolato la massima escursione
tramite constrain(), scrive i tre angoli (contenuti nell’array data) utilizzando
la funzione WriteData() vista precedentemente. Nel caso di errore stampa un
messaggio.
void sendAngles ( uint16_t eyepan , uint16_t eyetilt , uint16_t
neckpan ) {
uint16_t data [3];
data [0]= eyepan ;
data [1]= eyetilt ;
data [2]= neckpan ;
constrain ( data [0] , data [1] , data [2]) ; // Limita le escursioni
if ( IsConnected () ) { // Se è connesso mando i dati
WriteData (& data [0] , 2) ;
WriteData (& data [1] , 2) ;
WriteData (& data [2] , 2) ;
}
else
printf ( " Il dispositivo NON è connesso .\ n " ) ;
}
M. Scarpiniti
Una Introduzione ad Arduino
54 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Infine la funzione computeAndSendAngles() trasforma una coordinata cartesiana
[x0 , y0 , z0 ], espressa nella terna di riferimento solidale alla testa, negli angoli da
passare ai servomotori per orientare la testa e gli occhi verso il punto in questione,
inviando tali dati attraverso la connessione seriale.
void c o m p u t e A n d S e n d A n g l e s ( double x0 , double y0 , double z0 ) {
double x = x0 ;
double y = y0 -24;
// Le webcam sono a 24 cm dalla base
double z = z0 -5.5;
// Le webcam distano 5.5 cm dall ’ asse
double r = sqrt ( x * x + z * z ) ; // Uso le coordinate polari
double phi = atan2 (y , r ) ; // Angolo del tilt dell ’ occhio
double max35 = (( double ) 35/180) * M_PI ;
double max4 = (( double ) 4/9) * M_PI ;
if ( phi > max35 )
phi = max35 ;
else if ( phi < - max35 )
phi = - max35 ;
M. Scarpiniti
Una Introduzione ad Arduino
// 35 gradi
// 80 gradi
// -35 <= phi <= 35
55 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
Si controlla che gli angoli non eccedono i limiti impostati (nel caso impostando il
valore massimo) e si stampa sul prompt il valore dei tre angoli.
double thetaneck = atan2 (x , z ) ; // Pan del collo
double thetaeye ;
// Pan dell ’ occhio
if ( thetaneck > max4 ) {
thetaeye = thetaneck - max4 ;
thetaneck = max4 ;
// -35 <= thetaeye <= 35
if ( thetaeye > max35 * M_PI ) // -80 <= thetaneck <= 80
thetaeye = max35 * M_PI ;
}
else if ( thetaneck < - max4 ) {
thetaeye = thetaneck + max4 ;
thetaneck = - max4 ;
if ( thetaeye < - max35 * M_PI )
thetaeye = - max35 * M_PI ;
} else
thetaeye =0;
printf ( " Angles ( eyepan , tilt , neckpan ) : % f % f % f \ n \ n " ,
thetaeye , phi , thetaneck ) ;
M. Scarpiniti
Una Introduzione ad Arduino
56 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il driver per Bender
A questo punto, i tre valori calcolati vengono convertiti nel valore corretto da
passare alla scheda attraverso la funzione map() e trasformati in interi a 16 bit.
Infine, la terna appena calcolata viene inviata alla scheda con la precedente funzione
sendAngles().
double neckpand = map ( thetaneck , - max4 , max4 ,750 ,2200) ;
double eyepand = map ( thetaeye , - max35 , max35 ,1610 ,950) ;
double eyetiltd = map ( phi , - max35 , max35 ,1990 ,1370) ;
uint16_t neckpan =( uint16_t ) ( neckpand ) ;
uint16_t eyepan =( uint16_t ) ( eyepand ) ;
uint16_t eyetilt =( uint16_t ) ( eyetiltd ) ;
sendAngles ( eyepan , eyetilt , neckpan ) ;
}
M. Scarpiniti
Una Introduzione ad Arduino
57 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il funzionamento della testa robotica
La testa robotica funziona con due algoritmi di localizzazione che lavorano congiuntamente.
1
localizzazione binaurale: utilizza l’audio raccolto dai due microfoni per
localizzare la coordinata del parlatore. E’ basata sulle due grandezze
seguenti:
ILD (Interaural Level Difference): differenza del livello sonoro tra i due
sensori;
ITD (Interaural Time Difference): differenza tra i tempi di arrivo
dell’onda sonora ai due sensori.
2
face detection: utilizza una delle due webcam. Utilizza il metodo di
Viola-Jones, basato sull’estrazione delle features di Haar.
Purtroppo, negli ambienti indoor reali il riverbero introduce un errore nella
localizzazione acustica. A tal proposito, per correggere tale errore (angolare) si
utilizza il face detector: la testa si “aggancia” alla faccia e la segue per qualche
istante.
M. Scarpiniti
Una Introduzione ad Arduino
58 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La localizzazione binaurale
Il modello della localizzazione binaurale è il seguente:
xl [n] = hl [n] ∗ s[n] + ηl [n],
xr [n] = hr [n] ∗ s[n] + ηr [n],
in cui s[n] è il segnale del parlatore, hl [n] e hr [n] sono le risposte impulsive del
canale sinistro e destro, xl [n] e xr [n] sono i segnali raccolti dal sensore sinistro e
destro, e ηl [n], ηr [n] sono due eventuali rumori additivi.
Per il calcolo dell’ILD e ITD, si effettua la Short Time Fourier Transform (STFT)
dei segnali xl [n] e xr [n], ottenendo per l’n-esimo frame
Xln (ω, θ, φ) ,
Xrn (ω, θ, φ) ,
in cui ω è la frequenza, θ e φ sono gli angoli di elevazione e azimut,
rispettivamente.
M. Scarpiniti
Una Introduzione ad Arduino
59 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La localizzazione binaurale: ILD
L’Interaural Level Difference o ILD è calcolato, per il generico frame n, nel seguente
modo:
n
Xr (ω, θ, φ) n
.
ILD (ω, θ, φ) = 20 log10 n
X (ω, θ, φ) l
Esprime dunque, in dB, la differenza dei moduli del segnale ricevuto al sensore destro rispetto a quello ricevuto al sensore sinistro. Descrive il fenomeno dell’effetto
ombra provocato dalla testa. Tale indice diviene ambiguo al di sotto di circa 1.5
kHz in quanto l’effetto ombra provocato dalla testa è nullo.
M. Scarpiniti
Una Introduzione ad Arduino
60 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La localizzazione binaurale: ITD
L’Interaural Time Difference o ITD è calcolato, per il generico frame n, nel seguente
modo:
X n (ω, θ, φ)
1
∠ rn
+ 2πp .
ITD n (ω, θ, φ) =
ω
Xl (ω, θ, φ)
Esprime dunque, la differenza di fase tra il segnale ricevuto al sensore destro e quello
ricevuto al sensore sinistro. La variabile p costituisce un fattore di molteplicità della
fase e, purtroppo, non è noto a priori. Tale indice diviene ambiguo al di sopra di
circa 1.5 kHz per via della molteplicità.
M. Scarpiniti
Una Introduzione ad Arduino
61 / 69
L’hardware
Il software
Il funzionamento
Introduzione
La Testa Robotica
La localizzazione binaurale: le HRTF di riferimento
La localizzazione avviene per confronto degli indicatori ILD e ITD calcolati con
quello relativo a un database di riferimento di HRTF (Head Related Transfer
Function). Tali funzioni sono valutate mantenendo fissa l’elevazione θ:
HRTFrn (ω, φ) ,
ILD (ω, φ) = 20 log10 HRTFln (ω, φ) 1
HRTFrn (ω, φ)
n
∠
+ 2πp .
ITD (ω, φ) =
ω
HRTFln (ω, φ)
n
Esiste un database, il CIPIC, che contiene 45 HRTF registrati su persone reali e
un manichino KEMAR. In particolare, per la localizzazione Bender utilizza il
soggetto 21, corrispondente al manichino.
M. Scarpiniti
Una Introduzione ad Arduino
62 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La localizzazione binaurale: le HRTF di riferimento
hange dramatically across azimuth [3]. Smoothing across azimuth with a
ant Q filter was performed on the ILD lookup set in order to better represent
mits of human interaural level difference perception. More specifically, a
sian filter was employed, as indicated in the CIPIC database [5].
omparison between the ILD and ITD lookup sets and the estimated ILD
TD allows to estimate the azimuth of the sound source. In particular ILD
ploited to find the correct value of the unwrapping factor p and to select
zimuth value minimizing the difference between the ITD-only and ILDestimates. This p-estimation procedure was repeated for each available time
e. A time average across frames was performed and the results graphed.
final azimuth estimations selected were those displaying a minimum in the
T
T
ence function that was consistent across frequencies.
n simulations with
n,pthe
s an example, fig. 2 shows the results obtained in
e placed at different azimuth angles. Joint exploitation of ILD and ITD
s to obtain an azimuth estimate which is correct over the whole frequency
L
and for different positions of the source.
n
Si effettua la differenza tra i valori di ILD e ITD calcolati dai segnali registrati
T
e le HRTF, prendendo i valori minimi θnL (ω) e θn,p
(ω): al minimo corrisponderà
T
l’angolo corrispondente al parlatore. Rimane una ambiguità su θn,p
(ω) dovuta alla
scelta di p. Tale ambiguità è risolta prendendo il valore di p che rende minimo
l’ITD, cioè
θ (ω) = θ (ω)p=argmin θT (ω)
}
p { n,p
Infine si effettua la media dei valori θ (ω) e θnT (ω) su tutti i frame n, ottenendo le
stime finali θL (ω) e θT (ω) per ogni frequenza.
ILD
ILD
ILD
ILD
8
8
8
8
6
6
6
6
6
4
2
4
2
4
2
4
2
4
2
ITD
Frequency [kHz]
ILD
8
ITD
ITD
ITD
8
6
8
6
8
6
8
6
8
6
4
4
4
4
4
2
2
2
2
Joint
Joint
8
6
8
6
4
2
−80 0
Joint
4
2
80
M. Scarpiniti
−80 0
80
2
Joint
8
6
8
6
4
2
4
2
Mediando quindi in frequenza, è possibile
determinare la direzione media θL e θT .
Utilizzando congiuntamente queste due
informazioni (media) è dunque possibile ottenere
una stima θ della direzione del parlatore.
ITD
−80 0 80
−80 0
Azimuth [degrees]
Joint
8
6
4
2
80
−80 0
80
Una Introduzione ad Arduino
2. Source azimuth estimate in an anechoic room and Gaussian noise: ILD, ITD
63 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
La localizzazione binaurale
E’ possibile riassumere la localizzazione binaurale implementata, nei passi riportati
nel seguente algoritmo:
1:
2:
3:
4:
5:
6:
7:
8:
9:
for n = 1 to Nf do
Calcolo di ILD n (ω, θ, φ) e ITD n (ω, θ, φ);
Calcolo dei riferimenti ILD n (ω, φ) e ITD n (ω, φ);
T
Stima delle differenze θnL (ω) e θn,p
(ω);
Stima del valore ottimale di p e quindi di θnT (ω);
end for
Media su tutti i frames, ottenendo θL (ω) e θT (ω);
Media su tutte le frequenze, ottenendo θL e θT ;
Stima della direzione di arrivo θ basata sull’utilizzo congiunto di θL e θT .
Nf indica il numero totale di frames utilizzati.
M. Scarpiniti
Una Introduzione ad Arduino
64 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il face detector
Il riconoscimento facciale è ottenuto tramite il metodo di Viola-Jones (VJM),
implementato in C nella librerie OpenCV. Il processo di rilevazione classifica le immagini basandosi sui valori di specifiche feature piuttosto che sul valore di intensità
dei singoli pixel. I concetti chiave sono quattro:
1
Haar features: ottenute per somme e differenze delle somme dei valori dei
pixel in zone chiare e scure;
2
integral image, per la rilevazione veloce delle feature: determina la
presenza o assenza di centinaia di queste features per tutta l’immagine e con
diverse scalature;
3
il metodo di Machine Learning AdaBoost: la procedura seleziona vari
classificatori deboli e ne fa una combinazione pesata, cosi da ottenere un
classificatore robusto;
4
un classificatore a cascata per la combinazione efficiente delle molteplici
features: combina una serie di classificatori AdaBoost in cascata, catena
particolarmente efficiente per la classificazione di porzioni di immagini.
M. Scarpiniti
Una Introduzione ad Arduino
65 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il face detector: tracking
Una volta estratta la regione video contenente la rivelazione della faccia, è necessario manipolare gli angoli di tilt e pan della testa facendo si che la faccia stessa
venga fatta posizionare, in vari step, sempre al centro del video in esame.
La realizzazione del controllo è realizzata con un sistema di retroazione ad anello
chiuso in cui una coppia di controlli proporzionali è impiegata per correggere la
differenza di posizione tra il centro della faccia rilevata e il centro del frame video.
Uno dei due regolatori correggerà la differenza in direzione orizzontale, l’altro in
direzione verticale. Tale sistema è rappresentato nella seguente figura.
Proportional controller
Input
coordinates
M. Scarpiniti
e t 
Una Introduzione ad Arduino
Kp
u t 
Head
actuators
Output
coordinates
66 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Il software per la localizzazione audio-video
Le funzioni utilizzate per la localizzazione sono contenute nel file recording.cpp,
mentre i prototipi delle funzioni che utilizzano l’audio e il video sono contenuti nel
file recording.h:
int camdetect () ;
void detectAndDraw ( Mat & img , C a s c a d e C l a s s i f i e r & cascade ,
C a s c a d e C l a s s i f i e r & nestedCascade , double scale ) ;
static int reco rdCallba ck ( ) ;
static int playCallback ( ) ;
double STFT ( SAMPLE chLeft [] , SAMPLE chRight [] , int signalLength ,
int hopSize ) ;
Tali funzioni attivano la wecam, identificano le facce (disegnando un rettangolo
in corrispondenza del volto) e registrano l’audio. La localizzazione è effettuata
all’interno della funzione STFT(), che calcola anche la STFT dei segnali
registrati.
M. Scarpiniti
Una Introduzione ad Arduino
67 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Integrazione audio-video
CAPITOLO 5. LA TESTA ROBOTICA: PARTE AUDIO
97
L’algoritmo di face tracking andrà a coadiuvare
quello basato sull’audio, in modo da perseguire
una stima dell’angolo di arrivo attraverso il matching delle informazioni provenienti dalla catena
video e da quella audio. Una volta localizzata
la provenienza del suono, e mossa la testa di
conseguenza, la funzione camdetect() darà luogo alla localizzazione video. La testa, a partire
dall’angolo stimato dal lato audio, affinerà la stima inquadrando il volto del soggetto pronunciante la parola. La localizzazione video durerà qualche secondo, dopo di che si procederà nuovamente
al controllo della soglia sui frame, per dar luogo
eventualmente a una nuova localizzazione audio.
L’intero procedimento è illustrato nel diagramma
a lato.
Figura 5.7: Diagramma di flusso dell’algoritmo di localizzazione
M. Scarpiniti
Una Introduzione ad Arduino
68 / 69
Introduzione
La Testa Robotica
L’hardware
Il software
Il funzionamento
Bibliografia
Arduino Tutorials.
https://www.arduino.cc/en/Tutorial/HomePage.
M. Margolis.
Arduino - Progetti e soluzioni.
O’Reilly, 2013.
M. Banzi e M. Shiloh.
Arduino – La guida ufficiale.
Tecniche Nuove, 2015.
M. Schmidt.
Il manuale di Arduino.
APOGEO, 2011.
S. Majocchi.
Arduino UNO. Programmazione avanzata e librerie di sistema.
Vispa, 2012.
D. J. Russell.
Introduction to Embedded Systems: Using ANSI C and the Arduino Development Environment.
Morgan and Claypool Publishers, 2010.
M. Scarpiniti
Una Introduzione ad Arduino
69 / 69