SlideShare a Scribd company logo
1 of 53
Download to read offline
UNIVERSITÀ DEGLI STUDI DI TRIESTE
Dipartimento di Ingegneria e Architettura
Corso di Studi in Ingegneria Elettronica
Progetto di un sistema di controllo,
basato su piattaforma Arduino, atto a
stabilizzare il volo di un drone
Tesi di Laurea Triennale
Laureando: Relatore:
Tobia DALL’ACQUA Prof. Stefano MARSI
_____________________________________
ANNO ACCADEMICO 2016-2017
Indice
Introduzione........................................................................................... 1
Hardware ............................................................................................... 3
1.1 Arduino ......................................................................................... 3
1.1.1 Caratteristiche.........................................................................3
1.2 Motori ........................................................................................... 6
1.3 E.S.C. ............................................................................................. 9
1.3.1 Programmare gli E.S.C. ............................................................ 9
1.3.2 Impostazioni E.S.C. ................................................................ 11
1.4 MPU-9250 ................................................................................... 12
1.4.1 Caratteristiche sensori........................................................... 13
1.5 Trasmettitore e ricevente RC....................................................... 15
1.5.1 Modulazione ......................................................................... 16
Software............................................................................................... 18
2.1 Angoli di Eulero ........................................................................... 18
2.1.1 Disturbi.................................................................................. 18
2.1.2 Il Filtro Complementare......................................................... 19
2.1.3 Filtro complementare con Arduino........................................ 21
2.1.4 Matrici di Rotazione .............................................................. 23
2.2 PID............................................................................................... 26
2.2.1 PID con Arduino..................................................................... 27
2.3 Trasmettitore e ricevente RC....................................................... 29
2.3.1 Interrupt................................................................................ 29
2.3.2 Calibrazione radiocomando................................................... 31
Approfondimenti Software................................................................... 35
3.1 Matrice di rotazione .................................................................... 35
3.1.1 Fast ypr2rot........................................................................... 36
3.2 Timer........................................................................................... 38
3.2.1 Tempo di ciclo ....................................................................... 39
3.2.2 ISR ......................................................................................... 40
3.2.3 PWM ..................................................................................... 42
3.3 EEPROM ...................................................................................... 43
3.3.1 Bit Manipulation.................................................................... 44
Conclusioni........................................................................................... 46
Fonti Bibliografiche e Sitografia............................................................ 47
1
Introduzione
Nel corso di questa tesi si vanno a descrivere le principali dinamiche che
legano il volo di un quadricottero alla sua implementazione software. Si
dedica in particolare l’attenzione prima alle componenti del drone e alla
loro scelta, per poi soffermarsi sulla programmazione in ambiente
Arduino, che è stata oggetto di studio e approfondimento del candidato.
Infine, si sposta l’attenzione sui dettagli e le ottimizzazioni che hanno
posto le basi per una buona riuscita del progetto.
La tesi rappresenta la conclusione di un percorso di tirocinio svolto
presso l’Università degli Studi di Trieste volto all’apprendimento e allo
studio della piattaforma Arduino tramite piccoli progetti dedicati alla
valutazione dei dati restituiti dai più comuni sensori di posizione, alla
gestione di servomotori e al controllo PID.
Il quadricottero si pone dunque come sintesi di un lavoro svolto su più
livelli, che sfrutta le conoscenze acquisite dal laureando in ambito
elettronico e informatico e allo stesso tempo richiede continui
miglioramenti e ottimizzazioni.
2
3
Capitolo 1
Hardware
1.1 Arduino
Arduino è una piattaforma elettronica open source, ideata e sviluppata
da alcuni membri dell'Intercalino Design Institute di Ivrea come
strumento per la prototipazione rapida e per scopi hobbistici, didattici e
professionali [1]
. Esso basa il suo funzionamento sul microcontrollore
ATmega328P, un dispositivo multifunzione dotato di: CPU, memoria
Flash, memoria RAM e memoria EEPROM. Arduino è dotato inoltre di un
cristallo al quarzo, Pin I/O, un connettore USB, un jack di alimentazione
e un pulsante di reset. Analizziamo ora singolarmente tutte queste
componenti.
1.1.1 Caratteristiche
L’ATmega328P è un microcontrollore low-power CMOS a 8 bit, basato su
architettura di tipo RISC. Esso è in grado di svolgere più operazioni per
ogni ciclo di clock, permettendogli di raggiungere throughput dell’ordine
di 1 MIPS (Million Instructions Per Second) per MHz.
La memoria da 32 KB, dove viene salvato il codice da compilare, è di tipo
Flash e viene sovrascritta ogni volta che si carica un nuovo programma
sulla scheda Arduino. Le memorie di tipo Flash sono non volatili e
sfruttano dei particolari FET chiamati “floating gate MOSFET”, i quali
sono in grado di contenere carica elettrica per lunghi periodi di tempo
grazie ad effetti capacitivi. Ogni transistor costituisce una cella di
4
memoria che conserva il valore di un bit. Una piccola parte (0,5 KB) della
memoria Flash è riservata al bootloader.
Oltre alla memoria Flash è presente sul microcontrollore un’altra
memoria non volatile, detta EEPROM, della capacità di 1 KB. Anche le
memorie EEPROM (Electrically Erasable Programmable Read-Only
Memory) sfruttano i floating gate MOSFET, la differenza con le memorie
Flash sta nel meccanismo per l’iniezione di carica.
L’ultima tipologia di memoria che si trova sull’ATmega328 è una SRAM
da 2 KB. Le SRAM sono memorie volatili che consentono di mantenere le
informazioni per un tempo teoricamente infinito, sono molto veloci e
dissipano poco calore, necessitano però di molti componenti per la
costruzione, il che le rende costose e ne limita la capienza.
Il compito della CPU è quello di assicurare la corretta esecuzione del
programma, essa è in grado di accedere alle varie memorie e di eseguire
calcoli. L’architettura di tipo RISC (Reduced Instruction Set Computer)
permette di eseguire molte istruzioni per ogni ciclo di clock e inoltre
riserva molto spazio per i registri interni: speciali locazioni di memoria
della CPU che ne determinano lo “stato” [2]
.
I pin dell’ATmega328P (Figura 1.1) sono connessi alle varie componenti
di Arduino. I pin 9 e 10 sono collegati ad un oscillatore al quarzo da
16MHz, il pin 1 è collegato al pulsante di reset, i pin 7, 8, 20 e 22 sono
riservati ad alimentazione e massa mentre il pin 21 rappresenta la
tensione di riferimento per la lettura dei pin analogici. I rimanenti pin
5
sono dedicati all’ I/O: Arduino presenta 14 pin digitali (lavorano solo con
tensioni HIGH o LOW) programmabili come input o output, 6 di questi pin
presentano la particolarità di poter essere utilizzati per generare un
output PWM. Affiancati ai digitali si trovano 6 pin analogici, utilizzabili
solo come input, in grado di convertire un valore analogico di tensione in
ingresso nel suo corrispondente digitale con risoluzione 10-bit[3]
.
Figura 1.1: ATmega328P pin mapping
6
1.2 Motori
Prima di parlare dei motori a livello tecnico è necessario soffermarsi sulla
scelta di questi ultimi. La scelta dei motori è fondamentale per ottenere
velocità, precisione del volo ed efficienza; una giusta proporzione fra
queste specifiche va decisa dal costruttore a seconda del budget e della
finalità del quadricottero (gare di velocità, volo acrobatico, filmati
professionali, ecc.). Si vuole partire ora dalle 2 componenti che più
influiscono sulla scelta dei motori: telaio ed eliche.
Per il progetto è stato acquistato un telaio di dimensione 450 mm, dove
la dimensione si riferisce all’interasse di due motori opposti
diagonalmente. È stato così definito un limite superiore per la
dimensione delle eliche e considerato lo spazio occupato dalla scheda
centrale questa misura è 10 pollici (254 mm) di diametro.
È doveroso ora parlare dei parametri che influenzano la scelta dell’elica:
• Diametro: dà una misura della difficoltà nel far girare le eliche
dovuta all’attrito dell’aria (direttamente proporzionale al
diametro). Eliche più piccole sono più rapide a partire e fermarsi,
mentre eliche più grandi richiedono più tempo per cambiare
velocità.
• Passo: esprime la distanza che percorre un’elica in un giro o in altre
parole: quanta aria è in grado di spostare un’elica in un giro, e.g.
un’elica di passo 3 sposterà una colonna d’aria lunga 3 pollici. Un
passo più alto farà spostare al quadricottero una maggiore
quantità d’aria creando maggiore turbolenza, ma generando
7
anche più spinta e restituendo quindi una maggiore velocità
massima.
Per concludere, eliche più grandi e con passo maggiore sono in grado di
garantire velocità maggiori, a discapito del consumo di corrente causato
dalla difficoltà dei motori di spostare maggiori quantità d’aria. Per il
nostro progetto sono state scelte delle eliche 1045, ossia 10 pollici di
diametro (compatibili con il telaio) e 4.5 pollici di passo.
Si hanno ora tutti gli elementi che permetteranno di scegliere i motori
adeguati, le cui caratteristiche dovranno essere:
• Dimensioni ridotte
• Peso ridotto
• Rendimento ed efficienza alti
• Precisione elevata in velocità e accelerazione
La scelta più adatta per un quadricottero è quella dei motori di tipo
brushless, di cui verranno scelte le caratteristiche in base alle specifiche
di progetto.
Innanzitutto, va stimata la massa del quadricottero completo:
considerata la massa del telaio (300 g), della scheda Arduino compresa di
vari moduli e cavi (circa 70 g), della batteria (circa 200 g), dei motori che
dovranno aggirarsi attorno ai 70 g l’uno e tralasciando la massa delle
eliche si otterrà un quadricottero di circa 850 g.
Considerato che una regola generale per avere un quadricottero stabile
è quella di avere un rapporto almeno di 2:1 fra spinta dei motori e peso,
saranno necessari motori capaci di generare almeno
8
850*2*10 /4 = 4250 N di spinta (il doppio del peso del quadricottero
diviso per quattro motori).
Un’altra limitazione è data dalla dimensione delle eliche, un motore in
grado di generare un elevato numero di giri al minuto infatti non è adatto
per eliche grandi, in quanto consumerebbe troppa corrente e
rischierebbe di fondere. Nei datasheet troviamo i giri al minuto espressi
in KV: il KV è definito come il rapporto fra il numero di rotazioni al minuto
e la tensione applicata ad un motore senza carico. Per questo progetto
un adeguato KV si aggira attorno a 1000 [4]
.
I motori scelti sono dunque gli A2212 (in figura 1.2 già con le eliche
assemblate). L’A2212 è un motore da 1000 KV, di massa 57.2 g e in grado
di sollevare fino a 800 g come indicato nel datasheet [5]
.
Figura 1.2: motori brushless A2212 con eliche
9
1.3 E.S.C.
I moduli E.S.C., acronimo di Electronic Speed Controller, sono dispositivi
elettronici che hanno il compito di regolare la velocità di rotazione dei
motori elettrici. Essi sono in grado, attraverso l’elaborazione di un
microprocessore interno, di convertire un segnale di tipo PWM in
ingresso in una corrente trifase (il cui amperaggio massimo è indicato
sulla guaina che riveste il modulo) proporzionale al duty cycle, la quale
andrà a variare il numero di giri al minuto del motore brushless. La
frequenza di lavoro tipica di un E.S.C. è 50 Hz, ma i moderni moduli sono
in grado di lavorare a frequenze anche notevolmente più elevate e per
questo progetto, per favorire un migliore controllo della fase di volo, si è
scelta una frequenza di lavoro di 100 Hz costruendo frame PWM da 10
ms.
Gli E.S.C. sono inoltre programmabili, in particolare quelli montati sul
quadricottero presentano una sequenza di programmazione che si
interfaccia verso l’esterno attraverso una serie di suoni emessi dai motori
collegati.
1.3.1 Programmare gli E.S.C.
Il controllo della programmazione degli E.S.C. avviene attraverso la
lettura di due valori di throttle (HIGH o LOW) che vanno impostati
dall’utente, bisogna cioè fornire al microprocessore il full scale range del
segnale di comando. Per settare questi valori è necessario:
• Ad E.S.C. spenti, inviare ai moduli, tramite Arduino, un valore
(espresso in µs) che corrisponde al throttle massimo;
10
• Accendere gli E.S.C. ed aspettare circa due secondi, dopo i quali
verrà emesso un doppio suono corto, che conferma l’avvenuta
registrazione;
• Inviare ora ai moduli il segnale corrispondente al throttle minimo;
• Aspettare l’emissione prima di alcuni suoni corti consecutivi
(dipendenti dal tipo di batteria collegata), poi di un suono lungo
che avverte l’utente che il range di valori è stato correttamente
registrato.
Per fare ciò è stata scritta una routine Arduino che sfrutta la
comunicazione seriale tramite USB e la libreria Servo [6]
per inviare i
due segnali agli E.S.C.
Il codice di seguito mostra il funzionamento di tale routine: la variabile
data salva il valore inserito tramite tastiera dall’utente, in base a
questo viene deciso se inviare un segnale di throttle alto o basso; la
Figura 1.3: codice Arduino per il set-up degli E.S.C.
11
funzione writeMicroseconds(n) invia un segnale della durata di n
microsecondi inserito in un frame di 10 millisecondi ai vari E.S.C.
1.3.2 Impostazioni E.S.C.
Come è stato anticipato le impostazioni dei moduli sono controllate
dall’utente attraverso l’emissione di suoni generati dai motori attraverso
gli E.S.C. stessi. Per entrare in modalità programmazione è necessario:
impostare il throttle al massimo, accendere il sistema e attendere circa
sette secondi, dopo i quali verrà emesso un suono speciale.
Successivamente il sistema emetterà 8 diversi suoni in sequenza, ognuno
corrispondente ad un diverso parametro che si vuole modificare, come
indicato in tabella:
Tabella 1: corrispondenza fra suoni e funzioni. '*' indica un suono corto, '_' indica un
suono lungo
In corrispondenza del suono ricercato bisogna provvedere a settare il
throttle al minimo entro tre secondi, si accede così alla modifica di una
particolare funzione, i cui valori saranno nuovamente indicati da vari
Suono Modalità
* Modalità break
** Tipo di batteria
*** Modalità di protezione alla bassa tensione
**** Modalità di protezione all’abbassamento della
tensione della batteria
_ Modalità di startup
_* Timing
_** Impostazione di tutti i parametri ai valori di default
__ Uscita dalla modalità di programmazione
12
suoni (vedi tabella 2). Per scegliere l’impostazione di interesse si setterà
il throttle al massimo fino all’emissione di un tono speciale che conferma
la scelta del valore.
Modalità * ** ***
Brake Disabled Enabled
Tipo di batteria Li-xx Ni-xx
Modalità di protezione alla bassa
tensione
Soft Cut-
Off
Cut-Off
Modalità di protezione
all’abbassamento della tensione della
batteria
Low Medium High
Modalità di startup Normal Soft Super-
Soft
Timing Low Medium High
Tabella 2: corrispondenza fra suoni e valori
A questo punto, mantenendo il throttle al massimo si viene riportati nel
menu principale, potendo quindi modificare le altre modalità; se, al
contrario, si porta il throttle al suo valore minimo si esce dalla modalità
di programmazione e gli E.S.C. saranno pronti a controllare i motori.
1.4 MPU-9250
L’MPU-9250 appartiene alla famiglia degli IMU (i.e. Inerti al
Measurement Unit), dispositivi elettronici in grado di misurare
l’accelerazione inerziale e la velocità angolare di una massa; alcuni fra
questi dispositivi inoltre sono capaci di calcolare il campo magnetico in
cui il corpo è immerso e la sua altitudine.
Per misurare queste grandezze un IMU può essere dotato di:
• Un accelerometro;
13
• Un giroscopio;
• Un magnetometro;
• Un altimetro.
Il dispositivo utilizzato in questo progetto è l’InvenSense MPU-9250[7]
:
esso è dotato di un accelerometro, un giroscopio e un magnetometro,
tutti a 3 assi. Inoltre, l’MPU-9250 presenta un sensore di temperatura per
la compensazione dei dati. Per gli scopi di questa tesi verranno utilizzati
solo i dati provenienti da accelerometro e giroscopio in quanto questi
sono sufficienti per definire le coordinate spaziali di un drone.
L’MPU impiega il protocollo I2C per la comunicazione con l’esterno, e
tramite la libreria Wire [8]
di Arduino è possibile configurarne molte
impostazioni, scrivendo sui suoi registri. Purtroppo, l’utilizzo dei registri
non è banale e per lo più poco documentato, per questi motivi verrà
utilizzata un’apposita libreria [9]
che implementi le funzionalità più
importanti del sensore.
1.4.1 Caratteristiche sensori
Un accelerometro è un sensore in grado misurare l’accelerazione di un
corpo, è un tipo di sensore molto accurato mediamente e sul lungo
periodo, purtroppo subisce in maniera pesante l’effetto di vibrazioni e
disturbi, i quali si manifestano spesso durante il volo di un quadricottero.
Al contrario un giroscopio è poco soggetto ai disturbi in quanto misura
una velocità angolare e la integra nel tempo, l’integrazione può portare
però alla deriva dei valori nel tempo, fino ad allontanarsi sempre più dal
valore corretto. Per ovviare ai problemi dei sensori sarà necessario
14
rielaborarne i dati tramite appositi filtri e rimozioni di offset, che
verranno descritti in paragrafi dedicati.
Venendo ora al dettaglio dell’MPU-9250: esso fornisce 6 valori grezzi da
2 byte ciascuno, che corrispondono agli assi di accelerometro e
giroscopio. Le tensioni fornite dai sensori sono campionate da 6
convertitori AD da 16 bit, permettendo la conversione simultanea delle
tensioni per ogni asse.
Come già detto questi valori sono grezzi (raw) e vanno calibrati per
ottenere le velocità angolari e le accelerazioni richieste. Tramite software
è possibile configurare giroscopio e accelerometro su diversi livelli di
sensibilità, come illustrato nella tabella sottostante.
Grazie a queste informazioni è possibile trasformare i dati raw in velocità
angolari e accelerazioni, ad esempio un valore raw di 4096 rappresenta
1g con sensibilità ±8g. A questo punto è possibile ricavare gli angoli di
Eulero, ai quali sarà dedicato un capitolo, che forniscono l’orientazione
spaziale di un corpo attraverso angoli detti: rollio, beccheggio e
imbardata.
Gyro Full Scale
Range
(deg/sec)
Gyro Sensibility
(LSB/deg/sec)
Accel Full Scale
Range (g)
Accel
Sensibility
(LSB/g)
±250 131 ±2 16384
±500 65.5 ±4 8192
±1000 32.8 ±8 4096
±2000 16.4 ±16 2048
Tabella 3: Full scale range e sensibilità di accelerometro e giroscopio
15
1.5 Trasmettitore e ricevente RC
Il trasmettitore utilizzato in questo progetto è il Fly-Sky FS-T4B (figura
1.4), un trasmettitore a 4 canali che richiede 12V di alimentazione e
lavora su frequenze dai 2.40 ai 2.48 GHz [10]
. La ricevente è un modello:
Fly-Sky FS-R6B (figura 1.5) a 6 canali.
Prima di poter correttamente utilizzare i due dispositivi e interfacciarli
con Arduino è necessaria un’operazione detta: “binding”, che consiste
nella sincronizzazione fra ricevente e trasmettitore per evitare
interferenze con altri apparecchi RC. Per fare ciò nella confezione del
trasmettitore è sempre presente un apposito cavo (figura 1.5) che viene
collegato ai pin della ricevente dedicati al binding; dopo aver connesso la
ricevente all’alimentazione si accende il radiocomando tenendo
contemporaneamente premuto un apposito pulsante. Ora i due
dispositivi sono sincronizzati, e il legame rimane valido anche per utilizzi
successivi.
Figura 1.4: RC transmitter
16
1.5.1 Modulazione
È doveroso ora fare alcune precisazioni sulle differenze fra modulazione
PWM e PPM. Il primo tipo viene utilizzato per controllare gli E.S.C. ed è
anche il segnale in uscita dalla ricevente, il secondo è più complesso a
livello computazionale ma risulta vantaggioso quando dobbiamo
trasmettere le informazioni di 4 canali differenti contemporaneamente
su un unico canale: esattamente ciò che succede fra trasmettitore e
ricevente esaminati posco sopra (trasmettitore ha 4 canali, ricevente una
sola antenna).
La modulazione PWM, o modulazione a larghezza d’impulso, si basa sul
concetto di duty cycle e permette di ottenere una tensione media
dipendente dal rapporto tra la durata dell’impulso HIGH e quello LOW.
Nel caso in esame i due segnali sono inseriti in un frame da 20 ms e la
frequenza di aggiornamento sarà dunque di 50 Hz per canale. Questo
tipo di modulazione è facilmente interpretabile dalla scheda Arduino
grazie all’utilizzo di interrupt.
Figura 1.5: RC receiver and binding cable
17
La modulazione PPM, o modulazione a posizione d’impulso, riesce al
contrario ad inserire in un unico frame da 20 ms le informazioni
provenienti da più fonti diverse e codifica il segnale attraverso la
posizione di un impulso di durata fissa all’interno di un frame; di
conseguenza il numero di impulsi definisce il numero di canali, e la
distanza temporale fra questi impulsi definisce l’informazione. Il
vantaggio della modulazione PPM è il fatto di poter inviare più segnali
attraverso un unico cavo, lo svantaggio è che il dispositivo ricevente deve
essere in grado di elaborare un segnale molto complesso.
Nel caso del quadricottero gli E.S.C. vengono pilotati da un segnale PWM,
di conseguenza è più comodo gestire segnali separati in canali separati,
la ricevente avrà dunque 4 uscite collegate a 4 pin digitali di Arduino, che
a sua volta avrà 4 uscite collegate ai singoli moduli E.S.C.
Tuttavia il segnale di uscita dal telecomando è un segnale PPM, il che
significa che sulla ricevente è presente un microcontrollore in grado di
convertire l’ingresso sull’antenna in 4 diversi segnali PWM.
18
Capitolo 2
Software
2.1 Angoli di Eulero
L’MPU-9250, come già anticipato nel capitolo precedente, è un
dispositivo in grado di analizzare velocità angolari e accelerazioni di un
corpo, per poi salvarle all’interno dei propri registri in sei diverse variabili
da due byte:
• Le prime tre corrispondono alle componenti della velocità
angolare del sistema rispetto agli assi x, y e z di un riferimento
ortogonale il cui centro coincide con il centro di massa della
struttura;
• Il secondo gruppo rappresenta invece le componenti del vettore
accelerazione rispetto agli stessi assi. Nel caso in cui il sistema sia
fermo, l’unica componente rilevata è l’accelerazione di gravità.
2.1.1 Disturbi
Le misurazioni del sensore sono sensibili a vari fattori, i due principali
elencati di seguito:
• Utilizzando i dati grezzi del giroscopio per determinare la posizione
angolare del quadricottero nello spazio si va incontro ad
un’operazione di integrazione. Si ricorda infatti che il giroscopio
misura velocità angolari e, definita la velocità angolare come
𝜔 =
𝜕𝜃
𝜕𝑡
, l’angolo θ risulta: 𝜃 = ∫ 𝜔𝑑𝑡
𝑡
0
. Grazie a questa operazione
la misura è accurata e poco suscettibile ad agenti esterni, ma
19
presenta anche un effetto di deriva a lungo termine dovuto
all’errore che si accumula durante l’integrazione.
• Se si considerassero solo i dati grezzi dell’accelerometro per
stabilire la direzione dell’accelerazione di gravità, si potrebbe
attraverso questa stimare almeno parzialmente l’orientamento
del sistema nello spazio. Purtroppo il sistema non è inerziale ed è
soggetto a molte accelerazioni diverse, per cui l’output risulta
giocoforza soggetto a molte forme di perturbazione.
Un obiettivo di questo progetto è stato elaborare opportunamente i dati
forniti dai sensori per ottenere una rappresentazione che sia il più
corretta possibile degli Angoli di Eulero:
• Roll: corrispondente alla rotazione attorno all’asse x;
• Pitch: corrispondente alla rotazione attorno all’asse y;
• Yaw: corrispondente alla rotazione attorno all’asse z.
2.1.2 Il Filtro Complementare
Per eliminare i disturbi sopra citati si è scelto di utilizzare un filtro
complementare, la cui idea di base consiste in: far passare i dati
provenienti dall’accelerometro attraverso un filtro passa basso, per
eliminare il rumore ad alta frequenza causato da accelerazioni istantanee
e mantenere la stabilità dei dati sul lungo periodo. I dati del giroscopio
invece passeranno attraverso un filtro passa alto, per rimuovere l’effetto
di deriva dell’integrale. I due gruppi di dati così filtrati verranno sommati
per ottenere una stima degli angoli che tenga in considerazione i valori
più significativi restituiti dai due sensori.
20
L’input dei filtri sarà un angolo e non il dato grezzo proveniente dai
sensori, quindi :
• Per i dati provenienti dal giroscopio, come già affrontato, verrà
fatta un’operazione di integrazione;
• Per i dati dell’accelerometro si farà utilizzo della funzione:
𝑎𝑡𝑎𝑛2(𝑦, 𝑥) =
{
atan (
𝑦
𝑥
) , 𝑠𝑒 𝑥 > 0
atan (
𝑦
𝑥
) + 𝜋, 𝑠𝑒 𝑥 < 0 ∧ 𝑦 ≥ 0
atan (
𝑦
𝑥
) − 𝜋, 𝑠𝑒 𝑥 < 0 ∧ 𝑦 < 0
+
𝜋
2
, 𝑠𝑒 𝑥 = 0 ∧ 𝑦 > 0
−
𝜋
2
, 𝑠𝑒 𝑥 = 0 ∧ 𝑦 < 0
𝑛𝑜𝑛 𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑎, 𝑠𝑒 𝑥 = 0 ∧ 𝑦 = 0
Questa funzione è in grado di gestire la divisione per 0 e il segno
dell’angolo ed è implementata dalla maggior parte dei linguaggi di
programmazione. La funzione prende in input due valori
(rispettivamente la componente z del vettore accelerazione e una tra le
componenti x e y, in base all’angolo che si vuole determinare) e
restituisce l’angolo in radianti tra il semiasse positivo delle x e un punto
di coordinate (x, y) restituendo un valore nell’intervallo (-π, π), dove x e
y sono riferiti agli input della funzione.
Figura 2.1: schema a blocchi relativo al funzionamento di un filtro complementare
21
Per quanto riguarda l’angolo di imbardata, è possibile determinarlo solo
attraverso l’elaborazione dei dati provenienti dal giroscopio, in quanto
qualsiasi variazione di tale angolo risulta ininfluente rispetto alla
variazione del vettore gravitazionale.
2.1.3 Filtro complementare con Arduino
Il filtro sviluppato nel corso di questo progetto è un filtro del “primo
ordine”: una tipologia di filtro grazie alla quale si è in grado di ottenere
una buona stima dei valori reali. Filtri del secondo e terzo ordine
garantirebbero maggiore separazione tra la banda passa-alto e quella
passa-basso, ma sono stati scartati essendo questi ultimi molto più
complessi da realizzare a livello software e non garantendo un guadagno
in accuratezza tale da giustificare l’aumento di complessità.
In primo luogo è stata fatta una calibrazione sui dati di giroscopio e
accelerometro per rimuovere eventuali offset grossolani, di seguito viene
riportata la porzione di codice per la calibrazione dell’angolo di rollio
proveniente dal giroscopio:
La costante CALIBRATION_STEPS vale 400, il che significa che vengono
fatte 400 misurazioni dell’angolo su cui poi si fa una media. Il valore finale
22
della variabile gyroX_cal sarà questa media e rappresenterà l’offset del
giroscopio da rimuovere in tutte le misurazioni successive.
In seguito si sfrutterà la funzione atan21
per determinare gli angoli di
rollio e beccheggio leggendo i dati dell’accelerometro.
Per i dati del giroscopio la questione è leggermente più complicata in
quanto il microprocessore lavora a tempo discreto e non può gestire
l’integrazione di funzioni continue. Per ovviare al problema è necessario
sommare agli angoli calcolati durante i cicli precedenti i dati dell’ultima
lettura, moltiplicandoli prima per un fattore pari al periodo di tempo che
intercorre tra due rilevazioni successive (periodo minore = maggiore
precisione). Questo periodo è pari al reciproco della frequenza del loop
(100 Hz), ossia 10 ms.
I dati vengono poi convertiti in due particolari matrici2
(per motivi che si
vedranno nella prossima sezione) e filtrati. Per implementare il filtro in
linguaggio software si ricorre all’alpha blending (figura 2.2): una tecnica
che richiede di moltiplicare i valori provenienti dal giroscopio (matrice A)
per un valore α t.c. 0 ≤ α ≤ 1, i dati dell’accelerometro (matrice B) per
un valore: 1 – α e poi sommarli. In questo modo si attribuisce un peso
diverso ai due sensori: un valore α prossimo ad 1 porta a considerare in
misura maggiore i valori istantanei simulando un filtro passa alto mentre
un valore prossimo allo 0 tiene conto del lungo periodo riproducendo il
comportamento di un filtro passa basso. Il valore di α scelto per questo
progetto è: 0.9998, attribuendo così un peso del 99,98 % ai dati
1
Vedi sezione 2.1.2
2
Vedi sezione 2.1.4
23
istantanei del giroscopio e correggendo la deriva sul lungo periodo con i
dati dell’accelerometro.
2.1.4 Matrici di Rotazione
Un problema affrontato nel capire l’orientazione di un quadricottero è
stato quello di dover computare gli angoli di rollio, beccheggio e
imbardata durante il ciclo3
k + 1 conoscendo i tre angoli al ciclo k e le
variazioni misurate dai due sensori. Gli angoli misurabili secondo il
sistema di assi “drone” o angoli di Eulero infatti non possono essere
banalmente sommati tra loro per stimare la nuova orientazione, ma
bisogna introdurre considerazioni legate alla variazione del sistema di
riferimeno, per fare ciò bisogna far ricorso alle matrici di rotazione,
operatori in grado di:
• trasformare una terna di coordinate “drone” in coordinate
inerziali;
• ruotare un vettore in una stessa terna di coordinate.
Per il progetto di questa tesi è stata sfruttata la seconda funzionalità:
creata la matrice MA rappresentante una rotazione lungo i tre assi
rispettivamente di imbardata, beccheggio e rollio (figura 2.3) e la matrice
3
Set di istruzioni Arduino eseguito completamente e ripetuto solo alla ricezione di un nuovo input da
parte dell’MPU
Figura 2.2: alpha blending implementato in ambiente di sviluppo Arduino
24
MB rappresentante la precedente orientazione di un quadricottero, è
sufficiente moltiplicarle per ottenere la matrice di rotazione MA+B
dell’orientazione al ciclo k + 1.
La matrice di figura 2.3 richiede alcuni chiarimenti:
• con le lettere “c” e “s” si sono voluti indicare rispettivamente il
coseno e il seno dell’angolo;
• gli angoli ϕ, ϑ e ψ sono rispettivamente imbardata, beccheggio e
rollio;
• la matrice R(φ) è data dalla composizione delle tre matrici di
rotazione secondo i singoli assi e rappresenta una rotazione
intorno all’asse z (yaw), asse y (pitch) e asse x (roll) in questo
ordine.
Per ritrovare gli angoli, data una matrice di rotazione, è stata scritta una
routine rot2ypr mostrata di seguito:
Figura 2.3: Matrice di rotazione ypr
25
Il metodo ha come input le variabili su cui scrivere il valore degli angoli e
una matrice di rotazione. MAT[6]4
, come si vede dalla figura 2.3,
corrisponde al seno negativo del beccheggio, per computare l’angolo è
sufficiente dunque trovare l’arcoseno di quel valore. I rapporti fra MAT[3]
e MAT[0] e fra MAT[7] e MAT[8] indicano rispettivamente le tangenti
dell’angolo di imbardata e dell’angolo di rollio, sfruttiamo allora la già
citata5
funzione atan2 per ottenere i due angoli. Le variabili y, p e r
vengono infine moltiplicate per un fattore 180
𝜋⁄ per la conversione da
radianti a gradi.
2.1.4.1 Blocco cardanico
Le matrici di rotazione presentano il problema del cosiddetto “Gimbal
Lock” o “Blocco Cardanico”, cioè la perdità di un grado di libertà quando
avviene una rotazione dell’oggetto tale da far coincidere due assi spaziali.
Si supponga che il quadricottero passi dall’avere una rotazione di 0°
rispetto all’asse delle y ad una rotazione di 90° rispetto allo stesso asse,
in questa situazione l’asse delle x e quello delle z vengono a coincidere,
impedendo la distinzione fra i due e causando il “blocco” appunto di tutto
il sistema.
La scelta di sfruttare comunque le matrici di rotazione è data dal fatto
che il quadricottero di questo progetto non si troverà mai in una
situazione come quella del precedente paragrafo, tipica dei velivoli per
acrobazie.
4
La matrice di rotazione è salvata sotto forma di array, i cui indici vanno da 0 a 8. MAT[6] indica quindi
il valore in riga 3 e colonna 1.
5
Vedi sezione 2.1.2
26
2.2 PID
Il controllo Proporzionale-Integrativo-Derivativo, comunemente
abbreviato come PID, è un sistema di controllo in retroazione negativa.
Grazie a un input che determina il valore attuale, è in grado di reagire a
un eventuale errore positivo o negativo tendendo verso un valore
definito. Il controllore acquisisce in ingresso un valore (nel caso in esame
un angolo) e lo confronta con un valore di riferimento. La differenza, o
errore, fra i due valori viene utilizzata per determinare la variabile di
uscita dal controllore (figura 2.4).
Un controllore PID regola l’uscita in base a:
• Il valore dell’errore (azione proporzionale);
• La somma dei valori passati di errore (azione integrativa);
• La velocità di variazione dell’errore (azione derivativa).
Questi tre valori vengono moltiplicati per 3 costanti (KP, KI e KD) che
determinano il peso di ogni azione necessaria alla stabilizzazione del volo.
Figura 2.4: schema a blocchi di un controllore PID
27
2.2.1 PID con Arduino
Per questo progetto si è fatto utilizzo della libreria PID_v1 di Brett
Beauregard[11]
. Questa libreria offre, oltre alle funzioni base che verranno
descritte in seguito, alcuni accorgimenti software quali:
• Opportunità di cambiare le costanti PID durante il volo;
• Derivazione e integrazione dipendenti dal periodo di
campionamento;
• Filtro per bruschi cambiamenti dell’azione derivativa6
;
• Eliminazione del windup7
.
Il funzionamento principale della libreria si basa però su un semplice
algoritmo (figura 2.5) che prende in input:
• Un angolo;
• Il setpoint deciso dal costruttore;
• Le costanti KP, KI e KD.
Con i primi due viene calcolato l’errore e salvato in una variabile error,
questa viene sommata alla variabile errSum che rappresenta la
sommatoria di tutti gli errori passati. La variabile lastErr indica l’errore
del ciclo precedente e sottratta dalla variabile error permette di capire
quanto velocemente sta crescendo o diminuendo l’errore (dErr).
L’output viene computato sommando error, errSum e dErr moltiplicati
per le rispettive costanti (KP, KI, KD).
6
In caso di cambio del setpoint, l’errore può crescere di molto, il termine derivativo aumenterebbe a
dismisura, rischiando oscillazioni pericolose per il sistema
7
Problema che deriva dall’operazione di integrale, se questa non viene bloccata ad un valore massimo,
c’è il rischio che il termine integrale renda ininfluenti gli altri due
28
Per il progetto del quadricottero sono necessari tre diversi setpoint e di
conseguenza tre diversi controllori PID, due dei quali (i controllori
dedicati a rollio e beccheggio) avranno le stesse costanti in quanto il
comportamento di un drone è molto simile lungo entrambi gli assi sopra
citati. I setpoint di un quadricottero devono essere variabili: a seconda
del segnale ricevuto dal telecomando essi possono diventare più o meno
positivi o negativi; se nessun input, oltre a quello del throttle, è ricevuto
dal trasmettitore RC tutti i setpoint saranno a zero (quadricottero
parallelo a terra), se al contrario un qualunque input proveniente dal
radiocomando modificasse l’orientazione del drone i setpoint si
adatteranno di conseguenza (e.g. un segnale che facesse ruotare il drone
lungo l’asse di rollio di 10° sposterebbe il setpoint del controllore del
rollio a 10°)
Figura 2.5: algoritmo controllore PID
29
2.3 Trasmettitore e ricevente RC
Il trasmettitore o radiocomando è un dispositivo in grado di comandare
a distanza un apparecchio usando le onde radio come mezzo di
trasmissione. Nel nostro progetto, come già accennato8
, il radiocomando
invia un segnale modulato PPM all’antenna della ricevente che lo
converte in 4 differenti segnali PWM. Le 4 uscite della ricevente sono
collegate a 4 input digitali di Arduino, che può elaborare il segnale
tramite Interrupt.
2.3.1 Interrupt
Un interrupt o interruzione è un segnale asincrono che interrompe
qualunque operazione in corso e indica il “bisogno di attenzione” da
parte di una periferica, finalizzata a una particolare richiesta di servizio.
Nel caso della trasmissione RC abbiamo un interrupt ogni qual volta la
ricevente invii un segnale ad Arduino tramite uno dei suoi 4 canali.
Arduino deve essere opportunamente programmato per reagire a questi
segnali ed elaborarli tramite una funzione chiamata: Interrupt Service
Routine (ISR).
Osservando il datasheet del microcontrollore ATmega328P si nota che i
pin predisposti a gestire interrupt sono i pin digitali 2 e 3. Due soli pin non
permetterebbero la lettura di quattro canali, ma un’opportuna modifica
ai registri dell’ATmega tramite la libreria PinChangeInt [12]
permette di
rendere tutti i pin sensibili al riconoscimento di un’interruzione, inoltre
sarà possibile la lettura dell’interrupt per qualunque segnale di tipo
8
Vedi sezione 1.5.1
30
CHANGE: si andrà a registrare un interrupt al passaggio del segnale da
basso a alto e uno per il cambiamento inverso.
All’arrivo di un interrupt su uno dei pin connessi alla ricevente, Arduino
interrompe il processo in corso ed esegue una ISR, che deve essere poco
complessa a livello computazionale e deve richiedere pochi microsecondi
di calcolo, in modo riprendere il ciclo il più velocemente possibile. L’ISR
scritta per calcolare il throttle è mostrata di seguito, le altre tre sono
equivalenti:
Il metodo digitalRead() indica lo stato del pin (HIGH o LOW), la condizione
è verificata solo se nel frame PWM il segnale è appena cambiato da LOW
a HIGH ed è dunque necessario iniziare a misurare la durata del segnale,
ciò avviene sfruttando la variabile throttleIntStart che registra il valore
del timer in quell’istante. Si esce così dall’ISR e il loop può riprendere.
Al successivo cambiamento di stato digitalRead() restituirà un valore
LOW e la condizione sarà non verificata, nella variabile throttleShared
viene salvata la differenza fra l’istante attuale e throttleIntStart, questa
differenza corrisponde alla durata del segnale. La variabile
31
updateFlagShared si aggiorna per indicare che il throttle è già stato
valutato e tornerà a 0 all’inizio di ogni ciclo.
Dopo l’esecuzione dell’ISR è necessario salvare una copia locale dei valori
rilevati in modo che i valori non vengano modificati accidentalmente
dall’arrivo di un altro interrupt. La copia locale dei valori viene
opportunamente calibrata ed elaborata, per poi essere trasmessa ai
moduli E.S.C. che controlleranno la velocità dei motori. È quindi
necessario convertire un valore numerico in un segnale PWM,
operazione che viene ancora una volta eseguita sfruttando gli interrupt
tramite la libreria RCArduinoFastLib [13]
: versione più rapida della già
citata9
libreria Servo.
2.3.2 Calibrazione radiocomando
Idealmente il radiocomando invia alla ricevente impulsi separati da un
tempo compreso fra 1000 µs e 2000 µs, la ricevente converte alla
perfezione il segnale PPM in PWM e ad ogni uguale spostamento delle
levette del telecomando relative ai vari assi corrisponde una identica
risposta del quadricottero. Ovviamente la situazione sopra descritta è
irrealistica e per ridurre l’errore introdotto da ogni modulo è stata scritta
un’apposita routine per la calibrazione dei valori ricevuti dal
radiocomando.
La routine sfrutta le stesse ISR del programma principale per calcolare la
durata degli impulsi ricevuti e memorizza i cosiddetti “endpoints” (valori
massimo, minimo e centrale) delle levette del radiocomando. Non
9
Vedi sezione 1.3.1
32
essendo la routine ripetibile, per motivi pratici, ad ogni nuovo avvio del
drone, essa dovrà memorizzare in maniera permanente gli endpoints; si
utilizzerà a questo scopo la memoria EEPROM di Arduino.
Il programma, tramite comunicazione seriale, accompagna l’utente
attraverso la procedura per la corretta configurazione del radiocomando.
Si inizia aspettando 10 secondi tramite il metodo wait_for_receiver10
illustrato di seguito affinché il trasmettitore venga acceso dall’utente:
Le variabili Shared indicano i valori letti dalle ISR, la variabile zero si
aggiorna ogni qual volta un valore sia nel range indicato (2000 < x < 4000)
fino a raggiungere il valore 15 quando tutti gli input sono corretti. A
questo punto inizia la configurazione.
Viene chiesto all’utente di spostare le levette e i trim (dispositivi
compensatori) in posizione centrale; dopo 10 secondi l’ultimo valore
inviato viene letto e salvato in variabili center, ottenendo così il primo
10
Tutti i metodi illustrati richiederanno valori fra 2000 e 4000 µs, questo perché il prescaler del timer
è impostato a ½.
33
valore d’interesse. Successivamente si chiede di muovere le levette fino
ai loro estremi i quali vengono salvati in variabili high e low dalla funzione
register_min_max, di cui viene mostrato solo il funzionamento relativo
agli endpoint del throttle in quanto gli altri tre metodi sono equivalenti:
Finché la variabile zero non raggiunge il valore 15, ossia quando tutte le
levette vengono riportate in posizione centrale, i valori massimo e
minimo vengono continuamente aggiornati: ogni volta che si registra un
impulso più lungo (breve) la variabile high (low) viene aggiornata con il
nuovo valore.
La configurazione è terminata, ma le variabili sono ancora salvate solo
all’interno della memoria Flash, che si riscriverà al caricamento del
programma principale. Si importa dunque la libreria EEPROM [14]
, e si
scrivono, un byte alla volta, i valori appena registrati. I valori ottenuti, dal
peso di 2 byte ciascuno, andranno divisi in scrittura e ricostruiti
opportunamente in lettura. Avendo 4 controlli e 3 endpoint da 2 byte per
ognuno saranno necessarie 4*3*2 = 24 istruzioni EEPROM per poter
salvare tutti i dati senza perdite.
34
La libreria EEPROM mette a disposizione il metodo write( address, value)
per la scrittura come mostrato nella porzione di codice:
dove viene scritto su due celle il valore centerYaw. La scrittura o lettura
di ogni byte richiede 3.3 ms, per cui la EEPROM non potrà essere letta ad
ogni ciclo del main program ma verrà salvata su un array. Il perché la
scrittura di un solo valore sia divisa in due istruzioni sarà argomento del
prossimo capitolo.
35
Capitolo 3
Approfondimenti Software
3.1 Matrice di rotazione
Come discusso nel capitolo 2, dati tre angoli quali rollio, beccheggio e
imbardata è possibile costruire una matrice di rotazione R, necessaria per
poter interpretare correttamente i dati raccolti da giroscopio e
accelerometro. A livello software la matrice viene costruita sfruttando la
seguente procedura:
la quale prende in input tre angoli e un array bidimensionale, che verrà
aggiornato all’interno del metodo e rappresenterà la matrice R.
All’interno delle variabili c e s vengono salvati rispettivamente i coseni e
36
i seni dei tre angoli espressi in radianti11
. I seni e coseni vengono poi
opportunamente moltiplicati e salvati nelle celle dell’array.
È così possibile ridurre il numero delle funzioni trigonometriche
calcolate, necessarie alla costruzione della matrice R, da 29 a 6: fattore
che influenza non poco la velocità del loop in quanto seni e coseni sono
fra le funzioni più lente da computare e richiedono un grande lavoro del
processore. Per questo particolare progetto però si può velocizzare
ancora il calcolo, sfruttando le caratteristiche del giroscopio e gli sviluppi
di Taylor-Maclaurin.
3.1.1 Fast ypr2rot
Il giroscopio è stato impostato per avere un Full Scale Range di 500 dps
(degrees per second), moltiplicando questo valore per il periodo (10 ms)
otteniamo che la massima variazione rilevabile a ogni ciclo dal giroscopio
è di 5 gradi (0.08727 rad).
Gli sviluppi in serie di Taylor-Maclaurin del seno e del coseno sono:
sin(𝑥) = ∑
(−1) 𝑛
(2𝑛 + 1)!
∞
𝑛=0
𝑥2𝑛+1
∀𝑥 ∈ ℝ
cos(𝑥) = ∑
(−1) 𝑛
(2𝑛)!
∞
𝑛=0
𝑥2𝑛
∀𝑥 ∈ ℝ
E per piccoli angoli possono essere approssimati a:
11
La conversione avviene attraverso la moltiplicazione per il fattore 𝜋
180⁄ .
37
sin(𝑥) = 𝑥
cos(𝑥) = 1 −
𝑥2
2
Vediamo quanto vale l’errore rilevato dal quadricottero nel caso
peggiore:
5 deg = 0.087266 rad = x;
sin(x) = 0.087156;
cos(x) = 0.996194;
1 – x2 / 2 = 0.996191;
Nel caso del seno l’errore è minore di 10-3
(< 10-5
per il coseno) e dunque
trascurabile. La routine riportata di seguito è equivalente a ypr2rot12
ma
sfrutta gli sviluppi in serie di Taylor-Maclaurin per velocizzare i calcoli:
12
Pag. 33
38
3.2 Timer
Un timer o contatore è un dispositivo elettronico che viene utilizzato per
misurare eventi temporali, similmente a quanto fa un orologio. Il timer
o, per essere precisi, i timer di Arduino possono essere programmati
attraverso opportuni registri dell’ATmega. È possibile configurare ad
esempio il prescaler e la modalità operativa.
Il microcontrollore montato su Arduino è dotato di 3 timer, chiamati:
timer0, timer1 e timer2. Il primo e l’ultimo hanno una risoluzione di 8 bit,
il secondo di 16 bit e può essere utilizzato per un conteggio più lungo o
per ottenere maggiore precisione. I timer dipendono dal clock di Arduino,
nel caso di Arduino Uno il clock è 16 MHz.
Ad ogni timer sono assegnate differenti funzioni:
• Timer0 è usato per le funzioni di timing richiamabili dallo sketch,
quali delay(), millis() e micros(), oltre a gestire l’output PWM dei
pin 5 e 6. Modificare i registri del timer0 potrebbe modificare il
comportamento del programma. Timer0 nel progetto di questa
tesi è utilizzato per controllare il tempo di ciclo e fissarlo a 10 ms;
• Timer1 ha il vantaggio di essere a 16 bit, e viene utilizzato ad
esempio dalla libreria Servo e per la gestione dei PWM sui pin 9 e
10. Per il corretto funzionamento del drone timer1 viene utilizzato
anche per la gestione di tutti gli interrupt: sia quelli del
radiocomando sia quelli della libreria RCArduinoFastLib, che ha un
funzionamento equivalente alla libreria Servo;
39
• Timer2 viene utilizzato per la funzione tone()13
e per i PWM sui pin
3 e 11.
Qualunque libreria faccia uso dei timer va utilizzata con cautela per
evitare conflitti: non è ad esempio possibile generare PWM sui pin 9 e 10
se si sfrutta la libreria Servo, allo stesso modo è impossibile fare uso della
funzione tone() e contemporaneamente generare segnali PWM sui pin 3
e 11.
Dunque, i problemi di timing in cui ci si può imbattere durante la scrittura
di un programma Arduino in grado di controllare il volo di un drone sono
molteplici, purtroppo alcuni di questi non sono addirittura risolvibili
totalmente, vedremo però che tramite un buon design è possibile ridurli
fino a garantire le specifiche richieste.
3.2.1 Tempo di ciclo
Il primo problema a cui si va incontro è quello del controllo del tempo di
ciclo, che deve essere quanto più preciso possibile per garantire una
corretta interpretazione dei dati provenienti dal giroscopio.
Per prima cosa è doveroso scegliere un loop time che sia in grado di
contenere tutte le operazioni del ciclo più un lasso di tempo (differenza
fra periodo di ciclo e tempo impiegato dal processore per eseguire le
istruzioni del ciclo stesso) dell’ordine delle centinaia di microsecondi.
13
Genera un’onda quadra alla frequenza decisa dall’utente, può essere usata per riprodurre suoni su
dispositivi come i buzzer piezoelettrici
40
In secondo luogo, è doveroso portare all’attenzione del lettore che
timer0, affinché sia possibile avvalersi della funzione micros() per il
controllo del tempo di ciclo, non sarà utilizzabile per altre operazioni (e.g.
non sarà possibile generare output PWM sui pin 5 e 6).
Come ultima cosa si ricorda che un interrupt, in quanto tale, potrebbe
interrompere il ciclo in qualunque istante, e per quanto sia veloce un’ISR,
per il controllo di un quadricottero quest’ultima viene richiamata molte
volte sia dalla libreria per il controllo degli E.S.C sia da ogni input del
radiocomando.
Per il progetto di questa tesi è stato scelto un loop time di 10 ms: il ciclo
completo richiede circa 8 ms e 2 ms sono stati assegnati ad eventuali
interruzioni. Inoltre, una frequenza di 100 Hz assicura una lettura dei dati
del giroscopio e di conseguenza un controllo PID sufficientemente
accurati.
3.2.2 ISR
Un’ISR è una routine la cui esecuzione è innescata dal verificarsi di un
interrupt. Il tempo impiegato dal processore per tornare al ciclo
principale dopo un’interruzione è dato da:
• Tempo necessario ad accedere all’ISR;
• Tempo di esecuzione dell’ISR.
L’analisi [15]
svolta dall’autore della libreria PinChangeInt mostra che la
durata totale (accesso + esecuzione) di una ISR semplice, che incrementa
il valore di una variabile, è circa 13 µs.
41
Poiché un singolo input PPM del radiocomando genera 8 interrupt ogni
20 ms, è stato necessario cercare di ridurre le istruzioni all’interno
dell’ISR al minimo indispensabile, attraverso alcuni accorgimenti quali:
• Utilizzo della variabile statica pinState: la lettura dello stato di un
pin tramite la funzione predefinita digitalRead()14
di Arduino
richiede circa 1.4 µs, la lettura della variabile pinState definita
all’interno della libreria PinChangeInt avviene in 0.4 µs;
• Lettura dei registri di timer1: anziché andare a richiamare la
funzione micros(), è stata implementata la lettura diretta del
registro TCNT del timer1. Si risparmia in questa maniera un
ulteriore microsecondo e inoltre, essendo timer1 a 16 bit, si avrà
un guadagno in risoluzione;
• Variabile a 2 byte: la funzione micros() restituisce una variabile di
tipo long a 32 bit, la variabile TCNT1 è invece a 16 bit e ciò
permette di dimezzare la durata delle operazioni di lettura,
scrittura e salvataggio.
Tutti questi cambiamenti trasformano la ISR del capitolo 2.3.1 in:
14
Tutte le funzioni predefinite sono disponibili alla pagina: https://www.arduino.cc/reference/en/
42
3.2.3 PWM
Anche la libreria Servo sfrutta gli interrupt per funzionare, in questo caso
si parla però di Output Compare Interrupt. Un’interruzione di questo tipo
viene generata dal confronto fra il contatore TCNT1 e un numero salvato
in un registro chiamato Output Compare Register (OCR1A): quando il
valore di TCNT1 raggiunge OCR1A viene generato un interrupt e
richiamata la rispettiva ISR.
Ciò che avviene durante la generazione dei frame PWM è riassumibile
con i seguenti passaggi:
• Creazione di un array monodimensionale di lunghezza N + 1, dove
N è il numero di dispositivi (Servo, E.S.C. ecc.);
• Inserimento, in ogni posizione dell’array, di un numero
corrispondente alla durata in microsecondi dell’impulso del
rispettivo frame PWM;
• Si imposta poi a livello HIGH il pin corrispondente al primo
elemento dell’array e si setta il registro OCR1A al valore
TCNT1 (attuale) + durata impulso;
• Al raggiungimento di OCR1A da parte di TCNT1 scatta l’interrupt e
viene richiamata un’ISR che porta a livello LOW il pin attuale e a
livello HIGH il successivo;
• Si prosegue fino all’ultimo elemento dell’array, per cui viene
generato un segnale LOW fino alla durata totale del frame PWM
(10 ms per questo progetto).
43
Anche la libreria Servo dovrebbe svolgere tutte queste operazioni alla
massima velocità possibile per garantire accuratezza dell’output. È stato
notato inoltre che sfruttando la libreria Servo classica si possono
verificare conflitti con l’ISR del radiocomando, in quanto questa ha
bisogno di leggere i registri del timer1, mentre la prima resetta il registro
TCNT1 ogni volta che viene generato un nuovo frame.
È stato deciso dunque di adottare una diversa libreria per la gestione
degli E.S.C. ossia la libreria RCArduinoFastLib15
che opera con gli stessi
principi della libreria Servo ma ottimizzati per ottenere maggiore
accuratezza e routine più veloci. Essa è inoltre compatibile con le ISR per
la lettura dei valori ricevuti dal trasmettitore in quanto non resetta il
valore TCNT1.
3.3 EEPROM
Come anticipato nelle sezioni 1.1.1 e 2.3.2 la memoria EEPROM di cui è
dotata la scheda Arduino ha capacità totale di 1 KB, con singole celle di
memoria da 1 byte (8 bit). In una memoria da 8 bit è possibile scrivere
valori nel range 0-25516
, di conseguenza risulterebbe impossibile salvare
gli endpoint del radiocomando, che appartengono al range 2000-4000. È
stato necessario dunque dividere un valore da 2 byte in due termini
distinti da un byte ciascuno da ricostruire opportunamente tramite Bit
Manipulation.
15
Vedi sezione 2.3.1 per il riferimento bibliografico
16
28
= 256 valori
44
3.3.1 Bit Manipulation
Con Bit Manipulation si intente generalmente una tecnica che tramite
“operatori” è in grado di modificare manualmente i singoli bit di una
variabile.
L’elenco completo degli operatori utilizzabili in ambiente Arduino è
disponibile sul sito della scheda17
, di seguito sono forniti quelli utilizzati
nel corso di questa tesi:
• &: operatore AND, confronta indipendentemente ogni bit di due
diverse parole, restituendo 1 se entrambi i bit sono 1, 0 in tutti gli
altri casi, come illustrato nella seguente tabella
1st
word 0 0 1 1
2nd
word 0 1 0 1
result 0 0 0 1
Tabella 4: operatore AND
• >>: operatore Right Shift, causa lo spostamento verso destra dei
bit più a sinistra di una parola di un numero di posizioni che viene
indicato dall’utente. La sintassi per l’utilizzo dell’operatore Right
Shift è la seguente:
variabile >> numero di bits
• <<: operatore Left Shift, opera come Right Shift ma sposta verso
sinistra i bit più a destra di una parola di un numero di posizioni
indicato dall’utente, con la seguente sintassi:
variabile << numero di bits
17
https://www.arduino.cc/reference/en/
45
Verso la fine della sezione 2.3.2 è riportata una parte di codice atta alla
scrittura degli endpoint sulla memoria EEPROM; il codice riportato anche
qui, diventa ora di facile interpretazione:
Il metodo write della libreria EEPROM18
prende in ingresso due valori:
• Address: variabile di tipo int (2 byte) che identifica un indirizzo di
memoria della EEPROM e può assumere valori da 0 a 1023;
• Value: variabile di tipo byte da salvare in memoria.
La scrittura “0xff” indica il byte in base esadecimale ff (tutti i bit a 1), di
conseguenza l’operazione: centerYaw & 0xff restituirà gli 8 bit più a
destra del valore centerYaw. L’operazione centerYaw >> 8 sposta gli 8 bit
più a sinistra della variabile centerYaw di 8 posizioni, eliminando i bit più
a destra. Si ottengono così due byte distinti che mantengono tutte le
informazioni relative alla variabile di partenza. Per la ricostruzione sarà
sufficiente sommare al byte di una cella quello della cella successiva
spostato a sinistra di 8 posizioni, istruzione che si esegue con la riga:
dove start indica l’indirizzo di salvataggio della prima parte di un
endpoint. Ad esempio, se il valore di un endpoint fosse: 3416
(00001101010110002 in codice binario) esso verrebbe trasformato dalla
prima istruzione in: 3416 & 0xff = 010110002 e dalla seconda in:
3416 >> 8 = 000011012. Per la ricostruzione avremo:
000011012 << 8 = 00001101000000002 + 010110002 =
00001101010110002, che è appunto il valore 3416 di partenza.
18
Riferimento bibliografico [14]
46
Conclusioni
Come si è visto, le limitazioni di questo genere di progetto sono tante,
alcune di queste sono state affrontate dal candidato, altre richiederanno
studi futuri. Il quadricottero di fine progetto è pronto per spiccare il volo,
ma richiederà sicuramente ulteriori miglioramenti, non si è ad esempio
affrontato il problema del blocco Cardanico o la stabilità durante le
operazioni di manovra in volo, che richiederanno ulteriori test e
modifiche software. Il lavoro svolto pone quindi le fondamenta per uno
studio futuro, che potrebbe sfruttare l’utilizzo di nuovi sensori (GPS,
sensore di prossimità, fotocamera, ecc.) così come quello di nuovi
algoritmi, in una realtà che al giorno d’oggi è fonte di ispirazione per
studiosi e appassionati.
47
Fonti Bibliografiche e Sitografia
[1] Arduino (hardware) [Online].
Disponibile: https://it.wikipedia.org/wiki/Arduino_(hardware).
[2] ATMEL, ATmega328/P Datasheet, 11/2016.
Disponibile:
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-
42735-8-bit-AVR-Microcontroller-ATmega328-
328P_Datasheet.pdf
[3] Introduction to the Arduino Board [Online].
Disponibile: https://www.arduino.cc/en/Guide/Board?
from=Tutorial.ArduinoBoard.
[4] Scegliere motori ed eliche per il vostro quadricottero.
Disponibile: https://www.cosecinesi.it/tutorials-e-
guide/scegliere-motori-eliche-quadricottero/
[5] A2212/13T technical data.
Disponibile:
https://www.batteryheatedclothing.com/pages/a2212-13t-
technical-data.html
[6] Michael Margolis, Servo library.
Disponibile: https://www.arduino.cc/en/Reference/Servo
[7] MPU-9250 Datasheet.
Disponibile:
https://www.invensense.com/download-pdf/mpu-9250-
datasheet/
[8] Nicholas Zambetti, Wire Library.
Disponibile: https://www.arduino.cc/en/Reference/Wire
48
[9] SparkFun Electronics, Inc. SparkFun_MPU-9250
DMP_Arduino_Library.
Disponibile: https://github.com/sparkfun/SparkFun_MPU-9250-
DMP_Arduino_Library
[10] Fly-Sky FS-T4B.
Disponibile:
http://www.flyskycn.com/products_detail/productId=39.html
[11] Brett Beauregard, Arduino-PID-Library.
Disponibile: https://github.com/br3ttb/Arduino-PID-Library
[12] Mike Schwager, PinChangeInt.
Disponibile: https://github.com/GreyGnome/PinChangeInt
[13] Scott Gibson, RCArduinoFastLib.
Disponibile: https://github.com/scottjgibson/RCArduinoFastLib
[14] Christopher Andrews, EEPROM Library V2.0 for Arduino.
Disponibile:
https://github.com/arduino/Arduino/tree/master/hardware
/arduino/avr/libraries/EEPROM
[15] Mike Schwager, Pin Change Interrupt Timing.
Disponibile:
https://github.com/GreyGnome/EnableInterrupt/blob/master/Int
errupt%20Timing.pdf

More Related Content

Similar to Tesi

Architettura dei calcolatori
Architettura dei calcolatoriArchitettura dei calcolatori
Architettura dei calcolatorikaliaragorn
 
Microcontrollori
MicrocontrolloriMicrocontrollori
Microcontrollorisamu97
 
Stm32 vl discovery recensione - 2010-11-11
Stm32 vl discovery   recensione  - 2010-11-11Stm32 vl discovery   recensione  - 2010-11-11
Stm32 vl discovery recensione - 2010-11-11Ionela
 
Digitalizzazione di un processo industriale
Digitalizzazione di un processo industrialeDigitalizzazione di un processo industriale
Digitalizzazione di un processo industrialeGiulioDeBiasio2
 
Ptek RCHF3
Ptek RCHF3Ptek RCHF3
Ptek RCHF3Ptek srl
 
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...Andrea Gulberti
 
Progettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computerProgettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computerAlessandro Mascherin
 
Guida al computer - Lezione 9 - Il processore
Guida al computer - Lezione 9 - Il processoreGuida al computer - Lezione 9 - Il processore
Guida al computer - Lezione 9 - Il processorecaioturtle
 
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...LeonardoIurada
 
Assoautomazione guida encoder
Assoautomazione guida encoderAssoautomazione guida encoder
Assoautomazione guida encoderLika Electronic
 

Similar to Tesi (20)

Architettura dei calcolatori
Architettura dei calcolatoriArchitettura dei calcolatori
Architettura dei calcolatori
 
Microcontrollori
MicrocontrolloriMicrocontrollori
Microcontrollori
 
Assemblare un pc
Assemblare un pcAssemblare un pc
Assemblare un pc
 
Stm32 vl discovery recensione - 2010-11-11
Stm32 vl discovery   recensione  - 2010-11-11Stm32 vl discovery   recensione  - 2010-11-11
Stm32 vl discovery recensione - 2010-11-11
 
Personal computer
Personal computerPersonal computer
Personal computer
 
Lezioni 2009
Lezioni 2009Lezioni 2009
Lezioni 2009
 
Digitalizzazione di un processo industriale
Digitalizzazione di un processo industrialeDigitalizzazione di un processo industriale
Digitalizzazione di un processo industriale
 
Arduino ICT2016 [IT]
Arduino ICT2016 [IT]Arduino ICT2016 [IT]
Arduino ICT2016 [IT]
 
Ptek RCHF3
Ptek RCHF3Ptek RCHF3
Ptek RCHF3
 
Tesi Todone
Tesi TodoneTesi Todone
Tesi Todone
 
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
 
Progettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computerProgettazione e sviluppo di un software applicativo su un single board computer
Progettazione e sviluppo di un software applicativo su un single board computer
 
Modulo 1 - Lezione 2
Modulo 1 - Lezione 2Modulo 1 - Lezione 2
Modulo 1 - Lezione 2
 
Presentazione tesi 2.0
Presentazione tesi 2.0Presentazione tesi 2.0
Presentazione tesi 2.0
 
Guida al computer - Lezione 9 - Il processore
Guida al computer - Lezione 9 - Il processoreGuida al computer - Lezione 9 - Il processore
Guida al computer - Lezione 9 - Il processore
 
PALUZZANO TESI
PALUZZANO TESIPALUZZANO TESI
PALUZZANO TESI
 
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...Summary of “The Case for Writing Network Drivers in High-Level Programming La...
Summary of “The Case for Writing Network Drivers in High-Level Programming La...
 
DHow2 - L4
DHow2 - L4DHow2 - L4
DHow2 - L4
 
Arduino galileo edison_udoo
Arduino galileo edison_udooArduino galileo edison_udoo
Arduino galileo edison_udoo
 
Assoautomazione guida encoder
Assoautomazione guida encoderAssoautomazione guida encoder
Assoautomazione guida encoder
 

Recently uploaded

Giornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI Daniele
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI DanieleGiornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI Daniele
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI DanieleServizi a rete
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' Davide
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' DavideGiornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' Davide
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' DavideServizi a rete
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO Andrea
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO AndreaGiornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO Andrea
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO AndreaServizi a rete
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI Giovanni
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI GiovanniGiornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI Giovanni
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI GiovanniServizi a rete
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA Giorgio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA GiorgioGiornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA Giorgio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA GiorgioServizi a rete
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO Antonio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO AntonioGiornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO Antonio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO AntonioServizi a rete
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO Simone
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO SimoneGiornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO Simone
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO SimoneServizi a rete
 

Recently uploaded (7)

Giornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI Daniele
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI DanieleGiornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI Daniele
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | RENZI Daniele
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' Davide
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' DavideGiornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' Davide
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ROMANO' Davide
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO Andrea
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO AndreaGiornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO Andrea
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | ALBIERO Andrea
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI Giovanni
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI GiovanniGiornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI Giovanni
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | CADEI Giovanni
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA Giorgio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA GiorgioGiornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA Giorgio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | SERRA Giorgio
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO Antonio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO AntonioGiornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO Antonio
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DISCIPIO Antonio
 
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO Simone
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO SimoneGiornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO Simone
Giornata Tecnica da Piave Servizi, 11 aprile 2024 | DI DOMENICO Simone
 

Tesi

  • 1. UNIVERSITÀ DEGLI STUDI DI TRIESTE Dipartimento di Ingegneria e Architettura Corso di Studi in Ingegneria Elettronica Progetto di un sistema di controllo, basato su piattaforma Arduino, atto a stabilizzare il volo di un drone Tesi di Laurea Triennale Laureando: Relatore: Tobia DALL’ACQUA Prof. Stefano MARSI _____________________________________ ANNO ACCADEMICO 2016-2017
  • 2.
  • 3. Indice Introduzione........................................................................................... 1 Hardware ............................................................................................... 3 1.1 Arduino ......................................................................................... 3 1.1.1 Caratteristiche.........................................................................3 1.2 Motori ........................................................................................... 6 1.3 E.S.C. ............................................................................................. 9 1.3.1 Programmare gli E.S.C. ............................................................ 9 1.3.2 Impostazioni E.S.C. ................................................................ 11 1.4 MPU-9250 ................................................................................... 12 1.4.1 Caratteristiche sensori........................................................... 13 1.5 Trasmettitore e ricevente RC....................................................... 15 1.5.1 Modulazione ......................................................................... 16 Software............................................................................................... 18 2.1 Angoli di Eulero ........................................................................... 18 2.1.1 Disturbi.................................................................................. 18 2.1.2 Il Filtro Complementare......................................................... 19 2.1.3 Filtro complementare con Arduino........................................ 21 2.1.4 Matrici di Rotazione .............................................................. 23 2.2 PID............................................................................................... 26 2.2.1 PID con Arduino..................................................................... 27 2.3 Trasmettitore e ricevente RC....................................................... 29
  • 4. 2.3.1 Interrupt................................................................................ 29 2.3.2 Calibrazione radiocomando................................................... 31 Approfondimenti Software................................................................... 35 3.1 Matrice di rotazione .................................................................... 35 3.1.1 Fast ypr2rot........................................................................... 36 3.2 Timer........................................................................................... 38 3.2.1 Tempo di ciclo ....................................................................... 39 3.2.2 ISR ......................................................................................... 40 3.2.3 PWM ..................................................................................... 42 3.3 EEPROM ...................................................................................... 43 3.3.1 Bit Manipulation.................................................................... 44 Conclusioni........................................................................................... 46 Fonti Bibliografiche e Sitografia............................................................ 47
  • 5.
  • 6. 1 Introduzione Nel corso di questa tesi si vanno a descrivere le principali dinamiche che legano il volo di un quadricottero alla sua implementazione software. Si dedica in particolare l’attenzione prima alle componenti del drone e alla loro scelta, per poi soffermarsi sulla programmazione in ambiente Arduino, che è stata oggetto di studio e approfondimento del candidato. Infine, si sposta l’attenzione sui dettagli e le ottimizzazioni che hanno posto le basi per una buona riuscita del progetto. La tesi rappresenta la conclusione di un percorso di tirocinio svolto presso l’Università degli Studi di Trieste volto all’apprendimento e allo studio della piattaforma Arduino tramite piccoli progetti dedicati alla valutazione dei dati restituiti dai più comuni sensori di posizione, alla gestione di servomotori e al controllo PID. Il quadricottero si pone dunque come sintesi di un lavoro svolto su più livelli, che sfrutta le conoscenze acquisite dal laureando in ambito elettronico e informatico e allo stesso tempo richiede continui miglioramenti e ottimizzazioni.
  • 7. 2
  • 8. 3 Capitolo 1 Hardware 1.1 Arduino Arduino è una piattaforma elettronica open source, ideata e sviluppata da alcuni membri dell'Intercalino Design Institute di Ivrea come strumento per la prototipazione rapida e per scopi hobbistici, didattici e professionali [1] . Esso basa il suo funzionamento sul microcontrollore ATmega328P, un dispositivo multifunzione dotato di: CPU, memoria Flash, memoria RAM e memoria EEPROM. Arduino è dotato inoltre di un cristallo al quarzo, Pin I/O, un connettore USB, un jack di alimentazione e un pulsante di reset. Analizziamo ora singolarmente tutte queste componenti. 1.1.1 Caratteristiche L’ATmega328P è un microcontrollore low-power CMOS a 8 bit, basato su architettura di tipo RISC. Esso è in grado di svolgere più operazioni per ogni ciclo di clock, permettendogli di raggiungere throughput dell’ordine di 1 MIPS (Million Instructions Per Second) per MHz. La memoria da 32 KB, dove viene salvato il codice da compilare, è di tipo Flash e viene sovrascritta ogni volta che si carica un nuovo programma sulla scheda Arduino. Le memorie di tipo Flash sono non volatili e sfruttano dei particolari FET chiamati “floating gate MOSFET”, i quali sono in grado di contenere carica elettrica per lunghi periodi di tempo grazie ad effetti capacitivi. Ogni transistor costituisce una cella di
  • 9. 4 memoria che conserva il valore di un bit. Una piccola parte (0,5 KB) della memoria Flash è riservata al bootloader. Oltre alla memoria Flash è presente sul microcontrollore un’altra memoria non volatile, detta EEPROM, della capacità di 1 KB. Anche le memorie EEPROM (Electrically Erasable Programmable Read-Only Memory) sfruttano i floating gate MOSFET, la differenza con le memorie Flash sta nel meccanismo per l’iniezione di carica. L’ultima tipologia di memoria che si trova sull’ATmega328 è una SRAM da 2 KB. Le SRAM sono memorie volatili che consentono di mantenere le informazioni per un tempo teoricamente infinito, sono molto veloci e dissipano poco calore, necessitano però di molti componenti per la costruzione, il che le rende costose e ne limita la capienza. Il compito della CPU è quello di assicurare la corretta esecuzione del programma, essa è in grado di accedere alle varie memorie e di eseguire calcoli. L’architettura di tipo RISC (Reduced Instruction Set Computer) permette di eseguire molte istruzioni per ogni ciclo di clock e inoltre riserva molto spazio per i registri interni: speciali locazioni di memoria della CPU che ne determinano lo “stato” [2] . I pin dell’ATmega328P (Figura 1.1) sono connessi alle varie componenti di Arduino. I pin 9 e 10 sono collegati ad un oscillatore al quarzo da 16MHz, il pin 1 è collegato al pulsante di reset, i pin 7, 8, 20 e 22 sono riservati ad alimentazione e massa mentre il pin 21 rappresenta la tensione di riferimento per la lettura dei pin analogici. I rimanenti pin
  • 10. 5 sono dedicati all’ I/O: Arduino presenta 14 pin digitali (lavorano solo con tensioni HIGH o LOW) programmabili come input o output, 6 di questi pin presentano la particolarità di poter essere utilizzati per generare un output PWM. Affiancati ai digitali si trovano 6 pin analogici, utilizzabili solo come input, in grado di convertire un valore analogico di tensione in ingresso nel suo corrispondente digitale con risoluzione 10-bit[3] . Figura 1.1: ATmega328P pin mapping
  • 11. 6 1.2 Motori Prima di parlare dei motori a livello tecnico è necessario soffermarsi sulla scelta di questi ultimi. La scelta dei motori è fondamentale per ottenere velocità, precisione del volo ed efficienza; una giusta proporzione fra queste specifiche va decisa dal costruttore a seconda del budget e della finalità del quadricottero (gare di velocità, volo acrobatico, filmati professionali, ecc.). Si vuole partire ora dalle 2 componenti che più influiscono sulla scelta dei motori: telaio ed eliche. Per il progetto è stato acquistato un telaio di dimensione 450 mm, dove la dimensione si riferisce all’interasse di due motori opposti diagonalmente. È stato così definito un limite superiore per la dimensione delle eliche e considerato lo spazio occupato dalla scheda centrale questa misura è 10 pollici (254 mm) di diametro. È doveroso ora parlare dei parametri che influenzano la scelta dell’elica: • Diametro: dà una misura della difficoltà nel far girare le eliche dovuta all’attrito dell’aria (direttamente proporzionale al diametro). Eliche più piccole sono più rapide a partire e fermarsi, mentre eliche più grandi richiedono più tempo per cambiare velocità. • Passo: esprime la distanza che percorre un’elica in un giro o in altre parole: quanta aria è in grado di spostare un’elica in un giro, e.g. un’elica di passo 3 sposterà una colonna d’aria lunga 3 pollici. Un passo più alto farà spostare al quadricottero una maggiore quantità d’aria creando maggiore turbolenza, ma generando
  • 12. 7 anche più spinta e restituendo quindi una maggiore velocità massima. Per concludere, eliche più grandi e con passo maggiore sono in grado di garantire velocità maggiori, a discapito del consumo di corrente causato dalla difficoltà dei motori di spostare maggiori quantità d’aria. Per il nostro progetto sono state scelte delle eliche 1045, ossia 10 pollici di diametro (compatibili con il telaio) e 4.5 pollici di passo. Si hanno ora tutti gli elementi che permetteranno di scegliere i motori adeguati, le cui caratteristiche dovranno essere: • Dimensioni ridotte • Peso ridotto • Rendimento ed efficienza alti • Precisione elevata in velocità e accelerazione La scelta più adatta per un quadricottero è quella dei motori di tipo brushless, di cui verranno scelte le caratteristiche in base alle specifiche di progetto. Innanzitutto, va stimata la massa del quadricottero completo: considerata la massa del telaio (300 g), della scheda Arduino compresa di vari moduli e cavi (circa 70 g), della batteria (circa 200 g), dei motori che dovranno aggirarsi attorno ai 70 g l’uno e tralasciando la massa delle eliche si otterrà un quadricottero di circa 850 g. Considerato che una regola generale per avere un quadricottero stabile è quella di avere un rapporto almeno di 2:1 fra spinta dei motori e peso, saranno necessari motori capaci di generare almeno
  • 13. 8 850*2*10 /4 = 4250 N di spinta (il doppio del peso del quadricottero diviso per quattro motori). Un’altra limitazione è data dalla dimensione delle eliche, un motore in grado di generare un elevato numero di giri al minuto infatti non è adatto per eliche grandi, in quanto consumerebbe troppa corrente e rischierebbe di fondere. Nei datasheet troviamo i giri al minuto espressi in KV: il KV è definito come il rapporto fra il numero di rotazioni al minuto e la tensione applicata ad un motore senza carico. Per questo progetto un adeguato KV si aggira attorno a 1000 [4] . I motori scelti sono dunque gli A2212 (in figura 1.2 già con le eliche assemblate). L’A2212 è un motore da 1000 KV, di massa 57.2 g e in grado di sollevare fino a 800 g come indicato nel datasheet [5] . Figura 1.2: motori brushless A2212 con eliche
  • 14. 9 1.3 E.S.C. I moduli E.S.C., acronimo di Electronic Speed Controller, sono dispositivi elettronici che hanno il compito di regolare la velocità di rotazione dei motori elettrici. Essi sono in grado, attraverso l’elaborazione di un microprocessore interno, di convertire un segnale di tipo PWM in ingresso in una corrente trifase (il cui amperaggio massimo è indicato sulla guaina che riveste il modulo) proporzionale al duty cycle, la quale andrà a variare il numero di giri al minuto del motore brushless. La frequenza di lavoro tipica di un E.S.C. è 50 Hz, ma i moderni moduli sono in grado di lavorare a frequenze anche notevolmente più elevate e per questo progetto, per favorire un migliore controllo della fase di volo, si è scelta una frequenza di lavoro di 100 Hz costruendo frame PWM da 10 ms. Gli E.S.C. sono inoltre programmabili, in particolare quelli montati sul quadricottero presentano una sequenza di programmazione che si interfaccia verso l’esterno attraverso una serie di suoni emessi dai motori collegati. 1.3.1 Programmare gli E.S.C. Il controllo della programmazione degli E.S.C. avviene attraverso la lettura di due valori di throttle (HIGH o LOW) che vanno impostati dall’utente, bisogna cioè fornire al microprocessore il full scale range del segnale di comando. Per settare questi valori è necessario: • Ad E.S.C. spenti, inviare ai moduli, tramite Arduino, un valore (espresso in µs) che corrisponde al throttle massimo;
  • 15. 10 • Accendere gli E.S.C. ed aspettare circa due secondi, dopo i quali verrà emesso un doppio suono corto, che conferma l’avvenuta registrazione; • Inviare ora ai moduli il segnale corrispondente al throttle minimo; • Aspettare l’emissione prima di alcuni suoni corti consecutivi (dipendenti dal tipo di batteria collegata), poi di un suono lungo che avverte l’utente che il range di valori è stato correttamente registrato. Per fare ciò è stata scritta una routine Arduino che sfrutta la comunicazione seriale tramite USB e la libreria Servo [6] per inviare i due segnali agli E.S.C. Il codice di seguito mostra il funzionamento di tale routine: la variabile data salva il valore inserito tramite tastiera dall’utente, in base a questo viene deciso se inviare un segnale di throttle alto o basso; la Figura 1.3: codice Arduino per il set-up degli E.S.C.
  • 16. 11 funzione writeMicroseconds(n) invia un segnale della durata di n microsecondi inserito in un frame di 10 millisecondi ai vari E.S.C. 1.3.2 Impostazioni E.S.C. Come è stato anticipato le impostazioni dei moduli sono controllate dall’utente attraverso l’emissione di suoni generati dai motori attraverso gli E.S.C. stessi. Per entrare in modalità programmazione è necessario: impostare il throttle al massimo, accendere il sistema e attendere circa sette secondi, dopo i quali verrà emesso un suono speciale. Successivamente il sistema emetterà 8 diversi suoni in sequenza, ognuno corrispondente ad un diverso parametro che si vuole modificare, come indicato in tabella: Tabella 1: corrispondenza fra suoni e funzioni. '*' indica un suono corto, '_' indica un suono lungo In corrispondenza del suono ricercato bisogna provvedere a settare il throttle al minimo entro tre secondi, si accede così alla modifica di una particolare funzione, i cui valori saranno nuovamente indicati da vari Suono Modalità * Modalità break ** Tipo di batteria *** Modalità di protezione alla bassa tensione **** Modalità di protezione all’abbassamento della tensione della batteria _ Modalità di startup _* Timing _** Impostazione di tutti i parametri ai valori di default __ Uscita dalla modalità di programmazione
  • 17. 12 suoni (vedi tabella 2). Per scegliere l’impostazione di interesse si setterà il throttle al massimo fino all’emissione di un tono speciale che conferma la scelta del valore. Modalità * ** *** Brake Disabled Enabled Tipo di batteria Li-xx Ni-xx Modalità di protezione alla bassa tensione Soft Cut- Off Cut-Off Modalità di protezione all’abbassamento della tensione della batteria Low Medium High Modalità di startup Normal Soft Super- Soft Timing Low Medium High Tabella 2: corrispondenza fra suoni e valori A questo punto, mantenendo il throttle al massimo si viene riportati nel menu principale, potendo quindi modificare le altre modalità; se, al contrario, si porta il throttle al suo valore minimo si esce dalla modalità di programmazione e gli E.S.C. saranno pronti a controllare i motori. 1.4 MPU-9250 L’MPU-9250 appartiene alla famiglia degli IMU (i.e. Inerti al Measurement Unit), dispositivi elettronici in grado di misurare l’accelerazione inerziale e la velocità angolare di una massa; alcuni fra questi dispositivi inoltre sono capaci di calcolare il campo magnetico in cui il corpo è immerso e la sua altitudine. Per misurare queste grandezze un IMU può essere dotato di: • Un accelerometro;
  • 18. 13 • Un giroscopio; • Un magnetometro; • Un altimetro. Il dispositivo utilizzato in questo progetto è l’InvenSense MPU-9250[7] : esso è dotato di un accelerometro, un giroscopio e un magnetometro, tutti a 3 assi. Inoltre, l’MPU-9250 presenta un sensore di temperatura per la compensazione dei dati. Per gli scopi di questa tesi verranno utilizzati solo i dati provenienti da accelerometro e giroscopio in quanto questi sono sufficienti per definire le coordinate spaziali di un drone. L’MPU impiega il protocollo I2C per la comunicazione con l’esterno, e tramite la libreria Wire [8] di Arduino è possibile configurarne molte impostazioni, scrivendo sui suoi registri. Purtroppo, l’utilizzo dei registri non è banale e per lo più poco documentato, per questi motivi verrà utilizzata un’apposita libreria [9] che implementi le funzionalità più importanti del sensore. 1.4.1 Caratteristiche sensori Un accelerometro è un sensore in grado misurare l’accelerazione di un corpo, è un tipo di sensore molto accurato mediamente e sul lungo periodo, purtroppo subisce in maniera pesante l’effetto di vibrazioni e disturbi, i quali si manifestano spesso durante il volo di un quadricottero. Al contrario un giroscopio è poco soggetto ai disturbi in quanto misura una velocità angolare e la integra nel tempo, l’integrazione può portare però alla deriva dei valori nel tempo, fino ad allontanarsi sempre più dal valore corretto. Per ovviare ai problemi dei sensori sarà necessario
  • 19. 14 rielaborarne i dati tramite appositi filtri e rimozioni di offset, che verranno descritti in paragrafi dedicati. Venendo ora al dettaglio dell’MPU-9250: esso fornisce 6 valori grezzi da 2 byte ciascuno, che corrispondono agli assi di accelerometro e giroscopio. Le tensioni fornite dai sensori sono campionate da 6 convertitori AD da 16 bit, permettendo la conversione simultanea delle tensioni per ogni asse. Come già detto questi valori sono grezzi (raw) e vanno calibrati per ottenere le velocità angolari e le accelerazioni richieste. Tramite software è possibile configurare giroscopio e accelerometro su diversi livelli di sensibilità, come illustrato nella tabella sottostante. Grazie a queste informazioni è possibile trasformare i dati raw in velocità angolari e accelerazioni, ad esempio un valore raw di 4096 rappresenta 1g con sensibilità ±8g. A questo punto è possibile ricavare gli angoli di Eulero, ai quali sarà dedicato un capitolo, che forniscono l’orientazione spaziale di un corpo attraverso angoli detti: rollio, beccheggio e imbardata. Gyro Full Scale Range (deg/sec) Gyro Sensibility (LSB/deg/sec) Accel Full Scale Range (g) Accel Sensibility (LSB/g) ±250 131 ±2 16384 ±500 65.5 ±4 8192 ±1000 32.8 ±8 4096 ±2000 16.4 ±16 2048 Tabella 3: Full scale range e sensibilità di accelerometro e giroscopio
  • 20. 15 1.5 Trasmettitore e ricevente RC Il trasmettitore utilizzato in questo progetto è il Fly-Sky FS-T4B (figura 1.4), un trasmettitore a 4 canali che richiede 12V di alimentazione e lavora su frequenze dai 2.40 ai 2.48 GHz [10] . La ricevente è un modello: Fly-Sky FS-R6B (figura 1.5) a 6 canali. Prima di poter correttamente utilizzare i due dispositivi e interfacciarli con Arduino è necessaria un’operazione detta: “binding”, che consiste nella sincronizzazione fra ricevente e trasmettitore per evitare interferenze con altri apparecchi RC. Per fare ciò nella confezione del trasmettitore è sempre presente un apposito cavo (figura 1.5) che viene collegato ai pin della ricevente dedicati al binding; dopo aver connesso la ricevente all’alimentazione si accende il radiocomando tenendo contemporaneamente premuto un apposito pulsante. Ora i due dispositivi sono sincronizzati, e il legame rimane valido anche per utilizzi successivi. Figura 1.4: RC transmitter
  • 21. 16 1.5.1 Modulazione È doveroso ora fare alcune precisazioni sulle differenze fra modulazione PWM e PPM. Il primo tipo viene utilizzato per controllare gli E.S.C. ed è anche il segnale in uscita dalla ricevente, il secondo è più complesso a livello computazionale ma risulta vantaggioso quando dobbiamo trasmettere le informazioni di 4 canali differenti contemporaneamente su un unico canale: esattamente ciò che succede fra trasmettitore e ricevente esaminati posco sopra (trasmettitore ha 4 canali, ricevente una sola antenna). La modulazione PWM, o modulazione a larghezza d’impulso, si basa sul concetto di duty cycle e permette di ottenere una tensione media dipendente dal rapporto tra la durata dell’impulso HIGH e quello LOW. Nel caso in esame i due segnali sono inseriti in un frame da 20 ms e la frequenza di aggiornamento sarà dunque di 50 Hz per canale. Questo tipo di modulazione è facilmente interpretabile dalla scheda Arduino grazie all’utilizzo di interrupt. Figura 1.5: RC receiver and binding cable
  • 22. 17 La modulazione PPM, o modulazione a posizione d’impulso, riesce al contrario ad inserire in un unico frame da 20 ms le informazioni provenienti da più fonti diverse e codifica il segnale attraverso la posizione di un impulso di durata fissa all’interno di un frame; di conseguenza il numero di impulsi definisce il numero di canali, e la distanza temporale fra questi impulsi definisce l’informazione. Il vantaggio della modulazione PPM è il fatto di poter inviare più segnali attraverso un unico cavo, lo svantaggio è che il dispositivo ricevente deve essere in grado di elaborare un segnale molto complesso. Nel caso del quadricottero gli E.S.C. vengono pilotati da un segnale PWM, di conseguenza è più comodo gestire segnali separati in canali separati, la ricevente avrà dunque 4 uscite collegate a 4 pin digitali di Arduino, che a sua volta avrà 4 uscite collegate ai singoli moduli E.S.C. Tuttavia il segnale di uscita dal telecomando è un segnale PPM, il che significa che sulla ricevente è presente un microcontrollore in grado di convertire l’ingresso sull’antenna in 4 diversi segnali PWM.
  • 23. 18 Capitolo 2 Software 2.1 Angoli di Eulero L’MPU-9250, come già anticipato nel capitolo precedente, è un dispositivo in grado di analizzare velocità angolari e accelerazioni di un corpo, per poi salvarle all’interno dei propri registri in sei diverse variabili da due byte: • Le prime tre corrispondono alle componenti della velocità angolare del sistema rispetto agli assi x, y e z di un riferimento ortogonale il cui centro coincide con il centro di massa della struttura; • Il secondo gruppo rappresenta invece le componenti del vettore accelerazione rispetto agli stessi assi. Nel caso in cui il sistema sia fermo, l’unica componente rilevata è l’accelerazione di gravità. 2.1.1 Disturbi Le misurazioni del sensore sono sensibili a vari fattori, i due principali elencati di seguito: • Utilizzando i dati grezzi del giroscopio per determinare la posizione angolare del quadricottero nello spazio si va incontro ad un’operazione di integrazione. Si ricorda infatti che il giroscopio misura velocità angolari e, definita la velocità angolare come 𝜔 = 𝜕𝜃 𝜕𝑡 , l’angolo θ risulta: 𝜃 = ∫ 𝜔𝑑𝑡 𝑡 0 . Grazie a questa operazione la misura è accurata e poco suscettibile ad agenti esterni, ma
  • 24. 19 presenta anche un effetto di deriva a lungo termine dovuto all’errore che si accumula durante l’integrazione. • Se si considerassero solo i dati grezzi dell’accelerometro per stabilire la direzione dell’accelerazione di gravità, si potrebbe attraverso questa stimare almeno parzialmente l’orientamento del sistema nello spazio. Purtroppo il sistema non è inerziale ed è soggetto a molte accelerazioni diverse, per cui l’output risulta giocoforza soggetto a molte forme di perturbazione. Un obiettivo di questo progetto è stato elaborare opportunamente i dati forniti dai sensori per ottenere una rappresentazione che sia il più corretta possibile degli Angoli di Eulero: • Roll: corrispondente alla rotazione attorno all’asse x; • Pitch: corrispondente alla rotazione attorno all’asse y; • Yaw: corrispondente alla rotazione attorno all’asse z. 2.1.2 Il Filtro Complementare Per eliminare i disturbi sopra citati si è scelto di utilizzare un filtro complementare, la cui idea di base consiste in: far passare i dati provenienti dall’accelerometro attraverso un filtro passa basso, per eliminare il rumore ad alta frequenza causato da accelerazioni istantanee e mantenere la stabilità dei dati sul lungo periodo. I dati del giroscopio invece passeranno attraverso un filtro passa alto, per rimuovere l’effetto di deriva dell’integrale. I due gruppi di dati così filtrati verranno sommati per ottenere una stima degli angoli che tenga in considerazione i valori più significativi restituiti dai due sensori.
  • 25. 20 L’input dei filtri sarà un angolo e non il dato grezzo proveniente dai sensori, quindi : • Per i dati provenienti dal giroscopio, come già affrontato, verrà fatta un’operazione di integrazione; • Per i dati dell’accelerometro si farà utilizzo della funzione: 𝑎𝑡𝑎𝑛2(𝑦, 𝑥) = { atan ( 𝑦 𝑥 ) , 𝑠𝑒 𝑥 > 0 atan ( 𝑦 𝑥 ) + 𝜋, 𝑠𝑒 𝑥 < 0 ∧ 𝑦 ≥ 0 atan ( 𝑦 𝑥 ) − 𝜋, 𝑠𝑒 𝑥 < 0 ∧ 𝑦 < 0 + 𝜋 2 , 𝑠𝑒 𝑥 = 0 ∧ 𝑦 > 0 − 𝜋 2 , 𝑠𝑒 𝑥 = 0 ∧ 𝑦 < 0 𝑛𝑜𝑛 𝑑𝑒𝑓𝑖𝑛𝑖𝑡𝑎, 𝑠𝑒 𝑥 = 0 ∧ 𝑦 = 0 Questa funzione è in grado di gestire la divisione per 0 e il segno dell’angolo ed è implementata dalla maggior parte dei linguaggi di programmazione. La funzione prende in input due valori (rispettivamente la componente z del vettore accelerazione e una tra le componenti x e y, in base all’angolo che si vuole determinare) e restituisce l’angolo in radianti tra il semiasse positivo delle x e un punto di coordinate (x, y) restituendo un valore nell’intervallo (-π, π), dove x e y sono riferiti agli input della funzione. Figura 2.1: schema a blocchi relativo al funzionamento di un filtro complementare
  • 26. 21 Per quanto riguarda l’angolo di imbardata, è possibile determinarlo solo attraverso l’elaborazione dei dati provenienti dal giroscopio, in quanto qualsiasi variazione di tale angolo risulta ininfluente rispetto alla variazione del vettore gravitazionale. 2.1.3 Filtro complementare con Arduino Il filtro sviluppato nel corso di questo progetto è un filtro del “primo ordine”: una tipologia di filtro grazie alla quale si è in grado di ottenere una buona stima dei valori reali. Filtri del secondo e terzo ordine garantirebbero maggiore separazione tra la banda passa-alto e quella passa-basso, ma sono stati scartati essendo questi ultimi molto più complessi da realizzare a livello software e non garantendo un guadagno in accuratezza tale da giustificare l’aumento di complessità. In primo luogo è stata fatta una calibrazione sui dati di giroscopio e accelerometro per rimuovere eventuali offset grossolani, di seguito viene riportata la porzione di codice per la calibrazione dell’angolo di rollio proveniente dal giroscopio: La costante CALIBRATION_STEPS vale 400, il che significa che vengono fatte 400 misurazioni dell’angolo su cui poi si fa una media. Il valore finale
  • 27. 22 della variabile gyroX_cal sarà questa media e rappresenterà l’offset del giroscopio da rimuovere in tutte le misurazioni successive. In seguito si sfrutterà la funzione atan21 per determinare gli angoli di rollio e beccheggio leggendo i dati dell’accelerometro. Per i dati del giroscopio la questione è leggermente più complicata in quanto il microprocessore lavora a tempo discreto e non può gestire l’integrazione di funzioni continue. Per ovviare al problema è necessario sommare agli angoli calcolati durante i cicli precedenti i dati dell’ultima lettura, moltiplicandoli prima per un fattore pari al periodo di tempo che intercorre tra due rilevazioni successive (periodo minore = maggiore precisione). Questo periodo è pari al reciproco della frequenza del loop (100 Hz), ossia 10 ms. I dati vengono poi convertiti in due particolari matrici2 (per motivi che si vedranno nella prossima sezione) e filtrati. Per implementare il filtro in linguaggio software si ricorre all’alpha blending (figura 2.2): una tecnica che richiede di moltiplicare i valori provenienti dal giroscopio (matrice A) per un valore α t.c. 0 ≤ α ≤ 1, i dati dell’accelerometro (matrice B) per un valore: 1 – α e poi sommarli. In questo modo si attribuisce un peso diverso ai due sensori: un valore α prossimo ad 1 porta a considerare in misura maggiore i valori istantanei simulando un filtro passa alto mentre un valore prossimo allo 0 tiene conto del lungo periodo riproducendo il comportamento di un filtro passa basso. Il valore di α scelto per questo progetto è: 0.9998, attribuendo così un peso del 99,98 % ai dati 1 Vedi sezione 2.1.2 2 Vedi sezione 2.1.4
  • 28. 23 istantanei del giroscopio e correggendo la deriva sul lungo periodo con i dati dell’accelerometro. 2.1.4 Matrici di Rotazione Un problema affrontato nel capire l’orientazione di un quadricottero è stato quello di dover computare gli angoli di rollio, beccheggio e imbardata durante il ciclo3 k + 1 conoscendo i tre angoli al ciclo k e le variazioni misurate dai due sensori. Gli angoli misurabili secondo il sistema di assi “drone” o angoli di Eulero infatti non possono essere banalmente sommati tra loro per stimare la nuova orientazione, ma bisogna introdurre considerazioni legate alla variazione del sistema di riferimeno, per fare ciò bisogna far ricorso alle matrici di rotazione, operatori in grado di: • trasformare una terna di coordinate “drone” in coordinate inerziali; • ruotare un vettore in una stessa terna di coordinate. Per il progetto di questa tesi è stata sfruttata la seconda funzionalità: creata la matrice MA rappresentante una rotazione lungo i tre assi rispettivamente di imbardata, beccheggio e rollio (figura 2.3) e la matrice 3 Set di istruzioni Arduino eseguito completamente e ripetuto solo alla ricezione di un nuovo input da parte dell’MPU Figura 2.2: alpha blending implementato in ambiente di sviluppo Arduino
  • 29. 24 MB rappresentante la precedente orientazione di un quadricottero, è sufficiente moltiplicarle per ottenere la matrice di rotazione MA+B dell’orientazione al ciclo k + 1. La matrice di figura 2.3 richiede alcuni chiarimenti: • con le lettere “c” e “s” si sono voluti indicare rispettivamente il coseno e il seno dell’angolo; • gli angoli ϕ, ϑ e ψ sono rispettivamente imbardata, beccheggio e rollio; • la matrice R(φ) è data dalla composizione delle tre matrici di rotazione secondo i singoli assi e rappresenta una rotazione intorno all’asse z (yaw), asse y (pitch) e asse x (roll) in questo ordine. Per ritrovare gli angoli, data una matrice di rotazione, è stata scritta una routine rot2ypr mostrata di seguito: Figura 2.3: Matrice di rotazione ypr
  • 30. 25 Il metodo ha come input le variabili su cui scrivere il valore degli angoli e una matrice di rotazione. MAT[6]4 , come si vede dalla figura 2.3, corrisponde al seno negativo del beccheggio, per computare l’angolo è sufficiente dunque trovare l’arcoseno di quel valore. I rapporti fra MAT[3] e MAT[0] e fra MAT[7] e MAT[8] indicano rispettivamente le tangenti dell’angolo di imbardata e dell’angolo di rollio, sfruttiamo allora la già citata5 funzione atan2 per ottenere i due angoli. Le variabili y, p e r vengono infine moltiplicate per un fattore 180 𝜋⁄ per la conversione da radianti a gradi. 2.1.4.1 Blocco cardanico Le matrici di rotazione presentano il problema del cosiddetto “Gimbal Lock” o “Blocco Cardanico”, cioè la perdità di un grado di libertà quando avviene una rotazione dell’oggetto tale da far coincidere due assi spaziali. Si supponga che il quadricottero passi dall’avere una rotazione di 0° rispetto all’asse delle y ad una rotazione di 90° rispetto allo stesso asse, in questa situazione l’asse delle x e quello delle z vengono a coincidere, impedendo la distinzione fra i due e causando il “blocco” appunto di tutto il sistema. La scelta di sfruttare comunque le matrici di rotazione è data dal fatto che il quadricottero di questo progetto non si troverà mai in una situazione come quella del precedente paragrafo, tipica dei velivoli per acrobazie. 4 La matrice di rotazione è salvata sotto forma di array, i cui indici vanno da 0 a 8. MAT[6] indica quindi il valore in riga 3 e colonna 1. 5 Vedi sezione 2.1.2
  • 31. 26 2.2 PID Il controllo Proporzionale-Integrativo-Derivativo, comunemente abbreviato come PID, è un sistema di controllo in retroazione negativa. Grazie a un input che determina il valore attuale, è in grado di reagire a un eventuale errore positivo o negativo tendendo verso un valore definito. Il controllore acquisisce in ingresso un valore (nel caso in esame un angolo) e lo confronta con un valore di riferimento. La differenza, o errore, fra i due valori viene utilizzata per determinare la variabile di uscita dal controllore (figura 2.4). Un controllore PID regola l’uscita in base a: • Il valore dell’errore (azione proporzionale); • La somma dei valori passati di errore (azione integrativa); • La velocità di variazione dell’errore (azione derivativa). Questi tre valori vengono moltiplicati per 3 costanti (KP, KI e KD) che determinano il peso di ogni azione necessaria alla stabilizzazione del volo. Figura 2.4: schema a blocchi di un controllore PID
  • 32. 27 2.2.1 PID con Arduino Per questo progetto si è fatto utilizzo della libreria PID_v1 di Brett Beauregard[11] . Questa libreria offre, oltre alle funzioni base che verranno descritte in seguito, alcuni accorgimenti software quali: • Opportunità di cambiare le costanti PID durante il volo; • Derivazione e integrazione dipendenti dal periodo di campionamento; • Filtro per bruschi cambiamenti dell’azione derivativa6 ; • Eliminazione del windup7 . Il funzionamento principale della libreria si basa però su un semplice algoritmo (figura 2.5) che prende in input: • Un angolo; • Il setpoint deciso dal costruttore; • Le costanti KP, KI e KD. Con i primi due viene calcolato l’errore e salvato in una variabile error, questa viene sommata alla variabile errSum che rappresenta la sommatoria di tutti gli errori passati. La variabile lastErr indica l’errore del ciclo precedente e sottratta dalla variabile error permette di capire quanto velocemente sta crescendo o diminuendo l’errore (dErr). L’output viene computato sommando error, errSum e dErr moltiplicati per le rispettive costanti (KP, KI, KD). 6 In caso di cambio del setpoint, l’errore può crescere di molto, il termine derivativo aumenterebbe a dismisura, rischiando oscillazioni pericolose per il sistema 7 Problema che deriva dall’operazione di integrale, se questa non viene bloccata ad un valore massimo, c’è il rischio che il termine integrale renda ininfluenti gli altri due
  • 33. 28 Per il progetto del quadricottero sono necessari tre diversi setpoint e di conseguenza tre diversi controllori PID, due dei quali (i controllori dedicati a rollio e beccheggio) avranno le stesse costanti in quanto il comportamento di un drone è molto simile lungo entrambi gli assi sopra citati. I setpoint di un quadricottero devono essere variabili: a seconda del segnale ricevuto dal telecomando essi possono diventare più o meno positivi o negativi; se nessun input, oltre a quello del throttle, è ricevuto dal trasmettitore RC tutti i setpoint saranno a zero (quadricottero parallelo a terra), se al contrario un qualunque input proveniente dal radiocomando modificasse l’orientazione del drone i setpoint si adatteranno di conseguenza (e.g. un segnale che facesse ruotare il drone lungo l’asse di rollio di 10° sposterebbe il setpoint del controllore del rollio a 10°) Figura 2.5: algoritmo controllore PID
  • 34. 29 2.3 Trasmettitore e ricevente RC Il trasmettitore o radiocomando è un dispositivo in grado di comandare a distanza un apparecchio usando le onde radio come mezzo di trasmissione. Nel nostro progetto, come già accennato8 , il radiocomando invia un segnale modulato PPM all’antenna della ricevente che lo converte in 4 differenti segnali PWM. Le 4 uscite della ricevente sono collegate a 4 input digitali di Arduino, che può elaborare il segnale tramite Interrupt. 2.3.1 Interrupt Un interrupt o interruzione è un segnale asincrono che interrompe qualunque operazione in corso e indica il “bisogno di attenzione” da parte di una periferica, finalizzata a una particolare richiesta di servizio. Nel caso della trasmissione RC abbiamo un interrupt ogni qual volta la ricevente invii un segnale ad Arduino tramite uno dei suoi 4 canali. Arduino deve essere opportunamente programmato per reagire a questi segnali ed elaborarli tramite una funzione chiamata: Interrupt Service Routine (ISR). Osservando il datasheet del microcontrollore ATmega328P si nota che i pin predisposti a gestire interrupt sono i pin digitali 2 e 3. Due soli pin non permetterebbero la lettura di quattro canali, ma un’opportuna modifica ai registri dell’ATmega tramite la libreria PinChangeInt [12] permette di rendere tutti i pin sensibili al riconoscimento di un’interruzione, inoltre sarà possibile la lettura dell’interrupt per qualunque segnale di tipo 8 Vedi sezione 1.5.1
  • 35. 30 CHANGE: si andrà a registrare un interrupt al passaggio del segnale da basso a alto e uno per il cambiamento inverso. All’arrivo di un interrupt su uno dei pin connessi alla ricevente, Arduino interrompe il processo in corso ed esegue una ISR, che deve essere poco complessa a livello computazionale e deve richiedere pochi microsecondi di calcolo, in modo riprendere il ciclo il più velocemente possibile. L’ISR scritta per calcolare il throttle è mostrata di seguito, le altre tre sono equivalenti: Il metodo digitalRead() indica lo stato del pin (HIGH o LOW), la condizione è verificata solo se nel frame PWM il segnale è appena cambiato da LOW a HIGH ed è dunque necessario iniziare a misurare la durata del segnale, ciò avviene sfruttando la variabile throttleIntStart che registra il valore del timer in quell’istante. Si esce così dall’ISR e il loop può riprendere. Al successivo cambiamento di stato digitalRead() restituirà un valore LOW e la condizione sarà non verificata, nella variabile throttleShared viene salvata la differenza fra l’istante attuale e throttleIntStart, questa differenza corrisponde alla durata del segnale. La variabile
  • 36. 31 updateFlagShared si aggiorna per indicare che il throttle è già stato valutato e tornerà a 0 all’inizio di ogni ciclo. Dopo l’esecuzione dell’ISR è necessario salvare una copia locale dei valori rilevati in modo che i valori non vengano modificati accidentalmente dall’arrivo di un altro interrupt. La copia locale dei valori viene opportunamente calibrata ed elaborata, per poi essere trasmessa ai moduli E.S.C. che controlleranno la velocità dei motori. È quindi necessario convertire un valore numerico in un segnale PWM, operazione che viene ancora una volta eseguita sfruttando gli interrupt tramite la libreria RCArduinoFastLib [13] : versione più rapida della già citata9 libreria Servo. 2.3.2 Calibrazione radiocomando Idealmente il radiocomando invia alla ricevente impulsi separati da un tempo compreso fra 1000 µs e 2000 µs, la ricevente converte alla perfezione il segnale PPM in PWM e ad ogni uguale spostamento delle levette del telecomando relative ai vari assi corrisponde una identica risposta del quadricottero. Ovviamente la situazione sopra descritta è irrealistica e per ridurre l’errore introdotto da ogni modulo è stata scritta un’apposita routine per la calibrazione dei valori ricevuti dal radiocomando. La routine sfrutta le stesse ISR del programma principale per calcolare la durata degli impulsi ricevuti e memorizza i cosiddetti “endpoints” (valori massimo, minimo e centrale) delle levette del radiocomando. Non 9 Vedi sezione 1.3.1
  • 37. 32 essendo la routine ripetibile, per motivi pratici, ad ogni nuovo avvio del drone, essa dovrà memorizzare in maniera permanente gli endpoints; si utilizzerà a questo scopo la memoria EEPROM di Arduino. Il programma, tramite comunicazione seriale, accompagna l’utente attraverso la procedura per la corretta configurazione del radiocomando. Si inizia aspettando 10 secondi tramite il metodo wait_for_receiver10 illustrato di seguito affinché il trasmettitore venga acceso dall’utente: Le variabili Shared indicano i valori letti dalle ISR, la variabile zero si aggiorna ogni qual volta un valore sia nel range indicato (2000 < x < 4000) fino a raggiungere il valore 15 quando tutti gli input sono corretti. A questo punto inizia la configurazione. Viene chiesto all’utente di spostare le levette e i trim (dispositivi compensatori) in posizione centrale; dopo 10 secondi l’ultimo valore inviato viene letto e salvato in variabili center, ottenendo così il primo 10 Tutti i metodi illustrati richiederanno valori fra 2000 e 4000 µs, questo perché il prescaler del timer è impostato a ½.
  • 38. 33 valore d’interesse. Successivamente si chiede di muovere le levette fino ai loro estremi i quali vengono salvati in variabili high e low dalla funzione register_min_max, di cui viene mostrato solo il funzionamento relativo agli endpoint del throttle in quanto gli altri tre metodi sono equivalenti: Finché la variabile zero non raggiunge il valore 15, ossia quando tutte le levette vengono riportate in posizione centrale, i valori massimo e minimo vengono continuamente aggiornati: ogni volta che si registra un impulso più lungo (breve) la variabile high (low) viene aggiornata con il nuovo valore. La configurazione è terminata, ma le variabili sono ancora salvate solo all’interno della memoria Flash, che si riscriverà al caricamento del programma principale. Si importa dunque la libreria EEPROM [14] , e si scrivono, un byte alla volta, i valori appena registrati. I valori ottenuti, dal peso di 2 byte ciascuno, andranno divisi in scrittura e ricostruiti opportunamente in lettura. Avendo 4 controlli e 3 endpoint da 2 byte per ognuno saranno necessarie 4*3*2 = 24 istruzioni EEPROM per poter salvare tutti i dati senza perdite.
  • 39. 34 La libreria EEPROM mette a disposizione il metodo write( address, value) per la scrittura come mostrato nella porzione di codice: dove viene scritto su due celle il valore centerYaw. La scrittura o lettura di ogni byte richiede 3.3 ms, per cui la EEPROM non potrà essere letta ad ogni ciclo del main program ma verrà salvata su un array. Il perché la scrittura di un solo valore sia divisa in due istruzioni sarà argomento del prossimo capitolo.
  • 40. 35 Capitolo 3 Approfondimenti Software 3.1 Matrice di rotazione Come discusso nel capitolo 2, dati tre angoli quali rollio, beccheggio e imbardata è possibile costruire una matrice di rotazione R, necessaria per poter interpretare correttamente i dati raccolti da giroscopio e accelerometro. A livello software la matrice viene costruita sfruttando la seguente procedura: la quale prende in input tre angoli e un array bidimensionale, che verrà aggiornato all’interno del metodo e rappresenterà la matrice R. All’interno delle variabili c e s vengono salvati rispettivamente i coseni e
  • 41. 36 i seni dei tre angoli espressi in radianti11 . I seni e coseni vengono poi opportunamente moltiplicati e salvati nelle celle dell’array. È così possibile ridurre il numero delle funzioni trigonometriche calcolate, necessarie alla costruzione della matrice R, da 29 a 6: fattore che influenza non poco la velocità del loop in quanto seni e coseni sono fra le funzioni più lente da computare e richiedono un grande lavoro del processore. Per questo particolare progetto però si può velocizzare ancora il calcolo, sfruttando le caratteristiche del giroscopio e gli sviluppi di Taylor-Maclaurin. 3.1.1 Fast ypr2rot Il giroscopio è stato impostato per avere un Full Scale Range di 500 dps (degrees per second), moltiplicando questo valore per il periodo (10 ms) otteniamo che la massima variazione rilevabile a ogni ciclo dal giroscopio è di 5 gradi (0.08727 rad). Gli sviluppi in serie di Taylor-Maclaurin del seno e del coseno sono: sin(𝑥) = ∑ (−1) 𝑛 (2𝑛 + 1)! ∞ 𝑛=0 𝑥2𝑛+1 ∀𝑥 ∈ ℝ cos(𝑥) = ∑ (−1) 𝑛 (2𝑛)! ∞ 𝑛=0 𝑥2𝑛 ∀𝑥 ∈ ℝ E per piccoli angoli possono essere approssimati a: 11 La conversione avviene attraverso la moltiplicazione per il fattore 𝜋 180⁄ .
  • 42. 37 sin(𝑥) = 𝑥 cos(𝑥) = 1 − 𝑥2 2 Vediamo quanto vale l’errore rilevato dal quadricottero nel caso peggiore: 5 deg = 0.087266 rad = x; sin(x) = 0.087156; cos(x) = 0.996194; 1 – x2 / 2 = 0.996191; Nel caso del seno l’errore è minore di 10-3 (< 10-5 per il coseno) e dunque trascurabile. La routine riportata di seguito è equivalente a ypr2rot12 ma sfrutta gli sviluppi in serie di Taylor-Maclaurin per velocizzare i calcoli: 12 Pag. 33
  • 43. 38 3.2 Timer Un timer o contatore è un dispositivo elettronico che viene utilizzato per misurare eventi temporali, similmente a quanto fa un orologio. Il timer o, per essere precisi, i timer di Arduino possono essere programmati attraverso opportuni registri dell’ATmega. È possibile configurare ad esempio il prescaler e la modalità operativa. Il microcontrollore montato su Arduino è dotato di 3 timer, chiamati: timer0, timer1 e timer2. Il primo e l’ultimo hanno una risoluzione di 8 bit, il secondo di 16 bit e può essere utilizzato per un conteggio più lungo o per ottenere maggiore precisione. I timer dipendono dal clock di Arduino, nel caso di Arduino Uno il clock è 16 MHz. Ad ogni timer sono assegnate differenti funzioni: • Timer0 è usato per le funzioni di timing richiamabili dallo sketch, quali delay(), millis() e micros(), oltre a gestire l’output PWM dei pin 5 e 6. Modificare i registri del timer0 potrebbe modificare il comportamento del programma. Timer0 nel progetto di questa tesi è utilizzato per controllare il tempo di ciclo e fissarlo a 10 ms; • Timer1 ha il vantaggio di essere a 16 bit, e viene utilizzato ad esempio dalla libreria Servo e per la gestione dei PWM sui pin 9 e 10. Per il corretto funzionamento del drone timer1 viene utilizzato anche per la gestione di tutti gli interrupt: sia quelli del radiocomando sia quelli della libreria RCArduinoFastLib, che ha un funzionamento equivalente alla libreria Servo;
  • 44. 39 • Timer2 viene utilizzato per la funzione tone()13 e per i PWM sui pin 3 e 11. Qualunque libreria faccia uso dei timer va utilizzata con cautela per evitare conflitti: non è ad esempio possibile generare PWM sui pin 9 e 10 se si sfrutta la libreria Servo, allo stesso modo è impossibile fare uso della funzione tone() e contemporaneamente generare segnali PWM sui pin 3 e 11. Dunque, i problemi di timing in cui ci si può imbattere durante la scrittura di un programma Arduino in grado di controllare il volo di un drone sono molteplici, purtroppo alcuni di questi non sono addirittura risolvibili totalmente, vedremo però che tramite un buon design è possibile ridurli fino a garantire le specifiche richieste. 3.2.1 Tempo di ciclo Il primo problema a cui si va incontro è quello del controllo del tempo di ciclo, che deve essere quanto più preciso possibile per garantire una corretta interpretazione dei dati provenienti dal giroscopio. Per prima cosa è doveroso scegliere un loop time che sia in grado di contenere tutte le operazioni del ciclo più un lasso di tempo (differenza fra periodo di ciclo e tempo impiegato dal processore per eseguire le istruzioni del ciclo stesso) dell’ordine delle centinaia di microsecondi. 13 Genera un’onda quadra alla frequenza decisa dall’utente, può essere usata per riprodurre suoni su dispositivi come i buzzer piezoelettrici
  • 45. 40 In secondo luogo, è doveroso portare all’attenzione del lettore che timer0, affinché sia possibile avvalersi della funzione micros() per il controllo del tempo di ciclo, non sarà utilizzabile per altre operazioni (e.g. non sarà possibile generare output PWM sui pin 5 e 6). Come ultima cosa si ricorda che un interrupt, in quanto tale, potrebbe interrompere il ciclo in qualunque istante, e per quanto sia veloce un’ISR, per il controllo di un quadricottero quest’ultima viene richiamata molte volte sia dalla libreria per il controllo degli E.S.C sia da ogni input del radiocomando. Per il progetto di questa tesi è stato scelto un loop time di 10 ms: il ciclo completo richiede circa 8 ms e 2 ms sono stati assegnati ad eventuali interruzioni. Inoltre, una frequenza di 100 Hz assicura una lettura dei dati del giroscopio e di conseguenza un controllo PID sufficientemente accurati. 3.2.2 ISR Un’ISR è una routine la cui esecuzione è innescata dal verificarsi di un interrupt. Il tempo impiegato dal processore per tornare al ciclo principale dopo un’interruzione è dato da: • Tempo necessario ad accedere all’ISR; • Tempo di esecuzione dell’ISR. L’analisi [15] svolta dall’autore della libreria PinChangeInt mostra che la durata totale (accesso + esecuzione) di una ISR semplice, che incrementa il valore di una variabile, è circa 13 µs.
  • 46. 41 Poiché un singolo input PPM del radiocomando genera 8 interrupt ogni 20 ms, è stato necessario cercare di ridurre le istruzioni all’interno dell’ISR al minimo indispensabile, attraverso alcuni accorgimenti quali: • Utilizzo della variabile statica pinState: la lettura dello stato di un pin tramite la funzione predefinita digitalRead()14 di Arduino richiede circa 1.4 µs, la lettura della variabile pinState definita all’interno della libreria PinChangeInt avviene in 0.4 µs; • Lettura dei registri di timer1: anziché andare a richiamare la funzione micros(), è stata implementata la lettura diretta del registro TCNT del timer1. Si risparmia in questa maniera un ulteriore microsecondo e inoltre, essendo timer1 a 16 bit, si avrà un guadagno in risoluzione; • Variabile a 2 byte: la funzione micros() restituisce una variabile di tipo long a 32 bit, la variabile TCNT1 è invece a 16 bit e ciò permette di dimezzare la durata delle operazioni di lettura, scrittura e salvataggio. Tutti questi cambiamenti trasformano la ISR del capitolo 2.3.1 in: 14 Tutte le funzioni predefinite sono disponibili alla pagina: https://www.arduino.cc/reference/en/
  • 47. 42 3.2.3 PWM Anche la libreria Servo sfrutta gli interrupt per funzionare, in questo caso si parla però di Output Compare Interrupt. Un’interruzione di questo tipo viene generata dal confronto fra il contatore TCNT1 e un numero salvato in un registro chiamato Output Compare Register (OCR1A): quando il valore di TCNT1 raggiunge OCR1A viene generato un interrupt e richiamata la rispettiva ISR. Ciò che avviene durante la generazione dei frame PWM è riassumibile con i seguenti passaggi: • Creazione di un array monodimensionale di lunghezza N + 1, dove N è il numero di dispositivi (Servo, E.S.C. ecc.); • Inserimento, in ogni posizione dell’array, di un numero corrispondente alla durata in microsecondi dell’impulso del rispettivo frame PWM; • Si imposta poi a livello HIGH il pin corrispondente al primo elemento dell’array e si setta il registro OCR1A al valore TCNT1 (attuale) + durata impulso; • Al raggiungimento di OCR1A da parte di TCNT1 scatta l’interrupt e viene richiamata un’ISR che porta a livello LOW il pin attuale e a livello HIGH il successivo; • Si prosegue fino all’ultimo elemento dell’array, per cui viene generato un segnale LOW fino alla durata totale del frame PWM (10 ms per questo progetto).
  • 48. 43 Anche la libreria Servo dovrebbe svolgere tutte queste operazioni alla massima velocità possibile per garantire accuratezza dell’output. È stato notato inoltre che sfruttando la libreria Servo classica si possono verificare conflitti con l’ISR del radiocomando, in quanto questa ha bisogno di leggere i registri del timer1, mentre la prima resetta il registro TCNT1 ogni volta che viene generato un nuovo frame. È stato deciso dunque di adottare una diversa libreria per la gestione degli E.S.C. ossia la libreria RCArduinoFastLib15 che opera con gli stessi principi della libreria Servo ma ottimizzati per ottenere maggiore accuratezza e routine più veloci. Essa è inoltre compatibile con le ISR per la lettura dei valori ricevuti dal trasmettitore in quanto non resetta il valore TCNT1. 3.3 EEPROM Come anticipato nelle sezioni 1.1.1 e 2.3.2 la memoria EEPROM di cui è dotata la scheda Arduino ha capacità totale di 1 KB, con singole celle di memoria da 1 byte (8 bit). In una memoria da 8 bit è possibile scrivere valori nel range 0-25516 , di conseguenza risulterebbe impossibile salvare gli endpoint del radiocomando, che appartengono al range 2000-4000. È stato necessario dunque dividere un valore da 2 byte in due termini distinti da un byte ciascuno da ricostruire opportunamente tramite Bit Manipulation. 15 Vedi sezione 2.3.1 per il riferimento bibliografico 16 28 = 256 valori
  • 49. 44 3.3.1 Bit Manipulation Con Bit Manipulation si intente generalmente una tecnica che tramite “operatori” è in grado di modificare manualmente i singoli bit di una variabile. L’elenco completo degli operatori utilizzabili in ambiente Arduino è disponibile sul sito della scheda17 , di seguito sono forniti quelli utilizzati nel corso di questa tesi: • &: operatore AND, confronta indipendentemente ogni bit di due diverse parole, restituendo 1 se entrambi i bit sono 1, 0 in tutti gli altri casi, come illustrato nella seguente tabella 1st word 0 0 1 1 2nd word 0 1 0 1 result 0 0 0 1 Tabella 4: operatore AND • >>: operatore Right Shift, causa lo spostamento verso destra dei bit più a sinistra di una parola di un numero di posizioni che viene indicato dall’utente. La sintassi per l’utilizzo dell’operatore Right Shift è la seguente: variabile >> numero di bits • <<: operatore Left Shift, opera come Right Shift ma sposta verso sinistra i bit più a destra di una parola di un numero di posizioni indicato dall’utente, con la seguente sintassi: variabile << numero di bits 17 https://www.arduino.cc/reference/en/
  • 50. 45 Verso la fine della sezione 2.3.2 è riportata una parte di codice atta alla scrittura degli endpoint sulla memoria EEPROM; il codice riportato anche qui, diventa ora di facile interpretazione: Il metodo write della libreria EEPROM18 prende in ingresso due valori: • Address: variabile di tipo int (2 byte) che identifica un indirizzo di memoria della EEPROM e può assumere valori da 0 a 1023; • Value: variabile di tipo byte da salvare in memoria. La scrittura “0xff” indica il byte in base esadecimale ff (tutti i bit a 1), di conseguenza l’operazione: centerYaw & 0xff restituirà gli 8 bit più a destra del valore centerYaw. L’operazione centerYaw >> 8 sposta gli 8 bit più a sinistra della variabile centerYaw di 8 posizioni, eliminando i bit più a destra. Si ottengono così due byte distinti che mantengono tutte le informazioni relative alla variabile di partenza. Per la ricostruzione sarà sufficiente sommare al byte di una cella quello della cella successiva spostato a sinistra di 8 posizioni, istruzione che si esegue con la riga: dove start indica l’indirizzo di salvataggio della prima parte di un endpoint. Ad esempio, se il valore di un endpoint fosse: 3416 (00001101010110002 in codice binario) esso verrebbe trasformato dalla prima istruzione in: 3416 & 0xff = 010110002 e dalla seconda in: 3416 >> 8 = 000011012. Per la ricostruzione avremo: 000011012 << 8 = 00001101000000002 + 010110002 = 00001101010110002, che è appunto il valore 3416 di partenza. 18 Riferimento bibliografico [14]
  • 51. 46 Conclusioni Come si è visto, le limitazioni di questo genere di progetto sono tante, alcune di queste sono state affrontate dal candidato, altre richiederanno studi futuri. Il quadricottero di fine progetto è pronto per spiccare il volo, ma richiederà sicuramente ulteriori miglioramenti, non si è ad esempio affrontato il problema del blocco Cardanico o la stabilità durante le operazioni di manovra in volo, che richiederanno ulteriori test e modifiche software. Il lavoro svolto pone quindi le fondamenta per uno studio futuro, che potrebbe sfruttare l’utilizzo di nuovi sensori (GPS, sensore di prossimità, fotocamera, ecc.) così come quello di nuovi algoritmi, in una realtà che al giorno d’oggi è fonte di ispirazione per studiosi e appassionati.
  • 52. 47 Fonti Bibliografiche e Sitografia [1] Arduino (hardware) [Online]. Disponibile: https://it.wikipedia.org/wiki/Arduino_(hardware). [2] ATMEL, ATmega328/P Datasheet, 11/2016. Disponibile: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel- 42735-8-bit-AVR-Microcontroller-ATmega328- 328P_Datasheet.pdf [3] Introduction to the Arduino Board [Online]. Disponibile: https://www.arduino.cc/en/Guide/Board? from=Tutorial.ArduinoBoard. [4] Scegliere motori ed eliche per il vostro quadricottero. Disponibile: https://www.cosecinesi.it/tutorials-e- guide/scegliere-motori-eliche-quadricottero/ [5] A2212/13T technical data. Disponibile: https://www.batteryheatedclothing.com/pages/a2212-13t- technical-data.html [6] Michael Margolis, Servo library. Disponibile: https://www.arduino.cc/en/Reference/Servo [7] MPU-9250 Datasheet. Disponibile: https://www.invensense.com/download-pdf/mpu-9250- datasheet/ [8] Nicholas Zambetti, Wire Library. Disponibile: https://www.arduino.cc/en/Reference/Wire
  • 53. 48 [9] SparkFun Electronics, Inc. SparkFun_MPU-9250 DMP_Arduino_Library. Disponibile: https://github.com/sparkfun/SparkFun_MPU-9250- DMP_Arduino_Library [10] Fly-Sky FS-T4B. Disponibile: http://www.flyskycn.com/products_detail/productId=39.html [11] Brett Beauregard, Arduino-PID-Library. Disponibile: https://github.com/br3ttb/Arduino-PID-Library [12] Mike Schwager, PinChangeInt. Disponibile: https://github.com/GreyGnome/PinChangeInt [13] Scott Gibson, RCArduinoFastLib. Disponibile: https://github.com/scottjgibson/RCArduinoFastLib [14] Christopher Andrews, EEPROM Library V2.0 for Arduino. Disponibile: https://github.com/arduino/Arduino/tree/master/hardware /arduino/avr/libraries/EEPROM [15] Mike Schwager, Pin Change Interrupt Timing. Disponibile: https://github.com/GreyGnome/EnableInterrupt/blob/master/Int errupt%20Timing.pdf