Marvin: progetto e sviluppo di un robot real-time guidato

Transcript

Marvin: progetto e sviluppo di un robot real-time guidato
Università Politecnica delle Marche
Facoltà di Ingegneria
Dipartimento di Ingegneria dell’Informazione
Corso di Laurea Triennale in Ingegneria Informatica e dell’Automazione
Marvin: progetto e sviluppo di un robot
real-time guidato da informazioni visive
Tesi di:
Francesco Di Benedetto
Relatore:
Prof. Aldo Franco Dragoni
Correlatore:
Dott. Andrea Claudi
Anno Accademico 2011/2012
Università Politecnica delle Marche
Facoltà di Ingegneria
Dipartimento di Ingegneria dell’Informazione
Corso di Laurea Triennale in Ingegneria Informatica e dell’Automazione
Marvin: progetto e sviluppo di un robot
real-time guidato da informazioni visive
Tesi di:
Francesco Di Benedetto
Relatore:
Prof. Aldo Franco Dragoni
Correlatore:
Dott. Andrea Claudi
Anno Accademico 2011/2012
Dipartimento di Ingegneria dell’Informazione
Università Politecnica delle Marche
Facoltà di Ingegneria
Via Brecce Bianche – 60131 Ancona (AN), Italy
Al mio caro nonno Guido
Ringraziamenti
Il paragrafo dedicato ai ringraziamenti è sicuramente il più bello da scrivere ma anche il più complesso.
Voglio ringraziare mio nonno Guido, a cui questa tesi è dedicata, che avrebbe dato di tutto per vedermi
finalmente Dottore: a lui va il mio pensiero più grande e spero che da lassù possa comunque gioirne. Non
posso però mettere in secondo piano tutta la mia famiglia che in questi anni mi ha sempre supportato e
fatto coraggio, per me è stato fondamentale considerando soprattutto il mio carattere! Grazie Mamma e
grazie Papà per la vostra vicinanza e comprensione sulle quali ho sempre potuto contare.
Non posso nemmeno dimenticare tutti gli amici che durante questo percorso mi sono stati vicino e con
cui ho condiviso i momenti più belli di questi anni universitari, tra gli altri uno speciale ringraziamento
va a Francesco e Luca.
Un sincero ringraziamento al Prof. Aldo Franco Dragoni per avermi dato la possibilità di lavorare
a questo bellissimo progetto che mi ha coinvolto per interi mesi, risultando un’esperienza fantastica
ed ottima per concludere questo percorso di studio di primo livello. Questa tesi mi ha permesso di
sperimentare argomenti che hanno spaziato dall’Informatica all’Automazione, passando per l’Elettronica.
Un doveroso ringraziamento va anche ai ragazzi del dipartimento del DII e principalmente al laboratorio
di Intelligenza Artificiale e Sistemi in Tempo Reale, tra i quali il correlatore Andrea Claudi. Lui è stato
una figura fondamentale per lo sviluppo di questo lavoro essendo sempre presente con il suo supporto e i
suoi consigli.
Ancona, Luglio 2012
Francesco Di Benedetto
v
Sommario
Nel linguaggio comune, un robot è un’apparecchiatura artificiale che compie determinate azioni sia
basandosi sulle istruzioni assegnate, sia autonomamente.
In questo lavoro il robot realizzato prevede esclusivamente un funzionamento autonomo. Esso è concepito per fornire una base hardware semplice e affidabile, rendendo possibile sviluppare in maniera indipendente applicazioni di alto livello basate sul sistema operativo mobile Android, disponibile tipicamente
su smartphone e tablet.
Le modalità di utilizzo del robot denominato Marvin - dall’androide paranoico di Guida galattica per
gli autostoppisti scritto da Douglas Adams - sono molteplici e vanno dall’aspetto puramente didattico
e di ricerca in ambito universitario fino a scenari più complessi quali la videosorveglianza e l’assistenza
personale.
Risulta interessante notare come la progettazione di questo sistema embedded ponga su piani diametralmente opposti l’attuazione di un comando dall’applicazione, e quindi dal cervello, del robot seguendo
la filosofia del Plug & Play; qualsiasi possessore di uno smartphone potrebbe sviluppare la sua applicazione utilizzando le primitive di movimento esposte dal robot in maniera separata dall’hardware essendo
certo sia che il dispositivo venga supportato, sia che l’applicazione con possa attuare i suoi comandi attraverso un sistema hardware di una certa complessità - utilizzando un set di API.
vi
Indice
1. Introduzione
1.1. Stato dell’arte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2. Obiettivi della tesi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3. Struttura del lavoro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2. Componenti di Marvin
2.1. Flex Full . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2. Convertitore TTL-USB PL2303 . . . . . . . . . . . . . . .
2.3. FTDI Vinculum-II . . . . . . . . . . . . . . . . . . . . . .
2.4. Libreria Open Accessory . . . . . . . . . . . . . . . . . . .
2.5. Arduino Mega ADK . . . . . . . . . . . . . . . . . . . . .
2.6. Control Module basato su chip Motion Processor MC3410
2.7. Servomotori DFRobotics DF15SR e Hitec HS-485HB . . .
2.8. Smartphone Android . . . . . . . . . . . . . . . . . . . . .
2.9. Circuito di Alimentazione, led e breadboard . . . . . . . .
3. Ambienti di sviluppo
3.1. Eclipse Indigo con Android SDK . . .
3.2. RT-Druid e ERIKA Enterprise v1.6.1 .
3.3. Microchip MPLAB v8.43 . . . . . . .
3.4. Arduino IDE v1.0 . . . . . . . . . . . .
3.5. Vinculum-II IDE v1.4.4 . . . . . . . .
3.6. RealTerm v2.0 . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
2
3
.
.
.
.
.
.
.
.
.
4
4
9
9
11
11
14
14
17
18
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
20
20
24
29
30
32
34
4. Analisi dei Requisiti e Progettazione del Sistema
4.1. Analisi dei Requisiti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Requisiti Funzionali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1. Dotare il robot dei movimenti spaziali tramite API portabili . . . .
4.2.2. Garantire un canale di comunicazione con ogni dispositivo Android
4.2.3. Garantire una comunicazione affidabile con Arduino . . . . . . . .
4.2.4. Implementare algoritmi di visione su Android . . . . . . . . . . . .
4.2.5. Aggiungere il motore che permette uno snodo “di testa” . . . . . .
4.3. Requisiti Aggiuntivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.1. Elaborazione tramite RTOS ERIKA . . . . . . . . . . . . . . . . .
4.3.2. Migliorare il programma di visione . . . . . . . . . . . . . . . . . .
4.3.3. Sostituire il Motion Processor . . . . . . . . . . . . . . . . . . . . .
4.3.4. Implementare un controllore PID . . . . . . . . . . . . . . . . . . .
4.3.5. Comunicazione wifi tramite Android . . . . . . . . . . . . . . . . .
4.4. Architettura e funzionamento del sistema . . . . . . . . . . . . . . . . . .
4.5. Protocolli di comunicazione . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5.1. Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.5.2. Arduino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
36
36
37
37
37
38
38
38
38
39
39
39
40
40
40
41
41
42
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
vii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Indice
4.5.3. Flex Full Board . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5. Implementazione del Software
5.1. Librerie Flex Full . . . . . . . . . . . . . . . . . . . .
5.1.1. Libreria EEuart.h . . . . . . . . . . . . . . .
5.1.2. Libreria Arduino.h . . . . . . . . . . . . . . .
5.1.3. Libreria Utility.h . . . . . . . . . . . . . . .
5.1.4. Libreria serialConsole.h . . . . . . . . . .
5.1.5. Libreria Servo.h . . . . . . . . . . . . . . . .
5.1.6. Libreria PWM.h . . . . . . . . . . . . . . . . .
5.1.7. Libreria PID.h . . . . . . . . . . . . . . . . .
5.2. Componenti Hardware Flex Full . . . . . . . . . . .
5.2.1. Oscillatori . . . . . . . . . . . . . . . . . . . .
5.2.2. USART . . . . . . . . . . . . . . . . . . . . .
5.2.3. Modulazione a Larghezza di Impulso (PWM)
5.3. RTOS ERIKA Enterprise . . . . . . . . . . . . . . .
5.4. Implementazione dell’applicazione ERIKA . . . . . .
5.5. Firmware Arduino . . . . . . . . . . . . . . . . . . .
5.6. Applicazioni Android . . . . . . . . . . . . . . . . . .
5.6.1. Caratteristiche comuni tra le due applicazioni
5.6.2. Differenze tra le due applicazioni Android . .
5.7. OpenCV e Linear Binary Pattern (LBP) . . . . . . .
43
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
44
44
44
45
45
45
46
46
47
47
47
49
51
54
58
60
62
62
66
75
6. Il Sistema di Controllo
6.1. Il controllore PID a tempo continuo: generalità . . . . . . . . . . . . . . . . . . . . . . . .
6.2. Il controllore PID a tempo discreto: generalità . . . . . . . . . . . . . . . . . . . . . . . .
6.3. Taratura dei parametri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
77
77
80
81
7. Conclusioni e sviluppi futuri
7.1. Test di funzionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2. Obiettivi raggiunti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3. Sviluppi futuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
83
84
85
A. Dettagli di cablaggio
87
B. Software utilizzato
92
viii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Elenco delle figure
1.1. AndroEEbot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2.1. Flex Full e Flex Base . . . . . . . . . . . . . . . . . . . . . .
2.2. Pinout del dsPIC . . . . . . . . . . . . . . . . . . . . . . . .
2.3. Funzioni e connettori della scheda Flex Full . . . . . . . . .
2.4. Microchip ICD 2 . . . . . . . . . . . . . . . . . . . . . . . .
2.5. Pinout della scheda Flex Full . . . . . . . . . . . . . . . . .
2.6. Retro e pinout del PL2303 . . . . . . . . . . . . . . . . . . .
2.7. Fronte del PL2303 . . . . . . . . . . . . . . . . . . . . . . .
2.8. Vinculum-II . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.9. Modulo di debug V2DIP2 . . . . . . . . . . . . . . . . . . .
2.10. Arduino Mega ADK . . . . . . . . . . . . . . . . . . . . . .
2.11. Pinout ATMega2560 . . . . . . . . . . . . . . . . . . . . . .
2.12. Hardware per il controllo del movimento di AndroEEBot . .
2.13. Esempio di onda rettangolare generata con la PWM . . . .
2.14. Servomotore HS-485HB . . . . . . . . . . . . . . . . . . . .
2.15. Corrispondenza tra angoli e tempi di T-on in microsecondi .
2.16. DF15SR con “Horns” . . . . . . . . . . . . . . . . . . . . . .
2.17. HTC Evo 3D . . . . . . . . . . . . . . . . . . . . . . . . . .
2.18. Regolatore di tensione LM7805CV . . . . . . . . . . . . . .
2.19. Circuito regolatore di tensione positiva stabilizzata . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
6
7
7
8
9
9
9
10
11
13
14
15
15
15
16
17
18
19
3.1. Architettura di Android . . . . . . . . . .
3.2. Ciclo di vita di una activity . . . . . . . .
3.3. Repository Android . . . . . . . . . . . .
3.4. Librerie Android . . . . . . . . . . . . . .
3.5. Proprietà del progetto e link delle librerie
3.6. Repository RT-Druid . . . . . . . . . . . .
3.7. Link librerie MPLAB . . . . . . . . . . . .
3.8. Build del progetto . . . . . . . . . . . . .
3.9. RT-Druid IDE . . . . . . . . . . . . . . .
3.10. Log della programmazione del dsPIC . . .
3.11. Setup ICD2 e MPLAB . . . . . . . . . . .
3.12. Selezione prototype board . . . . . . . . .
3.13. Vinculum IDE toolchain . . . . . . . . . .
3.14. Architettura Vinculum-II . . . . . . . . .
3.15. IDE del Vinculum-II . . . . . . . . . . . .
3.16. Ricezione dati dalla scheda Flex . . . . . .
3.17. Invio dati alla scheda Flex . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
20
21
22
23
23
25
26
27
27
29
30
31
33
33
34
35
35
4.1. Assi di Marvin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Flowchart per l’algoritmo di controllo del movimento . . . . . . . . . . . . . . . . . . . . .
38
39
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
ix
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Elenco delle figure
4.3. L’architettura a 4 livelli di Marvin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
5.1. Determinazione di Fosc . . . . . . . . . . . . . . . . . . . . . . .
5.2. Architettura hardware di una periferica USART . . . . . . . . .
5.3. Il protocollo UART . . . . . . . . . . . . . . . . . . . . . . . . .
5.4. Generazione dell’onda PWM . . . . . . . . . . . . . . . . . . .
5.5. Modifica del valore di duty cycle “on-the-fly” . . . . . . . . . .
5.6. API del kernel Erika Enterprise . . . . . . . . . . . . . . . . . .
5.7. Algoritmo di individuazione di un volto . . . . . . . . . . . . .
5.8. Calcolo delle coordinate e degli errori nell’applicazione “Marvin
5.9. Architettura della libreria OpenCV . . . . . . . . . . . . . . . .
5.10. Funzionamento dell’algoritmo LBP . . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
PID”
. . . .
. . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
49
50
51
52
53
57
66
72
75
76
6.1.
6.2.
6.3.
6.4.
6.5.
6.6.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
78
78
79
79
80
82
7.1. Architettura finale di Marvin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2. Marvin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
86
A.1.
A.2.
A.3.
A.4.
A.5.
A.6.
A.7.
A.8.
A.9.
87
88
88
89
89
90
90
91
91
Controllore PID . . . . . . . . . . . . . . . . . . . . . . . .
Azioni proporzionali a confronto per un ingresso a gradino
Azioni integrali a confronto per un ingresso a gradino . .
Azioni derivatrici a confronto per un ingresso a gradino .
Schema a blocchi di un sistema a dati campionati . . . . .
Ku e Tu . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Connessione Flex-Arduino tramite USART1 . . . . . . . . . . . . . . .
Connessione Flex-Convertitore tramite USART2 . . . . . . . . . . . .
Connessione Flex-Servomotore di testa tramite PWM1 . . . . . . . . .
Dettaglio del servomotore di testa . . . . . . . . . . . . . . . . . . . .
Connessione Flex-servomotori di propulsione tramite PWM2 e PWM3
Dettaglio dei servomotori di propulsione alloggiati sotto la struttura .
Connessione Flex e Arduino ai led presenti sulla breadboard . . . . . .
Circuito di alimentazione e linee di tensione . . . . . . . . . . . . . . .
Connessione Arduino-Smartphone tramite cavo USB . . . . . . . . . .
x
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Elenco delle tabelle
2.1. Coppia di stallo per il servo DF15SR a diversi valori di tensione . . . . . . . . . . . . . . .
17
4.1.
4.2.
4.3.
4.4.
Formato
Formato
Formato
Formato
A.1.
A.2.
A.3.
A.4.
A.5.
A.6.
A.7.
Connessione Flex-Arduino tramite USART1 . . . . . . . . . .
Connessione Flex-Convertitore tramite USART2 . . . . . . .
Connessione Flex-Servomotore di testa tramite PWM1 . . . .
Connessione Flex-servomotore di propulsione tramite PWM2
Connessione Flex-servomotore di propulsione tramite PWM3
Connessioni Flex-led . . . . . . . . . . . . . . . . . . . . . . .
Connessioni Arduino-led . . . . . . . . . . . . . . . . . . . . .
del
del
del
del
pacchetto
pacchetto
pacchetto
pacchetto
trasmesso
trasmesso
trasmesso
trasmesso
dall’applicazione Android “Marvin Grid View” .
dall’applicazione Android “Marvin PID” . . . . .
da Arduino nell’applicazione “Marvin Grid View”
da Arduino nell’applicazione “Marvin PID” . . .
xi
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
42
42
43
43
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
87
87
88
89
89
90
90
Capitolo 1.
Introduzione
Nel linguaggio comune, un robot è un’apparecchiatura artificiale che compie determinate azioni sia
basandosi sulle istruzioni assegnate, sia autonomamente.
In questo lavoro il robot realizzato prevede esclusivamente un funzionamento autonomo. Esso è concepito per fornire una base hardware semplice e affidabile, rendendo possibile sviluppare in maniera indipendente applicazioni di “alto livello” basate sul sistema operativo mobile Android, disponibile tipicamente
su smartphone e tablet.
Le modalità di utilizzo del robot denominato Marvin – dall’androide paranoico di Guida galattica per
gli autostoppisti scritto da Douglas Adams – sono molteplici e vanno dall’aspetto puramente didattico
e di ricerca in ambito universitario fino a scenari più complessi quali la videosorveglianza e l’assistenza
personale.
Risulta interessante notare come la progettazione di questo sistema embedded ponga su piani diametralmente opposti l’attuazione di un comando dall’applicazione, e quindi dal “cervello”, del robot seguendo
la filosofia del “Plug & Play”; qualsiasi possessore di uno smartphone potrebbe sviluppare la sua applicazione utilizzando le primitive di movimento esposte dal robot in maniera separata dall’hardware essendo
certo sia che il dispositivo venga supportato, sia che l’applicazione con possa attuare i suoi comandi attraverso un sistema hardware di una certa complessità - utilizzando un set di API.
1.1. Stato dell’arte
Lo sviluppo di Marvin nasce dalle ceneri di AndroEEbot (vedi fig. 1.1), dotato di funzionamento simile
ma di architettura più complessa.
La tesi ha come obiettivo una riprogettazione totale del sistema, con l’utilizzo di componenti hardware
più idonei, accessibili e poco costosi e in grado di interfacciarsi con dispositivi di origini diverse.
AndroEEbot basava i suoi spostamenti sul Motion Processor e riceveva dati solo da particolari telefoni
Android come il Nexus S, interfacciando questi componenti con il microcontrollore Flex Full sul quale è
in esecuzione Erika Enterprise, un sistema operativo real-time embedded.
Attraverso il Vinculum II, dispositivo dotato di due porte usb e una porta USART, i tre dispositivi
sopra citati erano messi in comunicazione. Il Vinculum-II quindi era impiegato come hub tra i vari
dispositivi.
1
Capitolo 1. Introduzione
Figura 1.1.: AndroEEbot
1.2. Obiettivi della tesi
Gli obiettivi e la direzioni intraprese per migliorare il progetto esistente e aggiungere nuove funzionalità
per evolvere il precedente sistema sono stati molteplici tra cui:
1. Definizione e studio del sistema e degli ambienti di sviluppo necessari: acquisizione e padronanza
tale che la loro configurazione diventi una procedura standardizzata da inserire in un “how-to”.
2. Semplificazione del “sistema a basso livello”. Questo significa avere a disposizione un layer di
funzionalità costituite dalla programmazione delle schede per lo svolgimento dei compiti di comunicazione, elaborazione dati, strutturazione del sistema real time in task, progettazione del sistema
con componenti più idonei alla robotica, ecc. . .
3. Realizzazione di librerie per accedere comodamente a numerose funzioni della Flex, tra cui la comunicazione USART (Universal Synchronous-Asynchronous Receiver/Transmitter), PWM (Pulse
Width Modulation), I/O digitale, comando dei servomotori.
4. Realizzazione e testing di strumenti di Debug in Run Time per la Flex Full attraverso la libreria
Serial Console.
5. Utilizzo e modifica della libreria Microbridge ADB per comunicare con qualsiasi dispositivo Android
e microcontrollore Arduino.
6. Aggiunta di features all’applicazione Android per fornire a Marvin migliori funzionalità di inseguimento di volti tramite libreria OpenCV e controllore PID implementato sulla Flex Full.
7. Progettazione e implementazione di controllori PID per il controllo in anello chiuso dei movimenti
spaziali del robot mediante un kernel real-time .
8. Aggiunta dello “snodo di testa” e miglioramento della meccanica rispetto al precedente AndroEEbot.
Risulta quindi evidente come il lavoro svolto ha coinvolto diversi fronti portando novità al precedente
sistema come il Plug & Play degli smartphone, la possibilità di utilizzare due microcontrollori per la
lettura di sensori o l’utilizzo di attuatori come i motori a corrente continua oppure servomotori attraverso
PWM, e infine le importanti funzioni di debug a run time originariamente non disponibili per la Flex
concludendo con la realizzazione di controllori PID per il controllo automatico del movimento del robot
attraverso varie politiche di controllo.
2
Capitolo 1. Introduzione
1.3. Struttura del lavoro
I diversi capitoli della tesi possono essere riassunti per macro-argomenti in maniera da avere una
panoramica generale su come il lavoro è stato impostato.
Nel capitolo 2 viene fornita una descrizione dettagliata sui dispositivi hardware e l’elettronica utilizzata
per familiarizzare con gli strumenti di lavoro.
Il capitolo 3 presenta gli ambienti di sviluppo riepilogando tutte le informazioni necessarie per l’installazione, l’importazione dei progetti esistenti e fornendo indicazioni sull’utilizzo per addolcire il più
possibile la curva di apprendimento dei numerosi strumenti.
Nel capitolo 4 si parlerà della progettazione sia hardware sia software che è stata necessaria per ricostruire dalle fondamenta il sistema, venendo illustrate l’analisi dei requisiti e il funzionamento di Marvin,
unitamente una schematizzazione a livelli del sistema per spiegarne a fondo l’architettura.
Il capitolo 5 tratta le scelte implementative e le soluzioni progettuali per l’hardware e il software,
verranno spiegate le problematiche incontrate e soluzioni progettuali intraprese nonché spiegato a fondo
il funzionamento del codice su Flex, Arduino e Android.
Nel Capitolo 6 è affrontato il problema del Controllo Automatico mediante PID a tempo discreto
implementato in maniera congiunta tra Android e Flex Full, oltre alle conoscenze matematiche e operative
necessarie per tarare i parametri del controllore.
Infine il capitolo 7 contiene i test e i risultati ottenuti con il nuovo sistema embedded e software
progettato e realizzato. Il capitolo contiene anche idee e spunti di riflessioni per sviluppi futuri di Marvin.
Seguono due appendici utili a livello pratico, cioè lo schema dei collegamenti elettrici e l’elenco dei
software utilizzati.
3
Capitolo 2.
Componenti di Marvin
Nelle applicazioni dei sistemi embedded, l’ambiente di sviluppo è caratterizzato da hardware e software.
A differenza dei sistemi PC general-purpose, dove grazie all’astrazione dei sistemi operativi e ai linguaggi di programmazione di alto livello, viene tendenzialmente ignorato l’hardware sottostante, nei sistemi
embedded l’hardware rappresenta un elemento fondamentale del sistema stesso, che lo caratterizza, e
vincola il progettista nelle scelte e nelle soluzioni da adottare
In questo capitolo viene effettuata una panoramica sulle caratteristiche dell’hardware utilizzato per
comprendere al meglio gli strumenti di lavoro.
2.1. Flex Full
Flex è una scheda embedded realizzata da Evidence srl, basata sui microcontrollori della famiglia dsPIC
DSC (Digital Signal Controller) di Microchip. Si tratta di una evaluation board che permette lo sviluppo
e il testing di applicazioni real-time per dsPIC DSC; è dotata di un’architettura hardware modulare e
fornisce supporto al kernel real-time Erika Enterprise. La Flex è il “cervello” di Marvin, in quanto le sono
affidati i compiti di coordinazione dei vari dispositivi ad essa connessi, nonché l’esecuzione del codice di
controllo del robot.
La Flex Full board adotta un’architettura modulare composta dalla board madre, su cui sono già presenti tutte le funzionalità del microcontrollore, e da schede figlie chiamate daughter boards, che estendono
e semplificano l’accesso ad alcuni dispositivi e l’uso di alcune funzionalità. La Demo Daughter Board,
ad esempio, fornisce supporto alla scrittura su display LCD, all’utilizzo di sensoristica come trasmettitori e ricevitori infrarossi, sensori di temperatura e luminosità, e facilità l’utilizzo delle periferiche di
comunicazione attraverso bus I 2 C o SPI.
Figura 2.1.: Flex Full e Flex Base
4
Capitolo 2. Componenti di Marvin
La Famiglia delle board Flex, come si nota in fig. 2.1, è composta da due board: la Flex Full – utilizzata
nel presente lavoro – e la Flex Base.
La Flex Base differisce dalla versione Full per l’assenza della porta USB e del PIC 18 predisposto alla
sua gestione (e non direttamente programmabile dall’utente). Inoltre lo stadio di alimentazione della Flex
Base accetta un range di tensioni di ingresso da 7 a 12 V, meno ampio rispetto ai 9-36 V della versione
Full.
Sempre dalla fig. 2.1, si può notare come i pin disponibili nel microcontrollore dsPIC33FJ256MC710
della famiglia dsPIC DSC di Microchip vengano esportati attraverso connettori standard a passo 2.54
mm, agevolando l’interconnessione con circuiti elettronici esterni.
La caratteristica che rende la Flex Full un buon hardware su quale sviluppare la logica di controllo
di Marvin è individuabile nella possibilità di avere da una parte il sistema operativo Real-Time Erika
Enterprise, con il quale organizzare l’esecuzione del codice in tasks, avendo così a disposizioni su un
microcontrollore il concetto di programmazione concorrente – cosa molto rara nei sistemi embedded
attuali – e dall’altra parte la possibilità di programmare a basso livello il dsPIC in linguaggio C o
Assembly, avendo a disposizione le periferiche tipiche di un microcontrollore.
Le caratteristiche principali del dsPIC33FJ256MC710 sono riassunte qui di seguito [1]:
• Architettura: 16-bit, di tipo Modified Harvard
• Massima velocità della CPU : 80 Mhz corrispondenti a 40 MIPS
• KB dedicati alla Memoria Programma: 256
• Tensione di funzionamento: da 3 a 3.6 Volt
• Pin disponibili: 100
• Oscillatori interni: 2 oscillatori, per due diverse modalità di funzionamento, rispettivamente 7.39
MHz e 512 KHz (con possibilità di usare un PLL – Phase Loop Locker) per incrementare la frequenza
fino a 80 MHz
• Periferiche di Comunicazioni digitali: 2 USART, 2 SPI, 2 I2C
• PWM (Pulse Width Modulation): 2 Moduli PWM dedicati al controllo dei motori, PWM con
risoluzione di 16 bits e possibilità di utilizzare 8 canali
• DMA (Direct Memory Access): 8 canali, 2 Kbytes DMA buffer area (DMA RAM) per memorizzare
i dati trasferiti via DMA così è possibile il trasferimento di informazioni tra RAM e periferiche
mentre la CPU sta eseguendo codice (no cycle stealing); la maggior parte delle periferiche supporta
DMA.
• Real-Time Clock Circuit (RTCC) Hardware: non disponibile all’interno ma è possibile usare una
configurazione per usare un RTCC esterno
• Timers: 9 Timers a 16 bits, oppure 8 utilizzabili in coppia per ottenere 4 timers a 32 bits
• Output Voltage: i pin digitali hanno uscite che al massimo raggiungono i 3.6 volt, perciò la logica
Alto(H)/Basso(L) rispetta lo standard 3.3/0 volt.
• Moduli ECAN: 2
• ADC (Convertitore Analogico Digitale): 2
5
Capitolo 2. Componenti di Marvin
Figura 2.2.: Pinout del dsPIC
6
Capitolo 2. Componenti di Marvin
I 100 pin del dsPIC sono riportati totalmente sulla Flex Full sui connettori CON6 e CON5 con la stessa
numerazione che si può trovare sul dsPIC (vedi fig. 2.2): ad esempio la Ricezione della USART 1 sul
dsPIC è multiplexata sulla linea 52 che corrisponde proprio al pin P52 sul connettore CON6 della Flex.
In fig. 2.3 sono evidenziati i connettori e le principali funzionalità della board Flex Full.
Per completezza, in fig. 2.5 è riportata la piedinatura della Flex Full.
Figura 2.3.: Funzioni e connettori della scheda Flex Full
La programmazione e il debug del microcontrollore dsPIC avviene attraverso delle apposite interfacce:
In-Circuit Serial Programming (ICSP), Enhanced ICSP e Joint Test Action Group (JTAG).
La ICSP è un’interfaccia proprietaria di Microchip, appositamente sviluppata per la programmazione
dei propri dispositivi. È quindi integrata nel core del MCU, dove una macchina a stati regola la scrittura in
memoria; oltre alla programmazione, la ICSP gestisce anche un canale per il debugging sul chip (in-circuit
debugging).
Il dispositivo MPLAB ICD2 (vedi fig. 2.4) è necessario per eseguire le operazioni di programmazione
e debug del MCU.
Figura 2.4.: Microchip ICD 2
Purtroppo data la complessità del sistema operativo Erika, non è possibile eseguire le operazioni di
Debug attraverso ICD2 e MPLAB. Per questo motivo è stato sviluppato durante questo lavoro di tesi
anche una libreria chiamata serialConsole.h, che va compilata insieme al programma di controllo del
7
Capitolo 2. Componenti di Marvin
robot sulla Flex, che permette di comunicare verso un PC attraverso un Convertitore TTL-USB basato
sul chip PL2303.
Figura 2.5.: Pinout della scheda Flex Full
8
Capitolo 2. Componenti di Marvin
2.2. Convertitore TTL-USB PL2303
Questo semplice convertitore presenta i pin per l’USART TX, RX e GND. Tali pin sono stati collegati
alla Flex Full ed utilizzati con la seconda USART della scheda, mentre si pone lato PC come porta seriale
Virtuale (VCOM su sistemi Windows).
Figura 2.6.: Retro e pinout del PL2303
Figura 2.7.: Fronte del PL2303
Per visualizzare le stringhe di Debug è necessario utilizzare la libreria serialConsole.h e un programma per la ricezione tramite porta seriale. Per questo lavoro è stato utilizzato Real Term in quanto
completo e preciso nonché freeware.
Si nota dalla foto come questo chip possa anche fornire due linee di alimentazione (3.3 e 5 V) a dispositivi
ad esso collegati, anche se questa caratteristica non è stata utilizzata per il progetto di Marvin.
I driver del chip PL2303, affinchè esso sia riconosciuto come VCOM, sono reperibili senza difficoltà per
i sistemi operativi Linux, Windows Vista e Windows 7.
2.3. FTDI Vinculum-II
Il Vinculum-II (VNC2) è la seconda versione della famiglia Vinculum di FTDI; si tratta di un controller
embedded dual USB host. È dotato di un microcontrollore a 16-bit con memoria Flash da 256KB e 16KB
di RAM.
Il VNC2 fornisce la funzionalità di interfaccia USB Host per una varietà di dispositivi USB.
Figura 2.8.: Vinculum-II
La comunicazione con dispositivi non-USB, come microcontrollori, può essere realizzata utilizzando le
interfacce USART, SPI oppure parallel FIFO (è presente inoltre anche un modulo PWM) e tutti i segnali
sono prelevabili attraverso 24 pin 2.54 mm configurabili.
9
Capitolo 2. Componenti di Marvin
Il VNC2 è un dispositivo completamente programmabile e permette la realizzazione di firmware personalizzati secondo le proprie esigenze, utilizzando l’apposito ambiente di sviluppo Vinculum- II IDE.
Il linguaggio di programmazione utilizzato è il C e per permettere la connettività e il funzionamento
dei vari dispositivi – come l’istanziamento dei driver – è necessario utilizzare le primitive del VOS, il
sistema operativo Real-Time del Vinculum che gestisce e schedula i tasks.
La programmazione del Vinculum-II avviene per mezzo di un apposito dispositivo, il VNC Debugger/Programmer Module progettato per fornire la connettività tra l’ambiente di sviluppo Vinculum-II IDE e
i pin dell’interfaccia di debug presenti nel V2DIP2.
Figura 2.9.: Modulo di debug V2DIP2
Il modulo di debug VNC2 è una mini-scheda con un connettore USB miniB usato per connettersi
all’ambiente di sviluppo sul PC; il connettore femmina a 6-vie è utilizzato per connettere il modulo di
debug al dispositivo VNC2, dotato di un connettore maschio compatibile.
Questo dispositivo comunque non è stato impiegato nella versione finale di Marvin mentre è stato
utilizzato come interfaccia per lo scambio di messaggi tra Flex Full, smartphone Nexus S e Control
Module per AndroEEbot.
Le ragioni che hanno spinto alla sostituzione di questo modulo con il microcontrollore Arduino sono da
individuarsi nell’aspetto Plug & Play verso tutti gli smartphone Android che Arduino permette e che il
Vinculum limita. Infatti seppur entrambi i dispositivi supportano la libreria Open Accessory di Google
solo Arduino supporta MicroBidge ADB.
Le due librerie differiscono molto per compatibilità dei dispositivi. Infatti la Microbridge ADB è
supportata da qualsiasi dispositivo Android con versione >= 1.5, mentre la Open Accessory è attualmente
supportata, solo da un paio di smartphone (Nexus S e Nexus One) e qualche tablet (come il Motorola
Xoom). Ciò impone un pesante vincolo progettuale e di costo, e limita il concetto di Plug & Play.
Con Arduino diverse applicazioni Android, create per comandare semplicemente l’hardware sottostante,
possono essere condivise e impiegate su un qualsiasi smartphone; ciò non potrebbe accadere utilizzando
il Vinculum-II.
10
Capitolo 2. Componenti di Marvin
2.4. Libreria Open Accessory
Open Accessory viene distribuita da Google per l’interfacciamento tra il mondo dei sistemi embedded
e il sistema operativo Android e i dispositivi che lo ospitano.
La libreria viene distribuita in due versioni: come Add-on, per le versioni 2.3.4+ di Android (è un
backporting) e dalla 3.0+ come libreria ufficiale. Open Accessory che permette ad un dispositivo Android
che la supporti di poter usare la porta USB per scambiare dati con altri dispositivi.
Questa libreria permette di utilizzare il dispositivo Android come USB Accessory e USB Host.
Nel primo caso, che è quello specifico di questa tesi, il dispositivo viene riconosciuto come un accessorio,
cioè è atto a svolgere il compito di slave e quindi non può enumerare altri device ad esso collegati attraverso
la porta USB e fornire loro alimentazione elettrica.
Il secondo caso invece permette al dispositivo di figurare come Master.
In generale attraverso questa libreria il dispositivo Android può interfacciarsi con altri dispositivi USB
come Mouse, Tastiere, Fotocamere, Schede di Sviluppo ecc...
La libreria è stata rilasciata verso la fine del 2011 e sono tutt’ora pochi i dispositivi che la utilizzano
appieno come riporta prorio Google1 stessa poiché oltre a delle feature software è necessario che i produttori di smartphone implementino via hardware la possibilità di utilizzare l’Open Accessory: Tipicamente
gli smartphone che la supportano appartengono alla Fascia Alta della gamma e perciò richiedono costi
elevati, nell’ordine dei 300A
C2 .
2.5. Arduino Mega ADK
Arduino Mega ADK è una scheda di sviluppo basata sul microcontrollore ATmega2560. Esso differisce
dalla versione Arduino Mega per la presenza di una interfaccia USB Host usata per connettere smartphone basati sul sistema operativo mobile Android. L’interfaccia USB è realizzata mediate l’integrato
MAX3421e.
Figura 2.10.: Arduino Mega ADK
Tra le caratteristiche più interessanti di questo microcontrollore si ha che esso dispone di 54 pin I/O,
un oscillatore interno a 16 MHz, bottone di reset, un ambiente di sviluppo di semplice utilizzo basato su
1 Note:
Accessory mode is ultimately dependent on the device’s hardware and not all devices will support accessory mode.
Devices that support accessory mode can be filtered using a <uses-feature> element in your corresponding application’s
Android manifest.For more information, see the USB Accessory Developer Guide. (dal sito dedicato alla libreria Open
Accessory, ultima consultazione – Luglio 2012)
2 Dato ricavato da ricerche condotte su negozi online nell’anno 2012
11
Capitolo 2. Componenti di Marvin
Processing, programmazione tramite linguaggio ad alto livello chiamato Wiring, supporto per la libreria
Open Accessory di Google per comunicare con Android.
Questo seconda board di sviluppo è stata scelta in sostituzione del precedente Vinculum-II sul robot
Marvin per la sua predisposizione naturale per la comunicazione con Android. Infatti oltre a supportare
nativamente la libreria Open Accessory di Google supporta (seppur con leggere modifiche) la libreria
Microbridge ADB che rende possibile l’interfacciamento di qualsiasi dispositivo Android (versione 1.5 o
maggiore) senza bisogno di permessi di root sul dispositivo. L’USB Host, che nel nostro caso è proprio
Arduino Mega ADK, tramite l’utilizzo del protocollo ADB (Android Debug Bridge) permette di aprire
una Shell sul telefono o inviare direttamente comandi tramite essa, trasmettere file tra PC e Android,
leggere i log di debug (logcat), aprire porte TCP e sockets Unix.
L’ultima caratteristica è quella usata dalla libreria Microbridge che utilizza sockets TCP per stabilire
un canale di connessione bidirezionale (pipe) tra un dispositivo Android e Arduino, l’applicazione Android
si comporta da Server ascoltando una determinata porta scelta dal programmatore e Arduino si connette
a quella porta tramite ADB comportandosi da Client; la libreria permette di effettuare riconnessioni
automatiche nell’eventualità che il device USB venga scollegato da Arduino o per altre cause come crash
dell’applicazione Android, etc... aumentando di molto l’affidabilità e permettendo il “Plug & Play”
concetto che si è voluto realizzare dai primi momenti del progetto di Marvin.
Si fa notare che per lo sviluppo del progetto non è necessario usare proprio l’Arduino Mega ADK,
infatti basterebbe utilizzare un qualsiasi Arduino con annessa la USB Shield che permette di avere le
stesse caratteristiche della board presentata (USB Host) ma attraverso un’architettura modulare del tipo
mother board + daughter board; questa soluzione è stata scartata in fase di progetto perché la versione
ADK rispetto alla USB Shield permette di avere funzionalità integrate senza perdere pin e senza bisogno
di ulteriori fonti di alimentazione.
In fase progettuale l’utilizzo di un secondo microcontrollore di facile accesso come Arduino è stata
un motivata anche dall’aumento delle capacità computazionali e di comunicazione del robot. In questo
modo infatti, risulta possibile dividere carichi di lavoro tra 2 CPU, già messe in comunicazione mediante
la libreria Arduino.h sulla Flex e nel file AndroidFlexComunication.ino su Arduino, risulta possibile
utilizzare sensoristica avanzata in maniera molto semplice grazie alle potenzialità di Wiring e per le altre
periferiche aggiunte con la board, principalmente:
• 15 PWM
• 16 Ingressi Analogici
• 3 USART
• 1 porta seriale Virtuale (VCOM) integrata nell’ambiente di sviluppo di Arduino
• 1 modulo SPI
12
Capitolo 2. Componenti di Marvin
Figura 2.11.: Pinout ATMega2560
13
Capitolo 2. Componenti di Marvin
2.6. Control Module basato su chip Motion Processor MC3410
AndroEEBot è stato progettato per interfacciarsi con il Control Module del robot ER1 sviluppato
dalla Evolution Robotics nel 2002. Il Control Module gestiva il movimento robot attraverso 2 motori
passo passo Shinano Kenshi SST58D3820 da 3.4 Volt, 1.8 gradi/step, 2 Ampere/fase, pilotati in modalità
bipolare.
I motori erano collegati al Control Module con due connettori seriali X.21 ed il connettore 1 era
associato alla ruota destra.
(a) Control Module del robot ER1
(b) Motore passo-passo Shinano Kenshi
Figura 2.12.: Hardware per il controllo del movimento di AndroEEBot
Il programmatore si interfaccia al modulo di controllo attraverso la porta USB e invia i comandi di
direzione e velocità tramite sequenze di byte che verranno poi interpretate dalla circuiteria interna e
attuate dai motori passo-passo.
Il Control Module è fondamentalmente composto da 3 chip, due motion processor MC3410 che si
occupano di trasformare i byte ricevuti in ingresso tramite porta USB in comandi di direzione, traiettoria
e velocità ,e da un chip FTDI RS232-USB utilizzato come convertitore USB → Seriale secondo lo standard
RS232.
Proprio la presenza di questo chip ha permesso di optare per il Vinculum-II nel precedente AndroEEBot,
anch’esso appartenente alla famiglia di chip della FTDI.
Questo componente è stato inizialmente utilizzato nell’architettura di Marvin come dimostrato in alcuni
video presi in fase di sviluppo ma poi è stato sostituito perché riduceva di molto i tempi di risposta del
sistema, spesso risultava non essere preciso e generalmente rappresenta una sorta di “black box” che
avrebbe potuto rallentare lo sviluppo e l’evoluzione di Marvin.
Il Motion Control e i motori passo-passo sono perciò stati sostituiti con dei Servomotori a rotazione
continua ad alta coppia: i DF15SR.
2.7. Servomotori DFRobotics DF15SR e Hitec HS-485HB
I Servomotori sono dei motori DC (motori a corrente continua) che includono al loro interno ingranaggi
di riduzione o moltiplica della coppia, un circuito di controllo e un potenziometro utilizzato come sensore
di posizione. Attraverso queste caratteristiche essi risultano molto semplici da utilizzare e da installare.
Per poter essere controllati questi motori hanno bisogno di un segnale di controllo PWM con duty cycle
variabile rispetto ad un periodo fissato; entrambi i motori utilizzati necessitano di un periodo si 20 ms
per il segnale PWM.
14
Capitolo 2. Componenti di Marvin
Il duty cycle è la frazione di tempo che un segnale passa in uno stato attivo in proporzione al tempo
totale considerato (periodo). In presenza di un segnale sotto forma di onda rettangolare, il duty cycle è
il rapporto tra la durata del segnale “alto” (τ ) e il periodo totale del segnale (T ), e serve a esprimere per
quanta porzione di periodo il segnale è a livello alto intendendo con alto il livello “attivo”.
Il duty cycle è definito come d = Tτ , dove τ è la porzione di periodo a livello alto (detta anche T-on) e
T è il periodo totale.
Figura 2.13.: Esempio di onda rettangolare generata con la PWM
I servomotori utilizzati nella costruzione di Marvin sono di due tipologie, un servomotore standard
(angolo di rotazione 0-180°) Hitec HS-485HB per lo snodo di testa alimentato a 5 V, coppia di stallo 4.8
Kg·cm, ingranaggi in karbonite e drain massimo di corrente di 150 mA senza carico. I tempi T-on sono
riportati nello schema sottostante. Per questo particolare servomotore il valore di duty cycle definisce
l’angolo in cui il motore deve posizionarsi.
(a) Rivestimento del servo HS-485HB
(b) Riduttori in karbonite
Figura 2.14.: Servomotore HS-485HB
Figura 2.15.: Corrispondenza tra angoli e tempi di T-on in microsecondi
15
Capitolo 2. Componenti di Marvin
Si noti che 1.5 ms corrisponde alla posizione 0° del servo. Variando il tempo di T-on del duty cycle si
possono ottenere i vari valori dell’angolo che il braccio del servo deve raggiungere.
Si riporta il cablaggio:
• Nero: Massa
• Rosso: Alimentazione (4.8 – 6 V)
• Giallo: Segnale PWM
Per la propulsione di Marvin, invece, sono stati utilizzati due servomotori a rotazione continua DF15SR
della DFRobotics che, a differenza del servomotore Hitec, permettono la rotazione continua (0-360°); il
valore di duty cycle determina il verso di rotazione, e non la posizione come accade per il precedente
modello.
Con valori di T-on di 1.5 ms il motore si ferma, con T-on pari a 2.4 ms esso ruota alla massima velocità
in senso orario mentre per T-on pari a 0.6 ms esso ruota alla massima velocità in senso antiorario,
tecnicamente per tutti i valori di T-on compresi nei range sopra descritti la velocità del motore dovrebbe
aumentare o diminuire linearmente, anche se data la limitazione di valori imponibili è difficile notare
cambiamenti di velocità apprezzabili; in ogni caso attraverso un controllore PID con mapping dei valori
è possibile notare concretamente l’accelerazione o la decelerazione dei motori.
Figura 2.16.: DF15SR con “Horns”
I servi di propulsione sono alimentati a 5 V, coppia di stallo 10 Kg*cm, e drain massimo di corrente di
1.2 A senza carico alla massima tensione di alimentazione (7.2 V).
Si riporta il cablaggio:
• Marrone: Massa
• Rosso: Alimentazione (4.8 – 7.2 V)
• Arancione: Segnale PWM
La particolarità di questo motore sta nel fatto di poter ottenere diversi valori di coppia di stallo per
diversi valori di tensione:
16
Capitolo 2. Componenti di Marvin
Coppia
10 Kg·cm
13 Kg·cm
15 Kg·cm
Tensione
4.8 V
6V
7.2 V
Tabella 2.1.: Coppia di stallo per il servo DF15SR a diversi valori di tensione
2.8. Smartphone Android
Uno smartphone è un “telefono multimediale/intelligente” cioè un dispositivo che incorpora le funzionalità di un telefono cellulare con quelle di un PDA, su questi dispositivi è possibile utilizzare un sistema
operativo ed installare e sviluppare applicazioni che ne sfruttano la sensoristica e le peculiarità.
Il progetto di Marvin ha previsto fin da subito l’utilizzo di uno smartphone che potesse interfacciarsi
con le componenti elettroniche e meccaniche sottostanti attraverso API portabili su diversi dispositivi così
da permettere il Plug & Play di applicazioni capaci di utilizzare il robot per effettuare movimenti, mentre l’elaborazione è affidata all’applicazione che può essere progettata indipendentemente dall’hardware
sottostante.
L’applicazione sviluppata prevede l’utilizzo del sistema operativo Android tramite il quale è possibile
accedere alla videocamera posteriore di cui ogni smartphone è dotato, ed applicare sui vari frame catturati
filtri e algoritmi volti messi a disposizione dalla libreria di visione artificiale Open CV per Android.
Inizialmente AndroEEbot prevedeva la sola compatibilità con lo smartphone Nexus S, ora attraverso
la libreria Microbridge ADB è possibile utilizzare un qualsiasi smartphone con Android >= 1.5.
Vari dispositivi sono stati messi alla prova tra cui
• LG Optimus One
• HTC Desire
• HTC Evo 3D
Su ognuno di essi la compatibilità è stata verificata con successo, ma al di là del testing l’HTC Evo 3D
è stato utilizzato come riferimento per il sistema poiché dotato di caratteristiche hardware nettamente
migliori e per la possibilità di utilizzare ben due fotocamere per la visione stereoscopica.
(a) HTC Evo 3D
(b) Particolare delle fotocamere stereoscopiche
Figura 2.17.: HTC Evo 3D
Caratteristiche e sensoristica:
17
Capitolo 2. Componenti di Marvin
• Giroscopio
• Accelerometro
• Sensore di prossimità
• Sensore di luminosità
• GPS integrato
• Doppia fotocamera da 5 megapixel con autofocus e doppio flash a LED
• Apertura f/2.2
• Registrazioni video in 2D/3D con risoluzione fino a 720p
• Fotocamera frontale da 1.3 megapixel a fuoco fisso
• CPU dual-core Qualcomm MSM8260 a 1.2 Ghz
• GPU Adreno 220
• RAM 1 GB
2.9. Circuito di Alimentazione, led e breadboard
Il robot è costituito, oltre che dai microcontrollori e dagli attuatori, anche da alcune parti elettroniche.
La circuiteria è stata realizzata mediante una breadboard per permettere una facile prototipizzazione.
Il circuito di alimentazione è diviso in due linee di tensione mediante il regolatore di tensione lineare
LM7805CV, dove nel pin di input entra la linea 12 V e dal pin di output esce la 5 V.
Figura 2.18.: Regolatore di tensione LM7805CV
Il regolatore di tensione lineare, mediante una serie di transistor, attua la regolazione per dissipazione
della tensione in eccesso. La potenza dissipata è:
P = (Ving − Vout ) · (Idrain )
18
(2.1)
Capitolo 2. Componenti di Marvin
Risulta chiaro, anche con un calcolo sommario, che se la linea a 5 V è utilizzata per alimentare i tre
servomotori con un drain di corrente pari a circa 800 mA e la caduta di potenziale è 7 V, la potenza
dissipata sarà pari nel caso peggiore 7 V * 0.8 A = 5.6 W.
Per cui risulta necessario inserire un dissipatore affinché la potenza sviluppata dal componente, se
troppo elevata, non lo distrugga.
Figura 2.19.: Circuito regolatore di tensione positiva stabilizzata
Lo schema del circuito di alimentazione risulta essere:
• C1: 1000 uF, elettrolitico 16 V
• C2: 47 nF, poliestere metallizzato
• C4: 470 uF, elettrolitico 16V
• IC1: LM7805CV, dove E = IN, M = GND e U = OUT
I condensatori hanno la seguente funzione:
• C1: livella la tensione a monte del circuito.
• C2: questi due condensatori servono per togliere i disturbi in alta frequenza, il più usato è quello
da 100 nF. C’è una cosa più importante della sua capacità, ed è la posizione: devono essere il più
vicino possibile al regolatore per svolgere bene il loro compito.
• C3: serve a “pulire” la tensione in uscita.
Nel circuito sono presenti anche 3 LED che servono per indicare gli stati della macchina ed hanno la
seguente funzionalità:
• Rosso: controllato da Arduino indica che l’applicazione Android sta inviando dei dati; serve per
verificare che l’applicazione stia effettivamente inviando i byte. Inoltre indica che tali byte sono
ricevuti e processati da Arduino.
• Verde: controllato da Arduino indica che la Flex ha inviato una richiesta tramite USART 1 ad
Arduino, ed Arduino ha processato e risposto tramite l’invio di byte alla Flex.
• Arancione: controllato dalla Flex indica che i dati ricevuti da Arduino corrispondono effettivamente
a dati utili per il movimento dei motori.
19
Capitolo 3.
Ambienti di sviluppo
Nel campo dell’informatica per ambiente di sviluppo si intende uno o più software che aiutano il
progettista/programmatore nello sviluppo e nel testing del codice. Normalmente un ambiente di sviluppo
consiste in un editor di codice sorgente, un compilatore e/o un interprete, un tool di building automatico
e solitamente, un debugger.
Per lo sviluppo di Marvin gli ambienti di sviluppo utilizzati sono stati molteplici.Saranno quindi descritti i vari tools e, in maniera concisa, verrà spiegato come installare e configurare tali software di
sviluppo1 .
3.1. Eclipse Indigo con Android SDK
L’ambiente di sviluppo per le applicazioni Android è basato su Eclipse, IDE flessibile multi- linguaggio
e multi-piattaforma open source che mediante l’utilizzo del plugin Android SDK diventa un validissimo
mezzo tramite il quale programmare, compilare, generare .apk (Android Package file: pacchetti eseguibili
per il sistema operativo Android), emulare terminali e mandare in esecuzione in debug, sul proprio
dispositivo, le applicazioni.
Android è un sistema operativo basato sul kernel Linux 2.6, appositamente realizzato per dispositivi
portatili. L’architettura è suddivisa in 5 componenti. Al di sopra del kernel Linux ci sono le librerie C/C++ utilizzabili dalle applicazioni; ad un livello superiore si trova l’Application Framework, che
fornisce le API e i servizi che possono essere utilizzati dalle applicazioni (chiamate anche App); queste
ultime si trovano in cima all’architettura, nel livello Application, e sono sviluppate usando il linguaggio
di programmazione Java.
Figura 3.1.: Architettura di Android
1 Affinché
tutti i tools di sviluppo possano funzionare correttamente è consigliato lavorare in ambiente Windows Vista o
Windows Seven
20
Capitolo 3. Ambienti di sviluppo
Il componente chiave del framework Android è l’Android Runtime, che contiene le librerie di sistema
e la Virtual Machine Dalvik, una macchina virtuale appositamente progettata e ottimizzata da Google
secondo le caratteristiche hardware dei dispositivi mobile.
Lo sviluppo delle applicazioni Android avviene utilizzando l’IDE Eclipse per Java, con installato il
plugin Android Develoment Tools (ADT); in aggiunta, è necessario il pacchetto Android SDK che contiene
i vari strumenti di sviluppo e le librerie per le versioni di Android, necessari per compilare l’applicazione
realizzata nel formato .apk.
Sono quattro i tipi di componenti delle applicazioni: Activity, Service, Content Providers, Broadcast
Receivers.
Una Activity visualizza una schermata singola; in una applicazione più attività funzionano in contemporanea per costruire un’interfaccia grafica più complessa, ma ognuna è indipendente dalle altre.
In applicazioni multi-activity, ne esiste una identificata come principale, che viene mostrata all’utente
quando l’applicazione è lanciata per la prima volta; le attività possono poi avviare altre attività per
svolgere determinate operazioni; in queste situazioni l’attività precedente è fermata e il sistema si occupa
di memorizzarne lo stato nello stack.
Il ciclo di vita delle Activity è il seguente:
Figura 3.2.: Ciclo di vita di una activity
21
Capitolo 3. Ambienti di sviluppo
Il prerequisito per l’installazione dell’Android SDK su Eclipse è l’avere sul proprio PC il JDK (Java
Developer Kit). Successivamente si passa all’installazione dell’Android SDK tramite l’installer che però
non contiene l’ambiente di sviluppo completo ma solo il nucleo dei tools utili a scaricare il resto del
package dell’SDK.
Nel momento in cui si installa il software è utile prendere nota della directory di installazione che verrà
richiesta durante l’installazione dell’ADT, il plugin per Eclipse.
Ad installazione avvenuta verrà visualizzata la finestra in fig. 3.3:
Figura 3.3.: Repository Android
Verranno automaticamente selezionati i pacchetti consigliati e raccomandati da installare. Nello specifico per la corretta compilazione ed esecuzione dell’applicazione Android “Marvin Face Follow” e “Marvin
PID” sono stati utilizzati i file di Android 2.3.3 con le Google API 10 rev.2.
Una volta ottenuti tali file è possibile passare all’installazione dell’ADT per Eclipse che viene installato
tramite il menù Help > Install New Software di Eclipse e digitando nel campo “Work with” l’URL
https//dl-ssl.google.com/android/eclipse/. Dare invio dopo aver selezionato tutti i plugin che
compariranno nel repository.
La fase successiva è la configurazione dell’ADT tramite il menù Windows > Preferences e selezionando
Android dal pannello a sinistra. Inserire la locazione nel file system dell’Android SDK precedentemente
installato attraverso il tasto Browse e successivamente confermare le modifiche, come illustrato in fig.
3.4.
L’ultimo passaggio è l’importazione dell’applicazione “Marvin Face Follow”, o equivalentemente “Marvin PID”, nel workspace selezionato: dal menù File > Import scegliere la directory contenente i file del
progetto (Android > Marvin Face Follow e le librerie Open CV) utilizzando l’opzione “Importa come
progetto esistente” e quindi spuntare “Copy project into workspace” e dare invio.
Dopo aver importato il progetto è necessario verificare che il link alle librerie Open CV sia stato
mantenuto: quindi andare in proprietà del progetto cliccando con tasto destro sul progetto nel package
explorer di Eclipse, segliere Properties > Android e confrontare la schermata con la fig. 3.5.
22
Capitolo 3. Ambienti di sviluppo
Figura 3.4.: Librerie Android
Figura 3.5.: Proprietà del progetto e link delle librerie
23
Capitolo 3. Ambienti di sviluppo
Se dovessero mancare le librerie OpenCV si può aggiungerle con il tasto “Add” e ricercarle tra i progetti
importati.
3.2. RT-Druid e ERIKA Enterprise v1.6.1
RT-Druid è l’ambiente di sviluppo per la Flex Board, o meglio per ERIKA RTOS. Infatti la particolare
architettura della Flex impone di utilizzare RT-Druid come unico IDE sia per la scrittura dei Task e dei
componenti del sistema Real-Time che per la scrittura a basso livello delle istruzioni del microcontrollore
dsPIC.
RT-Druid ha una struttura modulare, integrata nel framework Eclipse attraverso lo strumento dei
plugin, è composto da un modulo per la generazione del codice, e uno per l’analisi di schedulabilità.
Il code generator è distribuito anche in versione stand-alone indipendente da Eclipse, si tratta essenzialmente di un compilatore per OIL (il linguaggio dello standard OSEK ) che, in base alle specifiche definite
nel file OIL di configurazione del sistema, costruisce la struttura necessaria alla compilazione di ERIKA
(makefiles, inizializzazione delle strutture dati, ecc.). Il plugin per l’analisi della schedulabilità permette
di modellare, analizzare e simulare il comportamento temporale del sistema embedded progettato, ma è
disponibile solo nelle versioni commerciali di ERIKA.
RT-Druid è corredato di una serie di esempi, disponibili per varie di architetture hardware: ciò agevola
la realizzazione delle applicazioni, potendo prendere spunto da tali esempi di codice. Nel caso della Flex
è possibile trovare tali esempi nel menù File > New > RT-Druid OIL e C/C++ project dove, dando un
nome al progetto e cliccando su “next”, è possibile avere un elenco di hardware ed esempi collegati; i più
interessanti sono quelli per il pic30 che corrispondono ai progetti utili per l’architettura dsPIC.
Una applicazione per la Flex Board, come detto, è dipendente sia dai file del sistema operativo ERIKA
sia dal codice di basso livello del microcontrollore. Proprio per questo tutti gli oggetti che vengono
utilizzati dal sistema operativo devono essere definiti nel file OIL (di solito config.oil), che attraverso una
particolare sintassi, istanzia gli oggetti (ad esempio gli Alarm, i Task, le Risorse) da utilizzare e definisce
nell’oggetto OS le caratteristiche globali dell’applicazione, come la presenza di possibili stack non condivisi
dai task in esecuzione (MultiStack), del tipo di Kernel da utilizzare e le specifiche sul microcontrollore
attraverso la proprietà MCU_Data.
La scrittura del file OIL porta alla generazione del codice di configurazione per ERIKA Enterprise(EE),
del codice sorgente e dei makefiles richiesti per compilare l’applicazione.
Definito il file OIL si possono usare gli oggetti istanziati nei file .c che costituiscono il codice sorgente
dell’applicazione. Questi oggetti sono richiamati mediante opportuna sintassi: ad esempio un task è
istanziato con la keyword TASK(nometask) e richiamato attraverso particolari API messe a disposizione
da ERIKA tra cui la semplice ActivateTask(nometask).
La configurazione di questo ambiente di sviluppo su Windows prevede l’installazione di ERIKA Enterprise e RT-Druid. In questa tesi è stata utilizzata l’ultima versione disponibile di RT-Druid la 1.6.1.
Su Windows è necessario anche installare Cygwin 1.7.9, che viene utilizzato dall’IDE per compilare i file
sorgenti, e Java Runtime Environment versione 6 o superiore.
I passi necessari a configurare correttamente l’IDE sono:
1. Installare Java Runtime Environment
2. Installare Cygwin nella sua directory originaria C:/cygwin.
3. Copiare RT Druid ed Erika 1.6.1 in una directory. Se si usa Vista è necessario che non ci siano
spazi nella directory di installazione, ad esempio è consigliabile installare tutto in C:/Evidence
4. Quando si seleziona il workspace di lavoro per RT-Druid non bisogna usare spazi. Ad esempio, è
possibile posizionare il workspace in C:/Users/yourusername/workspace
24
Capitolo 3. Ambienti di sviluppo
5. È importante non creare mai delle directory, oltre a quelle specificate, con cui lavorare con questo
IDE in altri path tranne la directory Users, quindi scegliere sempre C:/Users/yourusername/ per
lavorare senza problemi
6. Una volta installato il pacchetto contenente Erika e RT-Druid 1.6.1 bisogna effettuare l’aggiornamento dei plugin da Eclipse, quindi andare su “Help > Install New Software” ed utilizzare
il seguente repository http://download.tuxfamily.org/erika/webdownload/rtdruid_161_nb/,
selezionando tutti gli aggiornamenti
Figura 3.6.: Repository RT-Druid
Per ultimare l’installazione è necessario installare il Compilatore per il dsPIC montato a bordo della
Flex Full e che avrà il compito di trasformare il codice scritto per la macchina e quello di ERIKA in codice
oggetto, producendo un .cof che, attraverso l’IDE MPLAB della Microchip, finalmente programmerà la
scheda di sviluppo.
Il compilatore testato e funzionante con RT Druid 1.6.1 è l’MPLAB C Compiler for PIC24 and dsPIC
v3.31 versione Combo, edizione per studenti, installato nella directory di default.
Utilizzando questo compilatore tutte le vecchie versioni di RT Druid non sono più funzionanti perciò è
consigliabile lavorare con 1.6.1.
Dopo aver finito di installare il compilatore, ritornare su RT-Druid e andare su Windows > Preferences
e dal menù laterale della schermata che si aprirà cercare RT Druid -> Oil -> dsPIC e verificare che la
schermata corrisponda alla fig. 3.7:
25
Capitolo 3. Ambienti di sviluppo
Figura 3.7.: Link librerie MPLAB
26
Capitolo 3. Ambienti di sviluppo
Infine andare su Project e togliere la spunta su Build Automatically; ogni volta che si vorrà fare la
build del progetto dalla finestra Project Explorer andare su Build Project (vedi fig. 3.8).
Figura 3.8.: Build del progetto
La Build si compone di due parti. Prima di tutto viene creato e compilato il sistema ERIKA; questo
richiede generalmente più tempo rispetto alla seconda parte che è invece solo la traduzione in codice
oggetto delle istruzioni presenti nei file .c o .h del progetto.
Se il file OIL non ha subito modifiche recenti la Build fa partire solo la seconda.
L’ambiente di sviluppo RT-Druid non supporta alcune funzionalità offerte da Eclipse, come il completamento automatico o il supporto completo a tutti i valori dei registri del microcontrollore, anche
un ambiente correttamente configurato mostrerà a schermo falsi errori, come è possibile notare nella
schermata sottostante:
Figura 3.9.: RT-Druid IDE
27
Capitolo 3. Ambienti di sviluppo
questo non compromette la compilazione del file .cof, infatti gli “errori” vengono “risolti” in fase di
compilazione.Tuttavia rendono questo IDE può risultare confusionario e di difficile accesso.
Per importare il progetto “Marvin Face Follow” (o equivalentemente Marvin PID) si procede attraverso
il menù File > Import > existing project into Workspace e si seleziona Marvin spuntando la copia del
progetto nel workspace.
Dopo aver importato il progetto è necessario spostarsi nel Project Explorer e selezionare dal menu a
tendina Clean Project e successivamente Build Project per ottenere un nuovo file .cof.
Il log della corretta compilazione di Marvin PID, ma è equivalente per il Face Follow, è il seguente che
include entrambi gli step cioè la compilazione di ERIKA e del codice .c [2]
**** Build of configuration Default for project Marvin PID ****
C :\ Users \ WISTA \ flexworkspace \ Marvin PID \ Debug \ make_launcher . bat all
C :\ cygwin \ bin \ bash found !
cygwin warning :
MS - DOS style path detected : C :\ Users \ WISTA \ flexworkspace \ Marvin PID \ Debug
Preferred POSIX equivalent is : / cygdrive / c / Users /.../ Marvin PID / Debug
CYGWIN environment variable option " n o do s f i l e w a r n i n g " turns off this warning .
Consult the user ’ s guide for more details about POSIX paths :
http :// cygwin . com / cygwin - ug - net / using . html # using - pathnames
Using erika files in / cygdrive / c / EVIDEN ~2/ eclipse / plugins /.../ ee_files
Looking for the MPLAB C30 directory ...
... Using C :\ Program Files \ Microchip \ mplabc30 \ v3 .25
CPP eecfg . c
CPP code . c
CPP ee_hal_s tructs . c
CPP ee_context . c
CPP ee_irq . c
CPP ee_utils . c
CPP ee_alcancel . c
CPP ee_altick . c
CPP ee_alget . c
CPP ee_alsetabs . c
CPP ee_alsetrel . c
CPP ee_irqsc . c
CPP ee_rqexchg . c
CPP ee_rqinsert . c
CPP ee_schedule . c
CPP ee_thact . c
CPP ee_thendin . c
CPP ee_mutex . c
CPP ee_internal . c
CPP ee_utils . c
AR libee . a
LD
OBJDUMP
************************************
Compilation terminated successfully !
**** Build Finished ****
28
Capitolo 3. Ambienti di sviluppo
3.3. Microchip MPLAB v8.43
Per la programmazione del dsPIC, a bordo della scheda FLEX, si utilizza il programmatore Microchip
MPLAB ICD2 collegando, con un apposito cavo, i due dispositivi attraverso la porta ICD2.
La Microchip mette a disposizione l’ambiente di sviluppo MPLAB IDE per programmare il microcontrollore, sono integrate diverse funzionalità: gestione dei file e organizzazione dei progetti, editor per i
sorgenti, compilatori, programmazione e debugging con MPLAB ICD2.
In questo lavoro l’IDE è utilizzato solamente nella gestione dei file, importando il file dell’applicativo
realizzato con RT-Druid per programmare il dsPIC.
Per programmare il dsPIC è necessario andare su File > Import e scegliere il .cof generato da RTDruid (nella directory Debug del progetto).
Successivamente dopo aver collegato fisicamente PC e Flex Full andare nel menù Programmer > Select
Programmer MPLAB ICD2; successivamente dopo che la comunicazione è stata stabilita seguire i seguenti
passaggi:
Programmer > Connect e successivamente Programmer > Program
Figura 3.10.: Log della programmazione del dsPIC
Una volta collegato l’ICD2 il dsPIC è tenuto in uno stato di “Reset”, per sbloccarlo è sufficiente
scollegare l’ICD2 oppure utilizzare Programmer > Release from Reset.
Per poter utilizzare correttamente questa procedura è necessario effettuare una configurazione per
l’ICD2 cioè andare in Configure > Select Device e settare i parametri come in fig. 3.11:
29
Capitolo 3. Ambienti di sviluppo
Figura 3.11.: Setup ICD2 e MPLAB
3.4. Arduino IDE v1.0
Arduino IDE è l’ambiente di sviluppo per il microcontrollore Arduino, basato su Processing, un software
nato in origine come ambiente di sviluppo Java. Arduino IDE è molto semplice da utilizzare e da
configurare e questo risulta un grande punto a favore di questo progetto open-source italiano. Una volta
ottenuto l’ambiente di sviluppo non c’è bisogno di nessuna installazione, basta lanciare Arduino.exe per
iniziare a lavorare sull’IDE.
Per utilizzare la Board Arduino Mega ADK sono necessari dei drivers di comunicazione USB tra il PC
e la board che una volta installati faranno apparire Arduino come una porta seriale virtuale VCOM.
Fatto questo bisogna definire in Tools > Board la board “Arduino Mega 2565 or Mega ADK” e definire
in Tools > Serial Port a quale porta seriale è associato Arduino così da poter uploadare il codice e aprire
il Serial Monitor (vedi fig. 3.12).
Il codice per Arduino di solito viene compilato nel momento in cui viene inviato alla Board attraverso
l’icona Upload
senza bisogno di un programmatore esterno, in quanto ogni board Arduino è fornita di un Bootloader:
un piccolo programma che permette di programmare il microcontrollore Atmel via USB.
Il bootloader è attivo per alcuni secondi nel momento in cui la board viene resettata e viene avviato
ogni qual volta c’è del nuovo codice sulla board. Dopo aver completato l’upload i led TX e RX sulla
board lampeggeranno e il codice srà quindi compilato ed inviato sulla board. Essa inizierà da subito la
sua esecuzione, non esiste modo -come succede programmando la Flex- di mantenere la board in uno
stato di Reset.
30
Capitolo 3. Ambienti di sviluppo
Figura 3.12.: Selezione prototype board
31
Capitolo 3. Ambienti di sviluppo
La libreria Microbridge ADB deve essere installata insieme all’IDE e per fare ciò basta copiare la
cartella nella directory libraries di Arduino.
Per utilizzare questa libreria con Arduino IDE 1.0 e la Mega ADK bisogna effettuare delle modifiche
ai file che la compongono:
• Adb.h, usb.cpp, max3421e.cpp : la stringa Wiring.h va sostituita con Arduino.h, poiché Wiring.h
ha subito una ridenominazione passando alla versione 1.0 dell’IDE
• Nel file max3421e.cpp alla riga 387 bisogna sostituire questo codice
// Wait until the PLL is stable
while (!( max3421e_read ( MAX_REG _USBIRQ ) & bmOSCOKIRQ ) )
{
// Timeout after 256 attempts .
tmp ++;
if ( tmp == 0)
return ( false ) ;
}
Con questo:
// Wait until the PLL is stable
while (!( max3421e_read ( MAX_REG _USBIRQ ) & bmOSCOKIRQ ) )
Per evitare che l’oscillatore interno non effettui un corretto setup.
Per effettuare il debug sulla board bisogna utilizzare la funzionalità Serial Monitor, infatti dall’Arduino
IDE non si ha la possibilità di impostare breakpoints ed effettuare una esecuzione del codice step-by-step.
Per questo Arduino ha a disposizione dei comandi per abilitare la porta seriale (comunicazione lato board
via USART) per inviare stringhe, caratteri di controllo oppure risultati di elaborazione sullo schermo del
PC.
La comunicazione seriale è abilitata con le istruzioni Wiring Serial.Begin(baudrate) e istruzioni di
scrittura come Serial.println(stringa,formato). Il Monitor Seriale viene aperto nell’IDE attraverso
l’icona
Si può affermare dunque il Serial Monitor è il mezzo built-in di Arduino equivalente alla libreria
SerialConsole.h e del convertitore PL2303 usato per il debug della Flex.
Per importare il progetto esistente di Marvin è sufficiente aprire il file Marvin.ino (File > Open) ed
effettuare l’upload sulla Board attraverso il comando Upload dell’IDE.
3.5. Vinculum-II IDE v1.4.4
FTDI mette a disposizione una serie di firmware precompilati per alcune semplici applicazioni realizzabili con il chip Vinculum-II; per applicazioni più complesse è necessario realizzare un proprio firmware
che deve essere programmato nel chip.
A tal fine FTDI ha creato il Vinculum-II Toolchain, un insieme di strumenti software necessari per
la compilazione e lo sviluppo di applicazioni per il VNC2, che includono: un compilatore C, assembler,
linker, debugger e un IDE.
Lo sviluppo di applicazioni per il VNC2 è facilitato dall’utilizzo di kernel, driver di dispositivo e librerie
di runtime fornite nel Vinculum-II Toolchain. I vari strumenti della toolchain sono delle applicazioni
console, e come tali vengono integrate nell’IDE.
32
Capitolo 3. Ambienti di sviluppo
Figura 3.13.: Vinculum IDE toolchain
Il Vinculum-II IDE è il software utilizzato nello sviluppo delle applicazioni per il VNC2. Gestisce i
file di progetto e permette di creare l’output binario dell’applicazione usando gli strumenti integrati nella
toolchain:
• il compilatore VinC;
• l’assembler VinAsm;
• il linker VinL;
• il debugger VinDbg;
Figura 3.14.: Architettura Vinculum-II
La programmazione del firmware per il VNC2 avviene utilizzando il linguaggio C; l’architettura del
firmware è composta da tre livelli:
• il VOS Kernel, responsabile della gestione delle risorse hardware, degli interrupt e dello scheduling
dei thread;
33
Capitolo 3. Ambienti di sviluppo
• i driver FTDI, forniscono un’interfaccia di programmazione per il controllo delle risorse hardware.
• le librerie FTDI, che mettono a disposizione un insieme di funzioni C per operazioni comuni di
input/output e gestione dinamica della memoria.
IL VNC2 RTOS (VOS) kernel è un sistema operativo preemptive, multi-tasking, basato su priorità; esegue i task secondo l’ordine deciso dallo scheduler sulle priorità di ognuno; inoltre fornisce anche
meccanismi di sincronizzazione tra i task come semafori e sezioni critiche.
Il C non è l’unico linguaggio con cui è possibile programmare il Vinculum II. Infatti esiste anche un
insieme di API semplificate chiamate Vinco libraries che sono inspirate al linguaggio Wiring - simile a
quello usato per programmare Arduino - che se da un lato semplificano l’accesso alla piattaforma dall’altra
non permettono di usare appieno tutte le funzioni del RTOS VOS.
L’installazione di questo IDE è molto semplice ma essendo stato escluso dal progetto l’utilizzo del
Vinculum-II, non si approfondirà l’argomento.
Si rende presente comunque che il Vinculum IDE ha strumenti ottimi per il debugging del codice
attraverso i quali è possibile monitorare quali task sono in esecuzione ed il loro stato, è possibile leggere
il valore di tutte le variabili e effettuare un run del codice step-by-step per mezzo della definizione di un
massimo di 3 breakpoints.
Figura 3.15.: IDE del Vinculum-II
3.6. RealTerm v2.0
RealTerm è uno dei tanti programmi freeware per leggere dati da porta seriale. Essenzialmente esso
è stato scelto per la sua facilità di installazione ed per le molte opzioni che mette a disposizione; viene
utilizzato come strumento di debug per la Flex. Le impostazioni per avere una corretta configurazione
sono:
• Nel tab Display spuntare “new line mode” in maniera tale che il programma processi la sequenza
di escape \n, inviata attraverso la libreria serialConsole.h, come un “a capo” .
• Nel tab Port impostare come porta seriale il convertitore Prolific e come Baud 115200, che è il baud
rate di comunicazione della Flex.
Fatto questo è possibile ricevere ed inviare correttamente i dati utilizzato il tab “Send”.
34
Capitolo 3. Ambienti di sviluppo
Figura 3.16.: Ricezione dati dalla scheda Flex
Un esempio dell’utilizzo della libreria in combinazione con RealTerm può essere di questo genere: La
libreria permette di inviare stringhe al PC senza aspettarsi una risposta attraverso la sintassi
S en dS tr i ng Re pl y ( " \ nTesto \ n " ,PC , NoReply , false , false , UARTx ) ;
oppure
SendNumReply (1234 , PC , NoReply , , false , false , UARTx ) ;
È anche possibile bloccare l’esecuzione del codice sulla Flex (come se si avessero dei breakpoints) finché
non vengono inviati un numero di caratteri sufficienti dal PC verso la board attraverso l’istruzione
S en dS tr i ng Re pl y ( " \ nTesto con risposta \ n " ,PC , Reply ,& reply [0] ,1 , UARTx ) ;
oppure
SendNumReply (1234 , PC , Reply ,& reply [0] ,1 , UARTx ) ;
Figura 3.17.: Invio dati alla scheda Flex
che inviano rispettivamente una stringa o un numero e si aspettano 1 carattere di risposta che la Flex
salverà nell’array reply partendo dalla posizione 0.
35
Capitolo 4.
Analisi dei Requisiti e Progettazione del
Sistema
Il sistema da realizzare è composto da diversi componenti hardware e software per questo la realizzazione
è stata condotta attraverso layer di funzionalità. Ogni layer deve essere in grado di fornire interfacce ai
livelli sovrastanti ed essere descritto mediante input ed output.
Il capitolo inizia con una panoramica sull’analisi dei requisiti del sistema, ovvero cosa deve fare il
sistema per poi spiegare le funzionalità dei vari layer realizzati.
4.1. Analisi dei Requisiti
Vi sono due diversi tipi di requisiti sul sistema, quelli funzionali – cioè necessari per rispondere al
quesito riguardante cosa il robot “deve fare” – e i requisiti aggiuntivi o non funzionali, che forniscono
vincoli addizionali, permettendo un ulteriore sviluppo del progetto nel tempo.
I requisiti sono schematizzati qui di seguito.
Requisiti funzionali:
• Dotare il robot dei movimenti spaziali tramite API portabili
• Garantire un canale di comunicazione con ogni dispositivo Android
• Garantire una comunicazione affidabile con Arduino
• Implementare algoritmi di visione e decisione del movimento su dispositivo mobili dotati di Android
OS
• Aggiungere il motore che permette uno snodo “di testa”
Requisiti aggiuntivi:
• Gestire l’elaborazione della scheda Flex Full attraverso l’RTOS ERIKA in maniera intelligente
• Migliorare il programma di visione attraverso un semplice algoritmo di ricerca volti
• Sostituire il Motion Processor con motori controllabili
• Implementare un controllore PID
• Rendere più accessibile la scheda Flex creando API per la gestione ad hoc delle periferiche sulla
falsariga di Wiring
• Comunicazione wifi tramite Android OS
36
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
4.2. Requisiti Funzionali
4.2.1. Dotare il robot dei movimenti spaziali tramite API portabili
Il sistema deve essere in grado di controllare i movimenti del robot; ricevuto in ingresso il comando che
identifica il movimento da eseguire, dovrà azionare i motori per muovere opportunamente il robot.
I comandi che il sistema deve gestire sono:
• avanti
• indietro
• gira a destra
• gira a sinistra
• stop
• muovi la testa verso l’alto
• muovi la testa verso il basso
In un primo momento si è implementato questa caratteristica così come era stato fatto su AndroEEBot, cioè utilizzando il Motion Processor ma, come precedentemente anticipato, questa versione è stata
modificata per raggiungere il requisito aggiuntivo relativo alla sostituzione del Motion Processor.
E’ stato necessario pensare all’elettronica di alimentazione e lo studio dei servomotori e la scrittura
della libreria Servo.h per permettere il controllo del robot attraverso comandi inviati dallo smartphone.
4.2.2. Garantire un canale di comunicazione con ogni dispositivo Android
Questo requisito è stato raggiunto attraverso l’inserimento nel sistema di Arduino poiché compatibile con la libreria Microbridge ADB, che è risultata la libreria migliore per gestire una comunicazione
affidabile con qualsiasi smartphone.
A livello applicativo sono state incluse in Android le classi:
• AbstractServerListener
• Client
• ServerListener
• Server
Per gestire la comunicazione con Android, inoltre, da parte di Arduino bisogna includere gli header
SPI.h, Adb.h. Nel setup() bisogna inizializzare l’ADB subsystem così:
ADB :: init () ;
connection = ADB :: addConnection ( " tcp :4568 " , true , ad b Ev en tH a nd le r ) ;
Il polling dell’ADB deve essere inserito in loop() per ricevere i dati ad ogni ciclo di elaborazione,
con l’istruzione ADB::poll(), che richiamerà l’unica funzione implementata, tra quelle disponibili nella
libreria, cioè
void a db Ev en tH a nd le r ( Connection * connection , adb_eventType event , uint16_t length ,
uint8_t * data )
filtrando solo gli eventi di tipo ADB_CONNECTION_RECEIVE.
37
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
4.2.3. Garantire una comunicazione affidabile con Arduino
Il requisito è raggiunto attraverso l’implementazione lato Flex della libreria Arduino.h che contiene
API per richiedere dati al microcontrollore, mentre lato Arduino la verifica di ricezione di informazioni
dalla Flex è ottenuta mediante l’API serialEvent() che viene richiamata automaticamente del sistema
Arduino ad ogni ciclo di loop() e verifica quali tipi di dato sono presenti nel registro. La ricezione avviene
dalla porta seriale 1 a cui la Flex è fisicamente collegata.
4.2.4. Implementare algoritmi di visione su Android
Il requisito relativo all’implementazione di algoritmi di visione e decisione del movimento su dispositivo
Android è stato soddisfatto ereditando quasi in toto l’applicazione dal precedente progetto. L’applicazione
utilizza l’algoritmo detectMultiScale() tramite il quale è possibile identificare, dato un frame, un
oggetto corrispondente ad alcune caratteristiche descritte nel file “cascade”, scritto in formato XML.
Nel progetto è stato utilizzato come cascade lbpcascade_frontalface.xml, permettendo il riconoscimento
di volti in posizione frontale attraverso l’algoritmo di face detection Local Binary Pattern (LBP).
4.2.5. Aggiungere il motore che permette uno snodo “di testa”
AndroEEBot effettuava movimenti solo sull’asse X e Z (vedi figura seguente), con Marvin si è reso
possibile il movimento anche sull’asse Y attraverso l’aggiunta del servomotore HS-485HB e lo studio ed
implementazione del modulo PWM che ha portato alla scrittura delle librerie PWM.h e Servo.h.
Figura 4.1.: Assi di Marvin
4.3. Requisiti Aggiuntivi
I requisiti aggiuntivi rappresentano una sorta di sperimentazione e una dimostrazione di come sia
possibile evolvere e migliorare un’idea di partenza attraverso passi incrementali.
Definiti gli obiettivi principali pian piano ci si è resi conto di come migliorare e aggiungere diversi
aspetti al sistema; questi requisiti risultano essere degli ulteriori vincoli.
38
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
4.3.1. Elaborazione tramite RTOS ERIKA
Il multithreading e lo sviluppo di thread concorrenti/collaborativi sono possibili anche su microcontrollore attraverso l’uso ottimale di ERIKA, seppur l’applicazione Marvin e AndroEEBot ne fanno un
utilizzo semplice, istanziando un thread periodico.
Il lavoro si è orientato principalmente nel capire come utilizzare al meglio l’RTOS e successivamente si
è ipotizzata una suddivisione dell’applicazione in thread secondo una politica “Produttore-Consumatore”.
4.3.2. Migliorare il programma di visione
AndroEEBot necessitava di un volto che fosse presente nella scena per applicare l’inseguimento. Estendendo questo concetto ad un contesto più reale risulta necessario che il robot debba effettuare una, seppur
semplice, ricerca di eventuali volti intorno ad esso.
Il semplice algoritmo implementato nell’applicazione Android permette di definire due intervalli di
tempo, regolabili in fase di programmazione: startBehaviour e stopBehaviour che indicano un numero
di cicli entro i quali fermare o mantenere attiva la ricerca di un volto. Il comportamento implementato
consiste nel far ruotare su se stesso il robot; il verso di rotazione dipende dall’ultimo spostamento che è
stato registrato. Se il volto prima di sparire dal frame si è spostato verso destra, ad esempio, il robot
girerà verso destra nella speranza di trovare da quella parte il volto.
Il comportamento di ricerca funziona anche nel caso in cui all’avvio del robot nessun volto dominante
è stato mai inquadrato nella scena, allora si impone un verso di rotazione a priori che nel caso di questa
tesi è destra.
Figura 4.2.: Flowchart per l’algoritmo di controllo del movimento
4.3.3. Sostituire il Motion Processor
Questo requisito è di fondamentale importanza per lo sviluppo futuro, il controllo e la personalizzazione
del progetto Marvin.
Come spiegato in precedenza, seppure il Motion Processor sia un’ottima soluzione tecnica, esso limitano
l’aspetto real-time dell’applicazione delegando ad un altro “processore” il compito di eseguire i comandi
di controllo. La soluzione è stata quella di inserire i servomotori DFRobotic ma in futuro, attraverso la
libreria PWM.h, l’API digitalWrite() e una circuiteria composta da un ponte H, sarà possibile sostituire
i servo con motori DC più performanti.
39
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
4.3.4. Implementare un controllore PID
La Meccanica, l’Elettronica e l’Informatica sono le scienze su cui l’Automazione si basa; avendo seguito
lo sviluppo del robot in tutte queste fasi è sembrato naturale cercare di attuare un Controllo per lo
spostamento nello spazio di Marvin. Non avendo a disposizione il modello matematico del robot, l’unico
controllo applicabile è stato quello PID realizzato mediante l’implementazione dell’azione proporzionale
prima, e poi dell’azione proporzionale ed integratrice poi.
Rendere più accessibile la scheda Flex creando API per la gestione ad hoc delle periferiche sulla falsariga
di Wiring: lo sviluppo del progetto in questo senso è stato dettato sia come evoluzione naturale dello
studio della scheda Flex e del microcontrollore dsPIC, sia come “emulazione” di Wiring: il linguaggio di
programmazione embedded di Arduino.
API semplici sono la forza del progetto Arduino poiché rendono accessibile la scheda di sviluppo in
poco tempo.
4.3.5. Comunicazione wifi tramite Android
Questa caratteristica disponibile già per AndroEEBot è stata mantenuta, ma non testata, anche in
Marvin; essa permette la comunicazione con un applicazione ad hoc su un PC attraverso la rete wifi di
cui ogni smartphone è dotato.
4.4. Architettura e funzionamento del sistema
L’architettura del sistema è divisa in 4 livelli dal più basso al più alto:
• Attuazione: è composto dall’elettronica, della meccanica e da tutti gli attuatori del sistema, ovvero
dai 3 servomotori
• Controllo: comprende l’ MCU dsPIC che gestisce il movimento del robot, l’interfacciamento con
la sensoristica e il sistema operativo Real Time ERIKA;
• Comunicazione: composto da Arduino e dalla libreria Microbridge ADB, questo livello funge
anche da espansione del sistema. Infatti è possibile sfruttare Arduino come una seconda logica di
controllo da affiancare alla Flex per controllare l’attuazione di comandi verso il mondo esterno
• Comando: è il livello rappresentato dallo smartphone che attraverso applicazioni Java permette
di controllare i livelli sottostanti e comunicare con PC attraverso wifi.
Uno schema grafico dell’architettura è visibile in fig.4.3
Il ciclo di funzionamento di Marvin è composto da diverse fasi di elaborazione gestite indipendentemente
da i vari livelli architetturali sopra descritti, l’elaborazione parte dal livello di Comando che analizzando
i frame video decide quali spostamenti imporre ai livelli sottostanti e/o inviare i dati tramite wifi al PC.
I dati sono inviati al layer di comunicazione in maniera asincrona, proprio come se il livello superiore
fosse un enorme sensore; i comandi di spostamento, espressi come singolo byte o insieme di essi, vengono
inviati tramite microbridge ADB ad Arduino che li conserva in una variabile globale, intanto esso resta
in attesa di interrupt sulla Serial 1 (è opportuno ricordare che Arduino ha 4 porte seriali USART) oppure
potrebbe elaborare altri dati provenienti da un eventuale sensoristica.
Indipendentemente dai livelli superiori sulla board Flex Full , dopo l’inizializzazione delle periferiche,
ogni 100 ms viene mandato in esecuzione da ERIKA un task periodico che richiede i dati via USART 1
ad Arduino.
La risposta che proviene da quest’ultimo è l’ultimo dato di movimento che Android ha inviato al
layer di comunicazione in modo asincrono. La Flex quindi elabora questi dati attivando, in base al
40
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
tipo di applicazione presente sul layer di comando il controllo PID oppure la semplice generazione dei
corrispondenti comandi di attuazione per i servomotori.
La Flex durante un suo ciclo di elaborazione può anche ricevere dati dalla sensoristica o inviare, tramite
USART 2, informazioni di debug verso Arduino o PC.
Figura 4.3.: L’architettura a 4 livelli di Marvin
4.5. Protocolli di comunicazione
Data la complessità del sistema, è fondamentale definire quali sono i dati che vengono scambiati tra
i vari componenti e le interfacce utilizzate. Il sistema è stato concepito per funzionare in due differenti
modalità, spostamento “manuale” e PID: è necessario, dunque, distinguere queste due istanze, creando
due opportuni protocolli di comunicazione.
4.5.1. Android
Esistono due versioni dell’applicazione Android e sono “Marvin Grid View” e “Marvin PID”.
“Marvin Grid View” calcola gli spostamenti in base alla posizione del volto rispetto a delle aree predefinite nel frame. La definizione predefinita delle aree è detta Grid View, e divide il frame in cinque
aree distinte; una centrale, due aree laterali – destra e sinistra –, un’area superiore ed una inferiore. La
41
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
presenza di un volto in ciascuna di queste aree induce la generazione di un particolare pacchetto che è
formattato come segue:
1 byte: MODE
OxOF
1 byte: DIRECTION
OxOn
Tabella 4.1.: Formato del pacchetto trasmesso dall’applicazione Android “Marvin Grid View”
MODE serve per notificare ad Arduino quale applicazione è in esecuzione su Android. Il byte associato
all’applicazione “Grid View” è 0x0F.
DIRECTION, invece contiene un byte di spostamento calcolato da Android e può assumere i seguenti
valori:
• 0x00 STOP
• 0x01 AVANTI
• 0x02 INDIETRO
• 0x03 GIRA A DESTRA
• 0x04 GIRA A SINISTRA
• 0x05 SNODO DI TESTA VERSO L’ALTO
• 0x06 SNODO DI TESTA VERSO IL BASSO
La seconda applicazione, “Marvin PID”, è invece pensata per sfruttare il PID e perciò utilizza una
diversa formattazione del pacchetto:
1 byte: MODE
OxOC
sX
errorX
15 byte: ERROR
sY errorY sZ
errorZ
Tabella 4.2.: Formato del pacchetto trasmesso dall’applicazione Android “Marvin PID”
Nell’applicazione “Marvin PID” MODE è pari a 0x0C.
I successivi 15 byte, ERROR, possono essere interpretati a blocchi di 5 byte. Ogni blocco contiene:
• sK: 1 byte che contiene il segno dell’errore sull’asse K;
• errorK: 4 byte che forniscono, quando interpretati, un float che rappresenta l’errore in valore
assoluto sull’asse K.
4.5.2. Arduino
Nel layer di comunicazione i due differenti comportamenti di controllo sono contemporaneamente presenti e il byte MODE inviato da Android determina quale comportamento implementare. I comandi che
Android invia vengono captati da Arduino attraverso void adbEventHandler(), che filtra solo gli eventi
di tipo ADB_CONNECTION_RECEIVE come spiegato in precedenza; in particolare il byte MODE viene salvato
nella variabile globale MODE e riutilizzato in fase di risposta alla Flex. I dati inviati da Android sono
contenuti nell’array data.
if ( event == A D B _ C O N N E C T I O N _ R E C E I V E )
{
MODE = data [0];
/* The Application is using the Grid View */
if ( MODE != 0 x0C )
42
Capitolo 4. Analisi dei Requisiti e Progettazione del Sistema
{
// data in position data [1] contains robot ’s direction
direction = data [1];
}
/* The application is using the PID View */
else
for ( i =0; i <15; i ++) directions [ i ]= data [ i +1];
}
Nella funzione void serialEvent1(), associata agli interrupt della Serial1, il seguente frammento di
codice Arduino verifica che la Flex abbia richiesto l’invio dei dati di direzione, e risponde in base al MODE
precedentemente salvato. Arduino antepone al pacchetto un byte di controllo per l’integrità dei dati.
if ( Serial1 . read () == 0 x7F )
{
Serial1 . write (0 x0A ) ;
/* The Application is using the PID View */
if ( MODE != 0 x0C )
Serial1 . write (( byte ) direction ) ;
/* The application is using the Grid View */
else
for ( j =0; j <15; j ++) Serial1 . write ( directions [ j ]) ;
}
1 byte: MODE
OxOF
1 byte: DIRECTION
direction
Tabella 4.3.: Formato del pacchetto trasmesso da Arduino nell’applicazione “Marvin Grid View”
1 byte: CTRL
OxOA
15 byte: ERROR
directions[j]
Tabella 4.4.: Formato del pacchetto trasmesso da Arduino nell’applicazione “Marvin PID”
4.5.3. Flex Full Board
La Flex Full, come detto, gestisce la comunicazione percependo Arduino e Android come un unico
sensore a cui richiedere, ogni 100 ms, i dati di spostamento attraverso il task periodico denominato
TaskSend. Sulla Flex esistono due diverse implementazioni del firmware a seconda di quale applicazione
Android si sta utilizzando, poiché varia il numero di dati da richiedere ad Arduino. La richiesta viene
fatta usando la funzione Arduinio_Data_Request() contenuta in Arduino.h.
Per l’applicazione “Grid View”, la funzione è:
A r d u i n o _ D a t a _ R e q u e s t (& arduinoData [0] , 2 , UART1 ) ;
Invece, per l’applicazione “PID”, la funzione è:
A r d u i n o _ D a t a _ R e q u e s t (& arduinoData [0] , 16 , UART1 ) ;
Il byte di controllo inviato da Arduino viene verificato in entrambi i casi dalla Flex e se esso corrisponde
al carattere di controllo atteso – 0x0A – allora esso farà illuminare il led Arancione (pin 25).
if ( arduinoData [0] == 0 x0A )
ledBlink (25 ,1 ,100) ;
43
Capitolo 5.
Implementazione del Software
Al termine della fase di progettazione e definizione del problema, dei requisiti e di vincoli si passa alla
fase di sperimentazione/studio e programmazione sia dei componenti embedded sia dell’applicazione ad
alto livello.
Apre il capitolo una descrizione delle librerie e delle API scritte per la Flex. Si passa poi alle caratteristiche hardware sfruttate; segue una descrizione di ERIKA Enterprise con uno sguardo alle sue peculiarità.
In seguito viene descritto il firmware per Arduino. L’implementazione per smartphone chiude il capitolo.
5.1. Librerie Flex Full
Il lavoro maggiore si è concentrato sullo studio della scheda Flex Full partendo dal suo nucleo il dsPIC.
Come già detto si può fare a meno dell’architettura modulare - soprattutto se la parte elettronica da
realizzare è ridotta all’osso – tutte le funzionalità sono già presenti sul microcontrollore e la flex esporta
tutti i 100 pin all’esterno.
L’obiettivo principale è stato quello di semplificare l’accesso a funzionalità ricorrenti come le porte
USART di comunicazione, il PWM, il comando servomotori e motori DC e dotare la scheda di strumenti
di debug a run time.
Le librerie realizzate ed utilizzabili senza troppe difficoltà, in quanto poco dipendenti dall’applicazione
Marvin, sono descritte qui di seguito.
5.1.1. Libreria EEuart.h
// - - - - - - - - - - - - - - - - - Public functions - - - - - - - - - - - - - - void ee_usb_init ()
void ee_usb_write ( BYTE * ch , BYTE len , BYTE UART )
void ee_usb_read ( BYTE * data , BYTE UART )
void e e_ us b_ re a d_ le n ( BYTE * data , BYTE len , BYTE UART )
// - - - - - - - - - - - - - - - - - Internal functions - - - - - - - - - - - - - - void EE_UART1_Init ( EE_UINT32 baud , EE_UINT16 format , EE_UINT16 mode )
EE_INT8 EE_UART1_Send ( unsigned char data )
EE_INT8 E E_ U A R T 1 _ R e c ei v e ( unsigned char * data )
void EE_UART2_Init ( EE_UINT32 baud , EE_UINT16 format , EE_UINT16 mode )
EE_INT8 EE_UART2_Send ( unsigned char data )
EE_INT8 E E_ U A R T 2 _ R e c ei v e ( unsigned char * data )
Con questa libreria è possibile inviare dati attraverso le due porte USART di cui la Flex Full è dotata.
ee_usb_init() attiva ed imposta il modulo hardware della USART1 e USART2 con baudrate a 115200
baud. Attraverso ee_usb_write() vengono inviati tutti i byte contenuti nel vettore data attraverso la
porta USART selezionata (1 o 2).
ee_usb_read() e ee_usb_read_len() permettono di leggere rispettivamente un byte o len byte e
salvarli nel vettore data.
44
Capitolo 5. Implementazione del Software
Queste letture sono “bloccanti” cioè la macchina resta bloccata su queste funzioni finché non riceve
esattamente len byte.
L’implementazione delle API pubbliche viene fatta attraverso le chiamate alle funzioni private che implementano a livello hardware la lettura/scrittura dei byte nei registri opportuni.
5.1.2. Libreria Arduino.h
void A r d u i n o _ D a t a _ R e q u e s t ( BYTE reply [] , BYTE len , BYTE UART )
float c o n v e r t 4 B y t e T O 1 F l o a t ( EE_INT32 byteArray []) ;
Arduino_Data_Request() permette di leggere len byte da Arduino e li salva nell’array reply.
Convert4ByteTO1Float() converte un array formato da 4 byte nel corrispondente numero float; è utilizzata per passare da Android alla Flex un numero in float sotto forma di byte e poi ricostruirlo sulla Flex.
5.1.3. Libreria Utility.h
void mydelay ( int ONEMILLION ) ;
void pinMode ( BYTE pin , BYTE mode ) ;
void digitalWrite ( BYTE pin , BYTE voltage ) ;
void ledBlink ( BYTE pin , BYTE times , int delay ) ;
float potenza ( float base , float esponente ) ;
double map ( double value , double in_min , double in_max , double out_min , double out_max ) ;
mydelay() è un semplice delay, utile soprattutto in fase di debug, che blocca la macchina per diversi
cicli di clock; con valori di 2000-3000 si riesce a bloccare la macchina per 1-2 secondi, ma non garantisce
la scansione precisa del tempo.
pinMode(), come su Arduino, attiva un determinato pin come input o output attraverso il parametro
mode, ogni pin sulla Flex è multiplexato, cioè può svolgere diverse funzionalità. Quindi solo alcuni pin
possono essere dati in ingresso a questa funzione e sono tutti quelli di PORTB [pin 20-27] e 2 di PORTA [pin
91-92].
digitalWrite() permette di cambiare lo stato logico di un pin precedentemente attivato con pinMode()
ponendolo HIGH o LOW, questa funzione può essere usata per accendere e spegnere un led oppure per inviare segnali a logiche elettroniche di controllo esterne (es. flip-flop). ledBlink() è appositamente pensata
per far “blinkare” un led impostando il pin a cui esso è associato, il numero di blink richiesti e il tempo
di blinking di solito tra i 100 e i 1000 ms, funziona sui pin attivabili con pinMode().
potenza() effettua l’elevamento a potenza anche con esponenti negativi, è stata necessaria implementarla poiché la libreria math.h della Flex non restituisce risultati corretti con esponenti negativi.
map() permette di effettuare un mapping di una variabile che varia in un insieme di valori A ad un
altro insieme di valori B.
5.1.4. Libreria serialConsole.h
void Se n dS tr in g Re pl y ( char string [] , BYTE ArduinoDebug , BYTE WithReply , BYTE reply [] , BYTE
len , BYTE UART ) ;
void SendNumReply ( unsigned long int number , BYTE ArduinoDebug , BYTE WithReply , BYTE reply
[] , BYTE len , BYTE UART ) ;
È la libreria che permette di inviare stringhe e numeri tramite porta USART.
Le API sono dotate di diversi parametri ed possibile inviare solo dati oppure bloccare la macchina in
attesa di una risposta attraverso il byte WithReply impostato a true e definendo quanti byte leggere
prima di sbloccarsi e dove salvarli.
Si può scegliere anche se effettuare debug tramite il serial Monitor di Arduino utilizzando la costante
“Arduino” oppure “PC” per debug con il convertitore.
45
Capitolo 5. Implementazione del Software
Se si comunica con Arduino si deve impostare il byte UART a UART1 mentre se si comunica con il PC
impostare il byte come UART2.
5.1.5. Libreria Servo.h
void
void
void
void
void
void
void
S e r v o M o d u l e _ i n i t () ;
S er vo Mo to r _i ni t ( BYTE motor ) ;
Servo_Neutral ( BYTE motor ) ;
Servo_plus90 ( BYTE motor ) ;
Servo_minus90 ( BYTE motor ) ;
S e r v o _ S e t _ P o s i t i o n ( BYTE motor , float hightime , float period ) ;
Servo_Move ( BYTE motor , float increment , float period ) ;
La libreria è basata sulla libreria PWM.h. Queste API sono delle funzioni pubbliche della PWM ma i due
insieme di API sono separati perché potrebbe essere necessario utilizzare la PWM non solo per utilizzare
i motori, ma anche per altre periferiche fisiche ad esempio variare la luminosità di un led.
ServoModule_init() è la prima funzione da chiamare per attivare il modulo hardware dei servomotori
al modulo hardware sono associati ben 8 uscite PWM. In Marvin ne vengono utilizzate solo 3 e il periodo
del PWM è impostato di default a 20 ms.
ServoMotor_init() dando le costanti HEAD, DX o SX attiva l’uscita PWM corrispondente che fa
parte dell’insieme degli 8 PWM attivabili dal modulo PWM inizializzato.
Servo_Neutral() in base al PWM scelto imposta il duty cycle a 1.5 ms questo significa che i motori
associati a tale uscita PWM ritornano in posizione neutra, i motore di testa quindi si pone all’angolo 0°
mentre i motori di propulsione smettono di girare.
Servo_plus90() e Servo_minus90() sono funzioni pensate per il motore di testa e impostano rispettivamente il duty cycle a 2.4 ms e 0.6 ms che corrispondono a +90 e -90 gradi. Se applicate ai motori di
propulsione questa API ha l’effetto di far ruotare in avanti o indietro i motori alla massima velocità.
Servo_Set_Position() è l’API migliore per controllare la posizione dello snodo di testa, infatti dato
un valore di hightime (T-on) esso si sposterà precisamente all’angolo corrispondente. E’ anche l’API
più utile per controllare i motori di propulsione in quanto specificando 1.5 < T-on < 2.4 si controlla la
velocità di rotazione dei servi di propulsione in senso orario mentre con 0.6 < T-on < 1.5 si controlla la
velocità di rotazione dei servi di propulsione in senso antiorario.
Servo_Move() è l’API ideale per muovere con precisione il motore di testa infatti questa funzione
ricorda in automatico la posizione precedente del motore e permette di dare un incremento positivo o
negativo allo snodo di testa così da effettuare micromovimenti partendo da una posizione fissata.
5.1.6. Libreria PWM.h
void
void
void
void
void
PWM_module_on () ;
Enable_PWM ( int PWM ) ;
P W M _ S e t _ D u t y _ C y c l e ( int PWM , float hightime , float period ) ;
P W M _ M o d u l e _ c l o s e () ;
Disable_PWM ( int PWM ) ;
Questa libreria controlla il PWM hardware.
PWM_module_on() attiva il modulo PWM impostando il periodo dell’onda quadra a 20 ms.
Enable_PWM() attiva una particolare uscita PWM da 1 a 3 del modulo PWM
PWM_Set_Duty_Cycle() imposta il registro P1DCx corrispondente ad una precisa uscita PWM
PWM_Module_close() disabilita il modulo PWM spegnendo tutte le uscite PWM
Disable_PWM() disabilita un preciso output PWM
46
Capitolo 5. Implementazione del Software
5.1.7. Libreria PID.h
float
float
float
float
float
float
PI_pid_Y ( float error )
P_pid_Y ( float error )
PI_pid_Z ( float error )
P_pid_Z ( float error )
PI_pid_X ( float error )
P_pid_X ( float error )
Contiene l’implementazione del controllore PID e le costanti impostate per i 3 assi di movimento:
• Y associato al motore di testa
• Z associato al movimento avanti/dietro dei motori di propulsione
• X associato al movimento destra/sinistra dei motori di propulsione
Questa libreria utilizza la libreria Servo.h ma l’utilizzo di questa maschera il comando diretto dei
motori.
Per utilizzare questa libreria bisogna utilizzare anche l’applicazione Android corrispondente.
Le API sono sempre le stesse sui tre assi e sono:
• PI_pid_K() utilizza il controllore proporzionale ed integrativo sull’asse K
• P_pid_K() utilizza il controllore proporzionale sull’asse K
5.2. Componenti Hardware Flex Full
5.2.1. Oscillatori
Un oscillatore è un circuito elettronico che genera forme d’onda di frequenza, forma e ampiezza di
molteplici tipi senza un segnale di ingresso. Gli oscillatori nella loro vastità sono impiegati in innumerevoli
applicazioni che spaziano dalla temporizzazione di circuiti digitali e non, alla generazione di portanti per
le telecomunicazioni, agli strumenti elettromedicali, ecc.
Gli oscillatori possono dividersi in due principali categorie:
• Armonici o sinusoidali (o, più propriamente, quasi-sinusoidali);
• A rilassamento o bloccati;
Gli oscillatori armonici producono un segnale di andamento sinusoidale (o quanto più possibile prossimo
ad esso). Essenzialmente si tratta di un amplificatore in cui l’uscita è riportata all’ingresso con una
retroazione positiva, attraverso un filtro passa-banda stretto. Quando il circuito è acceso, l’amplificatore
produce inevitabilmente in uscita del rumore. Il circuito di reazione riporta in ingresso le componenti del
rumore di frequenza determinata, le quali vengono amplificate. Il ciclo si ripete fino al raggiungimento del
regime di funzionamento. Essi sono suddivisibili in tre principali categorie in base agli elementi circuitali
utilizzati che cono RC, LC e Quarzati. Il dsPIC utilizza un oscillatore RC, composto esclusivamente da
resistori e condensatori.
Il dsPIC integra due oscillatori uno principale, FRC – Fast RC – a frequenza di 7.37 MHz e un
oscillatore secondario LP – Low Power – a 37.768 Khz e sono previste 7 diverse configurazioni per gestirli
via software:
• FRC Oscillator
• FRC Oscillator con PLL
• Primary Oscillator (XT, HS, EC)
47
Capitolo 5. Implementazione del Software
• Primary Oscillator con PLL
• Secondary Oscillator (LP)
• LPRC Oscillator
• FRC Oscillator con Postscaler
La frequenza dell’FRC può essere modificata via software attraverso il circuito PLL (Phase Loop
Locker) che ne incrementa di molto la frequenza i base portandola al massimo fino a 80 MHz.
Il Primary Oscillator può essere:
• XT: Risonatore in Cristallo e Ceramica, genera armoniche da 3 MHz a 10 MHz esso è connesso ai
pin OSC1 e OSC2
• HS: Cristallo ad alta velocità (High Speed) con frequenze di clock generabili da 10 MHz a 40 MHz
• EC: Identifica un segnale di clock dato da un oscillatore esterno che può variare nel range di
frequenze 0.8 – 64 MHz
L’oscillatore secondario (LP) è studiato per bassi regimi di potenza e per questo usa un cristallo che
oscilla a frequenze sensibilmente più basse rispetto a l’FRC; esso è collegato ai pin SOSCI e SOSCO.
LPRC – Low Power RC – è una diversa modalità di impiego dell’LP ed è usato come timer per il
Watchdog1 e FSCM (Fail Safe Clock Monitor).
La scelta della modalità è fatta attraverso i “Configuration Bits” FOSCSEL<2:0> e FOSC<1:0> in una
situazione di Power-on o Reset.
Per ottenere la frequenza di funzionamento del dispositivo Fc , la frequenza di output dell’oscillatore
(oppure oscillatore + PLL) Fosc va divisa per 2:
Fosc
(5.1)
2
Come detto, sia FRC sia LP possono utilizzare PLL per generare frequenze maggiori ma visto l’utilizzo
che si fa del dsPIC, in questa tesi si adopererà solo l’FRC e si indicherà con FOSC il suo output.
Fin indica la frequenza d’ingresso del PLL. Essa è divisa da un Prescaler, chiamato N1 che effettua
divisioni di 2, 3, ..., 33 prima che esso diventi input del PLL; a questo punto esso è indicato com Vco .
Per impostare il fattore del prescaler N 1 bisogna impostare i bits PLLPRE del registro CLKDIV. Il PLL
Feedback divisor PLLDIV del registro PLLFBD è denotato con M e rappresenta il fattore per il quale
l’ingresso del PLL, Vco , viene moltiplicato. Infine l’output del PLL è diviso ancora di un fattore deciso
dal Postscaler, chiamato N 2, il cui valore è impostato nei bit PLLPOST del registro CLKDIV. N 2 può essere
2, 4 oppure 8.
Per cui, Fosc è dato dalla formula:
Fc =
Fosc = Fin ·
1 letteralmente:
M
N1 · N2
(5.2)
cane da guardia. È un sistema di temporizzazione hardware che permette alla CPU la rilevazione di un
loop infinito o di una situazione di deadlock,tale rilevazione può consentire di prendere dei provvedimenti per correggere
la situazione, generalmente effettuando un reset del sistema
48
Capitolo 5. Implementazione del Software
Figura 5.1.: Determinazione di Fosc
La frequenza più importante è ovviamente Fc , ovvero quella di funzionamento del dispositivo. Nel
presente lavoro essa è impostata al massimo valore disponibile, 40 MHz. Per ottenere questo valore è
necessario che Fosc sia di 80 MHz per cui utilizzo:
• XT con PLL in questo modo ottengo circa 10 MHz
• N 1 = 2, cioè CLKDIVbits.PLLPRE = 0, questo porta la frequenza a 5 MHz
• M = 32, cioè PLLFBDbits.PLLDIV=0x1E (78 in decimale), ottenendo una frequenza di 160 MHz
• N 2 = 2, cioè CLKDIVbits.PLLPOST = 0 ottenendo finalmente Fosc = 80 MHz, da cui Fc =
MHz
80
2 =40
5.2.2. USART
È la periferica per la comunicazione seriale asincrona e le sue funzioni sono contenute nel file eeuart.h.
Le varie funzionalità sono precedute dall’istruzione __INLINE__ al fine di rendere le chiamate più veloci; infatti il compilatore di fronte a questa keyword sostituirà la chiamata alla funzione con il codice
corrispondente.
La Flex Full possiede due porte USART indipendenti denominate UART1 e UART2 e ogni porta può
essere configurata in maniera separata dall’altra.
Per le funzionalità necessarie in questa tesi esse sono configurate allo stesso modo, cioè con il protocollo
8-N-1-None ovvero:
• 8 Data Bits
• Parity None
• 1 Stop Bit
• Flow Control None
49
Capitolo 5. Implementazione del Software
Figura 5.2.: Architettura hardware di una periferica USART
Il diagramma semplificato della periferica vede 3 componenti principali: il Baud Rate Generator, in
Trasmettitore Asincrono e il Ricevitore Asincrono.
L’inizializzazione dei registri della periferica vengono effettuati dalla funzione ee_usb_init() che richiama EE_UART1_Init() e EE_UART2_Init(). L’attivazione della periferica è regolato dal bit UARTEN
del registro UxMODE: se esso è pari a 0 la periferica è disattivata, risulta buona norma disabilitare gli
interrupt che tale periferica può generare per la ricezione e l’invio di byte attraverso i bit UxRXIE ed
UxTXIE del registro IEC0 infine fare una pulizia dei flag degli interrupt dedicati ovviamente alla ricezione
e alla trasmissione nel registro IFS0.
Importantissimo per stabilire una comunicazione è definire il Baud Rate, che rappresenta il numero di
simboli che viene trasmesso in un secondo. Per simbolo non si intende un solo bit ma in insieme di essi;
per cui questa misura differisce dalla misura bps cioè bits per secondo. Per la Flex esso è impostato a
115200 baud/s per ottenere questo valore viene utilizzata la seguente formula nel caso di BRGH = 0:
Fc
−1
16 · DesideredBaud
Questa formula è riportata nel codice del microcontrollore in questo modo:
U xBRG =
(5.3)
U1BRG = (2500000 ul / baud ) - 1; // With BRGH = 0
U2BRG = (2500000 ul / baud ) - 1; // With BRGH = 0
dove:
Fc
40 · 106
=
= 2500000 ⇒ baud = 115000
(5.4)
16
16
Successivamente all’impostazione del Baud Rate è necessario definire i pin di output che assumeranno
il carattere di RX e TX. Essi sono stati scelti in accordo con il manuale di riferimento impostando i pin
corrispondenti ai bit 2 e 3 per la UART1 e ai bit 4 e 5 per la UART2 sulla porta di I/O digitale PORTF2 .
La funzione EE_UART1_Init() ha una struttura molto flessibile permettendo di impostare il Baud Rate
desiderato, la modalità di funzionamento (con o senza Flow Control ) e il byteformat per modificare il
protocollo 8-N-1.
2 Vedi
figura 3
50
Capitolo 5. Implementazione del Software
Figura 5.3.: Il protocollo UART
Il registro UxRSR è lo shift register3 , che si occupa della ricezione. I dati sono ricevuti sul pin UxRX
e sono inviati al Data Recovery Block che opera ad un velocità pari a 16 volte il Baud Rate; dopo che
è stato acquisito lo Stop Bit del protocollo seriale, i dati ricevuti nel registro UxRSR sono trasferiti in
una coda FIFO. Essa può contenere al massimo 4 word contemporaneamente; se arriva una quinta word
e il registro non è stato letto si entrerà in una situazione di buffer overrun, che deve essere gestita via
software.
Il registro UxTSR invece è lo shift register che si occupa dell’invio dei dati verso il mondo esterno. Esso
riceve i dati dal buffer FIFO UxTXREG che viene caricato via software con i dati in uscita. Esso è caricato
con nuovi dati se e solo se è stato inviato lo Stop Bit dall’UxTSR.
5.2.3. Modulazione a Larghezza di Impulso (PWM)
La modulazione di larghezza di impulso è un tipo di modulazione digitale che permette di ottenere una
tensione media variabile, dipendente dal rapporto tra la durata dell’impulso positivo e di quello negativo.
Tale modulazione è utilizzata per protocolli di comunicazione in cui l’informazione è codificata sotto forma
di durata nel tempo di ciascun impulso. Questa modalità è quella utilizzata dalla logica dei servomotori,
logica in cui la durata nel tempo di ciascun impulso determina il comportamento dell’attuatore.
La periferica del dsPIC utilizzata per generare la PWM è MCPWM1 che può generare output multipli e
sincronizzati rendendo la periferica ottimale per controllare diverse tipologie di motori.
Alcune delle features del modulo MCPWM1 sono:
• fino ad otto output PWM con quattro generatori di duty cycle
• possibilità di attivare o disattivare manualmente le singole uscite PWM
• possibilità di cambiare la PWM “on-the-fly”
• Dead time generabile via hardware
• Diverse modalità di utilizzo:
– Single event mode
– Edge-aligned mode
3 registro
a scorrimento costituito da una catena di celle di memoria ad 1 bit interconnesse tra loro. Ad ogni impulso di
clock consentono lo scorrimento dei bit da una cella a quella immediatamente adiacente, al fine di convertire i bit arrivati
in forma seriale a quella parallela.
51
Capitolo 5. Implementazione del Software
– Center-aligned mode
– Center-aligned mode with double updates
– Complementary output mode
– Independent output mode
Il dsPIC ha anche un secondo modulo per il controllo motori tramite PWM, MCPWM2, leggermente
diverso rispetto a MCPWM1. Tale modulo non è stato utilizzato nella progettazione di Marvin.
L’MCPWM1 è stato utilizzato nella modalità Free Running Mode Edge-aligned.
La generazione degli interrupts PWM dipende dalle modalità operative quindi dai bits PTMOD (Time
Base Mode) nel registro P1TCON (Time Base Control Register) e dai bits di PTOPS (Time Base Output
Postscaler) del registro P1TCON.
In modalità Free Running un interrupt è generato quando il registro PWM P1TMR (Time Base Register)
viene resettato a 0 a causa del raggiungimento del valore impostato nel registro PTPER.
I bits del postscaler sono utilizzati in questa modalità per ridurre la frequenza degli eventi di interrupt.
Per generare un’onda rettangolare, oltre al periodo – che definisce ogni quanti secondi il segnale viene
generato mediante interrupt – bisogna generare un corretto duty cycle mediante la scrittura dell’apposito
valore nel registro P1DCx.
I registri di duty cycle sono 4, ognuno legato a una coppia di uscite PWMxH/L. Nel progetto di Marvin
sono utilizzati in primi tre registri di duty cycle dell’MCPWM1 cioè P1DC1, P1DC2 e P1DC3. Il valore scritto
nel registro permette di generare un’onda PWM con opportuno duty cycle; infatti il segnale PWM è
alto all’inizio del periodo, cioè quando P1TMR = 0, dopodiché esso verrà incrementato fino a raggiungere
il valore contenuto nel registro P1DCx. Il segnale torna quindi basso e viene generato finché P1TMR non
raggiunge il valore di PTPER. A questo punto l’onda PWM è stata completamente generata e il ciclo si
ripete.
Figura 5.4.: Generazione dell’onda PWM
Una caratteristica interessante è la possibilità di cambiare il valore di duty cycle “on-the-fly” impostando il bit IUE = 1 nel registro PWM1CON2. Tale impostazione ha l’effetto di eliminare l’attesa che il
registro P1TMR raggiunga il valore di PTPER, e permette immediati aggiornamenti della larghezza dell’onda
rettangolare. Abilitando questa feature si va incontro a tre possibili casi:
52
Capitolo 5. Implementazione del Software
Figura 5.5.: Modifica del valore di duty cycle “on-the-fly”
1. se l’uscita PWM è attiva nel momento in cui in nuovo valore di duty cycle è scritto nel corrispondente
registro ed il nuovo valore è maggiore rispetto al corrente valore del registro P1TMR allora la larghezza
dell’onda rettangolare è estesa.
2. se l’uscita PWM è attiva nel momento in cui in nuovo valore di duty cycle è scritto nel corrispondente
registro ed il nuovo valore è minore rispetto al corrente valore del registro P1TMR allora la larghezza
dell’onda rettangolare è diminuita.
3. se l’uscita PWM non è attiva nel momento in cui il nuovo valore di duty cycle è scritto nel corrispondente registro, ed il nuovo valore è maggiore rispetto al corrente valore del registro P1TMR
allora l’uscita del PWM viene immediatamente attivata e rimane attiva per il valore impostato nel
registro duty cycle.
Il controllo dei servomotori viene fatto basandosi su un periodo di 20 ms. Questo valore è proporzionale
alla frequenza di funzionamento del dsPIC, Fc per cui è necessario imporre questa frequenza in base alle
considerazioni precedenti.
Affinché sia generato un segnale periodico con periodo di 20 ms, il registro PTPER associato alla periferica
PWM deve contenere un valore in bit opportuno. La formula che permette di calcolare questo valore è:
P T P ER =
Fc
−1
Fpwm · prescaler
(5.5)
Il prescaler serve a ridurre il valore calcolato quando Fc Fpwm . Poiché il registro PTPER è composto
da 15 bit il massimo valore rappresentabile è 215 − 1 = 32767.
La frequenza della PWM richiesta in questo progetto è di 50 Hz. Sappiamo infatti che il periodo
richiesto è di 20 ms, per cui la frequenza può essere determinata semplicemente come:
1
1
=
= 50Hz
(5.6)
T
20 · 10−3
Risulta evidente che Fc Fpwm , quindi è necessario un prescaler elevato. Si utilizzerà il prescaler
massimo, con rapporto 1:64, in questo modo:
Fpwm =
40 · 106
− 1 = 12499
(5.7)
50 · 64
Non rimane ora che impostare il valore corretto per il duty cycle, in modo da ottenere l’onda PWM
desiderata. Tale valore può essere ricavato in base ad un semplice ragionamento basato sulle proporzioni.
P T P ER =
53
Capitolo 5. Implementazione del Software
Infatti quello che si vuole ottenere è un segnale di periodo T che sia “alto” per un tempo pari a T − on.
Allora è sufficiente impostare la seguente relazione:
T − on : T =
P 1DCx
: P T P ER
2
(5.8)
da cui si ricava:
P T P ER · T − on
T
Per i tre valori limite dei servomotori scelti per Marvin, si ha dunque che:
P 1DCx = 2 ·
• +90° corrisponde ad un T-on di 0.6 ms, ovvero P 1DCx = 2 ·
• 0° corrisponde ad un T-on di 1.5 ms, ovvero P 1DCx = 2 ·
12499·0.6
20
12499·1.5
20
• -90° corrisponde ad un T-on di 2.4 ms, ovvero P 1DCx = 2 ·
(5.9)
= 750
= 1875
12499·2.4
20
= 3000
La formula 5.9 è stata inserita nella libreria Servo.h. In questo modo è la Flex che, dato un T-on,
calcola il valore di P1DCx e muove di conseguenza i motori.
5.3. RTOS ERIKA Enterprise
ERIKA (Embedded Real tIme Kernel Architecture) è un kernel di piccole dimensioni con piene funzionalità real-time, progettato per supportare applicazioni embedded su piccoli microcontrollori con scarsa
potenza di calcolo e memoria limitata, ma caratterizzate da vincoli temporali. È distribuito in doppia
licenza (commerciale e GNU GPL con linking exception) da Evidence srl, uno spin-off del laboratorio
ReTiS della Scuola Superiore Sant’Anna di Pisa. L’architettura del kernel ERIKA comprende due parti
principali: il Kernel Layer e l’Hardware Abstraction Layer (HAL).
Il Kernel Layer contiene un’insieme di moduli che implementano la gestione dei task e le varie strategie
di schedulazione real-time disponibili (FP ed EDF). Questo livello esporta per il livello di applicazione
un insieme di API RTOS per la gestione di Task, Alarms, Resources e Semaphores. L’HAL racchiude la
parte di codice dipendente dall’hardware, ad esempio la gestione delle interruzioni e i cambi di contesto.
Uno degli aspetti interessanti di ERIKA è il supporto alle API definite dallo standard OSEK (Offene
Systeme und deren Schnittstellen für die Elektronik im Kraft-fahrzeug - open system and the corresponding interfaces for automotive electronics), un progetto congiunto di alcune industrie automobilistiche
per lo sviluppo di sistemi di controllo distribuiti nei veicoli. Il consorzio prende il nome di OSEK/VDX
(VDX sta per Vehicle Distributed eXecutive) poiché si occupa della definizione di un insieme di API per
sistemi operativi real-time (OSEK) e di sistemi per la gestione di rete (VDX).
Gli standard OSEK/VDX sono orientati ad ottenere: portabilità e riutilizzo delle applicazioni software, scalabilità tra differenti requisiti per adattarsi alle particolari esigenze dell’applicazione (usando
le conformance classes), configurazione del sistema attraverso il linguaggio OIL (OSEK Implementation
Language), allocazione statica delle risorse del sistema durante la compilazione dell’applicazione.
ERIKA RTOS ha un footprint massimo di 4 Kb ed ha a disposizione diversi Kernel che vengono
tipicamente divisi in:
• Kernels standard OSEK/VDX, attraverso le Conformance Classes BCC1, BCC2, ECC1 ed ECC2
• Kernels non starndard FP, EDF e FRSH
Le differenze principali tra queste tipologie di kernel sono le API che vengono implementate: i kernels
non standard utilizzano solo un insieme ridotto di API per consentire il multithreading mentre quelli che
implementano le Conformance Class aggiungono all’insieme di API minimali altre funzionalità tipiche
dello standard OSEK.
54
Capitolo 5. Implementazione del Software
È possibile fare porting da un tipo di kernel non standard ad uno OSEK e viceversa. Evidence ha
provveduto ha stilare un documento di compatibilità relativamente al porting di applicazioni. [3]
Le Conformance Classes BCC1, BCC2, ECC1 ed ECC2 servono per implementare i diversi comportamenti del sistema; le classi di conformità BCC1 e BCC2 utilizzano meno spazio possibile e sono le più
indicate per realizzare piccoli sistemi a tasks concorrenti anche per la possibilità di avere la condivisione
dello stack tra i vari task.
Le classi di conformità ECC1 e ECC2 sono scelte per supportare task più complessi in quanto supportano le primitive di sincronizzazione e per questo ogni task deve essere dotato di uno stack separato.
Ovviamente ciò peggiora il footprint in memoria del sistema.
BCC1
Fornisce i Task Base, essi non hanno primitive bloccanti, possono terminare ed essere prelazionati,
possono condividere lo stack e può esserci una sola attivazione del task.
BCC2
Sono uguali ai BCC1 ma supportano attivazioni multiple. Per creare questo tipo di Tasks va specificato
nel Kernel che si utilizza la BCC2 con l’istruzione
OS myOS {
KERNEL_TYPE = BCC2 ;
}
e le attivazione multiple sono specificate nell’oggetto Task, come da esempio
TASK Task {
ACTIVATION = 4;
};
ECC1
Forniscono i Task Estesi che a differenza dei Tasks Base supportano gli Eventi e i Counting Semaphores
per effettuare sincronizzazioni. ECC1 non supporta le attivazioni multiple.
OS myOS {
KERNEL_TYPE = ECC1 ;
}
Mentre gli eventi sono così definiti
TASK Task {
PRIORITY = 0 x01 ;
ACTIVATION = 1;
SCHEDULE = FULL ;
AUTOSTART = TRUE ;
STACK = PRIVATE {
SYS_SIZE = 1024;
};
EVENT = " TimerEvent " ;
EVENT = " ButtonEvent " ;
};
EVENT TimerEvent { MASK = AUTO ; };
EVENT ButtonEvent { MASK = AUTO ; };
È necessario comunque definire nel file .c la maschera EventMaskType mask;
55
Capitolo 5. Implementazione del Software
ECC2
ECC2 è simile a ECC1 con la differenza che sono supportate le attivazioni multiple
OS myOS {
KERNEL_TYPE = ECC2 ;
}
TASK Task {
ACTIVATION = 4;
};
Nel documento [4] è possibile trovare la documentazione delle API di ERIKA, mentre per l’implementazione su microcontrollore e scrittura del file OIL si rimanda a [5].
Il Kernel Type può essere anche impostato a FP, EDF o FRSH, che sono trattate come Conformance
Classes non appartenenti allo standard OSEK/VDX:
• Fixed Priority (FP): supporta il multithreading a priorità fissa con più di 1 task per ogni priorità,
e con più di una pending activation per ogni task. In questa Conformance Class le risorse vengono
gestite tramite Immediate Priority Ceiling.
• Earliest Deadline First(EDF): provvede al supporto per lo scheduler EDF. Ogni task ha una propria deadline relativa che viene valutata al momento dell’attivazione del task. La deadline viene
codificata usando un circular timer. In questa Conformance Class le risorse vengono gestite tramite
Stack Resource Protocol (SRP).
• Frescor Scheduler (FRSH): include l’implementazione di uno scheduler EDF e, a livello superiore,
l’implementazione dello IRIS scheduler.
Le API disponibili sono elencate in fig. 5.6, per le specifiche delle varie primitive si rimanda al manuale
di ERIKA [4]
56
Capitolo 5. Implementazione del Software
Figura 5.6.: API del kernel Erika Enterprise
57
Capitolo 5. Implementazione del Software
5.4. Implementazione dell’applicazione ERIKA
Marvin utilizza solo una parte delle caratteristiche di ERIKA. L’applicazione istanzia un singolo task
periodico utilizzando attivamente gli oggetti Alarm, Counter e Task definiti nel file OIL:
CPU mySystem {
OS myOs {
EE_OPT = " DEBUG " ;
CPU_DATA = PIC30 {
APP_SRC = " code . c " ;
MULTI_STACK = FALSE ;
ICD2 = TRUE ;
};
MCU_DATA = PIC30 {
MODEL = P I C3 3F J2 5 6M C7 1 0 ;
};
BOARD_DATA = EE_FLEX {
USELEDS = TRUE ;
};
KERNEL_TYPE = FP ;
};
}
L’oggetto CPU imposta le proprietà CPU_DATA e MCU_Data per funzionare con il dsPIC ed utilizzare
il programmatore ICD2. APP_SRC indica quale file .c contiene il codice sorgente; in questo lavoro esso è
chiamato semplicemente code.c. Il kernel utilizzato è l’FP.
TASK TaskSend {
PRIORITY = 1;
STACK = SHARED ;
SCHEDULE = FULL ;
};
L’oggetto TASK istanzia TaskSend che rappresenta il task periodico. Come si può notare la periodicità
non è espressa attraverso istruzioni nell’oggetto TASK: essa infatti è data dall’oggetto ALARM:
COUNTER myCounter ;
ALARM AlarmSend {
COUNTER = " myCounter " ;
ACTION = ACTIVATETASK { TASK = " TaskSend " ; };
};
L’ALARM è legato ad un oggetto COUNTER (contatore), che dopo un determinato numero di tick richiama
l’oggetto ALARM in cui è specificata una ACTION che, per la nostra applicazione, corrisponde all’attivazione
del task TaskSend.
Una seconda versione più complessa del Kernel, studiata e non testata in questo progetto, prevede
un utilizzo più intelligente delle potenzialità di ERIKA. Nell’applicazione sono implementati 4 Task
periodici, dove TaskRead ha il compito di effettuare la lettura dei dati da Arduino e gli altri 3 tasks,
ognuno associato ad un asse, hanno il compito di eseguire le azioni di movimento4 . Di seguito il file OIL
associato all’applicazione appena descritta.
CPU mySystem {
OS myOs {
EE_OPT = " DEBUG " ;
CPU_DATA = PIC30 {
APP_SRC = " code . c " ;
MULTI_STACK = FALSE ;
ICD2 = TRUE ;
4 Vedi
code.c in Source > Flex Full > Marvin PID-flex Task sperimentale
58
Capitolo 5. Implementazione del Software
};
MCU_DATA = PIC30 {
MODEL = P I C3 3F J2 5 6M C7 1 0 ;
};
BOARD_DATA = EE_FLEX {
TYPE = DEMO {
OPTIONS = ALL ;
};
};
KERNEL_TYPE = FP ;
};
TASK TaskRead {
PRIORITY = 1;
// A high number corresponds to a high priority
STACK = SHARED ;
ACTIVATION = 1;
SCHEDULE = FULL ;
R E S O U R C E = " Motor_X " ;
R E S O U R C E = " Motor_Y " ;
R E S O U R C E = " Motor_Z " ;
};
TASK TaskMotor_X {
PRIORITY = 1;
ACTIVATION = 1;
STACK = SHARED ;
SCHEDULE = FULL ;
R E S O U R C E = " Motor_X " ;
};
TASK TaskMotor_Y {
PRIORITY = 1;
ACTIVATION = 1;
STACK = SHARED ;
SCHEDULE = FULL ;
R E S O U R C E = " Motor_Y " ;
};
TASK TaskMotor_Z {
PRIORITY = 1;
ACTIVATION = 1;
STACK = SHARED ;
SCHEDULE = FULL ;
R E S O U R C E = " Motor_Z " ;
};
COUNTER
COUNTER
COUNTER
COUNTER
CounterRead ;
Counter_X ;
Counter_Y ;
Counter_Z ;
ALARM Alarm_Read {
COUNTER = " CounterRead " ;
ACTION = ACTIVATETASK { TASK = " TaskRead " ; };
};
ALARM Alarm_onX {
COUNTER = " Counter_X " ;
ACTION = ACTIVATETASK { TASK = " TaskMotor_X " ; };
};
59
Capitolo 5. Implementazione del Software
ALARM Alarm_onY {
COUNTER = " Counter_Y " ;
ACTION = ACTIVATETASK { TASK = " TaskMotor_Y " ; };
};
ALARM Alarm_onZ {
COUNTER = " Counter_Z " ;
ACTION = ACTIVATETASK { TASK = " TaskMotor_Z " ; };
};
R E S O U R C E Motor_X { R E S O U R CE P R O P E R T Y = STANDARD ; };
R E S O U R C E Motor_Y { R E S O U R CE P R O P E R T Y = STANDARD ; };
R E S O U R C E Motor_Z { R E S O U R CE P R O P E R T Y = STANDARD ; };
}
L’oggetto Resource è utilizzato per le sezioni critiche ovvero semafori binari tali che il task di lettura
dei dati risulti avere priorità alta e non essere prelazionato dagli altri tasks se i dati di movimento non
sono disponibili; esso rilascerà le risorse sbloccando i task solo dopo la corretta ricezione da Arduino.
Gli oggetti Resources sono definiti dallo statement:
R E S O U R C E name { R E S O U R C E P R O P ER T Y = STANDARD ; };
e vanno incluse nell’oggetto Task che le utilizzerà.
Il concetto di risorsa critica è fondamentale per proteggere la variabile condivisa arduinoData in
modo che i task dei motori non accedano alla variabile per leggere i dati se essa non è stata riempita
precedentemente dal task di lettura.
5.5. Firmware Arduino
Il firmware realizzato per Arduino ricopre il ruolo di hub per lo scambio di informazioni dal livello di
Comando a quello di Controllo. Per questo motivo è stato progettato secondo una logica ad interrupt.
Un firmware Arduino si compone di due funzioni: void setup(), in cui vanno inserite le inizializzazioni
o le azioni da eseguire una sola volta, e void loop() che contiene le azioni da svolgere ciclicamente. Queste
due funzioni, in fase di compilazione, verranno inserite in una tipica struttura di un programma C, in cui
compare un main che chiama le funzioni sopra citate.
Il firmware realizzato per questa tesi effettua in setup le inizializzazioni dei led, delle porte seriali
Serial e Serial1 e dell’ADB subsystem
void setup ()
{
// Set pins as output used for LED
pinMode (22 , OUTPUT ) ;
pinMode (24 , OUTPUT ) ;
// Init serial port
Serial . begin (57600) ; // Computer & serial monitor DEBUG Comunication
Serial1 . begin (115200) ; // PIN 18 & 19 , FLEX BAUDRATE : 115200
// Init the ADB subsystem .
ADB :: init () ;
// Open an ADB stream to the phone ’s shell . Auto - reconnect .
connection = ADB :: addConnection ( " tcp :4568 " , true , ad b Ev en tH a nd le r ) ;
}
60
Capitolo 5. Implementazione del Software
loop() è composta dall’unica istruzione di polling dell’ADB subsystem in quanto la ricezione dei
dati sulla porta seriale è gestita da Arduino attraverso gli interrupt. Ogni volta il cui la periferica di
comunicazione riceve dati, automaticamente effettua una callback a serialEvent1(), funzione che si
occupa di gestire tale interruzione.
void loop ()
{
// serialEvent1 () is called in automatic , so
// in the loop the serialEvent1 is not present .
// Poll the ADB subsystem .
ADB :: poll () ;
}
Risulta quindi importante definire bene come interpretare e smistare i dati in arrivo su Serial1. Il
protocollo di comunicazione suddivide i tipi di messaggi in due categorie: Request Message e Debug
Message. I Request Message sono la parte fondamentale del protocollo di comunicazione attraverso i
quali Arduino risponde alla Flex inviando i dati ricevuti da Android; i Debug Message, invece, servono
per utilizzare Arduino come strumento di Debug per la Flex attraverso il Serial Monitor presente nell’IDE.
I messaggi di debug sono divisi in due tipi: stringhe e numeri.
void serialEvent1 ()
{
int i =0 , j =0;
byte msg [100];
int msgNumber =0;
byte messageType =0 x00 ;
u n s i g n e d long int number ;
byte fine =0 x00 ;
// A request data message
// Arduino sends the last stored command ( direction ) to Flex
if ( Serial1 . read () == 0 x7F )
{
Serial1 . write (0 x0A ) ;
if ( MODE != 0 x0C )
{
Serial1 . write (( byte ) direction ) ;
}
else
{
for ( j =0; j <15; j ++) Serial1 . write ( directions [ j ]) ;
}
// Uses the GREEN led to notify the reception of the message
d i g i t a l W r i t e (24 , HIGH ) ;
delay (10) ;
d i g i t a l W r i t e (24 , LOW ) ;
delay (10) ;
}
// A debug message
// Arduino write the number or the string received from Flex to the serial monitor
else if ( Serial1 . read () == 0 xA7 ) {
/* HEADER PROCESSING */
// Pop from the UART queque the lengh of payload that is in the position 1 of RX
buffer
msgNumber = Serial1 . read () ;
// Pop from the UART queque the code command that is in the position 2 of RX
buffer
messageType = Serial1 . read () ;
61
Capitolo 5. Implementazione del Software
/* PAYLOAD PROCESSING */
for ( i =0; i < msgNumber ; i ++) {
msg [ i ]= Serial1 . read () ;
}
// A String from Flex : processing ASCII byte values
if ( messageType == 0 xBB ) {
Serial . println ( " -- STRING MESSAGE - - " ) ;
for ( i =0; i < msgNumber ; i ++) Serial . write ( msg [ i ]) ;
Serial . println ( " " ) ;
}
// A number from Flex : processing DECIMAL values
else if ( messageType == 0 xDD )
{
Serial . println ( " -- NUMBER MESSAGE - - " ) ;
// Take the integer value back from the 4 byte array from Flex
number = ( ( msg [0] << 24) + ( msg [1] << 16) + ( msg [2] << 8) + ( msg [3] ) ) ;
Serial . println ( number , DEC ) ;
}
}
}
Per inviare messaggi di Debug dalla Flex verso Arduino bisogna utilizzare la libreria serialConsole.h.
Una tipica impostazione per fare questo è:
S en dS tr i ng Re pl y ( " \ nTesto \ n " , Arduino , NoReply , false , false , UART1 ) ;
oppure:
SendNumReply (1234 , Arduino , NoReply , false , false , UART1 ) ;
dove si è ipotizzato che Arduino sia collegato alla UART1 della Flex.
5.6. Applicazioni Android
Le applicazioni realizzate per lo smartphone sono due. Seppur condividano molte funzionalità di
base, esse differiscono nella classe ER1Direction. Questa classe, infatti, è predisposta come punto finale
dell’elaborazione dei dati acquisiti per mezzo delle altre classi.
Escludendo le classi AbstrasctServerListner, Server, ServerListner e Client che implementano
la Microbridge ADB, si ha:
• FdActivity: si occupa di impostare l’applicazione per tutti gli stati richiesti da Android
• FdView: estende CvClientView ed è il cuore dell’applicazione, si occupa principalmente di gestire i
thread della comunicazione wifi e di effettuare il riconoscimento dei volti tramite l’algoritmo LBP
ed il metodo per scegliere il volto dominante sulla scena.
• CvClientView: contiene il thread che operativamente utilizza l’algoritmo per il riconoscimento volti
e il calcolo degli FPS tramite la classe FpsMeter.
• FpsMeter: contiene i metodi per calcolare il numero di Frame per Secondo (FPS) cioè la frequenza
di cattura delle immagini attraverso la fotocamera.
5.6.1. Caratteristiche comuni tra le due applicazioni
Android Manifest
Il Manifest elenca i componenti del sistema che vengono utilizzati dall’applicazione; per esempio, se una
apk richiede la connessione alla rete, lo notifica nel Manifest e, qualora la connessione non sia disponibile,
l’applicazione verrà bloccata a run-time.
62
Capitolo 5. Implementazione del Software
<? xml version = " 1.0 " encoding = " utf -8 " ? >
< manifest xmlns:android = " http: // schemas . android . com / apk / res / android " package = " it . univpm .
dii . marvinPID " a n d r o i d : v e r s i o n C o d e = " 1 " a n d r o i d : v e r s i o n N a m e = " 1.0 " >
< uses - permission android:name = " android . permission . INTERNET " / >
< supports - s c r e e n s a n d r o i d : r e s i z e a b l e = " true " a n d r o i d : s m a l l S c r e e n s = " true "
a n d r o i d : n o r m a l S c r e e n s = " true " a n d r o i d : l a r g e S c r e e n s = " true " a n d r o i d : a n y D e n s i t y = " true
" />
< application android:label = " @string / app_name " android:icon = " @drawable / icon " >
< activity android:name = " it . univpm . dii . marvinPID . FdActivity " android:label = " @string /
app_name " a n d r o i d : s c r e e n O r i e n t a t i o n = " landscape " a n d r o i d : c o n f i g C h a n g e s = "
keyb oardHidde n | orientation " >
< intent - filter >
< action android:name = " android . intent . action . MAIN " / >
< category android:name = " android . intent . category . LAUNCHER " / >
</ intent - filter >
</ activity >
< menu xmlns:android = " http: // schemas . android . com / apk / res / android " >
< item android:id = " @ + id / serverIP " android:title = " @string / ServerIP " / >
< item android:id = " @ + id / help " android:title = " @string / help " / >
</ menu >
</ application >
< uses - sdk a n d r o i d : m i n S d k V e r s i o n = " 10 " / >
< uses - permission android:name = " android . permission . CAMERA " / >
< uses - feature android:name = " android . hardware . camera " / >
< uses - feature android:name = " android . hardware . camera . autofocus " / >
</ manifest >
In questo manifest vengono riportati l’orientamento dell’applicazione, cioè Landscape, e i permessi di
cui necessita, cioè l’accesso alla fotocamera e al modulo wifi.
Comunicazione USB
La logica di comunicazione è contenuta nelle classi che realizzano il modello client-server attraverso
l’ADB, l’obiettivo è stato utilizzare le API messe a disposizione all’interno dell’applicazione sostituendole
a quelle dell’Open Accessory.
Nella FdActivity viene instanziato l’oggetto mServer come pubblico e statico attraverso l’istruzione
public static Server mServer = null ;
Nel metodo di Android onCreate(), che viene chiamato dal sistema operativo al lancio dell’applicazione, mServer viene associato ad un oggetto Server che comunica sulla porta 4568 dopodichè esso viene
avviato attraverso il metodo start()
mServer = new Server (4568) ; // Use ADK port
mServer . start () ;
Tramite comunicazione USB possono essere inviati solo byte e questo avviene attraverso il metodo
mServer.send(), definito nella classe Server:
public void send ( byte [] data ) throws IOException
{
for ( Client client : clients )
client . send ( data ) ;
}
il metodo richiama il metodo send della classe Client:
63
Capitolo 5. Implementazione del Software
public void send ( byte [] data ) throws IOException
{
try {
output . write ( data ) ;
output . flush () ;
} catch ( So c ke tE xc e pt io n ex )
{
// Broken socket , disconnect
close () ;
server . d i s c o n n e c t C l i e n t ( this ) ;
}
}
Elaborazione Video
Le funzionalità del sistema di visione sono rese disponibili dalla libreria OpenCV appositamente compilata per il sistema operativo Android. La classe FdView è la classe centrale dell’applicazione e come
tale viene creata all’avvio; il metodo processFrame() contiene l’algoritmo per l’elaborazione e l’estrazione
di un volto da una scena
@Override
protected Bitmap processFrame ( VideoCapture capture ) {
capture . retrieve ( mRgba , Highgui . C V _ C A P _ A N D R O I D _ C O L O R _ F R A M E _ R G B A ) ;
capture . retrieve ( mGray , Highgui . C V _ C A P _ A N D R O I D _ G R E Y _ F R A M E ) ;
if ( mCascade != null ) {
// clear previous detected faces array
faces . clear () ;
// equalize gray image histogram
Imgproc . equalizeHist ( mGray , mGray ) ;
// invoke face detection algorithm , starting from a face dimension of 90 x90
mCascade . d e t e c t M u l t i S c a l e ( mGray , faces , 1.3 , 3 , 0 , DEFSIZE ) ;
// search each face on history face detected array
for ( Rect r : faces ) {
add = true ;
for ( CFace a : hFaces ) {
if ( a . updatePos ( r ) ) {
add = false ;
break ;
}
}
// face not found into history array , new face
if ( add ) hFaces . add ( new CFace ( r ) ) ;
// print a green rectangle around each face
if ( develop ) Core . rectangle ( mRgba , r . tl () , r . br () , new Scalar (0 , 255 , 0 , 255)
, 1) ;
}
// initialize array variables
newFace = null ;
maxT =0;
hcopy . clear () ;
// for each faces into history faces array , removes old face ( not yet detected )
and search dominant face ( most time present )
for ( CFace a : hFaces ) {
if ( a . aging () ) {
hcopy . add ( a ) ;
} else if ( a . findBest () ) {
64
Capitolo 5. Implementazione del Software
newFace = a ;
}
}
hFaces . removeAll ( hcopy ) ;
// if a face was detected
if ( newFace != null ) {
// draws a red rectangle around face
if ( develop ) Core . rectangle ( mRgba , newFace . pos . tl () , newFace . pos . br () , new
Scalar (255 ,0 ,0 ,255) ,2) ;
if ( dominantFace == null || newFace . id != dominantFace . id || repeat > REPEAT_LIMIT )
{
// send face to server when first one detected or new face or need to re send
dominantFace = newFace ;
repeat =0;
try {
// interrupt server response wait thread
waitResp = false ;
// create bitmap image to send
dominant = Bitmap . createBitmap ( mRgba . cols () , mRgba . rows () , Bitmap . Config .
ARGB_8888 ) ;
Utils . matToBitmap ( mRgba , dominant ) ;
dominant = Bitmap . createBitmap ( dominant , newFace . pos .x , newFace . pos .y ,
newFace . pos . width , newFace . pos . height ) ;
faceCheck = " " ;
sendImg = true ;
} catch ( Exception e ) {
Log . e ( TAG , " bitmap error " + e . toString () ) ;
}
Log . i ( TAG , " new Face " ) ;
}
else if ( newFace . id == dominantFace . id && repeat <= REPEAT_LIMIT ) {
// on same dominant face , count time until re - send to server
repeat ++;
}
}
else {
// no dominant faces , reset variables
dominantFace = null ;
dominant = null ;
sendImg = false ;
waitResp = false ;
repeat =0;
}
}
if ( develop ) {
// create image to send back to caller
bmp = Bitmap . createBitmap ( mRgba . cols () , mRgba . rows () , Bitmap . Config . ARGB_8888
);
if ( Utils . matToBitmap ( mRgba , bmp ) )
return bmp ;
bmp . recycle () ;
}
return null ;
}
Il video catturato con le istruzioni alle righe 2 e 3, viene elaborato equalizzandone l’istogramma, quindi
viene eseguito l’algoritmo di face-detection tramite l’istruzione di riga 10. La scansione ricerca i volti
con una dimensione minima di 110x110 pixel; ad ogni iterazione la dimensione viene incrementata di
65
Capitolo 5. Implementazione del Software
un fattore 1,3. La variabile faces contiene la lista delle posizioni di tutti i volti individuati nel frame
corrente; il passo successivo è quello di cercare ogni volto individuato nei frame precedenti, aggiornandone
le informazioni per mezzo del metodo updatePos(); il vettore hFaces contiene le informazioni relative
ai volti individuati nel frame attuale e in quelli precedenti. Il tipo di dati CFace è stato creato per
memorizzare le informazioni relative ai volti individuati, ovvero la posizione e il tempo di permanenza
sulla scena.
Dopo aver aggiornato lo storico con i nuovi volti individuati, questo viene scansionato alla ricerca del
volto dominante, eliminando i volti non più presenti nella scena.
L’operazione di ricerca del volto dominante si basa sul tempo di permanenza nella scena; ogni volto
individuato viene ricercato nello storico: se la posizione attuale del vertice superiore sinistro è in un
intorno della posizione precedente, i due volti confrontati sono marcati come identici (vedi fig. 5.7)
Figura 5.7.: Algoritmo di individuazione di un volto
Il metodo updatePos() della classe CFace si occupa di confrontare le posizioni dei due volti, restituendo
il valore false se non sono compatibili, altrimenti provvede ad aggiornare la posizione corrente e il tempo
di permanenza. La variabile noFace viene utilizzata per eliminare, con un metodo aging, i volti non più
presenti nella scena per un certo numero di frame consecutivi. Nella selezione del volto dominante, con
il metodo findBest si cerca il volto con il valore massimo della variabile time.
5.6.2. Differenze tra le due applicazioni Android
Marvin Grid View
Nell’applicazione “Marvin Grid View” la classe ER1Direction utilizza la Grid View, quindi calcola il
movimento da imporre al robot in base alla posizione e rispetto alle aree ben definite.
Il listato successivo riporta il modo in cui le aree sono definite il metodo init() che produce la
suddivisione nel momento in cui un’istanza ER1Direction viene creata .
public void init ( int width , int height ) {
this . heigh = height ;
this . width = width ;
output = " " ;
direction = cSTOP ;
paint = new Paint () ;
66
Capitolo 5. Implementazione del Software
paint . setColor ( Color . RED ) ;
paint . setTextSize (20) ;
limitLeft = width /4;
limitRight = limitLeft *3;
limitTop = height /4;
limitBottom = limitTop *3;
}
public void updateLimits ( int width , int height ) {
this . heigh = height ;
this . width = width ;
limitLeft = width /4;
limitRight = limitLeft *3;
limitTop = height /4;
limitBottom = limitTop *3;
}
Il seguente listato, invece, contiene il metodo calc() che elabora la posizione ricevuta da parametro e
stabilisce il comando da inviare al robot.
Esso controlla per prima cosa l’altezza del volto dominante; nel caso fosse maggiore di quella massima,
160px, viene inviato il comando di muovere il robot all’indietro per allontanarsi dal soggetto. Altrimenti
se è minore di 120px, il robot si avvicinerà al soggetto. Questo per mantenere il volto del soggetto né
troppo vicino né troppo distante dal robot.
Viene controllata la posizione rispetto alle zone prestabilite, quindi sono inviati i comandi per mantenere
il volto nella zona centrale del frame.
public void calc ( Rect a ) {
if ( a != null ) {
if ( a . height >160) {
direction = cREVERSE ;
output = " REVERSE " ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
}
else if ( a . height <120) {
direction = cFORWARD ;
output = " FORWARD " ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
}
else {
if ( a . tl () .x < limitLeft ) {
output = " LEFT " ;
direction = cLEFT ;
r es ea rc h Co mm an d = cLEFT ;
r e s e a r c h M o v e m en t = " LEFT RESEARCH ... " ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
} else if ( a . br () .x > limitRight ) {
output = " RIGHT " ;
direction = cRIGHT ;
r es ea rc h Co mm an d = cRIGHT ;
r e s e a r c h M o v e m en t = " RIGHT RESEARCH ... " ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
} else if ( a . tl () .y < limitTop ) {
output = " UP " ;
direction = cUP ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
} else if ( a . br () .y > limitBottom ) {
output = " DOWN " ;
direction = cDOWN ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
67
Capitolo 5. Implementazione del Software
} else {
output = " STOP " ;
direction = cSTOP ;
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
}
}
} else {
/* USE THIS SE NON HAI BISOGNO DELLA RICERCA /
direction = cSTOP ;
output =" STOP ";
*/
/* ricerca di un volto dopo n iterazioni */
startBehavior - -;
if ( startBehavior %10 == 0)
r es e a r c h M o v e m en t = " THE RESEARCH WILL BEGIN IN " + startBehavior + " ITER ... " ;
if ( startBehavior <= 0) // BEGIN THE RESEARCH TO THE RIGHT SIDE
{ // this will last until the endBehavior reach 0
r e s e a r c h M o v e m en t = " RIGHT RESEARCH ... " ;
r es ea rc h Co mm an d = cRIGHT ;
endBehavior - -;
}
if ( endBehavior <= 0)
{ // Now the robot stops
r e s e a r c h M o v e m en t = " RESEARCH STOPPED " ;
r es ea rc h Co mm an d = cSTOP ;
// begin new cycle of research behavior
startBehavior = D E F A U L T _ S T A R T _ D U R A T I O N ;
endBehavior = D E F A U L T _ E N D _ D U R A T I O N ;
}
output = r e s e a r c h M o v e m e n t ;
direction = r es ea rc h Co mm an d ;
}
try {
FdActivity . mServer . send ( new byte []{0 x0F , direction }) ;
} catch ( Exception e ) { }
}
Si nota come se a è null viene avviato l’algoritmo di ricerca.
In ogni caso il comando di movimento viene inviato attraverso l’mServer verso Arduino nel blocco
try/catch.
La direzione che il robot deve seguire è calcolata in base alla posizione dei vertici evidenziati: viene
utilizzato il vertice inferiore destro (a.br) quando il volto si trova nella zona destra o inferiore del frame,
in tutte le altre situazioni si usa il vertice superiore sinistro(a.tl).
I comandi sono costanti di tipo byte:
public
public
public
public
public
public
public
final
final
final
final
final
final
final
static
static
static
static
static
static
static
byte
byte
byte
byte
byte
byte
byte
cSTOP
cFORWARD
cREVERSE
cLEFT
cRIGHT
cUP
cDOWN
=
=
=
=
=
=
=
0 x00 ;
0 x01 ;
0 x02 ;
0 x03 ;
0 x04 ;
0 x05 ;
0 x06 ;
essi vengono inviati tramite il metodo send() di mServer
FdActivity . mServer . send ( new byte []{0 x0F , direction }) ;
che prende in ingresso un array di byte, creato al momento dell’invio inserendo due byte. In questo
caso si sta usando, dunque, il protocollo semplificato.
Dal lato Flex invece essi vengono gestiti dal TaskSend e da uno switch:
68
Capitolo 5. Implementazione del Software
A r d u i n o _ D a t a _ R e q u e s t (& arduinoData [0] ,2 ,1) ;
if ( arduinoData [0] == 0 x0A ) ledBlink (25 ,1 ,100) ;
switch ( arduinoData [1]) {
case 0 x00 : // stop
Servo_Neutral ( DX ) ;
Servo_Neutral ( SX ) ;
break ;
case 0 x01 : // forward
Servo_minus90 ( DX ) ;
Servo_plus90 ( SX ) ;
break ;
case 0 x02 : // reverse
Servo_plus90 ( DX ) ;
Servo_minus90 ( SX ) ;
break ;
case 0 x03 : // left
Servo_minus90 ( DX ) ;
Servo_minus90 ( SX ) ;
break ;
case 0 x04 : // right
Servo_plus90 ( DX ) ;
Servo_plus90 ( SX ) ;
break ;
case 0 x05 : // up
Servo_Neutral ( DX ) ;
Servo_Neutral ( SX ) ;
Servo_Move ( HEAD , DEFAULT_INCREMENT ,20) ;
break ;
case 0 x06 : // down
Servo_Neutral ( DX ) ;
Servo_Neutral ( SX ) ;
Servo_Move ( HEAD , - DEFAULT_INCREMENT ,20) ;
break ;
}
L’istruzione Servo_plus90(motor) è equivalente a Servo_Set_Position(motor,2.4,20), mentre Servo_minus90(mot
è equivalente alla Servo_Set_Position(motor,0.6,20).
La visualizzazione a griglia viene disegnata a schermo dal metodo draw():
public void draw ( Canvas canvas , float offsetx , float offsety ) {
canvas . drawLine ( limitLeft + offsetx , offsety , limitLeft + offsetx , totH + offsety , paint ) ;
canvas . drawLine ( limitRight + offsetx , offsety , limitRight + offsetx , totH + offsety , paint )
;
canvas . drawLine ( limitLeft + offsetx , limitTop + offsety , limitRight + offsetx , limitTop +
offsety , paint ) ;
canvas . drawLine ( limitLeft + offsetx , limitBottom + offsety , limitRight + offsetx ,
limitBottom + offsety , paint ) ;
canvas . drawText ( output + " " + FdView . faceCheck , 20 + offsetx , 90 , paint ) ;
}
Marvin PID
A differenza dell’applicazione precedente, mutuata in buona parte dal lavoro su AndroEEBot e quindi
considerabile come Demo per l’utilizzo di singoli comandi alla parte hardware, questa applicazione è stata
progettata per funzionare attraverso la legge di controllo PID.
Non vengono utilizzati dei comandi di spostamento: è l’implementazione digitale del controllo che
impone il giusto movimento al robot, attraverso gli errori calcolati sugli assi X, Y, Z affinché il volto sia
sempre mantenuto al centro del frame.
69
Capitolo 5. Implementazione del Software
Per errore si intende la differenza tra un set-point -cioè il riferimento da raggiungere- e la posizione
attuale.
La fase di inizializzazione della classe ER1Direction è:
public void init ( int width , int height ) {
this . heigh = height ;
this . width = width ;
output = " " ;
paint = new Paint () ;
paint . setColor ( Color . RED ) ;
paint . setTextSize (20) ;
paintRECT = new Paint () ;
paintRECT . setColor ( Color . RED ) ;
paintRECT . setStyle ( Paint . Style . STROKE ) ;
}
public void updateLimits ( int width , int height ) {
this . heigh = height ;
this . width = width ;
}
Qui vengono recuperati l’altezza e la larghezza totali del frame da elaborare. Segue quindi una parte
di calcoli per ricavare gli errori sui tre assi e convertirli prima da float a interi attraverso un metodo
della classe Float, e successivamente suddividendoli in 4 byte per poter essere inviati dall’mServer verso
Arduino.
public void calc ( Rect a , float offsetx , float offsety ) {
if ( a != null ) {
output = " PID " ;
data [0]=0 x0C ;
coordX = ( float ) (( a . tl () . x ) +( a . width /2) ) + offsetx ;
coordY = ( float ) (( a . tl () . y ) +( a . height /2) ) + offsety ;
ErrorX =( int ) (( width /2) -( a . tl () . x +( a . width /2) ) ) ;
ErrorY =( int ) (( heigh /2) -( a . tl () . y +( a . height /2) ) ) ;
ErrorZ =( int ) (( SetPoint_onZ ) -( a . height ) ) ;
// USED to decide the direction of the robot : 0 - > UP 1 - > DOWN
if ( ErrorY > 0) Ydirection =0;
else Ydirection =1;
// USED to decide the direction of the robot : 1 - > positive ( LEFT ) 0 - > negative (
RIGHT )
if ( ErrorX > 0) Xdirection =1;
else Xdirection =0;
// USED to decide the direction of the robot : 0 - > positive ( FORWARD ) 1 - > negative (
BACKWARD )
if ( ErrorZ > 0) Zdirection =0; //
else Zdirection =1;
// Now i take the absolute values of errors
ErrorY = Math . abs ( ErrorY ) ;
ErrorX = Math . abs ( ErrorX ) ;
ErrorZ = Math . abs ( ErrorZ ) ;
// Limita l ’ errore sull ’ asse Z . Infatti il volto p u
diventare molto grosso se
//
vicino alla telecamera e quindi l ’ errore p u
crescere molto rispetto
// in Forward rispetto a backward c o s
allora unifico i valori
if ( Zdirection ==1 && ErrorZ >=15) ErrorZ =14;
70
Capitolo 5. Implementazione del Software
// inserisco delle tolleranze su ogni asse
if ( ErrorY <=4 ) ErrorY =0;
else ErrorY = ErrorY -4; // else eliminate the acceptable zone
if ( ErrorX <=10 ) ErrorX =0;
else ErrorX = ErrorX -10; // else eliminate the acceptable zone
if ( ErrorZ <=5 ) ErrorZ =0;
else ErrorZ = ErrorZ -5; // else eliminate the acceptable zone
// Normalize the errors : ErrorK / ErrorMax_K
ErrorMax_X = (( width /2+ offsetx ) /2) ;
ErrorMax_Y = (( width /2+ offsetx ) /2) ;
ErrorMax_Z = 20;
con K ={ X ,Y , Z }
ErrorX = ErrorX / ErrorMax_X ;
ErrorY = ErrorY / ErrorMax_Y ;
ErrorZ = ErrorZ / ErrorMax_Z ;
/* transfomate the FLOAT ErrorX , ErrorY , ErroZ into a 4 bytes array and put them in
data [] */
// java method that with some bit ’s masks convert the float bits to bit and
// display bit with a int -> see official reference api
int Xint = Float . floatT oIntBits ( ErrorX ) ;
int Yint = Float . floatT oIntBits ( ErrorY ) ;
int Zint = Float . floatT oIntBits ( ErrorZ ) ;
// now i separate the int Xint into 4 bytes array
msg [0] = (( Xint >> 24) & 0 xFF ) ;
msg [1] = (( Xint >> 16) & 0 xFF ) ;
msg [2] = (( Xint >> 8) & 0 XFF ) ;
msg [3] = (( Xint & 0 XFF ) ) ;
// copy into the data [] array , that will be sended to flex , Xdirection and 0 -3 msg
byte
data [1]=( byte ) Xdirection ;
data [2]=( byte ) msg [0];
data [3]=( byte ) msg [1];
data [4]=( byte ) msg [2];
data [5]=( byte ) msg [3];
// now i separate the int Yint into 4 bytes array
msg [0] = (( Yint >> 24) & 0 xFF ) ;
msg [1] = (( Yint >> 16) & 0 xFF ) ;
msg [2] = (( Yint >> 8) & 0 XFF ) ;
msg [3] = (( Yint & 0 XFF ) ) ;
// copy into the data [] array , that will be sended to flex , Ydirection and 0 -3 msg
byte
data [6]=( byte ) Ydirection ;
data [7]=( byte ) msg [0];
data [8]=( byte ) msg [1];
data [9]=( byte ) msg [2];
data [10]=( byte ) msg [3];
// now i separate the int Yint into 4 bytes array
msg [0] = (( Zint >> 24) & 0 xFF ) ;
msg [1] = (( Zint >> 16) & 0 xFF ) ;
msg [2] = (( Zint >> 8) & 0 XFF ) ;
71
Capitolo 5. Implementazione del Software
msg [3] = (( Zint & 0 XFF ) ) ;
// copy into the data [] array , that will be sended to flex , Ydirection and 0 -3 msg
byte
data [11]=( byte ) Zdirection ;
data [12]=( byte ) msg [0];
data [13]=( byte ) msg [1];
data [14]=( byte ) msg [2];
data [15]=( byte ) msg [3];
//
//
//
//
QUINDI QUELLO CHE HO ORA E ’ UN ARRAY DI 4 BYTE CHE RAPPRESENTANO IL FLOAT
A QUESTO PUNTO LO INVIO AD ARDUINO CHE LO PASSA COSI ’ COM ’E ’ ALLA FLEX
SU CC E SS IV AM EN T E LA FLEX RICOMPATTERA ’ QUESTI 4 BYTE IN UN FLOAT CON UN METODO
CHE PUOI VEDERE SUL CODICE DELLA FLEX
} else {
int j =0;
output = " PID STOPPED " ;
data [0] = 0 x0C ;
// put the signal of stop
data [1] = 0 x0B ;
data [2] = 0 x12 ;
data [3] = 0 x0B ;
// for the draw
ErrorX = ErrorY = ErrorZ =0;
coordX = coordY = -999.0 f ;
}
try {
// Structure of data []: Control byte for Arduino [0] - X [1 -5] - Y [6 -11] - Z
[12 -16]
FdActivity . mServer . send ( data ) ;
} catch ( Exception e ) { }
}
CoordX e CoordY calcolano le coordinate sull’asse X e Y, in pixel, della posizione del volto dominante.
Esse verranno poi sottratte – senza offset – al set-point sui rispettivi assi per ottenere gli errori. I dati
che rappresentano gli errori e i segni di ogni errore vengono inviati nel blocco try/catch.
(a) Set-point e calcolo delle coordinate
(b) Calcolo degli errori sui tre assi di controllo
Figura 5.8.: Calcolo delle coordinate e degli errori nell’applicazione “Marvin PID”
Anche il metodo draw() si presenta differente in quanto non deve più mostrare un riferimento a “griglia”
72
Capitolo 5. Implementazione del Software
ma visualizzare, per ogni asse, il set-point da raggiungere in maniera tale che il volto, rappresentato dal
punto in verde, sia sempre tenuto al centro del frame.
public void draw ( Canvas canvas , float offsetx , float offsety ) {
Paint punto = new Paint () ;
punto . setColor ( Color . GREEN ) ;
punto . setStr okeWidth (10) ;
// print a line parallel to the y - axis
canvas . drawLine ( width /2+ offsetx , 0+ offsety , width /2+ offsetx , heigh + offsety , paint ) ;
// print a line parallel to the x - axis
canvas . drawLine (0+ offsetx , heigh /2+ offsety , width + offsetx , heigh /2+ offsety , paint ) ;
// print the Acceptable zone where error = 0
canvas . drawRect ( width /2+ offsetx -10 , heigh /2+ offsety -4 , width /2+ offsetx +10 ,
offsety +4 , paintRECT ) ;
heigh /2+
canvas . drawText ( output + " " + FdView . faceCheck , 20 + offsetx , 90 , paint ) ;
// print the point on Y
if ( coordX != -999.0 f && coordY != -999.0 f ) {
canvas . drawPoint ( coordX , coordY , punto ) ;
canvas . drawText ( " ERROR on X : " + ErrorX , 20 + offsetx , 200 , paint ) ;
canvas . drawText ( " ERROR on Y : " + ErrorY , 20 + offsetx , 220 , paint ) ;
canvas . drawText ( " ERROR on Z : " + ErrorZ , 20 + offsetx , 240 , paint ) ;
if ( Xdirection == 0) stringaX = " RIGHT " ;
else stringaX = " LEFT " ;
if ( Ydirection == 0) stringaY = " UP " ;
else stringaY = " DOWN " ;
if ( Zdirection == 0) stringaZ = " FORWARD " ;
else stringaZ = " BACKWARD " ;
canvas . drawText ( stringaX , 240+ offsetx , 200 , paint ) ;
canvas . drawText ( stringaY , 240 + offsetx , 220 , paint ) ;
canvas . drawText ( stringaZ , 240 + offsetx , 240 , paint ) ;
}
}
Il SetPoint dell’asse Z viene disegnato a schermo nella classe FdView dal codice
// draw a blue line next to the left angle of the dominant face to visualize the set point
on Z (=130 px )
CFace temp = new CFace ( newFace . pos ) ;
Point bo = temp . pos . tl () ;
bo . y +=130;
// draws a blue line over the red rectange on the dominant face
if ( develop ) Core . line ( mRgba , newFace . pos . tl () ,bo , new Scalar (0 ,0 ,255 ,255) , 4) ;
Dal lato Flex invece tale comportamento è gestito, sempre da TaskSend, in questo modo
TASK ( TaskSend )
{
BYTE i =0;
BYTE arduinoData [20];
float DutyCycle =0;
EE_INT32 datoX [4];
73
Capitolo 5. Implementazione del Software
BYTE Xsign ;
float Er ro r_ o n_ X_ ax i s =0;
EE_INT32 datoY [4];
BYTE Ysign ;
float Er ro r_ o n_ Y_ ax i s =0;
EE_INT32 datoZ [4];
BYTE Zsign ;
float Er ro r_ o n_ Z_ ax i s =0;
EE_led_on () ;
A r d u i n o _ D a t a _ R e q u e s t (& arduinoData [0] ,16 , UART1 ) ;
if ( arduinoData [0] == 0 x0A ) ledBlink (25 ,1 ,100) ;
/* VERIFY IF THE PID IS ACTIVE OR NOT , THE PID IS NOT ACTIVE IF NO DOMINAT FACE IS
FOUND ON THE SCREEN */
if ( arduinoData [1] == 0 x0B && arduinoData [2]== 0 x12 && arduinoData [3] == 0 x0B )
{
// So the PID is stopped then put DX e SX motors in a neutral position : stop the
motor
Servo_Neutral ( DX ) ;
Servo_Neutral ( SX ) ;
} else {
// X AXIS : DIRECTIONS OF TURNING THE ROBOT
Xsign = arduinoData [1];
for ( i =0; i <4; i ++) datoX [ i ]= arduinoData [ i +2];
// Y AXIS -> " HEAD MOTOR " CORRESPONDING TO THE Y AXIS ON THE SMARTPHONE
Ysign = arduinoData [6];
for ( i =0; i <4; i ++) datoY [ i ]= arduinoData [ i +7];
// Z AXIS : DIRECTIONS FORN FORWARD / BACKWARD THE ROBOT
Zsign = arduinoData [11];
for ( i =0; i <4; i ++) datoZ [ i ]= arduinoData [ i +12];
/* Converting the 4 Byte to 1 Float */
E rr or _o n _X _a xi s = c o n v e r t 4 B y t e T O 1 F l o a t ( datoX ) ;
E rr or _o n _Y _a xi s = c o n v e r t 4 B y t e T O 1 F l o a t ( datoY ) ;
E rr or _o n _Z _a xi s = c o n v e r t 4 B y t e T O 1 F l o a t ( datoZ ) ;
// Seleziona quale movimento effettuare con i motori di propulsione , infatti
essendone solo 2
// che vanno a gestire 4 movimenti ( AVANTI , DIETRO , DX , SX ) essi devono essere "
condivisi "
// la politica
attuare la direzione in cui l ’ errore
massimo in maniera da
avere una
// compensazione media accettabile
if ( E r ro r_ on _Z _ ax is >= E rr or _o n_ X _a xi s ) // based on absolute value
{
/* Set the right sign of Z float used for the PI_pid controller , Ysign is used
in the P_pid function instead */
if ( Zsign == 1) Er ro r _o n_ Z_ a xi s *= -1;
DutyCycle = P_pid_Z ( Er ro r_ o n_ Z_ ax i s ) ;
// attua il movimento Avanti o Indietro ( in questo caso i due motori fanno
sempre la stessa cosa : sono coordinati )
74
Capitolo 5. Implementazione del Software
S e r v o _ S e t _ P o s i t i o n (2 , DutyCycle ,20) ; // motore DX
// find the opposite duty cycle
float O p p o s i t e _ D u t y C y c l e = map ( DutyCycle ,0.6 ,2.4 ,2.4 ,0.6) ;
S e r v o _ S e t _ P o s i t i o n (3 , Opposite_DutyCycle ,20) ;
} else {
/* Set the right sign of X float used for the PI_pid controller , Ysign is used
in the P_pid function instead */
if ( Xsign == 1) Er ro r _o n_ X_ a xi s *= -1;
DutyCycle = PI_pid_X ( E r ro r_ on _X _ ax is ) ;
// attua il movimento Gira a DX o Gira a SX
S e r v o _ S e t _ P o s i t i o n (2 , DutyCycle ,20) ;
S e r v o _ S e t _ P o s i t i o n (3 , DutyCycle ,20) ;
}
// Actuate always the positioning on the HEAD motor , because this motor is not
shared between different movements
if ( Ysign == 1) Er ro r _o n_ Y_ a xi s *= -1;
DutyCycle = PI_pid_Y ( E r ro r_ on _Y _ ax is ) ;
S er v o _ S e t _ P o s i t i o n (1 , DutyCycle ,20) ;
}
EE_led_off () ;
mydelay (200) ;
}
5.7. OpenCV e Linear Binary Pattern (LBP)
OpenCV (Open Source Computer Vision) è una libreria open-source contenente centinaia di funzioni
per l’analisi di immagini e video, nel contesto della computer vision. A partire dalla versione OpenCV
2.2 è stato aggiunto il supporto per il sistema operativo Android.
Figura 5.9.: Architettura della libreria OpenCV
Il progetto Marvin affronta l’argomento della Visione Artificiale e nello specifico quello della face
detection. Esistono diversi algoritmi per l’elaborazione di un frame video; tra di essi l’algoritmo di
75
Capitolo 5. Implementazione del Software
Viola-Jones risulta il più affidabile e robusto per la localizzazione dei volti ed oggetti, sia in immagini
statiche sia in video. Diverse caratteristiche rendono questo metodo veloce e poco soggetto ai problemi
di illuminazione, rotazione, scalatura e parziale occlusione dei soggetti inquadrati.
Il metodo Local Binary Pattern (LBP) è un diverso metodo per la localizzazione di oggetti che prende
spunto da Viola Jones e ne migliora alcune caratteristiche; esso usa un codice binario per descrivere un
pattern della texture locale, costruito confrontando i valori di grigio dei pixel vicini al punto centrale,
preso come riferimento.
Nella versione originaria del metodo LBP viene utilizzata una matrice di 3x3 pixel: gli 8 pixel che
circondano il pixel centrale vengono confrontati con il valore in scala di grigio di quest’ultimo; il risultato
è un numero binario, usato come descrittore della texture.
Figura 5.10.: Funzionamento dell’algoritmo LBP
Il metodo descritto è disponibile in versione migliorata tanto da implementare la ricerca di uniform pattern (cioè pattern ricorrenti) oppure adattare la matrice di ricerca 3x3 ad una dimensione
personalizzata.
76
Capitolo 6.
Il Sistema di Controllo
Il controllo automatico si prefigge di modificare il comportamento del sistema da controllare, le sue
uscite, attraverso la manipolazione delle grandezze d’ingresso. Il controllo del sistema in esame viene
affidato ad un altro sistema costruito appositamente, detto sistema controllante o controllore, che viene
progettato dopo uno studio preliminare del sistema da controllare per individuarne il modello matematico
esatto, servendosi degli strumenti messi a punto dalla teoria dei sistemi.
6.1. Il controllore PID a tempo continuo: generalità
Il modello matematico di un sistema da controllare è determinato da dinamiche complesse e dai fenomeni fisici, meccanici ed elettrici, che intervengono nel funzionamento del sistema. Per questo motivo è
molto difficile ricavare un modello matematico di un sistema da controllare. Il caso di Marvin è esempio
di quanto appena detto.
Per quanto il problema possa essere affrontato con discreto successo mediante tecniche di identificazione
e modellistica, in questo lavoro si è scelto un approccio più semplice e molto diffuso nei processi industriali,
ovvero l’utilizzo di un controllore PID.
Questo controllore prende il nome dalle tre azioni che costituiscono la sua risposta impulsiva che nel
dominio di Laplace è:
1
+ τd · s
R(s) = Kp · 1 +
τi · s
(6.1)
u(s) = R(s) · e(s)
(6.2)
per cui:
mentre l’uscita nel dominio del tempo è:
1
u(t) = Kp · e(t) +
τi
Z
0
∞
de(t)
e(t)dt + τd ·
dt
(6.3)
Il controllore acquisisce in ingresso un valore dal processo, e lo confronta con un valore di riferimento.
La differenza, il segnale di errore e(t), viene quindi usata per determinare il valore della variabile di uscita
del controllore u(t), che è la variabile manipolabile del processo.
Il PID regola l’uscita in base a:
• il valore del segnale di errore (azione proporzionale);
• i valori passati del segnale di errore (azione integrale);
• la velocità di variazione del segnale di errore (azione derivativa).
77
Capitolo 6. Il Sistema di Controllo
Figura 6.1.: Controllore PID
Il contributo delle azioni del PID può essere riassunto come segue.
Azione Proporzionale: è l’azione principale ed il suo scopo è quello di modificare l’uscita in modo che
essa sia proporzionale all’errore rilevato. Questa azione aumenta la prontezza del sistema aggiungendo
guadagno, che in termini di risposta in frequenza corrisponde allo spostamento verso destra della pulsazione di attraversamento, provocando un aumento della banda passante e una diminuzione del tempo di
salita. In questo modo il transitorio risulta essere più breve. Se il processo ha più di 3 poli l’aumento
incontrollato del guadagno porta il sistema inevitabilmente all’instabilità.
Figura 6.2.: Azioni proporzionali a confronto per un ingresso a gradino
Azione Integrale: migliora il tipo del sistema, rendendolo almeno di tipo 1. Questo significa che
a regime permanente l’errore rispetto ad un ingresso a gradino risulta essere nullo, in quanto l’ordine
dell’ingresso a gradino è pari a 0. Inoltre rende il sistema astatico rispetto a disturbi a gradino che
agiscono in catena diretta. Lo svantaggio è riscontrabile attraverso l’inserimento del polo in s = 0 che
corrisponde a un ritardo di fase di -90° che potrebbe abbassare il margine di fase al di sotto dei 40° (minimo
margine di fase consigliato). Il vantaggio apprezzabile che apporta questo termine è lo smorzamento delle
oscillazioni introdotte dal termine proporzionale anche se questo è apprezzabile per alte frequenze infatti
1
1
s s=jω = jω , che per ω → ∞ da contributo pari a 0.
78
Capitolo 6. Il Sistema di Controllo
Effettivamente il termine integrale peggiora anche la prontezza del sistema attraverso il polo in s = 0.
Per rendersene conto utilizzando le nozioni dell’analisi modale notiamo che se un modo aperiodico è
collocato nell’origine esso tenderà a non estinguersi mai o comunque molto lentamente.
Figura 6.3.: Azioni integrali a confronto per un ingresso a gradino
Azione Derivatrice: è l’azione che la maggior parte delle volte non viene inserita durante la realizzazione del controllore PID rendendolo di fatto un PI, questa azione ha lo scopo di migliorare la stabilità
del sistema in quanto aggiunge uno zero in s = 0 che corrisponde in termini di risposta armonica ad un
aumento di fase pari a +90°. Non viene quasi mai utilizzata; infatti l’operazione di derivata, non essendo
un operatore lineare, potrebbe far divergere l’uscita ad infinito se sul sistema agisce del rumore. Inoltre
tende ad amplificare i disturbi alle alte frequenze.
I vantaggi, comunque, non sono trascurabili. Se l’errore tende a diminuire, la correzione viene aumentata non proporzionalmente, ma in base alla velocità di variazione. L’azione derivatrice può accelerare
o decelerare l’intervento del regolatore in modo dinamico seguendo la tendenza dell’errore e “prevede”
nella prossima lettura l’andamento dell’errore.
Figura 6.4.: Azioni derivatrici a confronto per un ingresso a gradino
La formula 6.3 deve essere discretizzata per poter essere inserita in un sistema di controllo digitale,
come il dsPIC, poiché tale sistema accetta ingressi campionati e quantizzati, dovendo essi essere elaborati
da un calcolatore.
79
Capitolo 6. Il Sistema di Controllo
Il tipico schema di controllo di un sistema digitale a dati campionati è il seguente
Figura 6.5.: Schema a blocchi di un sistema a dati campionati
Si noti la presenza del blocco A/D e D/A che effettuano rispettivamente la conversione analogicodigitale, che nel nostro sistema può essere individuato in Android, e il blocco digitale-analogico che
trasforma dei segnali numerici in segnali che variano nel tempo che nel nostro sistema è visto come il
modulo MCPWM1.
I servomotori sono rappresentati dal blocco di attuazione mentre il blocco impianto è il processo “Marvin”. Il clock è rappresentato dalla periodicità del task di acquisizione garantita del RTOS ERIKA e
impostato a 100 ms, infine Android figura anche come trasduttore.
6.2. Il controllore PID a tempo discreto: generalità
La discretizzazione non interessa il termine proporzionale, poiché esso è una moltiplicazione, ma è
necessaria per l’integrale e la derivata. Esistono diversi metodi per discretizzarli ma in questa tesi sono
stati scelti quelli più semplici:
Z ∞
∞
X
e(k) · Tc
(6.4)
e(t)dt '
0
k=0
e(k) − e(k − 1)
de(t)
'
dt
Tc
(6.5)
avendo realizzato un controllore P e uno PI il termine derivato non è stato utilizzato.
Si nota che il termine integrale richiede ad ogni istante k di calcolare una sommatoria. Tale somma
risulta un’operazione computazionalmente dispendiosa. Se si utilizza la versione ricorsiva dell’algoritmo,
che tiene memoria dell’uscita passata u(k − 1), è possibile migliorare la situazione. Attraverso alcune
semplici sostituzioni si perviene così a questo algoritmo per il controllore PI:
Tc
· e(k − 1)
(6.6)
u(k) = u(k − 1) + Kp · e(k) − e(k − 1) +
τi
banalmente il controllore P è invece:
u(k) = Kp · e(k)
(6.7)
Nel caso specifico si somma all’uscita, u(k), una costante pari a 1,5, utile a traslare i valori dell’uscita
verso i valori di ingresso del servomotore. Infatti per u(k) = 0, e senza questa costante il servomotore
funzionerebbe con un duty cycle pari a 0,6, che non corrisponde alla posizione “neutra” dell’attuatore,
così come l’uscita del controllore richiederebbe.
L’algoritmo di calcolo del P e del PI è implementato in questo modo sulla Flex per un generico asse K:
float P_pid_K ( float error )
80
Capitolo 6. Il Sistema di Controllo
{
float U = 0;
U = Kp_K *( error ) + 1.5;
return U ;
}
float PI_pid_K ( float error )
{
float U = 0;
Ki_K = ( Tc / Ti_K ) ;
float q1 = 1;
float q2 = ( -1 + Ki_K ) ;
U = ( lastU_K + Kp_K * ( q1 * ( error ) + q2 * ( lastError_K ) ) ) + 1.5;
lastU_K = U - 1.5;
lastError_K = error ;
return U ;
}
L’algoritmo PID è semplice da utilizzare ma risulta complicata la taratura dei parametri. Per ogni
asse è necessario trovare empiricamente i parametri Kp , τi , τd , non possedendo il modello matematico
del processo. Essi dipendono fortemente dall’assetto del sistema e dai componenti utilizzati. Questa
caratteristica del controllore PID si scontra leggermente con il concetto di Plug & Play che è alla base
della progettazione di Marvin: infatti sostituendo lo smartphone potrebbe essere necessario ritarare i
parametri del PI e i margini di tolleranza.
Segue quindi una metodologia di taratura che può essere replicata in diversi contesti.
6.3. Taratura dei parametri
Per tarare i parametri ci si è basati sulla seconda tecnica di Ziegler e Nichols – che prevede la taratura
in catena chiusa – dove i parametri vengono trovati con il controllore collegato al sistema.
Questa tecnica si basa sul trovare il guadagno critico Ku , cioè quel guadagno che porta la variabile
controllata a presentare oscillazioni sostenute, oscillazioni, cioè, che non si esauriscono nel tempo. Ovviamente il guadagno critico si trova imponendo τi = τd = 0. Il Ku è importante perché fornisce una
misura del ritardo e della dinamica del processo.
Successivamente viene osservato il Tu , cioè il periodo di oscillazione. A partire da questi dati si applicano
delle formule semi-empiriche per la taratura dei parametri.
Per ogni asse sono stati eseguiti i seguenti passi:
1. Partendo dal controllore P, ponendo a zero le altre azioni, si è trovato Ku , cioè il guadagno che
portasse all’oscillazione il sistema. Per trovare Ku si è incrementato per tentativi il guadagno
partendo da un valore basso.
2. Le oscillazioni attorno al set-point, per ogni asse, sono state misurate “ad occhio”, non avendo avuto
il tempo costruire una corretta misura dell’uscita oppure un esperimento di simulazione. In ogni
caso trovato il Ku si misura il periodo di tempo che intercorre tra un’oscillazione e la successiva,
indicandolo come Tu .
81
Capitolo 6. Il Sistema di Controllo
Figura 6.6.: Ku e Tu
3. Trovati Ku e Tu si procede al calcolo dei parametri Kp , τi e τd , secondo la tabella costruita da
Ziegler e Nichols.
Controllore
Kp
τi
τd
P
0, 5Ku
-
-
PI
0, 45Ku
Tu
1,2
-
PID
0, 6Ku
Tu
2
Tu
8
4. Quindi si testa il sistema inserendo l’algoritmo completo del controllore desiderato con i parametri
calcolati.
5. Si conclude il lavoro di taratura con un ulteriore fine tuning dei parametri calcolati per adattarli in
maniera migliore al processo.
I parametri calcolati per lo smartphone di riferimento sono:
• Asse Y: Kp = 0, 17, τi = 1, 25, τd = 0;
• Asse X: Kp = 0, 4, τi = 2, τd = 0;
• Asse Z: Kp = 1, τi = 0, τd = 0;1
1È
stato tarato anche un controllore PI con i seguenti parametri Kp = 1, 35, τi = 0, 5 ma non è usato nella build finale.
82
Capitolo 7.
Conclusioni e sviluppi futuri
In questo ultimo capitolo vengono riportati i test di funzionamento sul prototipo realizzato e un riepilogo
dei risultati ottenuti, concludendo il lavoro con uno sguardo al futuro del progetto.
7.1. Test di funzionamento
I test di funzionamento sono stati eseguiti attraverso diversi step. Nelle fasi iniziali di lavoro è
stato necessario concentrarsi sull’importazione e sul setup del precedente sistema, nello studio e nella
comprensione approfondita di come è stato sviluppato.
Lo studio ha portato all’individuazione dei punti deboli del sistema. Da qui si è partiti per la
progettazione e l’acquisto dei nuovi componenti: in primis Arduino e i Servomotori.
I test di funzionamento si sono spostati sulla Flex, portando a capire come il microcontrollore è implementato all’interno della architettura progettata da Evidence, in che modo effettuare il debug e come
l’architettura del dsPIC integrata nella Flex potessero essere utilizzate per lo sviluppo.
I test di funzionamento si sono concentrati su come i vari tasks vengono schedulati da ERIKA e come
creare i diversi oggetti del sistema operativo quali risorse, os, cpu, kernel ecc.. Contemporaneamente sono
state sviluppate le librerie serialConsole.h, eeuart.h e utility.h.
Lo studio del Vinculum II e del suo IDE è stato il secondo step anche successivamente è stato sostituito
da Arduino e dalla libreria Microbridge ADB. Ulteriori test sono stati effettuati sia su Arduino creando
Marvin.ino e la libreria Arduino.h sulla Flex per effettuare le comunicazioni UART.
Diversi giorni sono stati impiegati per portare il sistema a funzionare nella configurazione: Arduino–
Vinculum-II–Flex–Control Module, poi scartata per le basse prestazioni.
Quindi si è passati, nel terzo step, allo studio delle periferiche tra cui timers, oscillatori e PWM,
attraverso test di funzionamento sui motori, prima provando senza carico e successivamente inserendo un
carico -la ruota- per studiarne le prestazioni in termini di velocità e stabilità.
In contemporanea con le periferiche si è anche condotto lo studio dell’alimentazione creando il circuito di
potenza e dividendo la breadboard in due linee di alimentazione. Test sull’elettronica sono stati condotti
attraverso un multimetro e un oscilloscopio per verificare la forma d’onda della PWM.
Una volta terminati i vari test sul lato hardware e scelta la configurazione Arduino-Flex- Servomotori si
è passati allo studio di Android, attraverso debug dell’applicazione già esistente e progettando un diverso
tipo di controllo del robot, non più secondo Aree ma utilizzando algoritmi tipici dell’automatica.
I restanti test si sono concentratati appunto sull’applicazione ad alto livello e sulla la taratura dei
parametri del PID.
Sono stati ipotizzati anche test formali al fine di estrarre risultati numerici dal prototipo realizzato.
L’idea di base consiste nel calcolare la velocità massima che un volto può assumere rimanendo riconoscibile
e continuando ad essere inseguito dal sistema. La velocità è legata al numero di frames che il sistema
riesce ad elaborare, e quindi si è stimato che processando 10 frame al secondo, un volto viene riconosciuto
se ha una velocità minore di 10 cm/s.
83
Capitolo 7. Conclusioni e sviluppi futuri
Studi più precisi possono essere condotti costruendo un sistema di test, come ad esempio una foto di un
volto mossa da un motore a rotazione continua, dove sarebbe possibile impostare la velocità di rotazione
del motore. Noto il diametro della ghiera e la velocità di rotazione, si potrebbe verificare effettivamente
la velocità massima di riconoscimento dei volti dato un tetto massimo di frames per secondo.
7.2. Obiettivi raggiunti
Attraverso i test eseguiti si è notato un generale raggiungimento di tutti i requisiti e degli obiettivi
prefissati. Infatti il sistema è stato riprogettato rendendolo più “snello” e capace di evolversi nel tempo
senza troppe difficoltà. La scheda Flex è stata studiata e si è dimostrato come sia possibile usarne le
periferiche in maniera interessante, nonchè creare delle librerie che permettano una sempre più facile
prototipizzazione ed accesso all’hardware.
Il sistema ERIKA è stato approfondito attraverso esperimenti e ricerche in maniera tale da poter usare
tutti gli oggetti avanzati e non, messi a disposizione per il programmatore dimostrando come anche su
un sistema embedded e dalla capacità di calcolo ridotta sia possibile effettuare uno scheduling real-time.
Il lavoro di ricerca si è spostato anche sul versante Arduino ed Android, mostrando le potenzialità e
gli ambiti di applicazione soprattutto con la libreria Microbridge ADB, capace di eliminare il problema
dei pochi smartphone compatibili e OpenCV per gli algoritmi di visione. Infine si è implementato un
controllore PID funzionante, permettendo un ottimo inseguimento di volti, riutilizzabile all’occasione
in molti ambiti diversi, tra quelli più affini -come l’inseguimento di oggetti- o per scopi più complessi
manipolando gli errori e i Set points.
Infine per una gestione manuale dei comandi di spostamento è stata costruita una sorta di “demo” sia
in ambito Android che su Flex per inviare e ricevere i singoli comandi di direzione.
Figura 7.1.: Architettura finale di Marvin
84
Capitolo 7. Conclusioni e sviluppi futuri
7.3. Sviluppi futuri
Marvin è da considerarsi un vero è proprio laboratorio mobile, su cui sperimentare sia applicazioni a
basso livello tra cui l’estensione della sensoristica e delle periferiche utilizzabili tra cui SPI, CAN bus,
Bottoni, LCD l’inserimento un nuovo motore per l’attuazione lineare del movimento di testa in maniera
tale che la testa, oltre a spazzare angoli, si muova linearmente attraverso un sistema meccanico che dia
piena libertà di movimento lungo l’asse Y e sensoristica varia.
E’ auspicabile la sostituzione del layer di Comunicazione attraverso porting della libreria ADB sulla
Flex, oppure utilizzando un modulo bluetooth per scambiare i dati tra Flex e Android.
Ad alto livello è possibile avere uno scenario molto più ampio di possibili applicazioni. Ad esempio,
si potrebbe utilizzare il protocollo Voice XML per permettere di processare informazioni vocali e quindi
estrapolare da essi comandi e attraverso un TTS (text-to-speech) “dare la parola” a Marvin utilizzando
l’altoparlante dello smartphone.
L’intelligenza artificiale trova grandi campi di applicazione su robot mobili tra cui la possibilità di
tracciare percorsi, riconoscere path e imparare attraverso reti neurali.
L’ambito di controllo automatico può essere esplorato oppure affiancato alla sensoristica esistente per
l’esplorazione di ambienti sconosciuti e la creazione di mappe. Infine è possibile approfondire la computer
vision sia implementando nuovi algoritmi di visioni tra quelli disponibili in OpenCV sia idearne dei nuovi.
85
Capitolo 7. Conclusioni e sviluppi futuri
Figura 7.2.: Marvin
86
Appendice A.
Dettagli di cablaggio
Flex
P51 (U1TX)
P52 (U1RX)
GND
Arduino
19 (RX1)
18 (TX1)
GND
Tabella A.1.: Connessione Flex-Arduino tramite USART1
Figura A.1.: Connessione Flex-Arduino tramite USART1
Flex
P50 (U2TX)
P49 (U2RX)
GND
Convertitore PL2303
RX
TX
GND
Tabella A.2.: Connessione Flex-Convertitore tramite USART2
87
Appendice A. Dettagli di cablaggio
Figura A.2.: Connessione Flex-Convertitore tramite USART2
Flex
P94 (PWM1H)
+5V
GND
Hitec HB-485HS
YELLOW
RED
BLACK
Tabella A.3.: Connessione Flex-Servomotore di testa tramite PWM1
Figura A.3.: Connessione Flex-Servomotore di testa tramite PWM1
88
Appendice A. Dettagli di cablaggio
Figura A.4.: Dettaglio del servomotore di testa
Flex
P99 (PWM2H)
+5V da breadboard
GND
DFRobotic (SX)
ORANGE
RED
BROWN
Tabella A.4.: Connessione Flex-servomotore di propulsione tramite PWM2
Flex
P3 (PWM3H)
+5V da breadboard
GND
DFRobotic (DX)
ORANGE
RED
BROWN
Tabella A.5.: Connessione Flex-servomotore di propulsione tramite PWM3
Figura A.5.: Connessione Flex-servomotori di propulsione tramite PWM2 e PWM3
89
Appendice A. Dettagli di cablaggio
Figura A.6.: Dettaglio dei servomotori di propulsione alloggiati sotto la struttura
Flex
P25 (DGTL-OUTP)
P26 (DGTL-OUTP)
Led
ORANGE
YELLOW
Tabella A.6.: Connessioni Flex-led
Arduino
24 (Digital)
22 (Digital)
Led
GREEN
RED
Tabella A.7.: Connessioni Arduino-led
Figura A.7.: Connessione Flex e Arduino ai led presenti sulla breadboard
90
Appendice A. Dettagli di cablaggio
Figura A.8.: Circuito di alimentazione e linee di tensione
Figura A.9.: Connessione Arduino-Smartphone tramite cavo USB
91
Appendice B.
Software utilizzato
In questa Appendice vengono riportate le versioni dei software utilizzati nello sviluppo di Marvin1 .
Programmazione della scheda FLEX
• Java JRE 1.6.0_27 a 32-bit
• Cygwin 1.7.9
• ERIKA Enterprise e RT-Druid 1.6.1
• Microchip MPLAB IDE v8.43
• Microchip C30 Compiler v3.30c
• RealTerm per il Debug
Programmazione della scheda Arduino
• Arduino 1.0
• Microbridge ADB (modificata)
Programmazione dell’applicazione Android
• Eclipse IDE for Java Developers, INDIGO (v3.7.1)
• Android SDK
• ADT Plugin per Eclipse
• Android 2.3.4 (Google API 10) installati tramite l’Android SDK Manager
Programmazione del Vinculum-II
• Vinculum-II toolchain v 1.4.4
• Drivers per V2DIP
1I
software citati sono tutti disponibili nella cartella “software” nel CD della tesi.
92
Bibliografia
[1] “dsPIC33FJXXXMCX06/X08/X10 Motor Control Family Data Sheet.” [Online]. Available:
http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en024663#1
[2] “Microchip dsPIC – wiki page for ERIKA.” [Online]. Available: http://erika.tuxfamily.org/wiki/
index.php?title=Microchip_dsPIC
[3] “Erika Enterprise Conformance Classes Comparison Guide.” [Online]. Available:
tuxfamily.org/download/manuals/pdf/ee_porting_1_0_1.pdf
[4] “Erika Enterprise reference manual.” [Online]. Available:
manuals/pdf/ee_refman_1_4_4.pdf
http://erika.
http://erika.tuxfamily.org/download/
[5] “RT-Druid reference manual.” [Online]. Available: http://erika.tuxfamily.org/download/manuals/
pdf/rtdruid_refman_1_5.0.pdf
93