Realizzazione e controllo di un robot mobile differenziale

Transcript

Realizzazione e controllo di un robot mobile differenziale
UNIVERSITÀ DEGLI STUDI DI ROMA
TOR VERGATA
FACOLTÀ DI INGEGNERIA
CORSO DI LAUREA IN INGEGNERIA
DELL'AUTOMAZIONE
A.A. 2009/2010
Tesi di Laurea
REALIZZAZIONE E CONTROLLO DI UN ROBOT
MOBILE DIFFERENZIALE
RELATORE
CANDIDATO
Ing. Daniele Carnevale
Moreno Mattia
0121909
...alla mia famiglia
e ad Alessandra.
Indice
Ringraziamenti
1
Introduzione
2
1 Descrizione Hardware
5
1.1
Sensori di sistanza
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.2
Controller Motori . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.2.1
Led di segnalazione . . . . . . . . . . . . . . . . . . . . . . . .
9
1.2.2
Comandi principali del M.M.B.e.
. . . . . . . . . . . . . . . .
10
1.3
Motori DC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
1.4
Encoder
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.5
Motorizzazione della torretta . . . . . . . . . . . . . . . . . . . . . . .
14
1.6
Modulo wireless . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.7
Scheda ARDUINO
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
1.7.1
Alimentazione e memorie Arduino . . . . . . . . . . . . . . . .
19
1.7.2
Input e Output
. . . . . . . . . . . . . . . . . . . . . . . . . .
20
Circuito di alimentazione . . . . . . . . . . . . . . . . . . . . . . . . .
21
1.8
2 Gestione dell'hardware
2.1
INDICE
Gestione dei motori . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
23
I
INDICE
2.2
2.1.1
Errore di compilazione
. . . . . . . . . . . . . . . . . . . . . .
2.1.2
Librerie SoftSerial e NewSoftSerial
. . . . . . . . . . . . . . .
24
2.1.3
Software gestione motori . . . . . . . . . . . . . . . . . . . . .
27
Gestione della comunicazione Arduino Matlab
24
. . . . . . . . . . . . .
28
2.2.1
Trasmissione . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
2.2.2
Ricezione
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
2.3
Gestione Sensori
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
2.4
Gestione Servomotore . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
3 Applicazioni
3.1
38
Interfaccia graca di comando . . . . . . . . . . . . . . . . . . . . . .
38
3.1.1
Creazione dell'applicazione GUI . . . . . . . . . . . . . . . . .
38
3.1.2
Elaborazione dati . . . . . . . . . . . . . . . . . . . . . . . . .
42
3.2
Modellizzazione del sistema
. . . . . . . . . . . . . . . . . . . . . . .
45
3.3
Controllo distanza
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
3.4
Controllo di posizione . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
Conclusioni e sviluppi futuri
54
Appendice
56
Elenco delle gure
79
Bibliograa
80
INDICE
II
Ringraziamenti
Grazie al mio relatore per i consigli, il supporto e la partecipazione che ha dimostrato
nel guidarmi in questo mio lavoro, per la sua esperienza e la sua professionalità messe a
mia disposizione. Un grazie speciale anche ai miei compagni di corso, che dall'inizio di
questi tre anni non hanno mai lesinato su un aiuto o un consiglio. Alla mia famiglia
per aver creduto in me e ad Alessandra che ha avuto il coraggio e la pazienza di
aspettare che i miei sforzi e i miei tentativi si trasformassero in Octagon.
Introduzione
1
Introduzione
Il termine ROBOT deriva dalla parola ceca ROBOTA che signica lavoro pesante o
lavoro forzato ed identica una qualsiasi macchina, di forma più o meno antropomorfa, in grado di sostituire l'uomo nei lavori più pesanti, noiosi, faticosi o pericolosi.
La robotica è la scienza che cerca di sviluppare, appunto, metodologie che permattano ad una macchina (robot) dotata di opportuni sensori ed attuattori di percepire ed
interagire con l'ambiente esterno e di svolgere funzioni che sarebbero, altrimenti, ad
esclusivo appannaggio dell'uomo.
Numerosi sono i robot progettati e realizzati no ad oggi in campo industriale, medico, militare e nell'ambito della ricerca scientica:
quelli controllati in remoto, i
robot autonomi (droni), i robot sequenziali, quelli di formazione ed investigazione e i
microrobot, solo per elencarne alcuni.
Lo scopo del presente lavoro è quello di riprogettare un precedente robot mobile, l'Octagon, per realizzare un gruppo di Robot a basso costo e che siano versatili,
espandibili, ad elevata autonomia e semplici da riprodurre e mantenere. Gli Octagon,
sono stati creati con lo scopo di fornire uno strumento di grande valore didattico e di
rappresentare, in tal modo, un valido canale di comunicazione interdisciplinare.
Gli Octagon sono in grado di comunicare tramite un modulo radio che ha una portata
di 250 metri in linea d'aria ed un consumo molto ridotto. La capacità di comunicazione
è un requisito essenziale per l'implementazione di tutti quegli algoritmi di intelligenza
Introduzione
2
Introduzione
distribuita multi agente, in cui gli agenti comunicano tra di loro per scambiarsi diverse
informazioni (odometriche, stato, ecc..) e coordinarsi.
Il basso costo dell'hardware scelto per la realizzazione dei robot inuisce in modo molto
positivo sulla riproducibilità e li qualica come un'ottima piattaforma per l'immissione sul mercato di agenti mobili che potranno poi essere specializzati per speciche
applicazioni.
L'estrema modularità con cui gli Octagon sono stati progettati li rende totalmente
aperti ad eventuali modiche e, anche se nella loro versione di base dispongono solo
di quattro sensori ad infrarosso, essi sono in grado di utilizzare una vasta gamma di
sensori: pirometrici per il rilevamento di fonti di calore, periferiche per il controllo di
servocomandi, sensori ad ultrasuoni...
Gli Octagon una volta equipaggiati di un sensore di visione, costituiranno un ottimo
strumento di ricerca di elevata complessità, come ad esempio per: la Swarm Robotics,
ossia la robotica degli sciami . Si tratta di una recente disciplina che trae le sue origini dall'osservazione dei comportamenti di alcuni insetti sociali, organizzati intorno
ad un individuo, la regina, i quali manifestano quella che spesso viene denita intelligenza della colonia che dà luogo ad un comportamento collettivo auto-organizzante.
L'aspetto più interessante di questi sistemi sta nell'emergere di un comportamento
globale grazie allo scambio di messaggi tra i singoli individui e senza alcuna azione di
supervisione.
La presente tesi è divisa in tre capitoli.
Nel primo capitolo vengono descritti tutti i moduli ed i componenti elettrici e meccanici utilizzati per la costruzione del robot Octagon; in particolare si esporranno le
caratteristiche meccaniche ed elettriche di ognuno, fornendo indicazioni utili riguardo
al loro funzionamento e alla loro compatibilità con gli altri componenti.
Introduzione
3
Introduzione
Nel secondo capitolo si presenteranno tutti i programmi realizzati per la gestione di
ogni modulo: soprattutto lo sviluppo di applicazioni che consentano ai vari dispositivi di comunicare tra di loro in modo da creare un sistema più complesso, robusto ai
disturbi, in grado di svolgere funzioni complesse come il rilevamento di ostacoli e la
comunicazione con macchine di supervisione anche a distanze elevate.
Nel terzo ed ultimo capitolo si spiegherà, inne, la realizzazione delle tre applicazioni
create per il robot: in particolare verrà descritta la creazione di un'interfaccia graca
che permette ad un qualsiasi utente di interagire e comandare il robot.
Una volta
che il robot sarà dotato di sensori più sosticati e precisi, quali ad esempio sensori
per la visione articiale, si potrà utilizzare l'applicazione per comandare il robot dalla
postazione remota.
Nelle altre due applicazioni sono stati realizzati dei controlli. Nella prima si è cercato,
con ottimi risultati, di migliorare le prestazioni del motore nel caso in cui venga richiesta una posizione angolare dell'albero motore ben precisa: a causa dell'inerzia del
motore, essa di per se da scarsi risultati, ma grazie ad un controllo a ciclo chiuso di
questo sottosistema le prestazioni del robot sono state signicativamente migliorate.
Nella seconda applicazione è stato realizzato un programma che permetta al robot
di seguire un oggetto e di rimanere sempre alla stessa distanza da esso.
Quest'ul-
tima applicazione, nello specico, è utile per realizzare una delle idee originarie, in
cui si era pensato di utilizzare dei robot Octagon per simulare il comportamento di
più autovetture ferme ad un incrocio in cui è presente un semaforo; in questo caso il
controllo decentralizzato su ogni robot dovrebbe essere in grado di coordinare i robot
massimizzando l'attraversamento dell'incrocio.
Introduzione
4
Capitolo 1
Descrizione Hardware
In questo capitolo verrà descritta la struttura hardware del robot;
si spiegherà nel particolare il funzionamento di: controller motori
M.M.B.e, sensori di distanza GP2D12, scheda Arduino, motori DC
a 12V, encoder magnetici, modulo per la comunicazione wireless e
circuito di alimentazione.
1.1 Sensori di sistanza
I robot Octagon sono dotati di sensori di distanza SHARP GP2D12, i quali vengono
montati su un supporto in alluminio solidale all'asse di un servomotore che ne pemette la rotazione; tali sensori permettono di rilevare la distanza degli oggetti che
ne riettono il raggio infrarosso. Per permettere a più robot di operare nello stesso
ambiente vengono scelti sensori ad infrarossi rispetto a sensori ad ultrasuono.
La disposizione iniziale, in cui due sensori erano posti due nella parte anteriore del
robot e due nella parte posteriore, è stata modicata posizionando tutti e quattro i sensori nella parte anteriore del robot, alne di poter realizzare una delle tre applicazioni
che verranno di seguito descritte.
I sensori GP2D12 hanno un range di scansione che varia dai 10 agli 80cm; quando
un oggetto si trova all'interno di tale range, riettendo la luce generata dall'emettitore
5
Cap. 1
Descrizione Hardware
Ÿ1.1
Sensori di sistanza
Figura 1.1: Sensore SHARP GP2D12
a infrarosso, si ha una variazione del segnale analogico (prodotto dal sensore) che è
funzione non lineare della distanza del GP2D12 dall'ostacolo.
Figura 1.2: Package GP2D12
Le caratteristiche principali dei GP2D12 sono le seguenti:
•
Range di scansione 10cm - 80cm
•
Tensione di alimentazione compresa tra 4.5V e 5.5V
•
Consumo medio di corrente di 50mA
6
Cap. 1
•
Descrizione Hardware
Ÿ1.2
Controller Motori
Tempo di risposta medio 39ms
Si riporta di seguito la funzione non lineare che intercorre tra distanza e tensione
generata dal sensore
Figura 1.3: Segnale generato dai sensori GP2D12
La funzione distanza di cui si ha bisogno è l'inversa di quella mostrata in gura
1.3, che è stata invertita e approssimata via software (gura 1.4).
L'approssimazione della curva è stata eettuata in funzione dei punti di massima
variazione del coeciente angolare della stessa.
1.2 Controller Motori
Il motor mind b enhanced (M.M.B.e) è il circuito che si occupa del controllo diretto
dei motori DC a 12V utilizzati per la realizzazione del robot Octagon. I motor mind
comunicano con la scheda Arduino attraverso un'interfaccia seriale TTL del tipo 8N1,
7
Cap. 1
Descrizione Hardware
Ÿ1.2
Controller Motori
Figura 1.4: Relazione distanza tensione
protocollo che prevede 8 bit di dati, un bit di stop e non ha bit di parità . Il motor
mind supporta correnti di alimentazione elevate, è protetto contro i picchi di tensione,
quelli di corrente e contro il surriscaldamento. Le caratteristiche principali del motor
mind sono:
•
Fino a 1.75A di corrente continua (6A di picco);
•
Frequenza PWM di 242Hz o 15.5KHz;
•
Interfaccia seriale TTL a 2.4KBPS o 9.6KBPS di baud rate;
•
Memoria EEPROM accessibile all'utente sia in lettura che in scrittura;
•
Filtro PI per implementare il controllo a ciclo chiuso della velocità;
•
Led verde per la comunicazione visuale delle istruzioni ricevute;
8
Cap. 1
•
Descrizione Hardware
Ÿ1.2
Controller Motori
Led rosso per la comunicazione visuale delle condizioni di errore.
Per controllare i motori il motor mind deve ricevere delle istruzioni di comando da
un'unità master, che in questo caso è la scheda Arduino. Le istruzioni che il motor
mind riceve sono così strutturate:
•
un primo byte di sincronizzazione, il quale rappresenta il numero 85 in base 10
(01010101 in base 2);
•
un secondo byte che indica il comando che il motor mind deve eseguire;
•
da zero a quattro byte separati per indicare i parametri del comando indicato
nel secondo byte.
1.2.1
Led di segnalazione
Il motor mind presenta due led per la comunicazione visuale: un led verde, indicato
nello schema elettrico come D2 ed un led rosso, indicato nello schema elettrico come
D3. Il led verde si attiva nel momento esatto in cui viene alimentato il motor mind e
nel momento in cui esso riceve un'istruzione corretta, assumendo, in tal modo, anche
funzione di test per il controllo delle istruzioni inviate , come ad esempio il baud rate.
Il led rosso viene, invece, attivato al vericarsi di condizioni di errore ben precise:
•
la temperatura sul PCB supera i 175 gradi centigradi;
•
la corrente assorbita supera i 6A;
•
la tensione di alimentazione dei motori scende sotto i 5.6 volt.
Viene disattivato non appena la condizione di errore scompare.
9
Cap. 1
1.2.2
Descrizione Hardware
Ÿ1.2
Controller Motori
Comandi principali del M.M.B.e.
I controller M.M.B.e. sono una versione potenziata rispetto ai precedenti M.M.B. e
presentano un set di comandi più ricco e performante. La gura 1.5 presenta l'elenco
di tutti i comandi che possono essere utilizzati sul M.M.B.e
Figura 1.5: Elenco comandi M.M.B.e.
Come si può vedere ci sono due tipologie di comandi: quelli per operare direttamente
sul motore e quelli per stabilire i parametri interni del M.M.B.e., come ad esempio il
comando per impostare i termini kp e ki del ltro PI.
Nella prima tipologia si trovano ad esempio:
•
il comando SETDC (comando 3) il quale riceve un parametro il cui valore può
variare da 0 a 255; tale valore seleziona il duty cycle del segnale PWM che andrà
a comandare il motore: ad esempio per impostare un duty cycle del 50% basta
impostare il valore 127;
•
il comando SPDCON (comando 4) impone al motore una certa frequenza che può
variare da 0 a 65.535: in questo comando la frequenza viene espressa attraverso
10
Cap. 1
Descrizione Hardware
Ÿ1.2
Controller Motori
due byte e si ottiene attraverso l'espressione:
f requency = F reqHi ∗ 256 + F reqLo
dove FreqHi e FreqLo sono i due byte trasmessi come parametri del comando.
Una volta trasmesso il comando il motor mind controllerà il motore in due modi
diversi a seconda di come è stato impostato il bit STATUS.PIMODE nel registro
STATUS:
•
STATUS.PIMODE = 0.
In questa congurazione denita incremento/decre-
mento, di default nel M.M.B.e, il comando SPDCON seleziona la frequenza
desiderata e la velocità di rotazione del motore è gestita nel seguente modo:
viene incrementata se il tachimetro interno al motor mind segnala una velocità inferiore a quella richiesta; viene decrementata se il tachimetro segnala una
velocità maggiore di quella richiesta.
•
STATUS.PIMODE = 1. In questa congurazione il M.M.B.e. esegue un controllo a ciclo chiuso sulla velocità attraverso un controllore PI, i cui parametri
Kp e Ki sono memorizzati nella memoria EEPROM e possono essere modicati
dall'utente.
Il segnale di errore
∆f = fdesiderata − fattuale
è moltiplicato per un termine proporzionale. La somma degli errori calcolati su
una data nestra temporale è poi moltiplicata per un termine integrale e quest'ultimo valore viene, inne, sommato al precedente ed il risultato riportato in
un registro a 32 bit, di cui verranno impiegati solo gli 8 bit più signicativi. Gli
8 bit così ottenuti verranno utilizzati per la generazione del nuovo duty cycle del
11
Cap. 1
Descrizione Hardware
Ÿ1.3
Motori DC
segnale PWM di controllo dei motori. Se la modalità PI è attiva è raccomandata una frequenza non inferiore a 15 KHz. Il risultato delle operazioni eettuate
sul termine integrale sarà di gran lunga maggiore di 8 bit, pertanto si eettuerà il troncamento delle cifre meno signicative tramite divisione per
2n
con n
= PISCALER (valore indicato come terzo parametro del comando SPDCON).
Scegliendo valori inopportuni, specialmente sul parametro Ki, si ottiene un controllo del motore non adeguato; ne è un esempio pratico la scelta di un valore
di Ki troppo elevato, la quale causa la carica del termine integrale portando
facilmente il motore in saturazione e generando fastidiose sovraelongazioni.
1.3 Motori DC
Il movimento del robot Octagon avviene tramite due motori, i quali hanno i rispettivi
assi di rotazione coincidenti e discordi.
In particolare si è usato un motoriduttore
RHE158-99-100 dotato di soppressore di disturbi VDR sul collettore, cioè di un resistore non lineare che, superata la tensione caratteristica per cui è progettato, abbassa
bruscamente la propria resistenza in modo da attenuare ragguardevolmente il disturbo
(questi dispositivi sono infatti chiamati VDR, acronimo di Voltage Dependent Resistor: resistore variabile con la tensione); è dotato, inoltre, di ingranaggi in metallo e
di un asse posteriore del motore sporgente, per l'applicazione di encoders. La dimensione del riduttore e la cassa metallica consentono una coppia molto elevata.
Sono di seguito riportati il disegno con le dimensioni siche del motoriduttore e la
tabella delle caratteristiche tecniche.
12
Cap. 1
Descrizione Hardware
Ÿ1.4
Encoder
Figura 1.6: Motore DC
Figura 1.7: Caratteristiche Motore DC
1.4 Encoder
I motoriduttori sopra descritti sono dotati di encoder ad eetto hall. Questi sensori di
posizione sono molto stabili termicamente e resistenti alle sollecitazioni meccaniche,
pertanto, nonostante la bassa risoluzione che li caratterizza, sono stati impiegati nel
presente lavoro per l'implementazione del controllo di posizione del robot. Per ogni
giro del motore sono disponibili 3 impulsi, ed essendo il rapporto di riduzione del
motoriduttore pari a 94.37:1 si avranno 283.11 impulsi generati dall'encoder per ogni
giro dell'asse esterno del motoriduttore; la precisione sulla posizione è quindi di 1.27
◦
o 0.75 mm. L'uscita di questi sensori è di tipo open drain con un massimo di 20mA,
ciò signica che per ricevere correttamente un onda quadra dobbiamo inserire una
resistenza di pull-up del valore 10KΩ.
13
Cap. 1
Descrizione Hardware
Ÿ1.5
Motorizzazione della torretta
Figura 1.8: Schema di collegamento degli encoder
1.5 Motorizzazione della torretta
I sensori di posizione sono collocati su un supporto in alluminio solidale all'asse di
rotazione di un servomotore che ne permette l'orientamento. L'attuale posizionamen-
◦
to dei sensori non permette la scansione a 360 delle distanze degli oggetti intorno al
robot; essi, infatti, sono stati posizionati in modo da poter rilevare la distanza di un
oggetto che si muove davanti al robot, con una congurazione utile per due applicazioni che verranno discusse in seguito.
◦
Il servomotore utilizzato può compiere escursioni di 180 con una precisione di
1/4
di
grado. Di seguito è riportato lo schema di collegamento e la tabella delle caratteristiche tecniche del servomotore.
Figura 1.9: Caratteristiche servomotore
14
Cap. 1
Descrizione Hardware
Ÿ1.6
Modulo wireless
Figura 1.10: Servomotore
I servomotori sono controllati mediante un segnale PWM (Pulse width modulation) in cui il valore del duty cycle impone un certo angolo all'asse del servomotore.
Per un controllo ottimale il segnale di controllo deve avere una frequenza di 50HZ.
Come è possibile notare dalla gura 1.11 il periodo dell'onda quadra del segnale di
controllo può variare da 10ms a 25ms. Il duty cycle di tale segnale impone una certa
posizione angolare all'asse della torretta.
Il servomotore montato sul robot sarà controllato dalla scheda Arduino nella quale sono presenti delle librerie che includono le funzioni per il controllo delle uscite
PWM presenti sulla scheda e grazie alle quali si può gestire il servomotore ad alto
livello richiamando una funzione e passando come parametro la posizione angolare
desiderata.
1.6 Modulo wireless
Una delle caratteristiche essenziali del robot Octagon è quella di avere un modulo
radio che permette la comunicazione wireless con un calcolatore no ad una distanza
di circa 250m in linea d'aria. Il modulo radio ER400TRS è un ricetrasmettitore che
trasferisce i dati in modalità half duplex.
L'ER400TRS è un sottosistema a basso consumo costituito da un microcontroller,
un regolatore di tensione ed un trasmettitore FM. Il microcontroller esegue la fun-
15
Cap. 1
Descrizione Hardware
Ÿ1.6
Modulo wireless
Figura 1.11: Segnale di controllo del servomotore
zione di ricetrasmettitore RF, realizza l'interfaccia di trasferimento dati da e verso la
sorgente tramite I/O seriale e solleva, inoltre, il dispositivo host dal carico di lavoro
derivante dall'ottimizzazione del segnale radio, dal rilevamento degli errori, dalla correzione dei dati ricevuti in modo errato e dalla trasmissione dei dati in un formato
adatto al canale. Nel modulo è presente una memoria EEPROM programmabile che
permette di registrare i dati relativi alle varie congurazioni delle modalità operative
del ricetrasmettitore. L'ER400TRS è in grado di rilevare l'intensità del segnale ricevuto in modo da determinare il valore assoluto della distanza del robot dal calcolatore:
16
Cap. 1
Descrizione Hardware
Ÿ1.6
Modulo wireless
Figura 1.12: ER400TRS
Figura 1.13: Diagrmma a blocchi del ER400TRS
per questo genera un segnale analogico la cui ampiezza è inversamente proporzionale
all'energia RF presente nella banda passante del ricevitore. L'intensità di questo segnale può variare da 0 (massimo segnale -50dbm) a 1.2V (minimo segnale -105dbm)
ed ha una pendenza di circa 50db/volt. In gura 1.14 è riportato il segnale analogico
descritto.
La velocità della comunicazione seriale è di 19200 bit/sec. Dei buer interni permettono di accodare 192 byte di dati sia in ingresso che in uscita, in attesa che vengano
trasmessi o utilizzati dall'host.
Purtroppo i moduli EasyRadio non consentono una comunicazione full duplex, in
quanto, operando a coppie sulla stessa frequenza sia in trasmissione che in ricezione,
sono costretti a condividere uno dei canali di livello sico: l'etere. Per quanto detto in
precedenza, non avendo la possibilità di trasmettere e ricevere su frequenze dierenti,
il canale di comunicazione wireless sarà half-duplex. Una ovvia soluzione al problema,
17
Cap. 1
Descrizione Hardware
Ÿ1.7
Scheda ARDUINO
Figura 1.14: Segnale RSSI
sempre utilizzando i moduli ER400TRS, potrebbe essere impiegare due moduli su
ciascun host ed utilizzarli in modalità simplex, ma per contenere i costi e non ridurre
l'autonomia del robot si è scelto di equipaggiare gli Octagon con un solo modulo
EasyRadio e di limitare la dimensione dei frame che transitano nel canale radio.
1.7 Scheda ARDUINO
Tutti i dispositivi elettronici di cui è dotato il robot Octagon sono gestiti dalla scheda
Arduino duemilanove (il nome duemilanove deriva dal fatto che la scheda è in commercio dal 2009). Arduino è dotato di: un microcontrollore ATmega328 a 16MHz;
14 pin digitali che possono essere congurati come ingressi o come uscite digitali e
di queste 14, 6 possono essere utilizzate come uscite PWM; 6 ingressi analogici; un
oscillatore a 16MHz; un collegamento USB; un jack di alimentazione; un header ICSP;
un pulsante di reset.
18
Cap. 1
Descrizione Hardware
Ÿ1.7
Scheda ARDUINO
Figura 1.15: Schema elettrico Arduino
1.7.1
Alimentazione e memorie Arduino
L'Arduino Duemilanove può essere alimentato o attraverso una connessione USB o
tramite un alimentatore esterno; nel secondo caso si può utilizzare per la connessione
una spina da 2.1 millimetri con centro positivo oppure si possono utilizzare i pin GND e
Vin del connettore di alimentazione. L'alimentazione è selezionata automaticamente.
La tensione che riceve la scheda Arduino può variare dai 6 ai 20V, ma si deve tenere
presente che con alimentazioni sotto i 7V il pin di uscita a 5V fornisce meno di cinque
volt e la scheda può essere instabile; se si alimenta con una tensione maggiore di
12V il regolatore potrebbe riscaldarsi e danneggiare la scheda. E' quindi consigliato
l'intervallo 7 - 12 volt. I robot Octagon sono equipaggiati di una batteria a 12V che
19
Cap. 1
Descrizione Hardware
Ÿ1.7
Scheda ARDUINO
fornirà anche l'alimentazione, sempre a 12V, all'Arduino.
Il microcontrollore presente sulla scheda è un ATmega328 che dispone di: una memoria
ash di 32KB per memorizzare il codice (di cui 2KB utilizzati per il bootloader); di
una memoria SRAM di 2KB nella quale vengono memorizzate le variabili utilizzate
a run-time dal programma; una memoria EEPROM da 1KB che può essere letta e
scritta con la libreria EEPROM.
1.7.2
Input e Output
I 14 pin digitali presenti sulla scheda possono essere utilizzati sia come ingressi che
come uscite. Ogni pin può fornire o ricevere un massimo di 40mA ed è dotato di una
resistenza di pull-up di 20-50Ω. Alcuni di questi pin hanno funzioni specializzate:
•
Serial: 0(RX) e 1(tx), utilizzati per ricevere (RX) e trasmettere (TX) dati seriali
TTL;
•
Interrupt esterni:
2 e 3 i quali possono essere congurati per collegare un
interrupt;
•
PWM: 5, 6, 9, 10, 11 che forniscono un'uscita PWM ad 8-bit.
La scheda dispone anche di 6 ingressi analogici, ciascuno dei quali fornisce una risoluzione di 10 bit.
Di default questi ingressi misurano una tensione in ingresso che varia da 0 a 5V,
ma l'estremo superiore può essere modicato inserendo la tensione desiderata nel pin
AREF (Analog Reference). Il pin reset permette di resettare il microcontrollore.
L'arduino supporta anche altri protocolli di comunicazione come il protocollo I2C e
la comunicazione SPI.
20
Cap. 1
Descrizione Hardware
Ÿ1.8
Circuito di alimentazione
1.8 Circuito di alimentazione
Il robot Octagon è dotato di una batteria al piombo che fornisce una tensione di
12V sia all'Arduino che ai due Motor mind.
Tutti gli altri dispositivi:
il modulo
di comunicazione wireless, i sensori di distanza, il servomotore, la parte logica dei
Motor mind e i due encoders sono alimentati con una tensione di 5V. Per ottenere
tale valore sono stati utilizzati due stabilizzatori di tensione LM1117T5.0; in gura
1.16 viene riportato il circuito di alimentazione del robot. Quando tutti i circuiti del
robot sono alimentati si ha un assorbimento massimo di corrente di 800mA che è il
valore massimo di corrente che può assorbire lo stabilizzatore LM1117T, per questo
si è scelto di usarne due invece che uno.
Inne in gura 1.17 si riporta lo schema
Figura 1.16: Circuito di alimentazione
elettrico completo del robot Octagon.
21
Cap. 1
Descrizione Hardware
Ÿ1.8
Circuito di alimentazione
Figura 1.17: Schema elettrico robot Octagon
22
Capitolo 2
Gestione dell'hardware
In questo capitolo verranno descritti i software creati per la gestione
dell'hardware e le problematiche riscontrate nelle varie applicazioni
2.1 Gestione dei motori
Nei robot Octagon ogni motore è gestito da un controller M.M.B.e; i controller comunicano e vengono a loro volta gestiti dalla scheda Arduino. Possiamo immaginare il
motor mind come l'unità slave e l'Arduino come l'unità master.
In gura 2.1 viene mostrato lo schema a blocchi della gestione dei motori: il motor
Figura 2.1: Schema a blocchi per la gestione dei motori
mind riceve dal motore il segnale generato dall'encoder magnetico ed invia allo stesso
i segnali di alimentazione; la scheda Arduino comunica con il controller seguendo il
protocollo di comunicazione Seriale TTL 8-N-1, con il quale vengono utilizzati 10-bit
per spedire un singolo byte, di cui 8 sono bit di dati, uno è un bit di start ed un altro
23
Cap. 2
Gestione dell'hardware
Ÿ2.1
Gestione dei motori
è un bit di stop. I motor mind possono ricevere e trasferire dati ad una velocità di
2400 o 9600 bit/s.
Per ridurre i ritardi si è impostata la comunicazione con un baud/rate di 9600bit/s.
2.1.1
Errore di compilazione
In fase di programmazione della scheda Arduino non può essere però utilizzato lo schema mostrato in gura 2.1; non si riesce, infatti, ad eseguire l'upload del programma
scritto sull' Arduino e viene restituito, nella nestra di comunicazione un errore; la
scheda Arduino è collegata al pc attraverso la porta USB ed al motor mind attraverso
i pin di comunicazione seriale: dato che sulla scheda c'è un unico circuito integrato
che gestisce la comunicazione seriale e la porta USB, quando si è in questa fase si crea
qualche anomalia elettrica e l'upload non viene eseguito correttamente.
Le possibili soluzioni per risolvere questo problema sono due:
•
utilizzare un accoppiatore ottico per trasferire i dati dall'Arduino al M.M.B.e;
•
inserire un deviatore sul pin RX dell'Arduino.
Entrambe le soluzioni permettono di scollegare elettricamente l'Arduino dal controller
motori.
2.1.2
Librerie SoftSerial e NewSoftSerial
La scheda Arduino presenta, di default, un pin per la ricezione ed un pin la trasmissione; si è dovuta, quindi, trovare una soluzione anchè la scheda potesse comunicare
in modo seriale con tre diversi dispositivi del robot: i due motor mind ed il modulo
radio. Il problema è stato risolto collegando il modulo radio alla porta seriale di default dell'Arduino (pin 0 RX, pin 1 TX) ed i due motor mind ad altri 4 pin digitali
24
Cap. 2
Gestione dell'hardware
Ÿ2.1
Gestione dei motori
gestiti in modo che svolgano il ruolo di porte seriali.
In un primo momento si è pensato di creare delle funzioni che replicassero quelle della
gestione della porta seriale su gli altri pin, realizzando dei programmi che utilizzassero le funzioni generiche
digitalRead
e
digitalWrite
per leggere e scrivere byte
trasmessi e ricevuti ad una velocità pressata. Questa soluzione è stata poi abbandonata: infatti, dopo la creazione della prima funzione che replica la
Serial.print
per trasmettere byte dall'Arduino verso i motor mind, si è immediatamente riscontrato un rallentamento del programma, e ci si è resi conto che tali funzioni sarebbero
state poco essibili e non avrebbero potuto emulare tutte quelle che possono essere
utilizzate per la gestione della porta seriale. Inoltre per funzioni di ricezione, da parte
dell'Arduino, ci sarebbero stati notevoli problemi a livello di sincronizzazione.
La casa costruttrice della Scheda Arduino fornisce un insieme di librerie che possono essere implementate nel codice per l'esecuzione di funzioni non standard; una di
queste è la libreria SoftSerial che permette, appunto, di utilizzare semplici pin digitali
come porte seriali. In questa libreria ci sono, però, delle limitazioni:
•
velicità di lavoro no a 9600 bit/sec;
•
funzione Serial.Available() non disponibile;
•
perdita dei dati che arrivano quando la funzione Serial.Read() non è stata
invocata.
Esistono, però, anche altre librerie che non sono fornite dalla casa costruttrice di
Arduino, ma che possono essere comunque utilizzate: ne troviamo alcune sul sito di
ARDUINIANA, in particolare la libreria NewSoftSerial che è quella che verrà implementata nel codice di gestione dei motori per risolvere i problemi di cui sopra. Rispetto alla precedente SoftSerial, che esegue la tecnica del polling in fase di ricezione
25
Cap. 2
Gestione dell'hardware
Ÿ2.1
Gestione dei motori
con un considerevole rallentamento nell'esecuzione del programma, la NewSoftSerial
introduce notevoli miglioramenti:
1. implementa uno schema di buering circolare per rendere più eciente l'elaborazione RX;
2. può essere utilizzata su tutti i pin digitali dell'Arduino;
3. si possono denire simultaneamente più NewSoftwareSerial;
4. presenta una gamma di velocità più ampia;
5. fornisce un ag di overow() per rilevare il l'overow del buer;
6. supporta i processori ad 8 MHz e 20MHz;
7. supporta il software signal inversion.
Nell'uso di questa libreria si deve tener presente un importante accorgimento:
la
funzione mySerial.available non può essere utilizzata come condizione logica all'interno
di cicli while, perché questo causerebbe una ricezione errata dei dati.
Figura 2.2: Schema collegamento Arduino motor mind
26
Cap. 2
Gestione dell'hardware
2.1.3
Ÿ2.1
Gestione dei motori
Software gestione motori
Per completare la descrizione della gestione dei motori si riportano di seguito le
principale parti del codice scritto.
#include
#define
#define
#define
#define
1
<N e w S o f t S e r i a l . h>
2
3
rxPin_a 4
4
txPin_a 5
5
rxPin_b 7
6
txPin_b 8
7
8 N e w S o f t S e r i a l mySerial_a =
9 N e w S o f t S e r i a l mySerial_b =
N e w S o f t S e r i a l ( rxPin_a , txPin_a ) ;
N e w S o f t S e r i a l ( rxPin_b , txPin_b ) ;
In questa parte di codice viene inclusa la libreria NewSoftSerial, vengono deniti i pin
digitali da utilizzare per la comunicazione e le due comunicazioni una per ogni motor
mind.
void
1
setup ()
2 {
3 // d e f i n e p i n modes f o r tx , rx , l e d p i n s :
4
pinMode ( rxPin_a , INPUT) ;
5
pinMode ( txPin_a , OUTPUT) ;
6
pinMode ( rxPin_b , INPUT) ;
7
pinMode ( txPin_b , OUTPUT) ;
8
9
// s e t t h e d a t a r a t e f o r t h e S o f t w a r e S e r i a l p o r t
10
S e r i a l . begin (9600) ;
11
mySerial_a . b e g i n ( 9 6 0 0 ) ;
12
mySerial_b . b e g i n ( 9 6 0 0 ) ;
13 }
Nella funzione di setup della scheda Arduino vengono specializzati i pin per la trasmissione e per la ricezione e viene impostato il baud rate della comunicazione.
1
2
3
4
5
6
7
8
9
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( 1 5 0 ,BYTE) ;
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 5 ,BYTE) ;
delay (10) ;
( i =0; i <3; i ++)
{ b u f f e r 2 [ i ] = mySerial_b . r e a d ( ) ; }
for
27
Cap. 2
Gestione dell'hardware
Ÿ2.2
Gestione della comunicazione Arduino Matlab
In questa porzione di codice si fa un esempio di scrittura e lettura di dati sul
Motor mind. Le prime tre righe di codice eseguono il comando SETDC sul M.M.B.e;
la prima è la trasmissione del byte 85, che, come detto in precedenza, è il byte di
sincronizzazione, vengono poi trasmessi il byte 3 che identica il comando da eseguire
ed inne il byte 150 che è il parametro dell'istruzione richiesta ovvero la velocità.
Nella seconda porzione di codice si ha una lettura di alcuni parametri del motor mind,
in particolare dei valori che assumono le variabili Pterm, Iterm, Piscalar. Come sopra
troviamo la trasmissione del byte 85 e del byte 15 che indica, invece, la richiesta di
trasmissione da parte del motor mind verso l'Arduino; viene inserito un ritardo di
10ms e con un ciclo for vengono memorizzati i valori nel vettore buer.
2.2 Gestione della comunicazione Arduino Matlab
In questo paragrafo viene descritta la realizzazione della comunicazione wireless tra
l'Arduino ed il calcolatore, per la quale si è scelto di utilizzare il software Matlab. La
gura 2.3 mostra lo schema a blocchi della comunicazione. Il modulo ER400TRS e
l'antenna che sono connessi al calcolatore sono racchiusi in un unico modulo mentre, il
modulo e l'antenna che sono connessi alla scheda Arduino sono sicamente separati.
I moduli per la comunicazione wireless ER400TRS rendono trasparente la comunicazione gestendo autonomamente i segnali da trasmettere e ricevere ed è per questo
motivo che nei codici Matlab e Arduino si utilizzaranno le comuni funzioni di lettura
e scrittura su porta seriale; la velocità di comunicaizone è di 19200bit/sec.
Per gestire la comunicazione con una porta seriale su Matlab viene denito un oggetto
di tipo porta seriale; l'oggetto contiene tutti i parametri della comunicazione: il Baudrate, la porta seriale con cui comunicare, il numero di bit da cui è composto un dato
ed il numero di bit di stop.
28
Cap. 2
Gestione dell'hardware
Ÿ2.2
Gestione della comunicazione Arduino Matlab
Figura 2.3: Schema a blocchi comunicazione wireless
1
2
3
4
5
6
7
s = s e r i a l ( 'COM6 ' ) ;
s e t ( s , ' BaudRate ' , 1 9 2 0 0 ) ;
s e t ( s , ' DataBits ' , 8 ) ;
s e t ( s , ' StopBits ' , 1) ;
fopen ( s )
. . . . . comunicazione . . . . .
fclose (s)
Prima di iniziare la comunicazione è necessario connettersi alla porta con il comando
fopen(s);
2.2.1
terminata la comunicazione ci si disconnette con il comando
fclose(s).
Trasmissione
Per trasferire dati dall'Arduino a Matlab si esegue la seguente istruzione :
1 Serial . println ( alfa ) ;
dove alfa è un numero intero.
Nel caso in cui si vogliano trasmettere più valori, ad esempio gli elementi di un vettore,
si possono scrivere più
Serial.println() consecutive (oppure un'unica Serial.println()
all'interno di un ciclo for); è essenziale usare sempre l'istruzione
Serial.println(),
perché in fase di ricezione per distinguere la ne di un valore e l'inizio del successivo
si legge il carattere
\n
che con l'istruzione
Serial.print()
normale non viene tra-
29
Cap. 2
Gestione dell'hardware
Ÿ2.2
Gestione della comunicazione Arduino Matlab
smesso.
Per trasmettere dati da Matlab verso Arduino si usa l'istruzione
1 f w r i t e ( s , vector , ' uint16 ' ) ;
dove la variabile vector è un vettore di interi senza segno a 16 bit di dimensione
arbitraria.
In questo caso, a dierenza del precedente, per trasmettere più valori
si usa un'unica istruzione che ha come argomento un vettore; come si può vedere
dall'istruzione, gli elementi del vettore vengono trasmessi come interi senza segno a
16
16-bit e si possono, quindi, spedire valori che vanno da 0 a 65536 (2 ).
2.2.2
Ricezione
Descriviamo di seguito il funzionamento dei codici che realizzano le due funzioni di
ricezione, i quali, a dierenza delle precedenti applicazioni, sono più complessi perchè
devono rilevare autonomamente il numero di dati che vengono ricevuti.
Entrambe le funzioni restituiscono i dati organizzati in un vettore, in modo da semplicarne poi l'utilizzo.
•
Ricezione dei dati provenienti dalla scheda Arduino.
La funzione Matlab che permette di ricevere dati da una porta seriale è la
segeunte:
1 f r e a d ( s , x , ' char ' )
in cui il parametro
x
è un valore intero che identica il numero di caratteri da
ricevere. Questa funzione restituisce un vettore i cui elementi sono le cifre dei
valori trasmessi intervallate dai caratteri di separazione (\n).
Si supponga ora di eseguire il seguente codice su Arduino:
30
Cap. 2
Gestione dell'hardware
Ÿ2.2
Gestione della comunicazione Arduino Matlab
1 S e r i a l . println (2478) ;
2 S e r i a l . println (365) ;
in Matlab si riceve il vettore :
A = [50, 52, 55, 56, −35, −39, 51, 54, 53, −35, −39]
Apparentemente sembra che ci sia un errore, in realtà i singoli caratteri ricevuti
sono espressi nella codica ASCII; è, quindi, suciente convertire il vettore
ottenendone un secondo contenente i valori corretti:
B = [2, 4, 7, 8, −35, −39, 3, 6, 5, −35, 39]
come possiamo notare i caratteri corrispondenti a
\n
(-35, -39) rimangono co-
stanti.
La successiva operazione consiste nel costruire un vettore i cui elementi siano i dati trasmessi dalla scheda Arduino, nell'esempio il vettore [2478,365];
operazione realizzata attraverso il seguente codice:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
A = f r e a d ( s , 1 0 , ' char ' ) ;
B = A− ' 0 ' ;
NxM = s i z e ( v a l o r i ) ;
n = NxM( 1 ) ;
numero_valori = 0 ;
i =1:n
( v a l o r i ( i )==−35)
numero_valori=numero_valori +1;
end
end
numero_cifre ( numero_valori ) = 0 ;
p o s i z i o n e _ s l a s h ( numero_valori ) = 0 ;
j =1;
i =1;
( i <n )
(B( i ) == − 35)
posizione_slash ( j ) = i ;
j=j +1;
end
( j >numero_valori )
for
if
while
if
if
31
Cap. 2
Gestione dell'hardware
Ÿ2.2
Gestione della comunicazione Arduino Matlab
21
i=n ;
22
end
23
( j<=numero_valori && (B( i ) ~= − 35) && (B( i ) ~= − 38) )
24
numero_cifre ( j ) = numero_cifre ( j ) +1;
25
end
26
i=i +1;
27 end
28 b u f f e r ( numero_valori ) = 0 ;
29
w=1: numero_valori ;
30
q=1: numero_cifre (w)
31
b u f f e r (w) = b u f f e r (w)+B( q +p o s i z i o n e _ s l a s h (w)
32
− numero_cifre (w) −1) ∗ 10^( numero_cifre (w)−q ) ;
33
end
34 end
if
for
for
Nel codice vengono deniti due vettori :
numero_cifre
e
posizione_slash;
gli elementi del primo indicano il numero di cifre dei singoli valori da ricevere:
nell'esempio precedente si ha
e
365
numero_cifre uguale a [4, 3] perchè i numeri 2478
sono composti rispettivemente da quattro e tre cifre.
Gli elementi del secondo, invece, indicano in quale posizione del vettore compare
il valore -35: nell'esempio si ha
posizione_slash
uguale a
[5, 10].
Combinando poi le informazioni contenute nei vettori descritti si ottiene il
vettore desiderato.
•
Ricezione dei dati proveninti da Matlab.
Come detto in precedenza i dati che vengono trasmessi da Matlab verso Arduino
sono a 16-bit; ne consegue che per trasmettere un valore verranno spediti due
byte e in ricezione si avranno, quindi, due valori ricevuti per ogni singolo valore
spedito da Matlab. Se il dato da trasmettere è minore di 256 uno dei due byte
ricevuti sarà nullo perchè è suciente un solo byte per esprimere numeri da
0 a 255; se, invece, il dato è maggiore di 256 verranno ricevuti due byte che
rappresentano il quoziente ed il resto della divisione tra interi
valore/256
La funzione seguente realizza la ricezione dei dati su Arduino.
32
Cap. 2
Gestione dell'hardware
Ÿ2.3
Gestione Sensori
if
1
( S e r i a l . a v a i l a b l e ( ) >0)
2 {
3
delay (10) ;
4
buffer [ Serial . available () ] ;
5
i =0;
6
( Serial . available () )
7
{
8
a = S e r i a l . read ( ) ;
9
S e r i a l . p r i n t l n ( a ,DEC) ;
10
buffer [ i ] = a ;
11
i ++;
12
}
13 }
int
while
La funzione
Serial.available()
restituisce il numero di dati presenti nel buer di
ricezione; se nel buer ci sono dati si verica la condizione logica del primo
if
e si
può eseguire il resto della funzione. All'interno del costrutto c'è un ritardo di 10ms
perché si deve attendere che tutti i dati vengano memorizzati nel buer e che quindi
la funzione
Serial.available()
restituisca il valore corretto. Viene denito un vet-
tore di grandezza opportuna e con un ciclo
while
vengono memorizzati nel vettore
i dati trasmessi dal software Matlab. A dierenza della comunicazione con i motor
mind, ora la funzione
di un costrutto
Serial.available()
si può utilizzare come condizione logica
while, questo perchè si stanno utilizzando le funzioni standard per la
gestione della porta seriale su Arduino e non funzioni della libreria NewSoftSerial.
2.3 Gestione Sensori
I sensori GP2D12 sono collegati agli input analogici della scheda Arduino. La funzione
che legge il valore dei sensori per ricavare la distanza di un oggetto che si trova nel
volume di scansione del robot, viene eseguita ad ogni ciclo della funzione
void loop()
di Arduino. Come detto nel paragrafo 1.1 il segnale generato dai sensori è funzione
non lineare della distanza a cui si trova un ostacolo; questa curva caratteristica è stata
33
Cap. 2
Gestione dell'hardware
Ÿ2.3
Gestione Sensori
approssimata a tratti via software.
Viene ora analizzato il codice che permette di determinare la distanza tra il robot ed
un eventuale ostacolo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int sensorPin_1 = 1 ;
int sensorValue_1 = 0 ;
double t e n s i o n e _ 1 = 0 ;
double d i s t a n z a _ o s t a c o l o _ 1 =
int d i s t a n z a 1 [ ] = { 0 , 0 , 0 , 0 ,
int media =0;
void s e t u p ( ) {}
void l o o p ( ) {
0;
0};
sensorValue_1 = analogRead ( sensorPin_1 ) ;
t e n s i o n e _ 1 = sensorValue_1 ∗ 5 / 1 0 2 3 . 0 ;
( tensione_1 < 0 . 4 )
{ d i s t a n z a _ o s t a c o l o _ 1 = 98 ; }
( 0 . 4 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 1 = − 150 ∗ t e n s i o n e _ 1 + 140 ; }
( 0 . 5 9 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −72∗ t e n s i o n e _ 1 + 96 ; }
( 0 . 8 1 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 1 = − 36.7 ∗ t e n s i o n e _ 1 + 66 ; }
( 1 . 1 5 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −18∗ t e n s i o n e _ 1 + 45 ; }
( 1 . 6 3 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −8∗ t e n s i o n e _ 1 + 2 8 . 5 ; }
( 2 . 6 <= t e n s i o n e _ 1 )
{ d i s t a n z a _ o s t a c o l o _ 1 = 99 ; }
distanza1 [4]= distanza1 [ 3 ] ;
distanza1 [3]= distanza1 [ 2 ] ;
distanza1 [2]= distanza1 [ 1 ] ;
distanza1 [1]= distanza1 [ 0 ] ;
distanza1 [0]= distanza_ostacolo_1 ;
distanza2 [4]= distanza2 [ 3 ] ;
distanza2 [3]= distanza2 [ 2 ] ;
distanza2 [2]= distanza2 [ 1 ] ;
distanza2 [1]= distanza2 [ 0 ] ;
distanza2 [0]= distanza_ostacolo_1 ;
(
( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 1 ] ) >10) | | ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 1 ] ) <−10) ) &&
( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 2 ] ) >10) | | ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 2 ] ) <−10) ) &&
( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 3 ] ) >10) | | ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 3 ] ) <−10) ) &&
( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 4 ] ) >10) | | ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 4 ] ) <−10) ) )
{ distanza1 [0]= distanza1 [ 1 ] ; }
media=( d i s t a n z a 1 [ 0 ] + d i s t a n z a 1 [ 1 ] + d i s t a n z a 1 [ 3 ] + d i s t a n z a 1 [ 2 ] + d i s t a n z a 1 [ 4 ] )
/5;
42
(
( ( ( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 1 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 1 ] )
>−5)) &&((( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 2 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 2 ] )
>−5)) &&((( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 3 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 3 ] )
>−5)) &&((( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 4 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 4 ] )
if
if
if
if
if
if
if
if
if
34
Cap. 2
43
44
45
46
47
48
49
50
51
Gestione dell'hardware
Ÿ2.3
Gestione Sensori
>−5)) )
{
media=d i s t a n z a 2 [ 0 ] ;
distanza1 [4]= distanza2
distanza1 [3]= distanza2
distanza1 [2]= distanza2
distanza1 [1]= distanza2
distanza1 [0]= distanza2
}
[4];
[3];
[2];
[1];
[0];
Il codice segue i seguenti passi logici:
•
denizione dell'ingresso a cui si riceve il segnale proveniente dal sensore;
•
lettura del valore di tensione sul pin di ingresso
sensorValue_1 = analogRead(sensorPin_1);
•
conversione in segnali digitali da un convertitore A-D a 10 bit dei segnali in
ingresso agli input analogici dell'Arduino.
Per questo ad una tensione di 5V corrisponde il valore 1024
(210 )e
ad una ten-
sione di 0V corrisponde il valore 0.
Per ottenere, quindi, il valore di tensione corretto, ricevuto sul pin anologico, si
esegue la proporzione:
5 : 1024 = tensione1 : sensorV alue1
•
lettura del valore della tensione ricevuta per ottenere il valore numerico della
distanza (espressa in cm), individuazione della porzione di tratto lineare interessato e successivo calcolo della distanza.
Come si può notare il segnale di tensione ricevuto varia da 0.4V a 2.6V: se si
riceve un valore al di fuori di questo range vengono arbitrariamente assegnati
valori di distanza corrispondenti a 98cm e 99cm.
35
Cap. 2
Gestione dell'hardware
Nella variabile
Ÿ2.3
distanza_ostacolo_1
Gestione Sensori
è ora presente il valore della distanza.
Il segnale trasmesso dai sensori è soggetto a rumore, perciò, lasciando il robot fermo
davanti ad un ostacolo è possibile che si misurino valori di distanza che presentano
una certa oscillazione rispetto al valore corretto. Per eliminare tale rumore si calcola
la media tra cinque misure di distanza: la misura attuale e le ultime quattro misure
calcolate; in tal modo viene, quindi, determinato un nuovo valore di distanza ad ogni
ciclo di scansione e considerando i tempi tipici di esecuzione di una istanza si ha
un aggiornamento della variabile
distanza_ostacolo_1
ogni 10ms circa. Dato che i
tempi caratteristici del robot sono, invece, dell'ordine dei secondi la misura attuale e
le quattro precedenti corrispondono tutte alla stessa distanza che c'è tra il robot ed
un ostacolo.
Il valore di distanza misurato ad ogni ciclo può essere, a volte, molto diverso dai
valori misurati in precedenza. Questo delta può derivare da un disturbo sulla misura
o essere conseguenza della rimozione dell'ostacolo da parte di un agente esterno: il
valore deve essere, quindi, ltrato se aetto da disturbo o, al contrario, memorizzato
se rappresentante la misura reale.
Per ottenere la corretta misura vengono creati
due vettori contenenti entrambi i quattro valori precedenti ed il valore attuale: nel
primo la misura attuale viene memorizzata indipendentemente dal suo valore; nel
secondo, invece, la misura attuale viene memorizzata solo se il delta che la separa
dalle precedenti non è maggiore di una quantità predenita.
Unendo le informazioni contenute nei due vettori si riesce, in tal modo, ad ottenere
una misura di distanza corretta in cui tutti i disturbi siano ltrati.
36
Cap. 2
Gestione dell'hardware
Ÿ2.4
Gestione Servomotore
2.4 Gestione Servomotore
Nel software di sviluppo programmi per Arduino è presente la libreria servo.h, contenente le funzioni utili alla gestione dei servomotori.
Per utilizzare questa libreria si seguono i seguenti passi:
#include <Servo.h>
•
inclusione della libreria attraverso l'istruzione
•
creazione di un oggetto di tipo servo con l'istruzione
;
Servo myservo;
.
Le funzioni principali di questa libreria sono:
•
myservo.attach(pin): ssa la variabile myservo al pin passato come argomento
della funzione;
•
myservo.write(pos): scrive un valore per il servo controllando l'albero motore di
conseguenza;
•
myservo.read(): legge la posizione angolare corrente dell'asse del servomotore.
37
Capitolo 3
Applicazioni
In questo capitolo verranno descritte le tre applicazioni realizzate
con il robot Octagon: il comando tramite pc, la funzione inseguimento ed il controllo di posizione.
Nella prima si è creata un'interfaccia graca per comandare il moto
del robot in modo che si muova in tutte le direzioni e con velocità
stabilite dall'utente; con la funzione inseguimento il robot segue autonomamente un oggetto in movimento cercando di interporre tra
sè e l'oggetto sempre la stessa distanza; il controllo posizione è fatto sui motori e migliora di molto le prestazioni del robot quando si
richiede una posizione angolare ben precisa.
3.1 Interfaccia graca di comando
L'interfaccia graca di comando è stata la prima applicazione che si è ritenuto opportuno creare; grazie alla trasmissione wireless di istruzioni di vario tipo si rende agevole
comandare il robot da una postazione remota. Essa è stata realizzata utilizzando il
software Matlab ed in particolare l'applicazione GUI (Graphical User Interface).
3.1.1
Creazione dell'applicazione GUI
Per creare un'applicazione GUI si esegue inizialmente l'istruzione
guide
nella com-
mand window Matlab, da cui appare una nestra che permette di creare un nuovo
progetto o di aprirne uno già esistente. Scegliendo di creare un lavoro ex-novo si ini-
38
Cap. 3
Applicazioni
Ÿ3.1
Interfaccia graca di comando
zierà a lavorare nella nestra mostrata in gura 3.1 Come si può notare, nella parte
Figura 3.1: Finestra di lavoro GUI
sinistra è presente un menù dal quale è possibile selezionare quali componenti inserire
nell'interfaccia graca.
Per il robot Octagon si è scelto di creare l'interfaccia mostrata in gura 3.2 In essa
sono presenti dei pulsanti per attivare il robot e delle caselle di testo per inserire i
parametri dei comandi quali: velocità di movimento; gradi che deve compiere il robot
e verso di rotazione; distanza da percorrere e numero di gradi di rotazione della torretta su cui sono montati i sensori.
Si spiega ora l'eetto di ogni comando sul robot:
•
AVANTI: comanda al robot di muoversi in avanti alla velocità specicata nella
casella velocità; con questo comando il robot si ferma solo nel caso in cui arrivi
ad una distanza di 15cm da un oggetto o venga premuto il comando ARRESTO;
39
Cap. 3
Applicazioni
Ÿ3.1
Interfaccia graca di comando
Figura 3.2: Interfaccia robot octagon
•
INDIETRO: il robot si muove indietro secondo le stesse modalità del comando
AVANTI;
•
ARRESTO: ferma il robot qualunque movimento esso stia compiendo;
•
RUOTA ROBOT: comanda al robot di ruotare, sul proprio asse verticale, di
una quantità indicata nella casella gradi e nel verso indicato nella casella verso
rotazione. Se nell'editor c'è il numero 0 la rotazione avviene in senso antiorario,
se c'è 1 avviene la rotazione avviene in senso orario;
•
PERCORRI DISTANZA: fa muovere il robot no a compiere la distanza denita
nella casella [ cm ]. Se nella casella verso distanza c'è il numero 1 la distanza è
percorsa in avanti, se c'è 0 la distanza è percorsa all'indietro;
•
RUOTA SENSORI: ruota la torretta di una quantità espressa nella casella
[gradi] ;
•
ACQUISISCI DISTANZA: viene visualizzata la distanza dell'oggetto che si trova
davanti al robot.
40
Cap. 3
Applicazioni
Ÿ3.1
Interfaccia graca di comando
Creata l'interfaccia in cui sono presenti tutti i componenti, Matlab genera automaticamente un M-le che contiene una funzione per ogni elemento presente nell'interfaccia:
nel momento in cui si interagisce con uno di essi (ad esempio viene premuto uno dei
pulsanti), viene richiamata la funzione associata al componente stesso. Per comandare il robot Octagon è suciente utilizzare solo due elementi: pulsanti ed editor di testo.
Le funzioni associate agli editor di testo eseguono un controllo sui valori inseriti,
in particolare vericano che essi appartengano al range ammesso. Si riporta di seguito
il codice associato all'editor Velocità.
1
2
3
4
5
6
7
8
9
10
f u n c t i o n v e l o c i t a _ C a l l b a c k ( hObject , e ve nt da ta , h a n d l e s )
v a l o r e = s t r 2 d o u b l e ( g e t ( hObject , ' S t r i n g ' ) ) ;
v a l o r e _ v e l o c i t=v a l o r e +1;
( v a l o r e _ v e l o c i t >255)
valore_velocit = 255;
end
( isempty ( v a l o r e _ v e l o c i t ) )
s e t ( hObject , ' S t r i n g ' , ' 0 ' )
end
g u i d a t a ( hObject , h a n d l e s ) ;
if
if
Quando si preme un pulsante la funzione associata ad esso esegue le seguenti
operazioni:
•
lettura delle stringhe presenti negli editor di testo interessati;
•
conversione della stringa in un numero double;
•
creazione del vettore da trasmettere al robot;
•
trasmissione del vettore.
Viene di seguito riportata la funzione associata al pulsante PERCORRI DISTANZA.
1 f u n c t i o n p e r c o r r i _ d i s t a n z a _ C a l l b a c k ( hObject , ev ent da ta , h a n d l e s )
2 display percorri_ditanza ;
3 a = get ( handles . distanza , ' String ' ) ;
41
Cap. 3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Applicazioni
Ÿ3.1
Interfaccia graca di comando
a = str2double (a) ;
b = get ( handles . velocita , ' String ' ) ;
b = str2double (b) ;
c = get ( handles . verso_distanza , ' String ' ) ;
c = str2double ( c ) ;
display (a) ;
vettore = [1 4 0 0 0 ] ;
vettore (3) = a ;
vettore (4) = b ;
vettore (5) = c ;
s = s e r i a l ( 'COM6 ' ) ;
s e t ( s , ' BaudRate ' , 1 9 2 0 0 ) ;
s e t ( s , ' DataBits ' , 8 ) ;
s e t ( s , ' StopBits ' , 1) ;
fopen ( s ) ;
fw r i te ( s , vettore , ' uint16 ' ) ;
fclose (s) ;
L'ordine in cui vengono memorizzati i dati all'interno del vettore, che verrà poi trasmesso al robot, denisce il protocollo di trasmissione da seguire. Il primo elemento
identica il robot a cui trasferire i dati (il protocollo prevede la trasmissione dei dati
a più robot presenti nello stesso ambiente); il secondo elemento identica il comando che il robot dovrà eseguire. Gli elementi successivi sono, invece, i parametri del
comando dato: se, ad esempio, si è richiesto di percorrere una distanza pressata il
terzo elemento sarà la distanza da percorrere, il quarto la velocità da utilizzare ed il
quinto il verso.
3.1.2
Elaborazione dati
Quando il robot deve essere comandato tramite l'interfaccia creata, viene caricato su
Arduino il programma che si occupa della gestione dei dati ricevuti e dell'azionamento
opportuno dei motori. Questo programma esegue ciclicamente tre passi:
1. lettura del valore di distanza fornito dai sensori;
2. lettura del buer di ricezione del modulo radio;
42
Cap. 3
Applicazioni
Ÿ3.1
Interfaccia graca di comando
3. interpretazione del vettore ricevuto e azionamento dei motori tramite opportune
funzioni.
Le funzioni che vengono richiamate permottono di far eseguire al robot il comando
richiesto da un utente che sta utilizzando l'interfaccia.
•
Avanti: è la funzione che viene richiamata quando un utente preme il pulsante
AVANTI. Essa controlla il primo bit del registro di stato di entrambi i motor
mind per controllare il verso di rotazione attuale di ogni singolo motore ed
esegue un cambiamento nel caso un cui la congurazione corrente non produca
un movimento in avanti del robot. Terminato il controllo aziona i motori alla
velocità desiderata;
void
int
int
1
avanti (
velocita )
2 {
3
temp=0;
4
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
5
mySerial_b . p r i n t ( 5 ,BYTE) ;
6
delay (10) ;
7
temp=mySerial_b . r e a d ( ) ;
8
( temp==40)
9
{
10
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
11
mySerial_b . p r i n t ( 1 ,BYTE) ;
12
}
13
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
14
mySerial_a . p r i n t ( 5 ,BYTE) ;
15
delay (10) ;
16
temp=mySerial_a . r e a d ( ) ;
17
( temp==41)
18
{
19
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
20
mySerial_a . p r i n t ( 1 ,BYTE) ;
21
}
22
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
23
mySerial_a . p r i n t ( 3 ,BYTE) ;
24
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
25
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
26
mySerial_b . p r i n t ( 3 ,BYTE) ;
27
mySerial_b . p r i n t ( v e l o c i t a +7,BYTE) ;
if
if
43
Cap. 3
•
Applicazioni
Ÿ3.1
Interfaccia graca di comando
INDIETRO: il robot si muove seguendo la stessa logica adoperata nel comando
Avanti, ma in questo caso retrocedendo;
•
ARRESTO: arresta i motori
void
1
arresto ()
2 {
3
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
4
mySerial_a . p r i n t ( 0 ,BYTE) ;
5
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
6
mySerial_b . p r i n t ( 0 ,BYTE) ;
7 }
•
PERCORRI DISTANZA: calcola il numero di passi encoder necessari anchè
la rotazione del motore produca lo spostamento lineare richiesto. Come nella
funzione Avanti si ha il controllo del primo bit del registro di stato.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void p e r c o r r i _ d i s t a n z a ( int
int a n g o l o _ r a d i a n t i ;
int a n g o l o _ g r a d i ;
{
distanza ,
int
velocita ,
int
verso )
angolo_radianti = ( distanza ∗0.01) /0.027;
angolo_gradi = angolo_radianti ∗180/3.141457;
gradiDes = angolo_gradi ;
i m p u l s i =0;
numero_giri =0;
alfa ;
beta ;
k;
k = (283.0/360.0) ;
i m p u l s i=k ∗ g r a d i D e s ;
( i m p u l s i >256)
{
numero_giri=i m p u l s i / 2 5 6 ;
a l f a=numero_giri ;
b e t a=i m p u l s i − (256 ∗ a ) ;
}
double
double
int
int
int
double
if
else
{
a l f a =0;
b e t a=i m p u l s i ;
}
temp=0;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 6 ,BYTE) ;
mySerial_a . p r i n t ( a l f a ,BYTE) ;
mySerial_a . p r i n t ( beta ,BYTE) ;
int
44
Cap. 3
31
32
33
34
35
36
37
Applicazioni
Ÿ3.2
Modellizzazione del sistema
mySerial_a . p r i n t l n ( v e l o c i t a ,BYTE) ;
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 6 ,BYTE) ;
mySerial_b . p r i n t ( a l f a ,BYTE) ;
mySerial_b . p r i n t ( beta ,BYTE) ;
mySerial_b . p r i n t l n ( v e l o c i t a +7,BYTE) ;
}
Nel codice non è riportata la porzione in cui si esegue il controllo del registro di
stato che è uguale a quello della funzione precedente.
•
RUOTA ROBOT: come Percorri Distanza, ma, in questo caso, il primo bit del
registro di stato dei due motor mind viene impostato in modo da produrre una
rotazione del robot.
•
RUOTA SENSORI: controlla la posizione angolare dell'asse del servomotore.
void
1
ruota_sensori (
2 {
3 myservo . w r i t e ( pos ) ;
4 }
int
pos )
3.2 Modellizzazione del sistema
Prima di spiegare le due applicazioni di controllo è opportuno ricavare un modello matematico del robot. Il robot Octagon può essere rappresentato dallo schema mostrato
in gura 3.3. Il motor mind riceve in ingresso lo scalare 'u' (che può variare tra 0 e
Figura 3.3: Modello matematico del sistema
45
Cap. 3
Applicazioni
Ÿ3.3
Controllo distanza
255) e fornisce un valore di tensione direttamente proporzionale a tale variabile. Tutta
la parte elettrica del motore è approssimata con un blocco di guadagno di Ke che ricevendo la tensione v in entrata fornisce una corrente i. Nei motori a corrente continua
si può approssimare la coppia come una grandezza direttamente proporzionale alla
corrente e quindi attraverso un altro blocco Km si ottiene la coppia motrice fornita
dal motore. A tale valore è poi sottratto quello della coppia di carico opportunamente
diviso per il rapporto di riduzione n ottenendo la coppia utile. L'ultimo blocco, quello
che da la posizione angolare dell'albero motore, è ricavato dalla seguente equazione:
Cu = J · α + d · ω
dove
α
e
ω
(3.2.1)
sono rispettivamente l'accalerazione e la velocità angolare, J il momento
di inerzia e d il coeciente di attrito. La funzione di trasferimento di questo sistema
non è stata ricavata ma viene presa da una precedente tesi ed è la seguente:
F DT =
−0.058122(z − 2.958)
(z − 1)(z − 0.6671)(z 2 + 0.548z + 0.2061)
(3.2.2)
Su questa FDT sono fatte le due successive applicazioni.
3.3 Controllo distanza
La seconda applicazione realizzata per il robot Octagon è stata la funzione di insegui-
mento. In questo caso il robot interagisce autonomamente con l'ambiente esterno: nel
momento in cui i sensori non rilevano nessun ostacolo il robot rimane fermo, se invece
riscontrano la presenza di un ostacolo il robot si posiziona ad una distanza di 30cm
da esso, indierentemente dal fatto che la distanza iniziale sia minore o maggiore di
30cm.
Per realizzare tale applicazione è stato creato sia un sistema di controllo a ciclo chiuso
di tipo proporzionale.
46
Cap. 3
Applicazioni
Ÿ3.3
Controllo distanza
Figura 3.4: Schema a blocchi funzione inseguimento
Figura 3.5: Posizionamento sensori
Ad ogni ciclo il programma controlla il valore di distanza fornito dal sensore numero
1 e denisce la variabile errore come la dierenza tra il valore letto dal sensore numero
uno e la costante 30:
errore = distanza1 − 30
la variabile errore è poi moltiplicata per una costante ed il risultato trasmesso alla
funzione del motor mind che controlla la velocità del motoriduttore. Queste appena
descritte sono le operazioni principali del programma, ma vengono eseguite anche altre
istruzioni che stabiliscono, ad esempio, l'avanzamento o la retrocessione del robot, o
rilevano se il valore di velocità esce dal range ammesso dal comando del motor mind.
SETDC.
1 e r r o r e = media − 30;
2 v e l o c i t a=e r r o r e ∗ 1 5 ;
3
( ( media==0)&&check1 )
4 {
if
47
Cap. 3
Applicazioni
Ÿ3.3
Controllo distanza
5
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
6
mySerial_b . p r i n t ( 0 ,BYTE) ;
7
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
8
mySerial_a . p r i n t ( 0 ,BYTE) ;
9
check1=f a l s e ;
10 }
11
( media >0)
12 {
13
( ( ( e r r o r e >10) | | ( e r r o r e <−10) ) )
14
{
15
check=t r u e ;
16
}
17
( check )
18 {
19
check1=t r u e ;
20
( e r r o r e <0)
21
{
22
v e l o c i t a=v e l o c i t a ∗ ( − 1) ;
23
}
24
( ( e r r o r e >0)&&(temp==40)&&(temp_a==41) ) // s e l ' e r r o r e è p o s i t i v o
muovi a v a n t i
25
{
26
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
27
mySerial_b . p r i n t ( 1 ,BYTE) ;
28
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
29
mySerial_a . p r i n t ( 1 ,BYTE) ;
30
temp =41;
31
temp_a=40;
32
}
33
( ( e r r o r e <0)&&(temp==41)&&(temp_a=40) ) // s e l ' e r r o r e è n e g a t i v o muovi
indietro
34
{
35
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
36
mySerial_b . p r i n t ( 1 ,BYTE) ;
37
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
38
mySerial_a . p r i n t ( 1 ,BYTE) ;
39
temp =40;
40
temp_a=41;
41 }
42
( v e l o c i t a >240)
43
{ v e l o c i t a =240;}
44
( v e l o c i t a <80)
45
{ v e l o c i t a =80;}
46
( ( e r r o r e <8)&&(e r r o r e >−8))
47
{
48
v e l o c i t a =0;
49
check=f a l s e ;
50
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
51
mySerial_b . p r i n t ( 0 ,BYTE) ;
52
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
53
mySerial_a . p r i n t ( 0 ,BYTE) ;
if
if
if
if
if
if
if
if
if
48
Cap. 3
54
55
56
57
58
59
60
61
62 }
Applicazioni
Ÿ3.4
Controllo di posizione
}
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 3 ,BYTE) ;
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
}
3.4 Controllo di posizione
Il motor mind ha la possibilità di eseguire una funzione denominata COUNT, che
riceve come parametri due interi x ed y, dove: il parametro x identica il numero di
passi encoder che il motore ruotando dovrà contare ed il parametro y è la velocità a
cui il robot deve muoversi. Questa funzione fornisce al motore una tensione, tale da
produrre una rotazione dell'albero alla velocità stabilita: la tensione viene fornita no
a quando il numero di passi encoder attuali è minore del numero di passi encoder richiesti; non appena questi due valori coincidono la funzione toglie tensione al motore.
Si deve tener conto del fatto che il motor mind a volte perde la misura di qualche
passo encoder e che l'inerzia del motore produce una rotazione ulteriore dell'albero
motore per il quale esso non si arresta nel momento esatto in cui viene tolta tensione;
ciò causa un errore di posizionamento, errore che cresce all'aumentare del numero di
passi encoder richiesti. Ne consegue che per grandi distanze l'errore accumulato avrà
un valore troppo elevato e non potrà essere trascurato.
L'ultima applicazione è propriamente un controllo di posizione che migliora signicativamente le prestazioni del robot.
In questo caso il segnale digitale prodotto
dall'encoder è trasmesso sia al M.M.B.e. sia alla scheda Arduino, che come detto in
precedenza è dotata di due pin per la ricezione di Interrupt esterni. Il segnale prodotto
dall'encoder ad eetto hall è un segnale digitale il cui valore logico 1 corrisponde ad
49
Cap. 3
Applicazioni
Ÿ3.4
Controllo di posizione
una tensione di circa 1.2V: per ottenere, quindi, un segnale digitale che possa variare
da 0V a 5V si usa un resistore di pull-up come mostrato in gura 3.6.
Per gestire
Figura 3.6: Schema collegamento encoder-Arduino
questo segnale di interrupt connesso al pin 3 la scheda Arduino utilizza la funzione
attachInterrupt(1,inc,CHANGE);
dove il numero 1 indica l'interrupt del pin 3 (se
ci fosse stato 0 si sarebbe indicato l'interrupt del pin 2), la stringa
inc
è il nome
della funzione che viene richiamata ogni qualvolta si verica la condizione impostata
come terzo parametro nella funzione
to
CHANGE
ovvero la funzione
inc
attachInterrupt.
è richiamata ogni volta che il segnale di interrupt
esegue una transizione da un livello logico ad un altro.
due modalità
RISING
e
FALLING,
In questo caso si è imposta-
in cui la funzione
inc
Si possono impostare altre
è richiamata solo quando si
verica una transizione del segnale da zero ad uno (RISING) o solo quando si verica
una transizione del segnale da uno a zero (FALLING).
Per realizzare l'applicazione è stato creato un piccolo sistema di controllo proporzionale integrale.
1
2
3
4
5
6
7
8
void
( setup )
{
a t t a c h I n t e r r u p t ( 1 , incremento , FALLING) ;
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_b . r e a d ( ) ;
( temp==40)
if
50
Cap. 3
Applicazioni
Ÿ3.4
Controllo di posizione
Figura 3.7: Schema a blocchi controllo posizione
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
temp =41;
}
check=t r u e ;
}
loop ()
{
e r r o r e= i m p u l s i −e n c o d e r ;
v e l o c i t a=e r r o r e ;
( ( e r r o r e >10) | | ( e r r o r e <−10) )
{
check=t r u e ;
}
( check )
{
( e r r o r e <0){
v e l o c i t a=v e l o c i t a ∗ ( − 1) ;
}
void
if
if
if
if ( ( e r r o r e >0)&&(temp==40) )
{
}
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
temp =41;
if ( ( e r r o r e <0)&&(temp==41) )
{
}
if
{
}
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
temp =40;
( v e l o c i t a >255)
v e l o c i t a =255;
51
Cap. 3
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
if
{
}
Applicazioni
Ÿ3.4
Controllo di posizione
( v e l o c i t a <80)
v e l o c i t a =80;
if ( ( e r r o r e <2)&&(e r r o r e >−2))
{
v e l o c i t a =0;
check=f a l s e ;
}
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a ,BYTE) ;
}
delay (100) ;
}
void i n c r e m e n t o ( )
if ( temp==41)
{ e n c o d e r ++;}
if ( temp==40)
{
{ encoder −−;}
}
Nel codice sono presenti una serie di controlli per ottenere il movimento corretto del
robot:
•
il verso di rotazione del motore è determinato dal valore logico assunto dal primo
bit del registro di stato del motor mind, il quale viene letto e modicato nel caso
in cui il robot debba muoversi nel verso opposto;
•
la velocità imposta al robot deve rientrare nel range di ammissibilità della funzione SETDC, la quale ammette solo valori compresi tra 0 e 255; nel caso in cui
l'errore sia molto grande il valore velocità, calcolato come termine proporzionale
rispetto all'errore, esce dal suddetto range ed è saturato al valore massimo ammissibile, ovvero 255. Cosa analoga accade quando l'errore è piccolo: il robot,
infatti, presenta una massa non trascurabile ed è per questo che valori compresi
52
Cap. 3
Applicazioni
Ÿ3.4
Controllo di posizione
tra 0 e 80 non producono nessuno spostamento.
Nel codice è riportata, inne, anche la funzioneincremento(), che è la funzione richiamata da
attacInterrupt quando si ha il passaggio del segnale digitale, prodotto
dall'encoder, dal livello logico alto al livello logico basso. Purtroppo questa applicazione è stata realizzata per un solo motore, perchè il pin digitale numero 2 (ovvero
l'interrupt 0) ha un assorbimento di corrente troppo elevato e non riesce, quindi, a
rilevare le transizioni presenti nel segnale digitale prodotto dall'encoder.
53
Conclusioni e sviluppi futuri
Con il presente lavoro è stata realizzata un'unità robotica mobile di tipo dierenziale
che potrà essere utilizzata per creare un sistema robotico più complesso nel quale uno
o più robot potranno interagire tra di loro, collaborare con un'unità di supervisione e
controllo o compiere simultaneamente entrambe le cose.
Le scelte hardware hanno permesso di realizzare un'unità economica ed espandibile
al tempo stesso, utilizzabile per la simulazione di sistemi multirobot (ad esempio
un incrocio stradale), sorveglianza, mapping o per rilevazioni di vario genere.
In
particolare ogni robot, grazie alla sua modularità, potrà essere ampliato e dotato di
sensori specici per le diverse applicazioni in cui verrà utilizzato.
Le prime modiche che potranno essere applicate al robot sono:
•
inserimento di un fotoaccoppiatore tra l'Arduino e il modulo radio ER400TRS;
•
studio dell'interrupt 0 per collegare entrambi gli encoders dei motori alla scheda
Arduino;
•
trasmissione alla scheda Arduino dei segnali prodotti dai sensori utilizzando il
protocollo di comunicazione
•
I 2C ,
già prevista sul microcontrollore;
realizzazione di una PCB in modo da avere un sistema più robusto a sollecitazioni meccaniche e più stabile elettricamente.
54
Conclusioni e sviluppi futuri
Un'ultima modica potrà essere quella di sostituire l'attuale batteria al piombo con
una più leggera che mantenga la stessa carica elettrica, avendo, però, cura di non utilizzare una batteria eccessivamente leggera che, diminuendo troppo il carico, potrebbe
creare fenomeni di slittameto.
55
Appendice
Listato
Programma per il controllo di posizione sul motore
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// i n c l u d e t h e S o f t w a r e S e r i a l l i b r a r y so you can use i t s f u n c t i o n s :
#include <N e w S o f t S e r i a l . h>
// d e f i n e p i n o f
rxPin_a
txPin_a
rxPin_b
txPin_b
#define
#define
#define
#define
s e r i a l communications
4
5
7
8
// b y t e d i r i c e z i o n e
byte incomingByte = 0 ;
incomingByte1 = 0 ;
int
// s e t up a new s e r i a l p o r t
N e w S o f t S e r i a l mySerial_a = N e w S o f t S e r i a l ( rxPin_a , txPin_a ) ;
N e w S o f t S e r i a l mySerial_b = N e w S o f t S e r i a l ( rxPin_b , txPin_b ) ;
b o o l e a n check ;
double g r a d i D e s =1800;
double i m p u l s i =0;
int a =0;
int a l f a ;
int b e t a ;
int i =0;
int j =0;
int b u f f e r 1 [ 2 ] ;
int v=0;
double k ;
volatile int e n c o d e r =
int e r r o r e =0;
int v e l o c i t a =0;
int temp=0;
void s e t u p ( )
0;
56
Appendice
36 {
37
a t t a c h I n t e r r u p t ( 1 , incremento , FALLING) ;
38 // d e f i n e p i n modes f o r tx , rx , l e d p i n s :
39
pinMode ( rxPin_a , INPUT) ;
40
pinMode ( txPin_a , OUTPUT) ;
41
pinMode ( rxPin_b , INPUT) ;
42
pinMode ( txPin_b , OUTPUT) ;
43
44
// s e t t h e d a t a r a t e f o r t h e S o f t w a r e S e r i a l p o r t
45
S e r i a l . begin (9600) ;
46
mySerial_a . b e g i n ( 9 6 0 0 ) ;
47
mySerial_b . b e g i n ( 9 6 0 0 ) ;
48 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . c a l c o l o d e i
p a s s i encoder da e s e g u i r e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49 k = ( 2 8 3 . 1 1 / 3 6 0 . 0 ) ;
50 i m p u l s i=k ∗ g r a d i D e s ;
51
( i m p u l s i >256)
52
{
53
a=i m p u l s i / 2 5 6 ;
54
a l f a=a ;
55
b e t a=i m p u l s i − (256 ∗ a ) ;
56
}
57
58
{
59
a l f a =0;
60
b e t a=i m p u l s i ;
61
}
62 S e r i a l . p r i n t ( " g r a d i D e s : " ) ;
63 S e r i a l . p r i n t l n ( g r a d i D e s ) ;
64 S e r i a l . p r i n t ( " i m p u l s i da e s e g u i r e : " ) ;
65 S e r i a l . p r i n t l n ( i m p u l s i ) ;
66 S e r i a l . p r i n t ( " p a r t e i n t e r a d e i g i r i e f f e t t u a t i d a l motore : " ) ;
67 S e r i a l . p r i n t l n ( a ) ;
68 S e r i a l . p r i n t ( " a l f a : " ) ;
69 S e r i a l . p r i n t l n ( a l f a ) ;
70 S e r i a l . p r i n t ( " b e t a : " ) ;
71 S e r i a l . p r i n t l n ( b e t a ) ;
72
73 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . movimentazione
de l robot in avanti
74 mySerial_b . p r i n t ( 8 5 ,BYTE) ;
75 mySerial_b . p r i n t ( 5 ,BYTE) ;
76 d e l a y ( 1 0 ) ;
77 temp=mySerial_b . r e a d ( ) ;
78
( temp==40)
79 {
80 mySerial_b . p r i n t ( 8 5 ,BYTE) ;
81 mySerial_b . p r i n t ( 1 ,BYTE) ;
82 temp =41;
83 }
84 //
if
else
if
57
Appendice
..................................................................................
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
check=t r u e ;
}
111
112
113
114
115
116
117
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
temp =41;
}
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
temp =40;
}
void
loop ()
{
e r r o r e= i m p u l s i −e n c o d e r ;
v e l o c i t a=e r r o r e ;
( ( e r r o r e >10) | | ( e r r o r e <−10) )
{
check=t r u e ;
}
( check )
{
/∗
mySerial_b . p r i n t ( 8 5 ,BYTE) ; / / . . . . . . . . . . l e g g i i l r e g i s t r o d i s t a t o
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_b . read ( ) ;
∗/
if
if
if
( e r r o r e <0) // . . . . . . . . . . . . . . . . . . . . . . . . imponi sempre v e l o c i t à p o s i t i v a
{
v e l o c i t a=v e l o c i t a ∗ ( − 1) ;
}
if ( ( e r r o r e >0)&&(temp==40) ) // . . . . . . . . . . s e
avanti
l ' e r r o r e è p o s i t i v o muovi
if ( ( e r r o r e <0)&&(temp==41) ) // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . s e
n e g a t i v o muovi i n d i e t r o
l ' errore è
if
if
if
( v e l o c i t a >240)
{ v e l o c i t a =240;}
( v e l o c i t a <80)
{ v e l o c i t a =80;}
( ( e r r o r e <2)&&(e r r o r e >−2))
{ v e l o c i t a =0;
check=f a l s e ; }
58
Appendice
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a ,BYTE) ;
}
delay (100) ;
S e r i a l . p r i n t l n ( e r r o r e ,DEC) ;
/ ∗ i f ( c h e c k==f a l s e )
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( 1 7 5 ,BYTE) ;
delay (1000) ;
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 0 ,BYTE) ;
} ∗/
}
void i n c r e m e n t o ( )
if ( temp==41)
{ e n c o d e r ++;}
if ( temp==40)
{
{ encoder −−;}
}
Programma per la comunicazione con interfaccia graca
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// i n c l u d e t h e S o f t w a r e S e r i a l l i b r a r y so you can use i t s f u n c t i o n s :
#include <N e w S o f t S e r i a l . h>
#include <Servo . h>
// d e f i n e p i n o f s e r i a l communications
#define rxPin_a 4
#define txPin_a 5
#define rxPin_b 7
#define txPin_b 8
// b y t e d i r i c e z i o n e
byte incomingByte = 0 ;
incomingByte1 = 0 ;
int
// s e t up a new s e r i a l p o r t
N e w S o f t S e r i a l mySerial_a = N e w S o f t S e r i a l ( rxPin_a , txPin_a ) ;
N e w S o f t S e r i a l mySerial_b = N e w S o f t S e r i a l ( rxPin_b , txPin_b ) ;
// c r e a t e s e r v o o b j e c t t o c o n t r o l a s e r v o
// a maximum o f e i g h t s e r v o o b j e c t s can be c r e a t e d
Servo myservo ;
59
Appendice
23 byte p i n S t a t e = 0 ;
24
25
grandezza_vettore ;
26
i;
27
a;
28
j;
29
30
sensorPin_1 = 1 ;
// s e l e c t t h e i n p u t p i n f o r t h e p o t e n t i o m e t e r
31
sensorPin_2 = 2 ;
// s e l e c t t h e i n p u t p i n f o r t h e p o t e n t i o m e t e r
32
sensorPin_3 = 3 ;
33
sensorPin_4 = 4 ;
34
35
sensorValue_1 = 0 ; // v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
sensor
36
sensorValue_2 = 0 ; // v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
sensor
37
sensorValue_3 = 0 ; // v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
sensor
38
sensorValue_4 = 0 ; // v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
sensor
39
40
41
tensione_1 = 0 ;
42
tensione_2 = 0 ;
43
tensione_3 = 0 ;
44
tensione_4 = 0 ;
45
46
47
distanza_ostacolo_1 = 0;
48
distanza_ostacolo_2 = 0;
49
distanza_ostacolo_3 = 0;
50
distanza_ostacolo_4 = 0;
51
52
vettore_distanze [ 4 ] ;
53
54
setup ()
55 {
56
// a t t a c h e s t h e s e r v o on p i n 9 t o t h e s e r v o o b j e c t
57
myservo . a t t a c h ( 9 ) ;
58
59
// d e f i n e p i n modes f o r tx , rx , l e d p i n s :
60
pinMode ( rxPin_a , INPUT) ;
61
pinMode ( txPin_a , OUTPUT) ;
62
pinMode ( rxPin_b , INPUT) ;
63
pinMode ( txPin_b , OUTPUT) ;
64
65
// s e t t h e d a t a r a t e f o r t h e S o f t w a r e S e r i a l p o r t
66
S e r i a l . begin (19200) ;
67
mySerial_a . b e g i n ( 9 6 0 0 ) ;
68
mySerial_b . b e g i n ( 9 6 0 0 ) ;
69
int
int
int
int
int
int
int
int
int
int
int
int
double
double
double
double
double
double
double
double
int
void
60
Appendice
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
}
void
{
loop ()
// . . . . . . . . . . . . . . . . . . . . . . . read t h e v a l u e from t h e s e n s o r :
sensorValue_1 = analogRead ( sensorPin_1 ) ;
sensorValue_2 = analogRead ( sensorPin_2 ) ;
sensorValue_3 = analogRead ( sensorPin_3 ) ;
sensorValue_4 = analogRead ( sensorPin_4 ) ;
// . . . . . . . . . . . . . . . . . . . . . . . . c o n v e r s i o n e v a l o r e l e t t o d a l s e n s o r e i n
tensione
t e n s i o n e _ 1 = sensorValue_1 ∗ 5 / 1 0 2 3 . 0 ;
t e n s i o n e _ 2 = sensorValue_2 ∗ 5 / 1 0 2 3 . 0 ;
t e n s i o n e _ 3 = sensorValue_3 ∗ 5 / 1 0 2 3 . 0 ;
t e n s i o n e _ 4 = sensorValue_4 ∗ 5 / 1 0 2 3 . 0 ;
// . . . . . . . . . . . . . . . . . . . . c o n v e r s i o n e v a l o r e l e t t o d i s t a n z a
( tensione_1 < 0 . 4 )
{ distanza_ostacolo_1 = 0 ;}
if
if
( 0 . 4 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 1 = − 150 ∗ t e n s i o n e _ 1 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −72∗ t e n s i o n e _ 1 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 1 = − 36.7 ∗ t e n s i o n e _ 1 + 66 ; }
if
( 1 . 1 5 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −18∗ t e n s i o n e _ 1 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −8∗ t e n s i o n e _ 1 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 1 )
{ d i s t a n z a _ o s t a c o l o _ 1 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
( tensione_2 < 0 . 4 )
{ distanza_ostacolo_2 = 0 ;}
if
if
( 0 . 4 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 2 = − 150 ∗ t e n s i o n e _ 2 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 2 = −72∗ t e n s i o n e _ 2 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 2 = − 36.7 ∗ t e n s i o n e _ 2 + 66 ; }
61
Appendice
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
if
( 1 . 1 5 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 2 = −18∗ t e n s i o n e _ 2 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 2 = −8∗ t e n s i o n e _ 2 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 2 )
{ d i s t a n z a _ o s t a c o l o _ 2 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−
( tensione_3 < 0 . 4 )
{ distanza_ostacolo_3 = 0 ;}
if
if
( 0 . 4 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 3 = − 150 ∗ t e n s i o n e _ 3 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 3 = −72∗ t e n s i o n e _ 3 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 3 = − 36.7 ∗ t e n s i o n e _ 3 + 66 ; }
if
( 1 . 1 5 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 3 = −18∗ t e n s i o n e _ 3 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 3 = −8∗ t e n s i o n e _ 3 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 3 )
{ d i s t a n z a _ o s t a c o l o _ 3 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
( tensione_4 < 0 . 4 )
{ distanza_ostacolo_4 = 0 ;}
if
if
( 0 . 4 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 4 = − 150 ∗ t e n s i o n e _ 4 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 4 = −72∗ t e n s i o n e _ 4 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 4 = − 36.7 ∗ t e n s i o n e _ 4 + 66 ; }
if
( 1 . 1 5 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 4 = −18∗ t e n s i o n e _ 4 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 4 = −8∗ t e n s i o n e _ 4 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 4 )
{ d i s t a n z a _ o s t a c o l o _ 4 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
62
Appendice
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/ ∗ v e t t o r e _ d i s t a n z e [0]= d i s t a n z a _ o s t a c o l o _ 1 ;
v e t t o r e _ d i s t a n z e [1]= d i s t a n z a _ o s t a c o l o _ 2 ;
v e t t o r e _ d i s t a n z e [2]= d i s t a n z a _ o s t a c o l o _ 3 ;
v e t t o r e _ d i s t a n z e [3]= d i s t a n z a _ o s t a c o l o _ 4 ;
S e r i a l . p r i n t (" d i s t a n z a 1 ") ;
S e r i a l . p r i n t ( distanza_ostacolo_1 , 1 ) ;
S e r i a l . p r i n t (" | | ") ;
S e r i a l . p r i n t (" d i s t a n z a 2 ") ;
S e r i a l . p r i n t ( distanza_ostacolo_1 , 1 ) ;
S e r i a l . p r i n t (" | | ") ;
S e r i a l . p r i n t (" d i s t a n z a 3 ") ;
S e r i a l . p r i n t ( distanza_ostacolo_ ,1 ) ;
S e r i a l . p r i n t (" | | ") ;
S e r i a l . p r i n t (" d i s t a n z a 4 ") ;
S e r i a l . p r i n t l n ( distanza_ostacolo_4 , 1 ) ;
d e l a y ( 1 0 0 0 ) ; ∗/
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f i n e l e t t u r a s e n s o r i
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− l e t t u r a d a t i da matlab
( S e r i a l . a v a i l a b l e ( ) >0)
{
delay (10) ;
grandezza_vettore = S e r i a l . a v a i l a b l e () ;
buffer [ Serial . available () ] ;
i =0;
( Serial . available () )
{
// S e r i a l . p r i n t (" d a t i d i s p o n i b i l i : ") ;
// S e r i a l . p r i n t l n ( S e r i a l . a v a i l a b l e ( ) ,DEC) ;
a = S e r i a l . read ( ) ;
// S e r i a l . p r i n t l n ( a ) ;
buffer [ i ] = a ;
i ++;
}
( i =0; i <g r a n d e z z a _ v e t t o r e ; i ++)
{
Serial . print (" buffer ") ;
S e r i a l . p r i n t ( i ,DEC) ;
Serial . print (" : ") ;
S e r i a l . p r i n t l n ( b u f f e r [ i ] ,DEC) ;
}
( b u f f e r [2]==3) //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e a v a n t i
{
avanti ( b u f f e r [4]+ b u f f e r [ 5 ] ∗ 2 5 6 ) ;
}
( b u f f e r [2]==2) //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e
indietro
218
{
219
i n d i e t r o ( b u f f e r [4]+ b u f f e r [ 5 ] ∗ 2 5 6 ) ;
220
}
if
int
while
for
if
if
63
Appendice
221
if
222
223
224
225
226
if
227
228
229
230
if
231
232
233
234
235
236
237
238
239
if
if
( b u f f e r [2]==1) //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e
arresto
{
arresto () ;
// S e r i a l . p r i n t l n (" a r r e s t o ") ;
}
( b u f f e r [2]==4) //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e
percorri distanza
{
percorri_distanza ( b u f f e r [4]+ b u f f e r [ 5] ∗2 56 , b u f f e r [6]+ b u f f e r [ 7]∗2 56 ,
buffer [8]) ;
}
( b u f f e r [2]==5) //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e r u o t a
robot
{
ruota_robot ( b u f f e r [ 4 ] + b u f f e r [ 5 ] ∗ 2 5 6 , b u f f e r [ 8 ] , b u f f e r [ 6 ] + b u f f e r
[7]∗256) ;
}
( b u f f e r [2]==6) //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e r u o t a
sensori
{
ruota_sensori ( buffer [ 4 ] ) ;
}
}
(((10 < d i s t a n z a _ o s t a c o l o _ 1 )&&(d i s t a n z a _ o s t a c o l o _ 1 <15) ) | | ( ( 1 0 <
d i s t a n z a _ o s t a c o l o _ 2 )&&(d i s t a n z a _ o s t a c o l o _ 2 <15) ) | | ( ( 1 0 <
d i s t a n z a _ o s t a c o l o _ 3 )&&(d i s t a n z a _ o s t a c o l o _ 3 <15) ) | | ( ( 1 0 <
d i s t a n z a _ o s t a c o l o _ 4 )&&(d i s t a n z a _ o s t a c o l o _ 4 <15) ) )
{
arresto () ;
}
240
241
242
243 }
244 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f i n e v o i d loop
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
245
246
247 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e a v a n t i
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
248
avanti (
velocita )
249 {
250
temp=0;
251
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
252
mySerial_b . p r i n t ( 5 ,BYTE) ;
253
delay (10) ;
254
temp=mySerial_b . r e a d ( ) ;
255
( temp==40)
256
{
257
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
258
mySerial_b . p r i n t ( 1 ,BYTE) ;
259
}
260
void
int
int
if
64
Appendice
261
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
262
mySerial_a . p r i n t ( 5 ,BYTE) ;
263
delay (10) ;
264
temp=mySerial_a . r e a d ( ) ;
265
( temp==41)
266
{
267
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
268
mySerial_a . p r i n t ( 1 ,BYTE) ;
269
}
270
271
272
273
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
274
mySerial_a . p r i n t ( 3 ,BYTE) ;
275
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
276
277
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
278
mySerial_b . p r i n t ( 3 ,BYTE) ;
279
mySerial_b . p r i n t ( v e l o c i t a +7,BYTE) ;
280 }
281 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e i n d i e t r o
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
282
indietro (
velocita )
283 {
284
285
temp=0;
286
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
287
mySerial_b . p r i n t ( 5 ,BYTE) ;
288
delay (10) ;
289
temp=mySerial_b . r e a d ( ) ;
290
( temp==41)
291
{
292
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
293
mySerial_b . p r i n t ( 1 ,BYTE) ;
294
}
295
296
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
297
mySerial_a . p r i n t ( 5 ,BYTE) ;
298
delay (10) ;
299
temp=mySerial_a . r e a d ( ) ;
300
( temp==40)
301
{
302
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
303
mySerial_a . p r i n t ( 1 ,BYTE) ;
304
}
305
306
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
307
mySerial_a . p r i n t ( 3 ,BYTE) ;
308
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
309
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
310
mySerial_b . p r i n t ( 3 ,BYTE) ;
if
void
int
int
if
if
65
Appendice
311
mySerial_b . p r i n t ( v e l o c i t a +7,BYTE) ;
312 }
313
314 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e a r r e s t o
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
315
arresto ()
316 {
317
// S e r i a l . p r i n t (" e s e g u i a r r e s t o ") ;
318
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
319
mySerial_a . p r i n t ( 0 ,BYTE) ;
320
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
321
mySerial_b . p r i n t ( 0 ,BYTE) ;
322 }
323
324 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e p e r c o r r i
d i s t a n z a −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
325
percorri_distanza (
distanza ,
velocita ,
verso )
326 {
327
distanza1 ;
328 d i s t a n z a 1= d i s t a n z a − d i s t a n z a ∗ ( 0 . 0 8 ) ;
329
angolo_radianti ;
330
angolo_gradi ;
331 a n g o l o _ r a d i a n t i = ( d i s t a n z a 1 ∗ 0 . 0 1 ) / 0 . 0 2 7 ;
332 a n g o l o _ g r a d i = a n g o l o _ r a d i a n t i ∗ 1 8 0 / 3 . 1 4 1 4 5 7 ;
333 // S e r i a l . p r i n t l n ( angolo_gradi ,DEC) ;
334
gradiDes = angolo_gradi ;
335
i m p u l s i =0;
336
numero_giri =0;
337
alfa ;
338
beta ;
339
i =0;
340
k;
341
342
343 k = ( 2 8 3 . 0 / 3 6 0 . 0 ) ;
344 i m p u l s i=k ∗ g r a d i D e s ;
345
( i m p u l s i >256)
346
{
347
numero_giri=i m p u l s i / 2 5 6 ;
348
a l f a=numero_giri ;
349
b e t a=i m p u l s i − (256 ∗ a ) ;
350
}
351
352
{
353
a l f a =0;
354
b e t a=i m p u l s i ;
355
}
356
357
temp=0;
358
( v e r s o ==0)
359 {
void
void
int
int
int
int
int
int
double
double
int
int
int
int
double
if
else
int
if
66
Appendice
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_b . r e a d ( ) ;
( temp==40)
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
}
if
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_a . r e a d ( ) ;
( temp==41)
{
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
}
if
}
if
{
( v e r s o ==1)
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_b . r e a d ( ) ;
( temp==41)
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
}
if
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_a . r e a d ( ) ;
( temp==40)
{
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
}
if
}
mySerial_a . p r i n t ( 8 5 ,BYTE) ; // . . . . . . . . . . . . . . . . . . . . . . . . . . e s e g u i comando
COUNT
mySerial_a . p r i n t ( 6 ,BYTE) ;
mySerial_a . p r i n t ( a l f a ,BYTE) ;
mySerial_a . p r i n t ( beta ,BYTE) ;
mySerial_a . p r i n t l n ( v e l o c i t a ,BYTE) ;
67
Appendice
409 mySerial_b . p r i n t ( 8 5 ,BYTE) ; // . . . . . . . . . . . . . . . . . . . . . . . . . . e s e g u i comando
COUNT
410 mySerial_b . p r i n t ( 6 ,BYTE) ;
411 mySerial_b . p r i n t ( a l f a ,BYTE) ;
412 mySerial_b . p r i n t ( beta ,BYTE) ;
413 mySerial_b . p r i n t l n ( v e l o c i t a +7,BYTE) ;
414 }
415
416 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e r u o t a r o b o t
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
417
ruota_robot (
angolo ,
segno ,
velocita )
418 {
419
distanza ;
420
angolo1 ;
421
angolo1_rad ;
422 a n g o l o 1 = a n g o l o ;
423 angolo1_rad = ( 3 . 1 4 1 4 5 7 / 1 8 0 . 0 ) ∗ a n g o l o 1 ;
424
425 d i s t a n z a = angolo1_rad ∗ 0 . 1 1 5 ∗ 1 0 0 ;
426 S e r i a l . p r i n t l n ( angolo1_rad ,DEC) ;
427
distanza1 ;
428 d i s t a n z a 1= d i s t a n z a − d i s t a n z a ∗ ( 0 . 0 8 ) ;
429
angolo_radianti ;
430
angolo_gradi ;
431 a n g o l o _ r a d i a n t i = ( d i s t a n z a 1 ∗ 0 . 0 1 ) / 0 . 0 2 7 ;
432 a n g o l o _ g r a d i = a n g o l o _ r a d i a n t i ∗ 1 8 0 / 3 . 1 4 1 4 5 7 ;
433 S e r i a l . p r i n t l n ( angolo_gradi ,DEC) ;
434
gradiDes = angolo_gradi ;
435
i m p u l s i =0;
436
numero_giri =0;
437
alfa ;
438
beta ;
439
i =0;
440
k;
441
442
443 k = ( 2 8 3 . 0 / 3 6 0 . 0 ) ;
444 i m p u l s i=k ∗ g r a d i D e s ;
445
( i m p u l s i >256)
446
{
447
numero_giri=i m p u l s i / 2 5 6 ;
448
a l f a=numero_giri ;
449
b e t a=i m p u l s i − (256 ∗ a ) ;
450
}
451
452
{
453
a l f a =0;
454
b e t a=i m p u l s i ;
455
}
456
457
temp=0;
void
int
double
double
int
int
int
int
int
int
double
double
int
int
int
int
double
if
else
int
68
Appendice
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
if
{
( s e g n o==0)
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_b . r e a d ( ) ;
( temp==41)
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
}
if
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_a . r e a d ( ) ;
( temp==41)
{
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
}
if
}
if
{
( s e g n o==1)
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_b . r e a d ( ) ;
( temp==40)
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
}
if
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp=mySerial_a . r e a d ( ) ;
( temp==40)
{
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
}
if
}
mySerial_a . p r i n t ( 8 5 ,BYTE) ; // . . . . . . . . . . . . . . . . . . . . . . . . . . e s e g u i comando
COUNT
505 mySerial_a . p r i n t ( 6 ,BYTE) ;
506 mySerial_a . p r i n t ( a l f a ,BYTE) ;
507 mySerial_a . p r i n t ( beta ,BYTE) ;
69
Appendice
508 mySerial_a . p r i n t l n ( v e l o c i t a ,BYTE) ;
509
510 mySerial_b . p r i n t ( 8 5 ,BYTE) ; // . . . . . . . . . . . . . . . . . . . . . . . . . . e s e g u i comando
COUNT
511 mySerial_b . p r i n t ( 6 ,BYTE) ;
512 mySerial_b . p r i n t ( a l f a ,BYTE) ;
513 mySerial_b . p r i n t ( beta ,BYTE) ;
514 mySerial_b . p r i n t l n ( v e l o c i t a ,BYTE) ;
515 }
516
517 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− f u n z i o n e r u o t a
s e n s o r i −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
518
ruota_sensori (
pos )
519 {
520 myservo . w r i t e ( pos ) ;
521 }
void
int
Programma per la funzione di inseguimento
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// i n c l u d e t h e S o f t w a r e S e r i a l l i b r a r y so you can use i t s f u n c t i o n s :
#include <N e w S o f t S e r i a l . h>
// d e f i n e p i n o f
rxPin_a
txPin_a
rxPin_b
txPin_b
#define
#define
#define
#define
s e r i a l communications
4
5
7
8
// s e t up a new s e r i a l p o r t
N e w S o f t S e r i a l mySerial_a = N e w S o f t S e r i a l ( rxPin_a , txPin_a ) ;
N e w S o f t S e r i a l mySerial_b = N e w S o f t S e r i a l ( rxPin_b , txPin_b ) ;
b o o l e a n check ;
b o o l e a n check1=f a l s e ;
i =0;
j =0;
buffer1 [ 2 ] ;
e r r o r e =0;
v e l o c i t a =0;
temp=0;
temp_a=0;
distanza1 []={0 , 0 , 0 , 0 , 0};
distanza2 []={0 , 0 , 0 , 0 , 0};
int
int
int
int
int
int
int
int
int
int
int
int
int
int
distanza1_3 []={0 , 0 , 0 , 0 , 0 } ;
distanza2_3 []={0 , 0 , 0 , 0 , 0 } ;
distanza1_4 []={0 , 0 , 0 , 0 , 0 } ;
distanza2_4 []={0 , 0 , 0 , 0 , 0 } ;
sensorPin_1 = 1 ;
// s e l e c t t h e i n p u t p i n f o r t h e p o t e n t i o m e t e r
70
Appendice
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
int sensorPin_2 = 2 ;
int sensorPin_3 = 3 ;
int sensorPin_4 = 4 ;
int sensorValue_1 = 0 ;
sensor
int sensorValue_2 = 0 ;
sensor
int sensorValue_3 = 0 ;
sensor
int sensorValue_4 = 0 ;
sensor
double
double
double
double
tensione_1
tensione_2
tensione_3
tensione_4
=
=
=
=
// s e l e c t t h e i n p u t p i n f o r t h e p o t e n t i o m e t e r
// v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
// v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
// v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
// v a r i a b l e t o s t o r e t h e v a l u e coming from t h e
0;
0;
0;
0;
double d i s t a n z a _ o s t a c o l o _ 1
double d i s t a n z a _ o s t a c o l o _ 2
double d i s t a n z a _ o s t a c o l o _ 3
double d i s t a n z a _ o s t a c o l o _ 4
int media =0;
int media3 =0;
int media4 =0;
void
{
=
=
=
=
0;
0;
0;
0;
setup ()
// d e f i n e p i n modes f o r tx , rx , l e d p i n s :
pinMode ( rxPin_a , INPUT) ;
pinMode ( txPin_a , OUTPUT) ;
pinMode ( rxPin_b , INPUT) ;
pinMode ( txPin_b , OUTPUT) ;
// s e t t h e d a t a r a t e f o r t h e S o f t w a r e S e r i a l p o r t
S e r i a l . begin (9600) ;
mySerial_a . b e g i n ( 9 6 0 0 ) ;
mySerial_b . b e g i n ( 9 6 0 0 ) ;
// . . . . . . . . . . . . . . . . . . . . . . . . movimentazione d e l r o b o t i n a v a n t i
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp = mySerial_b . r e a d ( ) ;
( temp==40)
{
if
71
Appendice
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
temp =41;
}
// . . . . . . . . . . . . . . . .
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 5 ,BYTE) ;
delay (10) ;
temp_a = mySerial_a . r e a d ( ) ;
( temp_a==41)
{
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
temp_a=40;
}
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 0 ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 0 ,BYTE) ;
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
check=t r u e ;
}
if
void
{
loop ()
// . . . . . . . . . . . . . . . . . . . . read t h e v a l u e from t h e s e n s o r :
sensorValue_1 = analogRead ( sensorPin_1 ) ;
sensorValue_2 = analogRead ( sensorPin_2 ) ;
sensorValue_3 = analogRead ( sensorPin_3 ) ;
sensorValue_4 = analogRead ( sensorPin_4 ) ;
// . . . . . . . . . . . . . . . . . . . . . . . . . . c o n v e r s i o n e v a l o r e l e t t o d a l s e n s o r e i n
tensione
t e n s i o n e _ 1 = sensorValue_1 ∗ 5 / 1 0 2 3 . 0 ;
t e n s i o n e _ 2 = sensorValue_2 ∗ 5 / 1 0 2 3 . 0 ;
t e n s i o n e _ 3 = sensorValue_3 ∗ 5 / 1 0 2 3 . 0 ;
t e n s i o n e _ 4 = sensorValue_4 ∗ 5 / 1 0 2 3 . 0 ;
// . . . . . . . . . . . . . . . c o n v e r s i o n e v a l o r e l e t t o d i s t a n z a
( tensione_1 < 0 . 4 )
{ distanza_ostacolo_1 = 0 ;}
112
113
114
115
116
117
118
119
120
( 0 . 4 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 0 . 5 9 )
121 { d i s t a n z a _ o s t a c o l o _ 1 = − 150 ∗ t e n s i o n e _ 1 + 140 ; }
122
123
( 0 . 5 9 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 0 . 8 1 )
124 { d i s t a n z a _ o s t a c o l o _ 1 = −72∗ t e n s i o n e _ 1 + 96 ; }
125
126
( 0 . 8 1 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 1 . 1 5 )
127 { d i s t a n z a _ o s t a c o l o _ 1 = − 36.7 ∗ t e n s i o n e _ 1 + 66 ; }
128
129
( 1 . 1 5 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 1 . 6 3 )
if
if
if
if
if
72
Appendice
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
{ d i s t a n z a _ o s t a c o l o _ 1 = −18∗ t e n s i o n e _ 1 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 1 && t e n s i o n e _ 1 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 1 = −8∗ t e n s i o n e _ 1 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 1 )
{ d i s t a n z a _ o s t a c o l o _ 1 = 1000 ; }
//−−−−−−−−−−−−−−
( tensione_2 < 0 . 4 )
{ distanza_ostacolo_2 = 0 ;}
if
if
( 0 . 4 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 2 = − 150 ∗ t e n s i o n e _ 2 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 2 = −72∗ t e n s i o n e _ 2 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 2 = − 36.7 ∗ t e n s i o n e _ 2 + 66 ; }
if
( 1 . 1 5 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 2 = −18∗ t e n s i o n e _ 2 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 2 && t e n s i o n e _ 2 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 2 = −8∗ t e n s i o n e _ 2 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 2 )
{ d i s t a n z a _ o s t a c o l o _ 2 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
( tensione_3 < 0 . 4 )
{ distanza_ostacolo_3 = 0 ;}
if
if
( 0 . 4 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 3 = − 150 ∗ t e n s i o n e _ 3 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 3 = −72∗ t e n s i o n e _ 3 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 3 = − 36.7 ∗ t e n s i o n e _ 3 + 66 ; }
if
( 1 . 1 5 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 3 = −18∗ t e n s i o n e _ 3 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 3 && t e n s i o n e _ 3 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 3 = −8∗ t e n s i o n e _ 3 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 3 )
{ d i s t a n z a _ o s t a c o l o _ 3 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
( tensione_4 < 0 . 4 )
if
73
Appendice
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
{ distanza_ostacolo_4 = 0 ;}
if
( 0 . 4 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 0 . 5 9 )
{ d i s t a n z a _ o s t a c o l o _ 4 = − 150 ∗ t e n s i o n e _ 4 + 140 ; }
if
( 0 . 5 9 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 0 . 8 1 )
{ d i s t a n z a _ o s t a c o l o _ 4 = −72∗ t e n s i o n e _ 4 + 96 ; }
if
( 0 . 8 1 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 1 . 1 5 )
{ d i s t a n z a _ o s t a c o l o _ 4 = − 36.7 ∗ t e n s i o n e _ 4 + 66 ; }
if
( 1 . 1 5 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 1 . 6 3 )
{ d i s t a n z a _ o s t a c o l o _ 4 = −18∗ t e n s i o n e _ 4 + 45 ; }
if
( 1 . 6 3 <= t e n s i o n e _ 4 && t e n s i o n e _ 4 < 2 . 6 )
{ d i s t a n z a _ o s t a c o l o _ 4 = −8∗ t e n s i o n e _ 4 + 2 8 . 5 ; }
if
( 2 . 6 <= t e n s i o n e _ 4 )
{ d i s t a n z a _ o s t a c o l o _ 4 = 1000 ; }
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
distanza1 [4]= distanza1 [ 3 ] ;
distanza1 [3]= distanza1 [ 2 ] ;
distanza1 [2]= distanza1 [ 1 ] ;
distanza1 [1]= distanza1 [ 0 ] ;
distanza1 [0]= distanza_ostacolo_1 ;
distanza2 [4]= distanza2 [ 3 ] ;
distanza2 [3]= distanza2 [ 2 ] ;
distanza2 [2]= distanza2 [ 1 ] ;
distanza2 [1]= distanza2 [ 0 ] ;
distanza2 [0]= distanza_ostacolo_1 ;
( ( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 1 ] ) >10) | | ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 1 ] )
<−10) ) && ( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 2 ] ) >10) | | ( ( d i s t a n z a 1 [0] − d i s t a n z a 1
[ 2 ] ) <−10) ) && ( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 3 ] ) >10) | | ( ( d i s t a n z a 1 [0] −
d i s t a n z a 1 [ 3 ] ) <−10) ) && ( ( ( d i s t a n z a 1 [0] − d i s t a n z a 1 [ 4 ] ) >10) | | ( (
d i s t a n z a 1 [0] − d i s t a n z a 1 [ 4 ] ) <−10) ) )
213 { d i s t a n z a 1 [ 0 ] = d i s t a n z a 1 [ 1 ] ; }
214 media=( d i s t a n z a 1 [ 0 ] + d i s t a n z a 1 [ 1 ] + d i s t a n z a 1 [ 3 ] + d i s t a n z a 1 [ 2 ] + d i s t a n z a 1 [ 4 ] )
/5;
215
(
( ( ( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 1 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 1 ] )
>−5)) &&((( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 2 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 2 ] )
>−5)) &&((( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 3 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 3 ] )
>−5)) &&((( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 4 ] ) <5)&&(( d i s t a n z a 2 [0] − d i s t a n z a 2 [ 4 ] )
>−5)) )
216
217 {
218 media=d i s t a n z a 2 [ 0 ] ;
219 d i s t a n z a 1 [ 4 ] = d i s t a n z a 2 [ 4 ] ;
220 d i s t a n z a 1 [ 3 ] = d i s t a n z a 2 [ 3 ] ;
221 d i s t a n z a 1 [ 2 ] = d i s t a n z a 2 [ 2 ] ;
222 d i s t a n z a 1 [ 1 ] = d i s t a n z a 2 [ 1 ] ;
if
if
74
Appendice
223
224
225
226
227
228
229
230
231
232
233
234
235
236
distanza1 [0]= distanza2 [ 0 ] ;
}
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
distanza1_3 [4]= distanza1_3 [ 3 ] ;
distanza1_3 [3]= distanza1_3 [ 2 ] ;
distanza1_3 [2]= distanza1_3 [ 1 ] ;
distanza1_3 [1]= distanza1_3 [ 0 ] ;
distanza1_3 [0]= distanza_ostacolo_3 ;
distanza2_3 [4]= distanza2_3 [ 3 ] ;
distanza2_3 [3]= distanza2_3 [ 2 ] ;
distanza2_3 [2]= distanza2_3 [ 1 ] ;
distanza2_3 [1]= distanza2_3 [ 0 ] ;
distanza2_3 [0]= distanza_ostacolo_3 ;
( ( ( ( d i s t a n z a 1 _ 3 [0] − d i s t a n z a 1 _ 3 [ 1 ] ) >10) | | ( ( d i s t a n z a 1 _ 3 [0] − d i s t a n z a 1 _ 3
[ 1 ] ) <−10) ) && ( ( ( d i s t a n z a 1 _ 3 [0] − d i s t a n z a 1 _ 3 [ 2 ] ) >10) | | ( ( d i s t a n z a 1 _ 3
[0] − d i s t a n z a 1 _ 3 [ 2 ] ) <−10) ) && ( ( ( d i s t a n z a 1 _ 3 [0] − d i s t a n z a 1 _ 3 [ 3 ] ) >10)
| | ( ( d i s t a n z a 1 _ 3 [0] − d i s t a n z a 1 _ 3 [ 3 ] ) <−10) ) && ( ( ( d i s t a n z a 1 _ 3 [0] −
d i s t a n z a 1 _ 3 [ 4 ] ) >10) | | ( ( d i s t a n z a 1 _ 3 [0] − d i s t a n z a 1 _ 3 [ 4 ] ) <−10) ) )
237 { d i s t a n z a 1 _ 3 [ 0 ] = d i s t a n z a 1 _ 3 [ 1 ] ; }
238 media3=( d i s t a n z a 1 _ 3 [ 0 ] + d i s t a n z a 1 _ 3 [ 1 ] + d i s t a n z a 1 _ 3 [ 3 ] + d i s t a n z a 1 _ 3 [ 2 ] +
distanza1_3 [ 4 ] ) / 5 ;
239
(
( ( ( d i s t a n z a 2 _ 3 [0] − d i s t a n z a 2 _ 3 [ 1 ] ) <5)&&(( d i s t a n z a 2 _ 3 [0] −
d i s t a n z a 2 _ 3 [ 1 ] ) >−5)) &&((( d i s t a n z a 2 _ 3 [0] − d i s t a n z a 2 _ 3 [ 2 ] ) <5)&&((
d i s t a n z a 2 _ 3 [0] − d i s t a n z a 2 _ 3 [ 2 ] ) >−5)) &&((( d i s t a n z a 2 _ 3 [0] − d i s t a n z a 2 _ 3
[ 3 ] ) <5)&&(( d i s t a n z a 2 _ 3 [0] − d i s t a n z a 2 _ 3 [ 3 ] ) >−5)) &&((( d i s t a n z a 2 _ 3 [0] −
d i s t a n z a 2 _ 3 [ 4 ] ) <5)&&(( d i s t a n z a 2 _ 3 [0] − d i s t a n z a 2 _ 3 [ 4 ] ) >−5)) )
240
241 {
242 media3=d i s t a n z a 2 _ 3 [ 0 ] ;
243 d i s t a n z a 1 _ 3 [ 4 ] = d i s t a n z a 2 _ 3 [ 4 ] ;
244 d i s t a n z a 1 _ 3 [ 3 ] = d i s t a n z a 2 _ 3 [ 3 ] ;
245 d i s t a n z a 1 _ 3 [ 2 ] = d i s t a n z a 2 _ 3 [ 2 ] ;
246 d i s t a n z a 1 _ 3 [ 1 ] = d i s t a n z a 2 _ 3 [ 1 ] ;
247 d i s t a n z a 1 _ 3 [ 0 ] = d i s t a n z a 2 _ 3 [ 0 ] ;
248 }
249 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
250 d i s t a n z a 1 _ 4 [ 4 ] = d i s t a n z a 1 _ 4 [ 3 ] ;
251 d i s t a n z a 1 _ 4 [ 3 ] = d i s t a n z a 1 _ 4 [ 2 ] ;
252 d i s t a n z a 1 _ 4 [ 2 ] = d i s t a n z a 1 _ 4 [ 1 ] ;
253 d i s t a n z a 1 _ 4 [ 1 ] = d i s t a n z a 1 _ 4 [ 0 ] ;
254 d i s t a n z a 1 _ 4 [ 0 ] = d i s t a n z a _ o s t a c o l o _ 4 ;
255 d i s t a n z a 2 _ 4 [ 4 ] = d i s t a n z a 2 _ 4 [ 3 ] ;
256 d i s t a n z a 2 _ 4 [ 3 ] = d i s t a n z a 2 _ 4 [ 2 ] ;
257 d i s t a n z a 2 _ 4 [ 2 ] = d i s t a n z a 2 _ 4 [ 1 ] ;
258 d i s t a n z a 2 _ 4 [ 1 ] = d i s t a n z a 2 _ 4 [ 0 ] ;
259 d i s t a n z a 2 _ 4 [ 0 ] = d i s t a n z a _ o s t a c o l o _ 4 ;
260
( ( ( ( d i s t a n z a 1 _ 4 [0] − d i s t a n z a 1 _ 4 [ 1 ] ) >10) | | ( ( d i s t a n z a 1 _ 4 [0] − d i s t a n z a 1 _ 4
[ 1 ] ) <−10) ) && ( ( ( d i s t a n z a 1 _ 4 [0] − d i s t a n z a 1 _ 4 [ 2 ] ) >10) | | ( ( d i s t a n z a 1 _ 4
[0] − d i s t a n z a 1 _ 4 [ 2 ] ) <−10) ) && ( ( ( d i s t a n z a 1 _ 4 [0] − d i s t a n z a 1 _ 4 [ 3 ] ) >10)
| | ( ( d i s t a n z a 1 _ 4 [0] − d i s t a n z a 1 _ 4 [ 3 ] ) <−10) ) && ( ( ( d i s t a n z a 1 _ 4 [0] −
d i s t a n z a 1 _ 4 [ 4 ] ) >10) | | ( ( d i s t a n z a 1 _ 4 [0] − d i s t a n z a 1 _ 4 [ 4 ] ) <−10) ) )
if
if
if
75
Appendice
261 { d i s t a n z a 1 _ 4 [ 0 ] = d i s t a n z a 1 _ 4 [ 1 ] ; }
262 media4=( d i s t a n z a 1 _ 4 [ 0 ] + d i s t a n z a 1 _ 4 [ 1 ] + d i s t a n z a 1 _ 4 [ 3 ] + d i s t a n z a 1 _ 4 [ 2 ] +
distanza1_4 [ 4 ] ) / 5 ;
263
(
( ( ( d i s t a n z a 2 _ 4 [0] − d i s t a n z a 2 _ 4 [ 1 ] ) <5)&&(( d i s t a n z a 2 _ 4 [0] −
d i s t a n z a 2 _ 4 [ 1 ] ) >−5)) &&((( d i s t a n z a 2 _ 4 [0] − d i s t a n z a 2 _ 4 [ 2 ] ) <5)&&((
d i s t a n z a 2 _ 4 [0] − d i s t a n z a 2 _ 4 [ 2 ] ) >−5)) &&((( d i s t a n z a 2 _ 4 [0] − d i s t a n z a 2 _ 4
[ 3 ] ) <5)&&(( d i s t a n z a 2 _ 4 [0] − d i s t a n z a 2 _ 4 [ 3 ] ) >−5)) &&((( d i s t a n z a 2 _ 4 [0] −
d i s t a n z a 2 _ 4 [ 4 ] ) <5)&&(( d i s t a n z a 2 _ 4 [0] − d i s t a n z a 2 _ 4 [ 4 ] ) >−5)) )
264
265 {
266 media4=d i s t a n z a 2 _ 4 [ 0 ] ;
267 d i s t a n z a 1 _ 4 [ 4 ] = d i s t a n z a 2 _ 4 [ 4 ] ;
268 d i s t a n z a 1 _ 4 [ 3 ] = d i s t a n z a 2 _ 4 [ 3 ] ;
269 d i s t a n z a 1 _ 4 [ 2 ] = d i s t a n z a 2 _ 4 [ 2 ] ;
270 d i s t a n z a 1 _ 4 [ 1 ] = d i s t a n z a 2 _ 4 [ 1 ] ;
271 d i s t a n z a 1 _ 4 [ 0 ] = d i s t a n z a 2 _ 4 [ 0 ] ;
272 }
273 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
274 // media=( d i s t a n z a _ o s t a c o l o _ 2+d i s t a n z a _ o s t a c o l o _ 1 ) / 2 ;
275 e r r o r e = media − 20;
276 v e l o c i t a=e r r o r e ∗ 1 5 ;
277
( ( media==0)&&check1 )
278 {
279 mySerial_b . p r i n t ( 8 5 ,BYTE) ;
280 mySerial_b . p r i n t ( 0 ,BYTE) ;
281 mySerial_a . p r i n t ( 8 5 ,BYTE) ;
282 mySerial_a . p r i n t ( 0 ,BYTE) ;
283 check1=f a l s e ;
284 }
285
286
287
( media >0)
288 {
289
( ( ( e r r o r e >10) | | ( e r r o r e <−10) ) )
290 {
291 check=t r u e ;
292 }
293
294
( check )
295 {
296
297 check1=t r u e ;
298
( e r r o r e <0) // . . . . . . . . . . . . . . . . . . . . . . . . imponi sempre v e l o c i t à p o s i t i v a
299 {
300 v e l o c i t a=v e l o c i t a ∗ ( − 1) ;
301 }
302
303
( ( e r r o r e >0)&&(temp==40)&&(temp_a==41) ) // . . . . . . . . . . . . . . . s e l ' e r r o r e è
p o s i t i v o muovi a v a n t i
304 {
305 mySerial_b . p r i n t ( 8 5 ,BYTE) ;
if
if
if
if
if
if
if
76
Appendice
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
mySerial_b . p r i n t ( 1 ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
temp =41;
temp_a=40;
}
if ( ( e r r o r e <0)&&(temp==41)&&(temp_a=40) ) // . . . . . . . . . . . . . . s e
n e g a t i v o muovi i n d i e t r o
l ' errore è
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 1 ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 1 ,BYTE) ;
temp =40;
temp_a=41;
}
if
if
if
( v e l o c i t a >240)
{ v e l o c i t a =240;}
( v e l o c i t a <80)
{ v e l o c i t a =80;}
( ( e r r o r e <2)&&(e r r o r e >−2))
{
v e l o c i t a =0;
check=f a l s e ;
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 0 ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 0 ,BYTE) ;
}
( ( media3 >10)&&(media3 <35) )
{
( v e l o c i t a >150)
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 3 ,BYTE) ;
mySerial_a . p r i n t ( v e l o c i t a − 50 ,BYTE) ;
}
if
if
else
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a +50 ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 3 ,BYTE) ;
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
77
Appendice
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
}
}
else
if ( ( media4 >10)&&(media4 <35) )
{
if ( v e l o c i t a >150)
{
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a − 50 ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 3 ,BYTE) ;
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
}
else
}
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 3 ,BYTE) ;
mySerial_a . p r i n t ( v e l o c i t a +50 ,BYTE) ;
}
else
{
mySerial_b . p r i n t ( 8 5 ,BYTE) ;
mySerial_b . p r i n t ( 3 ,BYTE) ;
mySerial_b . p r i n t ( v e l o c i t a ,BYTE) ;
mySerial_a . p r i n t ( 8 5 ,BYTE) ;
mySerial_a . p r i n t ( 3 ,BYTE) ;
mySerial_a . p r i n t ( v e l o c i t a ,BYTE) ;
}
}
}
}
delay (100) ;
// S e r i a l . p r i n t l n ( media3 ,DEC) ;
}
78
Elenco delle gure
1.1
Sensore SHARP GP2D12 . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.2
Package GP2D12
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.3
Segnale generato dai sensori GP2D12 . . . . . . . . . . . . . . . . . .
7
1.4
Relazione distanza tensione
. . . . . . . . . . . . . . . . . . . . . . .
8
1.5
Elenco comandi M.M.B.e.
. . . . . . . . . . . . . . . . . . . . . . . .
10
1.6
Motore DC
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
1.7
Caratteristiche Motore DC . . . . . . . . . . . . . . . . . . . . . . . .
13
1.8
Schema di collegamento degli encoder . . . . . . . . . . . . . . . . . .
14
1.9
Caratteristiche servomotore
. . . . . . . . . . . . . . . . . . . . . . .
14
1.10 Servomotore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
1.11 Segnale di controllo del servomotore . . . . . . . . . . . . . . . . . . .
16
1.12 ER400TRS
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
1.13 Diagrmma a blocchi del ER400TRS . . . . . . . . . . . . . . . . . . .
17
1.14 Segnale RSSI
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
1.15 Schema elettrico Arduino . . . . . . . . . . . . . . . . . . . . . . . . .
19
1.16 Circuito di alimentazione . . . . . . . . . . . . . . . . . . . . . . . . .
21
1.17 Schema elettrico robot Octagon
. . . . . . . . . . . . . . . . . . . . .
22
Schema a blocchi per la gestione dei motori . . . . . . . . . . . . . . .
23
2.1
79
ELENCO DELLE FIGURE
ELENCO DELLE FIGURE
2.2
Schema collegamento Arduino motor mind . . . . . . . . . . . . . . .
26
2.3
Schema a blocchi comunicazione wireless
. . . . . . . . . . . . . . . .
29
3.1
Finestra di lavoro GUI
. . . . . . . . . . . . . . . . . . . . . . . . . .
39
3.2
Interfaccia robot octagon . . . . . . . . . . . . . . . . . . . . . . . . .
40
3.3
Modello matematico del sistema . . . . . . . . . . . . . . . . . . . . .
45
3.4
Schema a blocchi funzione inseguimento
. . . . . . . . . . . . . . . .
47
3.5
Posizionamento sensori . . . . . . . . . . . . . . . . . . . . . . . . . .
47
3.6
Schema collegamento encoder-Arduino
. . . . . . . . . . . . . . . . .
50
3.7
Schema a blocchi controllo posizione
. . . . . . . . . . . . . . . . . .
51
80
Bibliograa
[1] Danilo Luzi, Progettazione e realizzazione di un robot per lo studio del moto di
formazioni',
81