You are on page 1of 54

UNIVERSITÀ DEGLI STUDI DI TRIESTE

FACOLTÀ DI INGEGNERIA

Dipartimento di Elettrotecnica, Elettronica ed Informatica

Tesi di Laurea in
PROGRAMMAZIONE DEI CALCOLATORI

Sviluppo di un Driver per il Controllo di un


Robot Mobile in Ambiente
Multipiattaforma

Laureando: Relatore:
Damiano VITTOR Dott. Ing. Massimiliano NOLICH

____________________________________

Anno Accademico 2007-2008


In memoria di
Remo Pezzetta
INDICE

INDICE ......................................................................................................................... I
INTRODUZIONE..............................................................................................................1
Il materiale ................................................................................................................................ 2
L’ambiente di sviluppo .............................................................................................................. 3
Fasi dello sviluppo ..................................................................................................................... 3

IL SISTEMA EMBEDDED ....................................................................................................5


Il Sistema Operativo .................................................................................................................. 5
La preparazione ......................................................................................................................... 6
Deployment del sistema operativo ......................................................................................... 11

IL PROGETTO............................................................................................................... 13
Lo sviluppo di controlli per Robot Mobili ................................................................................ 13
L’architettura generale............................................................................................................ 14
I task RTAI ................................................................................................................................ 15
Le FIFO e la Comunicazione Interprocesso ............................................................................. 17
Player, un framework Robotico .............................................................................................. 18
Il collegamento elettrico delle varie parti del robot ............................................................... 19

I TASK REALTIME ......................................................................................................... 21


Il modulo RTAI per la gestione del sensore ad ultrasuoni....................................................... 21
Il modulo RTAI per la gestione dell’infrarosso ........................................................................ 22
Il modulo RTAI per la gestione dei MOTORI............................................................................ 24
Il modulo RTAI per la gestione dei sensori ODOMETRICI........................................................ 26

I DRIVER PLAYER ......................................................................................................... 29


I driver Player .......................................................................................................................... 29
Srf005driver............................................................................................................................. 30
Indice

2d120xdriver ........................................................................................................................... 32
Driver MotoriDriver ................................................................................................................. 35
Lo script di configurazione ...................................................................................................... 35

CONCLUSIONI ............................................................................................................. 37
Risultati raggiunti .................................................................................................................... 37
Prospettive di sviluppo ............................................................................................................ 37

APPENDICI ................................................................................................................. 39
Redboot ................................................................................................................................... 39
Setup e configurazione di un server NFS ................................................................................. 41
Yaffs File-System...................................................................................................................... 42

RINGRAZIAMENTI ........................................................................................................ 45
BIBLIOGRAFIA ............................................................................................................. 47

ii
INTRODUZIONE

Motivazione della tesi


La tesi si inquadra in un progetto che prevede lo sviluppo di robot di servizio, che
siano capaci di muoversi su di un piano in modo autonomo, evitando, nei limiti
della loro percezione sensoriale, gli ostacoli sul loro percorso. Grazie a queste
proprietà si desidera renderli capaci di funzioni più complesse che possono variare
di situazione in situazione.
Per ottenere questo risultato si vogliono utilizzare più livelli di astrazione che
permettano almeno di separare la logica di alto livello da quella di livello più basso
che gestisce sensori e attuatori. In questo modo si possono ottenere vantaggi
notevoli dal punto di vista della riutilizzazione del codice e nella facilità del porting
verso altre piattaforme robotiche con caratteristiche hardware differenti.

Gli obiettivi della tesi


L’obiettivo del lavoro di tesi proposto è stato realizzare un pacchetto di driver per
una piattaforma robotica preesistente che si integri in un framework chiamato
Player. Si è realizzato, a tal proposito, del software che si interpone tra dei
dispositivi hardware e l’utilizzatore (il framework) in grado di pilotarne le
funzionalità. Si desidera, in questo modo, che tale software esponga un’interfaccia
standard che ne celi la complessità intrinseca. I driver sviluppati si occupano della
gestione dei sensori e degli attuatori montati sul robot. In particolare, sono stati
utilizzati sensori a ultrasuoni, ad infrarosso e odometrici, oltre che un circuito di
comando motori.
Grazie a questo pacchetto di driver si vuole anche rendere facilmente
interoperabile il robot con tutto il repertorio di software di alto livello già
realizzato all’interno del progetto Player come il “wavefront” e il “vhf”
(rispettivamente per il path-finding e la collision-avoidance) ed inoltre si vuole
permettere lo sviluppo di una logica indipendente dall’hardware.

1
Introduzione

I Vincoli
Il lavoro è stato sviluppato nel laboratorio Smartlab del Dipartimento di
Elettrotecnica Elettronica e Informatica della Facoltà di Ingegneria presso
l’Università degli Studi di Trieste. Il materiale necessario al progetto era già stato
acquistato dal laboratorio per altre attività e quindi è stato utilizzato anche in
funzione di questo lavoro. Ciò è stato vincolante sia nella scelta dell’ambiente di
sviluppo sia in quella del sistema operativo. Infatti in base ai sistemi operativi
supportati dalla ditta produttrice dell’hardware, al loro costo economico e alla
possibilità di essere impiegati con processi real-time la scelta è dovuta ricadere
più o meno obbligatoriamente su un sistema GNU/Linux.

Il materiale
• Sistema embedded Ts-7250 della Technologic Systems
• Sensori ultrasuoni Devantech SRF005
• Sensori infrarosso Sharp 2D120X
• Sensori Odometrici HEDS-5505 della Agilent Technologies
• Driver Motori #203 della Wirz Electronics
• Motori m455m63 della Globe Motors

Technologic System TS-7250


Il TS-7250 è un sistema embedded basato su un chip Cirrus Logic con core ARM9:
l’EP9302. Questo chip a basso consumo include nel suo package un processore
ARM920T funzionante a 200Mhz e una serie di periferiche standard come quelle
USB o Ethernet e linee di digital I/O.
La caratteristica che rende appetibile questo sistema per la robotica è il basso
consumo (circa 2 – 3 W) e la disponibilità di una moltitudine di periferiche on-
board.

Devantech SRF005
Il sensore SRF005 è un sensore distanziometrico a ultrasuoni che integra già un
microcontrollore che gestisce la generazione degli impulsi e la loro rilevazione. E’
controllabile tramite delle porte di Digital I/O (DIO).
La sua portata è di circa 4 metri con una precisione dell’ordine del centimetro.

2
Introduzione

Sharp GP2D120X
Il sensore Sharp GP2D120X è un sensore distanziometrico a infrarosso e funziona
come un normale fotodiodo. Va collegato direttamente ad un analog-digital
converter (ADC) per la lettura della caduta di tensione.
La sua portata è di circa 0,3 metri con una precisione superiore al centrimetro.

Wirz Electronics #203 Low Current Motor Driver


E’ un circuito amplificatore che serve per modulare la tensione fornita ai motori
allo scopo di poter regolare la velocità di rotazione degli stessi. Questo circuito
dispone di due controlli motori indipendenti che vengono pilotati tramite due
coppie di porte di digital I/O.

Sensori odometrici HEDS-5505


I sensori odometrici sono atti a rilevare il verso e la velocità di rotazione dell’asse
di un motore. Questo modello in particolare usa una tecnologia ottica a
quadratura. Ogni sensore si collega direttamente a due porte di digital I/O sulle
quali vengono trasmessi due segnali sfasati di 90°. Grazie a questi segnali si può
determinare il movimento del motore.

L’ambiente di sviluppo
La cross-compilazione dei moduli rtai, del kernel e il servizio nfs sono stati eseguiti
su di un sistema Gnu/Linux Kubuntu 8.04 eseguito come macchina virtuale su un
host Windows VISTA. Per lo sviluppo dei driver si è scelto di utilizzare KDevelop
come IDE e make come build-tool. Il gestore di macchine virtuali utilizzato è
VirtualBox prodotto dalla SUN Microsystems.
VirtualBox, Kubuntu, KDevelop e make sono software scaricabili ed utilizzabili
gratuitamente.

Fasi dello sviluppo


Il lavoro è stato organizzato nel modo seguente:
1. Scelta della GNU cross-platform toolchain.
2. Patch dei sorgenti del kernel linux con le estensione realtime.
3. Cross-compilazione del kernel e dei moduli necessari per il funzionamento
dell’hardware.

3
Introduzione

4. Cross-compilazione dei moduli/task realtime per il kernel.


5. Preparazione file-system.
6. Configurazione del bootloader e installazione del file-system (per il sistema di
sviluppo).
7. Cross-compilazione di player.
8. Analisi e sviluppo dei moduli real-time per la lettura dei dati acquisiti dai vari
sensori e l’azionamento dei motori.
9. Analisi e sviluppo dei driver per Player.
10. Preparazione degli script di configurazione e di avvio del robot.
11. Installazione di player, dei driver e degli script sul robot.
12. Configurazione del bootloader e installazione del file-system (per il sistema di
produzione).

4
IL SISTEMA EMBEDDED

Il Sistema Operativo
La Technologic System supporta per la TS-7250 GNU/Linux, WinCE e Netbsd. La
scheda viene precaricata dalla fabbrica con una distribuzione debian minimale
(TS-Linux), basata su kernel linux 2.4, realizzata dal produttore stesso.

La scelta del sistema operativo


Uno dei criteri di scelta del sistema operativo, oltre costo e supporto per il nostro
hardware, è stata la possibilità di soddisfare i requisisti imposti dal nostro
progetto.
Tra questi requisiti vi era per esempio la necessità di rispondere rapidamente ai
dati sensoriali che elabora, per esempio, al fine di evitare la collisione con oggetti
o persone nell’ambiente in cui si muove. Per questo motivo un sistema operativo
real-time è solitamente preferibile per lo sviluppo di sistemi robotici.
Nell’ambito dei sistemi operativi real-time utilizzabili che siano supportati e che
non siano commerciali, si è deciso di usare una distribuzione GNU/Linux con
estensioni real-time.

The Real-time Application Interface (RTAI)


RTAI si presenta come una patch per il kernel Linux e una serie di librerie di
supporto per lo sviluppo. La patch introduce, tramite le HAL (Hardware
Abstraction Layer) del kernel, un nuovo schedulatore che programma i processi in
realt-time (task) in maniera precisa e deterministica. Quest’ultimo considera il
kernel Linux come un idle task eseguendolo quando il kernel real-time non è
attivo. Il task Linux, inoltre, non può mai bloccare gli interrupt o impedire di
essere interrotto nella sua esecuzione (being preempted).

5
Il sistema embedded

RTAI è stato sviluppato dal Dipartimento di Ingegneria Aerospaziale del


Politecnico di Milano ed è liberamente utilizzabile.

La preparazione
Il bootloader
Sulla TS-7250 è precaricato un bootloader basato su eCos, un sistema operativo
real-time minimale per sistemi embedded. Questo bootloader si chiama RedBoot
ed è stato utilizzato nel nostro progetto per il caricamento dell’immagine del
kernel, per la sua esecuzione e per scrivere l’immagine stessa sulla memoria flash
della scheda.
Per questioni di praticità, a tal proposito, sono stati realizzati due script di avvio
separati per Redboot: uno utilizzato in fase di sviluppo, ed uno per il sistema finale
“dimostrativo”.
Per quanto riguarda l’utilizzo di Redboot si è provveduto a riportare nel testo,
quando necessario, i comandi utilizzati.
Per ulteriori dettagli su Redboot sono stati scritti degli approfondimenti
nell’appendice.

Scelta della GNU Cross-Platform Toolchain


Per poter compilare un codice valido per la nostra piattaforma robotica si è
dovuta utilizzare di una cross-platform toolchain, cioè di un insieme di programmi
e librerie necessari per la compilazione e la generazione di eseguibili per una
piattaforma diversa da quella su cui essa viene usata.
A questo scopo il produttore della scheda fornisce sul suo repository ftp1 già una
gamma di toolchain di cui si è scelto di utilizzare, in particolare, la crosstool-linux-
gcc-3.3.4-glibc-2.3.2-0.28rc39 .

Preparazione del kernel


Una volta recuperati i sorgenti del kernel tskernel-2.4.26-ts11 si è provveduto ad
applicare la patch adeos rttskernel-2.4.26-tsX-adeos.patch per l’estensione real-
time, disponibile sempre nel ftp della Technologic System. Questa patch consiste
in uno script di modifica dei sorgenti del kernel atto ad introdurre le nuove
funzionalità necessarie per trasformarlo in un Sistema Operativo real-time.

1
ftp://ftp.embeddedarm.com

6
Il sistema embedded

Prima di poter applicare la suddetta patch, è stato necessario definire al suo


interno alcune informazioni, in modo che la stessa venga applicata con successo.
In particolare, si sono modificate le righe che specificano la versione di kernel su
cui applicare la patch e il prefisso del cross-compilatore che si ha intenzione di
utilizzare.
Nella fattispecie, sono state aggiunte/rimosse le seguenti righe:

-EXTRAVERSION =-ts11
+EXTRAVERSION =-ts11-rt
+CROSS_COMPILE = /tools/crosstool/arm-9tdmi-
linux-gnu/gcc-3.3.4-glibc-2.3.2/bin/arm-
9tdmi-linux-gnu-
+DEPMOD= /bin/true
E’ stato, poi, bypassato l’utilizzo del comando depmod sostituendolo con
/bin/true in quanto non è in grado di gestire la cross-compilazione.
E’ stata quindi applicata la patch con il comando:

patch -p1 -b < ./../rt-tskernel-2.4.26-ts11-


adeos.patch
Si è passati quindi a modificare il Makefile del kernel assicurando che le seguenti
variabili fossero correttamente impostate.

ARCH := arm
CROSS_COMPILE = /tools/crosstool/arm-9tdmi-
linux-gnu/gcc-3.3.4-glibc-2.3.2/bin/arm-
9tdmi-linux-gnu-
DEPMOD = /bin/true

Configurazione del kernel


La configurazione del kernel è essenziale per far riconoscere ed utilizzare al
sistema operativo le periferiche del sistema. Tale operazione avviene attraverso
degli script di configurazione e un menu visuale in cui l’utente può scegliere
direttamente l’hardware che vuol fargli supportare. In tal senso la technologic
system ha provveduto a fornire, insieme ai sorgenti del suo kernel, più script di
configurazione per il loro hardware.
Questo avrebbe, in teoria, dovuto rendere questa operazione abbastanza
semplice. Tuttavia una modifica nella tipologia di flash montata sulla scheda (una
variazione nella dimensione dei blocchi di memoria) ha creato non pochi problemi
nella configurazione del kernel stesso. Il driver YAFFS, indicato nella
configurazione del sistema che si voleva utilizzare, non supporta il tipo di flash
memory con blocchi da 512byte e per questo impediva le operazione di scrittura
sulla flash della scheda.

7
Il sistema embedded

Per questo motivo nella configurazione del kernel è di notevole importanza


assicurarsi del tipo di flash presente sulla scheda e utilizzare uno dei due seguenti
script di configurazione per il suo corretto funzionamento.

ts7250_config per memoria con blocchi da


512byte
ts7250_2k_config per memoria con blocchi da
2kbyte
Quindi per una corretta configurazione del kernel per l’hardware utilizzato si deve
eseguire i seguenti comandi:

make [ts7250_config|ts7250_2k_config]
per configurare le periferiche della scheda

make oldconfig
per configurare il supporto RTAI attivando quando richiesto solamente attivando
solamente ADEOS e ADEOS DOMAINS ARE THREAD
e quindi

make dep
make menuconfig
A questo punto sarà possibile visualizzare la configurazione finora impostata ed
eventualmente integrare il supporto per altre periferiche.
Nel nostro caso in specifico i seguenti moduli sono stati attivati/integrati:
1. Loadable module support
1.1. Kernel module loader
2. System Type
2.1. EP9301 Options
2.1.1. EP9301 Internal DMA Support
3. Plug and Play configuration
3.1. Plug and Play support
3.1.1. ISA Plug and Play support
4. Sound
4.1. Sound support
4.1.1. OSS sound modules
4.1.2. Verbose initialisation
5. USB support
5.1. USB verbose debug messages
5.2. USB Audio support

8
Il sistema embedded

Compilazione del kernel


Per compilare il kernel si possono quindi eseguire i comandi

make
make zImage
make modules
make modules_install INSTALL_MOD_PATH=<percorso
di destinazione>
A questo punto si ha a disposizione nella directory ./arch/arm/boot/ l’immagine
del kernel da installare nella scheda e (nella cartella specificata dalla variabile
INSTALL_MOD_PATH) i moduli del kernel da inserire nel file system della scheda
arm.

Compilazione dei moduli rtai


Si è usata la versione di RTAI 3.2 (magma) che è quella ufficialmente supportata
dalla Technologic System.
Prima della compilazione può essere necessario modificare il codice sorgente per
evitare l’insorgere di problemi durante la configurazione.
Nel file
rtai-3.2/base/config/kconfig/mconf.c
alla riga 91 bisogna togliere l’attributo statico alla variabile current_menu
Fatto ciò si è preseguiti nella compilazione con i seguenti comandi:

make ARCH=arm
CROSS_COMPILE=/tools/crosstool/arm-9tdmi-linux-
gnu/gcc-3.3.4-glibc-2.3.2/bin/arm-9tdmi-
linux-gnu-
make install
Nel menu di configurazione bisogna prestare attenzione a selezionare il giusto
path ai sorgenti del kernel che si è compilato precedentemente. E inoltre
conveniente specificare il percorso tipo /usr/realtime dove verrà effettuata la
build da spostare nella board.

NOTA IMPORTANTE: E’ necessario ricompilare


rtai ogni qualvolta sia STATO
ricompilato il kernel

9
Il sistema embedded

Compilazione di player
Per compilare una versione minimale di player bisogna disporre delle seguenti
librerie oltre quelle già presenti nel file-system base della TS-7250. Queste
ovviamente devono essere compilate per la piattaforma arm:

libpthread
libsdtc++
libtools
Le prime due erano disponibili sul file-system esteso chiamato debian-sarge-
1.14.tar reperibile sul ftp della technology system.
La terza è stata ricompilata in quanto non era disponibile un binario già pronto. In
particolare è stata usata la versione libtool-1.5.26 per la compilazione della
libreria. La procedura usata è stata quella riportata nel file INSTALL della root dei
sorgenti. E’ importante ricordarsi di fare l’export dei path per i binari del cross
compilatore e assicurarsi che lo stesso venga utilizzato.
Per quanto riguarda player bisogna quindi impostare le seguenti variabile
d’ambiente:

export CC=gcc
export PATH=<crosscompilers binaries path>
export CCFLAGS = -I <kernel headers path> -l
<libtool headers path>
export LDFLAGS = -L libs <libtool path>
Dove ai blocchi comprendenti le parentesi angolari vanno sostituiti i relativi
percorsi assoluti necessari.
Quindi si può procedere con la configurazione del pacchetto con il comando:

./configure --prefix=/home/damiano/Player-
Stage/build/ --build=x86-linux --host=arm-
9tdmi-linux-gnu --disable-alldrivers --
disable-debug --disable-tests --disable-
examples
E alla compilazione con

make install
Il risultato della compilazione sarà posto nella directory specificata dal parametro
PREFIX del configure e cioè nel nostro caso in /home/damiano/Player-
Stage/build/.
In ogni caso è sconsigliabile tentare di compilare player direttamente sulla scheda
arm, in quanto non è una strada facilmente percorribile.

10
Il sistema embedded

Preparazione del file-system


Per la prepazione del file-system del nostro sistema embedded si è partiti dal file-
system originale, precaricato nella flash, al quale si sono aggiunti i moduli e le
librerie necessarie per il funzionamento di Player e RTAI.
In particolare:
• I moduli del kernel vanno copiati nella directory /lib/modules del root file-
system di destinazione.
• I moduli RTAI vanno copiati preferibilmente dentro /usr/realtime.
• Il contenuto della build di player è stata copiata integralmente dentro
/usr/local/
• Le librerie richieste da player (libpthread, libsdtc++ e libtools) sono state
copiate nella directory /usr/lib/
Tutti i percorsi qui menzionati sono relativi alla root del file system della scheda
arm.

Deployment del sistema operativo


Per poter utilizzare il file-system da noi preparato è necessario passare il device
che lo contiene come parametro all’esecuzione del kernel. Questo si può
effettuare modificando lo script di avvio del sistema operativo, nel bootloader.
Durante lo sviluppo di questo progetto, come già menzionato nell’introduzione,
sono stati utilizzati due modi per caricare il file-system.

Il sistema di sviluppo
Il primo modo “di sviluppo” prevede la condivisione del root file-system tramite
una seconda macchina di sviluppo. Grazie a ciò, non è stato necessario aggiornare
di continuo il file-system presente sulla flash della scheda ad ogni modifica delle
librerie o dei moduli sviluppata. Inoltre, tale approccio ciò non ci ha vincolato alla
dimensioni della flash.
Questo è stato realizzato utilizzando una condivisione nfs contentente il file-
system che è stato creato (maggiori dettagli a questo proposito vengono forniti in
appendice) e provvedendo a modificare i parametri del comando exec dello script
di caricamento del kernel nel bootloader. In particolare è stato rimosso il
parametro root ed è stato aggiunto il parametro nfsroot come segue:

exec –c”ttyAM0,115200 ip=<ip>


nfsroot=<ipnfsserver>:<nome condivisione>”

11
Il sistema embedded

dove
• <ipnfsserver> è l’ip del server che fa da host al servizio nfs
• <nome condivisione> è il nome della condivisione nfs contenente
il root file system da usare

Il sistema di Produzione
Il sistema di produzione è indipendente da altre macchine. Anzi, non è previsto sia
collegato in rete ad alcuna altra macchina. Deve quindi caricare il file-system dalla
memoria flash integrata nella scheda.
Per caricare il file-system sulla scheda è necessario seguire la procedura per il
ripristino del file-system specificata nell’appendice.
C’è da considerare, inoltre, un problema riguardante le dimensione del file-system
stesso. La scheda a nostra disposizione monta una memoria flash troppo piccola
(32MB) rispetto la dimensione necessaria a ospitare tutte le librerie di cui ha
bisogno Player per funzionare. Si è deciso quindi di dividere il file-system
spostando il contenuto di /usr su una memoria flash esterna da collegare alla
scheda tramite porta USB. Per fare ciò si è partizionata e formattata quest’ultima
con un file-system ext3 (con il comando mkfs). A questo punto non è rimasto che
copiare al suo interno la cartella /usr e fare il mount della stessa sul sistema con i
seguenti comandi.

/usr/bin/loadUSBModules.sh
Per caricare i moduli di gestione dell’USB.

mount -t auto
/dev/scsi/host0/bus0/target0/lun0/part1
/usr
Per fare il mount della prima partizione della chiavetta USB.
E’ tuttavia consigliabile salvare il primo script in /etc/init.d e richiamarlo con un
link simbolico in /etc/rc.d/rc3.d/ e aggiungere nel file /etc/fstab la seguente riga:

/dev/scsi/host0/bus0/target0/lun0/part1 ext3
/usr
Infine sarà necessario modificare la linea di avvio del kernel nello script di avvio
del bootloader nel seguente modo:

exec –c”ttyAM0,115200 ip=<ip>


root=/dev/mtdblock/1”

12
IL PROGETTO

Lo sviluppo di controlli per Robot


Mobili
Come citato nell’introduzione, una delle motivazioni fondamentali di questo
lavoro, è stata creare un piattaforma robotica che abbia una serie di
caratteristiche utili allo sviluppo di logiche robotiche.
In particolare:
• Semplifichi la portabilità.
• Permetta la simulazione.
• Permetta lo sviluppo in maniera indipendente dall’hardware a
disposizione.
• Permetta l’elaborazione distribuita.
• Sia di facile utilizzo.
A tal scopo, ci si è proposti di utilizzare una piattaforma già esistente e collaudata
chiamata “Player”.
Player, come verrà descritto più avanti, tenta di introdurre questi vantaggi tramite
una serie di interfacce e di livelli di astrazione. Tratteremo ora di come è realizzato
un sistema che presenti la funzionalità del proprio hardware all’interno di Player
attraverso la preparazione della piattaforma robotica e lo sviluppo di driver
specifici. Questo lavoro prevede
• la preparazione del sistema operativo che il robot utilizza, come abbiamo
già illustrato.
• lo sviluppo dei driver hardware necessari al funzionamento dei sensori e
degli attuatori.
• lo sviluppo dei driver per player.

13
Il progetto

L’architettura generale
Sono stati realizzati da me quattro task real-time atti a leggere le informazioni dai
sensori e al comando dei motori. Sul lato opposto, tre driver per il framework
player (sempre sviluppati da me) si occupano della gestione dei task real-time e
dell’interpretazione dei dati letti. Lo scambio delle informazioni tra il processo del
server player e dei task real-time avviene tramite FIFO di sistema. I driver di player
si occupano di rendere le informazioni tratte dei sensori disponibili tramite delle
interfacce standard ad altri driver Player o ai client stessi. Tale architettura viene
illustrata nel seguente diagramma:

Le parti sviluppate da me sono state evidenziate in giallo.

14
Il progetto

Con l’infrastruttura di player è possibile collegare l’output di questi driver ad altri


driver, che espongono interfacce a più alto livello di astrazione. Questo può essere
fatto tramite degli script di configurazione di player. Il risultato della elaborazione
successiva (così come i dati ad ogni stadio di processo) sarà disponibile al
programma che ne voglia gestire la logica tramite le librerie di player.

I task RTAI
I task RTAI sono, in pratica, dei moduli del kernel linux che fanno uso di
caratteristiche speciali tipiche dei sistemi operativi real-time introdotte da RTAI.

I moduli del kernel linux


Un modulo del kernel linux è una porzione di codice che può essere aggiunta al
kernel linux durante la sua esecuzione. Uno dei vantaggi principali di questa
caratteristica è che non è necessario ricompilare l’intero kernel del sistema
operativo ogniqualvolta si voglia far supportare al sistema operativo un nuovo
dispositivo hardware o implementarne una nuova funzionalità.
Il gestore che permette il caricamento di moduli in run-time si chiama Loadable
Kernel Module (LKM) e introduce diverse categorie di moduli (o meglio di servizi)
caricabili:
• Driver per periferiche.
• Driver per file-system.
• Driver di rete.
• Moduli per definire nuove chiamate a sistema o per ridefinirne quelle
esistenti.
• Nuovi interpreti per eseguibili.
E’ importante sapere che i moduli del kernel, essendo eseguiti in kernel-space,
NON possono:
• Usare funzioni della libreria standard C.
• Usare aritmetiche floating-point.
L’aggiunta e la rimozione di un modulo del kernel linux può venire eseguita
tramite i comandi di sistema insmod e rmmod.

La struttura di un modulo del kernel linux.


L’interfaccia di un modulo del kernel linux è costituita fondamentalmente da due
metodi che vengono chiamati rispettivamente all’inserimento e alla rimozione del
modulo stesso. Li riportiamo qui:

15
Il progetto

int init_module(void)
void cleanup_module(void)

Per sviluppare un modulo valido per il kernel è sufficiente implementare tali


moduli.

Sviluppo di un task real-time.


Come spiegato, un task real-time si presenta come un modulo del kernel linux.
Le due chiamate sopra citate dovranno quindi essere presenti nel codice del
modulo. Inoltre nell’inizializzazione avremo una serie di chiamate a funzione
necessarie per la creazione del task real-time e il suo schedulamento. In
particolare saranno presenti le seguenti chiamate a funzione:

rt_task_init;
rt_task_make_periodic_relative_ns
start_rt_timer

La prima istruzione crea un nuovo task real-time, la seconda imposta la periodicità


del task e infine la terza avvia il timer. Nella funzione di clean-up del modulo,
invece, si troveranno le rispettive funzioni per fermare il timer e distruggere il
task:

stop_rt_timer();
rt_task_delete();

Le principali funzioni RTAI


RT_TASK* rt_task_init ( int name, int priority, int stack_size,
int max_msg_size )

Crea un nuovo task real-time. “name” è l’identificatore unico con il quale


è possible referenziare il task. “priority” è la priorità del task.
int rtf_create ( unsigned int minor, int size )

Crea una FIFO real-time della dimensioni iniziale “size” e identificatore


“minor”
int rt_task_make_periodic_relative_ns ( RT_TASK * task,
RTIME start_delay, RTIME period )

Imposta il task “task” in modalità periodica con periodo “period”.


“start_delay” definisce il ritardo di prima esecuzione.
void rt_task_wait_period ( void )

16
Il progetto

Attende fino al sopraggiungere del prossimo periodo. E’ usato nei task


periodici. Permette l’esecuzione di altri task durante questo intervallo di
tempo.
start_rt_timer ( int )

Avvia un timer real-time.


stop_rt_timer

Ferma il timer real-time.

Le FIFO e la Comunicazione
Interprocesso
Uno dei punti cruciali del progetto è creare un sistema di comunicazione che
permetta di trasferire le informazione tra i task in real-time e il processo in user-
space (Player).
Per fare ciò, purtroppo, non è possibile utilizzare gli strumenti classici
dell’ambiente linux per l’IPC (Inter Process Communication). RTAI però mette a
disposizione strumenti simili che sopperiscono a questa mancanza.
Questi strumenti sono:

L E F IFO R EAL - TIME


RTAI fornisce una versione specializzata delle FIFO per l’ambiente real-
time. Sono dei buffer unidirezionali non bloccanti che permettono il
trasferimento di dati in modalità asincrona. Ad ogni FIFO corrisponde un
file del tipo /dev/rtf/<num> dove <num> e il numero identificatore della
FIFO.
La creazione e l’accesso deve avvenire dal task real-time tramite le API
fornite, mentre i processi in user-space possono accedervi tramite le
primitive classiche che linux mette a disposizione per l’accesso ai file.

S HARED MEMORY
Viene allocato un blocco di memoria che può essere letto e scritto da tutti
i processi attivi nella macchina. Si accede a questa memoria direttamente
con un puntatore. Per questo motivo bisogna garantire l’accesso in mutua
esclusione per il corretto funzionamento. Ciò può avvenire tramite dei
semafori. E’ possibile accedere alla memoria condivisa tramite un file di
sistema. (/dev/rtai_shm)

17
Il progetto

M ESSAGE Q UEUE E RPC


E’ un meccanismo di scambio di messaggi dove mittente e destinatario
devono conoscersi. Le code di messaggi vengono ordinate per priorità e le
chiamate sono bloccanti fintantoché il destinatario non riceve il
messaggio o nel caso delle RPC fino alla risposta del destinatario.

M AILBOX
In questo caso la mailbox fa da centro di smistamento dei messaggi. Più
produttori e consumatori possono registrarsi contemporaneamente alla
stessa mailbox e mandare e ricevere messaggi.
Nel nostro caso è stato scelto di utilizzare delle FIFO per le IPC in quanto l’uso che
ne dobbiamo fare è limitato e il loro utilizzo è molto semplice. Per utilizzare una
FIFO in un task real-time è sufficiente utilizzare i seguenti comandi:

int rtf_create(unsigned int fifo, int size)


Crea la FIFO real-time con identificativo “fifo” e dimensione iniziale “size”.

int rtf_put(unsigned int fifo, char * buf, int count)


Scrive nella FIFO “fifo”, un array di byte “buf” della dimensione “count”.

rtf_destroy ( int fifo )

Distrugge la FIFO real-time precedentemente creata con identificatore


“fifo”.

Player, un framework Robotico


Player è un HAL (Hardware Abstraction Layer) per dispositivi robotici. In pratica
definisce, tramite delle interfacce, sia una serie di caratteristiche e
comportamenti comuni dei dispositivi solitamente presenti sui robot, sia le azioni
standard con cui si può interagire con questi dispositivi. In questo modo chi
sviluppa la logica di comando del robot non deve preoccuparsi dei dettagli
hardware del robot e il codice che farà utilizzo di queste interfacce sarà facilmente
portabile anche tra robot con un diverso hardware.

18
Il progetto

Player mette a
disposizione, oltre che
queste librerie di driver e
interfacce, anche
numerosi tool di utilità per
chi sviluppa applicazioni
per la robotica. Tra questi
tool alcuni sono di
notevole interessere ed in
particolare il programma
“player” che è in pratica
un server di rete per il
controllo robotico e
permette quindi anche la
realizzazione di una
piattaforma robotica
distribuita.

Il collegamento elettrico delle varie


parti del robot
Il sensore ultrasuoni è stato collegato al connettore LCD della scheda TS-7250. In
particolare la coppia di porte LCD_1 LCD_0 della TS-7250, corrispondenti ai pin 7
ed 8 è stata collegata ai piedini rispettivamente di trigger e di echo.
L’alimentazione del sensore invece è stata prelevata dai pin 1 e 2 del connettore
LCD che sono rispettivamente 5v e GND.
Il lettore infrarosso invece è stato collegato all’ADC e, in particolare, il canale 0 del
ADC converter corrispondente al pin 1 del connettore A/D è stato collegato
all’uscita Vc del sensore infrarosso. La sua alimentazione è stata invece presa dai
pin 16 e 2 del connettore DIO corrispondenti a 3.3v e GND.
Il controllo motore gestito dal circuito Wirz (e dal suo circuito di opto-isolazione) è
stato collegato sulle coppie di porte DIO LCD_2 LCD_3 e LCD_4 LCD_5
corrispondenti ai pin 10, 9 e 12, 11 del connettore LCD. LCD_2 e LCD_4 regolano la
velocità, mentre LCD_3 e LCD_5 la direzione.
I sensori odometrici sono invece collegati alla porta DIO della TS-7250 e,
precisamente, alle coppie di porte DIO0, DIO1 e DIO2, DIO3 corrispondenti ai pin
1, 3 e 5, 7. Di queste, DIO0 e DIO1 saranno rispettivamente i canali A e B di un
odometro, e DIO2 e DIO3 quelli dell’altro.

19
Il progetto

20
I TASK REALTIME

Il modulo RTAI per la gestione del


sensore ad ultrasuoni

Il sensore ad ultrasuoni si interfaccia alla scheda


TS-7250 tramite due porte di digital I/O. Lo
schema di funzionamento è abbastanza semplice:
alzando il livello del segnale di una delle due
porte di digital I/O è possibile inviare un segnale
“trigger” che produce il segnale acustico.
Sull’altra linea, invece, sarà possibile osservare il tempo di percorrenza dell’eco
del segnale: dalla partenza all’arrivo.
Si veda dunque il seguente grafico illustrativo:

21
I Task RealTime

Il codice
Invio il trigger:

outb_p(DIO_OUTPUT_PIN_MASK,DIO_LCD_DATA);

rt_sleep(nano2count(15000LL));
outb_p(0x00,DIO_LCD_DATA);
Attendo che il segnale si alzi sulla seconda linea DIO e salvo un timestamp:

while ((inb_p(DIO_LCD_DATA) &


DIO_INPUT_PIN_MASK) == 0x00){

}
start_eco_pulse = rt_get_cpu_time_ns();
Attendo che il segnale si abbassi e calcolo da differenza:

while ((inb_p(DIO_LCD_DATA) &


DIO_INPUT_PIN_MASK) != 0x00){

}
distance = rt_get_cpu_time_ns()-start_eco_pulse;

Il modulo RTAI per la gestione


dell’infrarosso

Il sensore infrarosso si interfaccia con la scheda tramite un canale dell’ADC


integrato sulla scheda. Il segnale restituito dal sensore è un segnale analogico in
tensione che varia principalmente in funzione della distanza.

L’Adc integrato nel EP9302


L’adc integrato nell’ep9302 è un ADC con 5 canali a 12 bit che può misurare
tensioni da 0 a 3,3 volt.
Per poter utilizzare l’ADC bisogna prima seguire un procedura particolare atta ad
abilitarlo, alimentarlo e attivare il canale per la lettura. Tutto ciò avviene
impostando determinati registri in maniera opportuna.

22
I Task RealTime

In particolare i passi da seguire sono i seguenti:


1. Impostare il SYSSWLOCK per sbloccare il registro SYS
2. Impostare il bit TSEN per attivare il clock dell’ADC
3. Impostare il bit TIN per disabilitare la modalità touchscreen
4. Resettare il bit ADCPD per alimentare il device
5. Impostare il ADCSWLOCK per sbloccare il registro ADC
6. Impostare ADCSWITCH_OFFSET per selezionare il canale di lettura

A questo punto è possibile effettuare le misure iterando la lettura del registro


ADCRESULT_OFFSET e controllando se il bit SDR è settato. Qualora non lo fosse,
significa che la lettura è stata già letta e va scartata. Quindi:
7. Leggo il flag SDR da ADCRESULT_OFFSET
8. Leggo i dati da ADCRESULT_OFFSET

Il codice
L’inizializzazione

/* set SYSSWLOCK PUNTO 1 */


outl_p(UNLOCK_VAL, SYSCON_PAGE + SYSSWLOCK);
//unlock the software lock

/* set TSEN bit PUNTO 2 */


val = inl_p(SYSCON_PAGE + KEYTCHCLKDIV);
outl_p(TSEN_MASK | val, SYSCON_PAGE +
KEYTCHCLKDIV); //attivo il clock del adc

/* set TIN bit PUNTO 3 */


val = inl_p(SYSCON_PAGE + DEVICECFG);
outl_p(val | ADCEN_MASK, SYSCON_PAGE +
DEVICECFG); //disabilito il touchscreen

/* clear ADCPD bit PUNTO 4*/


val = inl_p(SYSCON_PAGE + DEVICECFG);
outl_p(val & ~ADCPD_MASK, SYSCON_PAGE +
DEVICECFG); //power up del clock e del adc

/* set ADCSWLOCK PUNTO 5*/


outl_p(UNLOCK_VAL, ADC_PAGE + ADCSWLOCK_OFFSET);
//unlock the soft lock

/* set adc channel PUNTO 6*/


outl_p(ADC_CH0, ADC_PAGE + ADCSWITCH_OFFSET);
e quindi poi per le letture si itera:

23
I Task RealTime

/* wait sdr set PUNTO 7*/


while(is_ADC_busy());

/* read data PUNTO 8*/


//read result from data register
val = inl_p(ADC_PAGE + DATA_OFFSET);
//scarto i bit 16bitt alti
val = val & DATA_MASK;
dove ADC_busy() è il controllo se il dato è nuovo
val = inl_p(ADC_PAGE + ADCRESULT_OFFSET);

if((val & SDR_MASK) == SDR_MASK)


return TRUE;
return FALSE;

Il modulo RTAI per la gestione dei


MOTORI

Il modulo RTAI per la gestione dei MOTORI colloquia attraverso quattro porte di
digital I/O (due per motore) con il circuito Wirz per il controllo motori.
Il circuito ha bisogno di due segnali distinti in ingresso per ogni motore,
rappresentanti la direzione del moto e la velocità. Per quanto riguarda la
selezione della direzione sarà necessario alternare il livello del segnale sulla porta
di digital I/O per invertire la direzione. Si noti che però occorre eseguire
l’operazione a motori fermi per non danneggiare il circuito. Per quanto riguarda
invece la modifica di velocità di rotazione dei motori, questa avviene tramite la
generazione di un’onda quadra a frequenza fissa (tra i 100Hz e i 20kHz) e variando
il “duty cycle”, ovverosia il tempo in cui il livello di tensione è alto nel periodo.
E’ stato creato quindi un task con il compito di generare il segnale per i due motori
in base ai dati letti dalla FIFO di input con la procedura rappresentata nel
seguente diagramma.

24
I Task RealTime

V e lo c it à V e lo c it à
M o to re M o to re Si
A B Vel A > 0 A ccendi A

No

Si
Vel B > 0 A ccendi B
A s p e t ta la Si
Vel A > 0 e
p r o s s im a No
Vel B > 0
s c h e d u la z io n e
No
No
Vel B > A

Si

Si A tte n d i il Si A tte n d i il
Vel B > 0 “ D u ty T im e ” Vel A > 0 “ D u ty T im e ”
di B di A

No No

Spegni B Spegni A

A tte n d i il A tte n d i il
A tt e n d i il “ D u ty A tt e n d i il “ D u ty
“ D u ty T im e ” “ D u ty T im e ”
T im e ” d i A T im e ” d i B
di A - B di B - A

Spegni A Spegni B

Il codice
N.B. Il funzionamento del seguente codice non è stato verificato sul robot

if (pwm_duty_cycle_A != 0 && pwm_duty_cycle_B !=


0) {
if (pwm_duty_cycle_A > 0)
outb_p(inb_p(DIO_MOTOR_DATA)|
0x01,DIO_MOTOR_DATA);
if (pwm_duty_cycle_B > 0)
outb_p(inb_p(DIO_MOTOR_DATA)|
0x04,DIO_MOTOR_DATA);

//decido chi devo spegnere per primo


time = TASK_PWM_PERIOD;
if (pwm_duty_cycle_A < pwm_duty_cycle_B) {
//aspetto e spengo A per primo
if (pwm_duty_cycle_A > 0) {
time =
TASK_PWM_PERIOD*pwm_duty_cycle_A/0x100;
rt_sleep(nano2count(time));
outb_p(inb_p(DIO_MOTOR_DATA)&
0xFE,DIO_MOTOR_DATA);
}
//quidni spengo B
rt_sleep(nano2count(TASK_PWM_PERIOD
- time));

25
I Task RealTime

outb_p(inb_p(DIO_MOTOR_DATA)&
0xFB,DIO_MOTOR_DATA);
}
else {
//aspetto e spengo B per primo
if (pwm_duty_cycle_B > 0) {
time =
TASK_PWM_PERIOD*pwm_duty_cycle_B/0x100;
rt_sleep(nano2count(time));
outb_p(inb_p(DIO_MOTOR_DATA)&
0xFB,DIO_MOTOR_DATA);
}
//quindi spengo A
rt_sleep(nano2count(TASK_PWM_PERIOD
- time));
outb_p(inb_p(DIO_MOTOR_DATA)&
0xFE,DIO_MOTOR_DATA);
}
}
rt_task_wait_period();

Il modulo RTAI per la gestione dei


sensori ODOMETRICI
Il modulo RTAI per la gestione dei sensori odometrici colloquia con i sensori
attraverso due coppie di porte di digital I/O. Infatti il sensore genera sulle due
digital I/O due segnali periodici uguale sfasati di 90°.

26
I Task RealTime

Questo consente di determinare il verso e la velocità di rotazione del motore. Il


verso infatti si determina dallo sfasamento dei due canali. La velocità di rotazione,
invece, dipende dalla durata del periodo.
In questo modulo verranno creati due task separati: uno per leggere i dati e uno
per riempire la FIFO. Si è scelto questo approccio in quanto è necessario
campionare lo stato delle due porte abbastanza velocemente da non perdere
l’ordine in cui i fronti d’onda salgono o scendono ma sarebbe inutile immettere
dati nella FIFO con questa cadenza. Si è quindi preferito inserire le informazioni
nella FIFO in un task separato con una periodicità diversa.
Il task per la lettura eseguirà quindi le seguente operazioni periodicamente:
1. Lettura dello stato delle due linee di ogni motore
2. Confronto con lo stato precedente di ogni motore
3. In caso di variazione di stato, incremento o decremento del contatore
motore

Il codice
// PUNTO 1
state=inb_p(PORTB);
nowa=state & DIO_ODOMETRY1_MASK;
nowb=state & DIO_ODOMETRY2_MASK;

// PUNTO 2
tempa = step_odo(&olda,nowa,DIO_ODOMETRY1_MASK);
tempb = step_odo(&oldb,nowb,DIO_ODOMETRY2_MASK);

// PUNTO 3
counta+=(signed int)tempa;
countb-=(signed int)tempb;

dove step_odo() assume come argomenti lo stato passato, lo stato attuale del
segnale e la maschera da usare per poi determinare il verso di rotazione.
Questa operazione viene eseguita secondo il grafico riportato all’inizio del
capitoletto.

27
I DRIVER PLAYER

I driver Player
Player può caricare
dinamicamente delle
estensioni chiamate
“driver” dagli
sviluppatori di player.
Questi driver
permettono sia di
integrare i vari
disposivi del robot
all’interno del
framework player, sia
di associare tra loro altri driver per esporre interfacce di livello più alto.
L’interfaccia di un driver presenta tre metodi principali:
• Setup
• Shutdown
• ProcessMessage
In particolare, i primi due vengono chiamati quando il modulo viene attivato o
disattivato.
Il terzo, invece, viene eseguito ogniqualvolta il driver è pronto per ricevere i
messaggi dagli altri driver a cui è collegato e ci sono dei messaggi in attesa di
essere elaborati. Il lavoro del driver verrà eseguito quindi all’interno di un thread
dove verrà gestito il flusso di informazioni come mostrato nell’immagine in alto.

virtual int Setup();


virtual int Shutdown();
virtual int ProcessMessage(QueuePointer
&resp_queue, player_msghdr * hdr, void *
data);

29
I Driver Player

Per generare il thread è possibile utilizzare una serie di metodi della


della classe Driver
che deve essere ereditata per pe poter scrivere un driver. In n particolare,
StartThread() e StopThread() generano e terminano un thread che andrà a
eseguire la funziona Main(),, già dichiarata dentro la classe Driver, di cui sarà
necessario fare l’override.

virtual void Main();


All’interno del main si chiamerà la funzione di driver ProcessMessages().. In
questo
sto modo, il nostro driver potrà rendersi disponibile a ricevere messaggi
tramite la ProcessMessage(…).
ProcessMessage(…) Si userà anche la funzione Publish(…) per
spedire messaggi contenenti informazioni
informazi relative all’hardware.
Se si vuole inoltre realizzare delle librerie caricate dinamicamente da player,
player
bisognerà includere dei blocchi di codice statici che si occupino di:
• registrare il driver stesso all’interno del registro dei driver di player
• istruire player su come generare una propria instanza.
Per far cio è necessario
ecessario implementare il seguente metodo come “esterno”:

int player_driver_init(DriverTable* table)


ed usare il metodo

DriverTable::AddDriver(char *name, DriverInitFn


DriverTable::
initfunc
initfunc)
per informare player su che
he metodo usare per instanziare un driver.

Srf005driver
er
Questo driver è dedicato a leggere i dati del
sensore a ultrasuoni dalla FIFO e metterli a
disposizione della piattaforma player attraverso
l’interfaccia “sonar”.. Oltre a ciò il driver si
occupa di installare e rimuovere il modulo real-
real
time della gestione del sensore quando
richiesto.. In questo modo è possibile sia
risparmiare capacità di calcolo sia allungare
l’autonomia del robot.
L’interfaccia “sonar” che questo driver espone
gestisce schiere di sensori ad ultrasuoni.
u Essa
prevede che il driver:

30
I Driver Player

• sia interrogato riguardo alla disposizione di ogni sensore nella schiera


• gli sia richiesta l’attivazione e la disattivazione dei sensori per risparmiare
capacità delle batterie (funzione che non è supportata dall’hardware a
nostra disposizione).
Riepilogando lo scopo del nostro driver sarà quello di:
• Leggere i dati dalla FIFO e trasformali in misure di distanza
• Rispondere alle richieste sulla disposizione dei sensori ad ultrasuoni
• Trasmettere le letture fatte

Eleaborazione delle distanze


Le letture vengono prese dal modulo RTAI per la gestione del sensore ad
ultrasuoni tramite le FIFO. Si ricordi che la FIFO è riempita con dei long int
rappresentanti il tempo tra il lancio dell’impulso sonoro e la ricezione dell’eco
espresso in nanosecondi. Prima di strutturare e inoltrare il messaggio con questo
dato si dovrà calcolare la distanza percorsa dall’impulso e dividerlo per due al fine
di calcolare la distanza dall’ostacolo presente dinanzi al sensore. Il calcolo da fare
è banale, considerata la velocità del suono nell’aria a temperatura ambiente è di
circa 343m/s.
ܵ[݉] = ‫ ∗ ]ݏ݊[ݐ ≅ ݐ ∗ ݒ‬5800000

Geometrie dei sensore ad ultrasuoni


L’interfaccia “sonar” di player prevede che per ogni sensore ad ultrasuoni sia
possibile richiederne la posizione in cui è montato e la direzione in cui è puntato
rispetto al robot. Questa richiesta verrà formulata con un messaggio del tipo
PLAYER_MSGTYPE_REQ e sottotipo PLAYER_SONAR_REQ_GET_GEOM. A tale
richiesta bisogna rispondere con un messaggio di tipo
PLAYER_MSGTYPE_RESP_ACK e sottotipo PLAYER_SONAR_REQ_GET_GEOM. A
questo messaggio è stata allegata una struttura dati di tipo player_sonar_geom_t
contenente le geometrie di tutti i sensori ad ultrasuoni disponibili (posizione e
direzione).
Si utilizza, infine, la funzione Publish() della classe Driver per pubblicare il
messaggio.

Trasmissione delle letture


Per le letture sarà necessario preparare un messaggio del tipo
PLAYER_MSGTYPE_DATA e sottotipo PLAYER_SONAR_DATA_RANGES con
allegata una struttura dati di tipo player_sonar_data_t.

31
I Driver Player

Questa struttura dati deve


contentere tutte le ultime
letture dei sensori ultrasuoni
compresi nell’arrayy
rappresentato dal driver. Nel
nostro caso ci sarà un’unicaa rilevazione.

Setup e Shutdown del driver


Il modulo si occupa, come detto,
detto anche del inserimento del modulo real-time
time e
della sua rimozione tramite delle semplice chiamate shell ai comandi insmod e
rmmod.

system("insmod rt_sonar.o");
system("rmmod rt_sonar.o");

2d120xdriver
Questo driver è dedicato alla lla lettura della FIFO contenente i dati acquisiti dal
d
sensore infrarosso e all’inserimento
mento degli stessi all’interno del sistema di eventi di
Player. L’interfaccia Player
layer per gli array di sensori infrarosso è molto simile a
quella per i sensori ad ultrasuoni.
ultrasuoni In questo caso, però, è necessario fare qualche
elaborazione in più per interpretare i dati letti dai sensori.
In particolare, la funzione che fa corrispondere alla distanza di un oggetto posto
dinanzi al sensore una tensione non è invertibile e quindi sarà necessario adottare
degli accorgimenti per poter ottenere delle letture significative.
Questo driver si occuperà come il precedente driver per il sensore ad ultrasuoni
delle seguenti operazioni:
• Leggere i dati dalla FIFO e trasformali in misure di distanza
• Rispondere alle richieste sulla disposizione dei sensori infrarosso
• Trasmettere
ttere le letture di tensione e di distanza fatte

Elaborazione delle distanze


Anche qui le letture verranno prese dalla FIFO riempita dal modulo RTAI per la
gestione del sensore infrarosso. Queste letture di tipo intero rappresentano i
livelli di quantizzazione del segnale di ingresso all’ADC. Le letture devono essere
correlate
ate con i due punti di riferimento misurati dal produttore per ogni canale

32
I Driver Player

dell’hardware e registrate nella EEPROM della stessa scheda tra l’indirizzo


l
0x07EB e l’indirizzo 0x07FE come valori da 16bit.
In particolare in questa zona di memoria si trova un array bidimensionale dalla
seguente struttura che definisce i valori delle
d tensioni riferimento a 0 e 2.5V

[channel number][0V ref. point, 2.5V ref. Point]

Calcolato il valore di tensione


ensione presente in ingresso all’ADC
a è possibile calcolare
calcol la
distanza dell’oggetto posto davanti al sensore.
Per fare ciò, però, prima bisogna rendere
rendere la funzione di trasformazione del
sensore invertibile.

33
I Driver Player

Questo è realizzabile semplicemente restringendo il dominio della funzione nel


intervallo [3cm - 40cm] e installando fisicamente il sensore in modo tale che
questa distanza minima sia sempre rispettata.
A questo punto la funzione è stata divisa in tante spezzate in cui può essere
considerata lineare. Si ottiene così la seguente tabella, in cui nella prima riga
abbiamo
biamo i valori di tensione e nella seconda riga i relativi valori di distanza
(assoluta):

0.31 0.37 0.43 0.52 0.65 0.73 0.81 0.93 1.05 1.26 1.4 1.55 1.76 2.1 2.34 2.73 2.98 3.3

40 35 30 25 20 18 16 14 12 10 9 8 7 6 5 4 3.5 3

Nel costruttore del driver vengono calcolati i coefficienti angolari delle spezzate.
Una volta determinata la spezzata di appartenenza del punto, questo dato verrà
poi utilizzato per calcolare la distanza effettiva nel seguente modo:

distance = uppermapping[1][c-1]
uppermapp +
m[c]*(irdaValue - uppermapping[0][c-1]);
dove uppermapping è l’array sopra m è l’array dei
’array rappresentante la tabella qua sopra,
coefficienti angolari delle spezzate relative ai punti noti e irdavalue è il valore
della tensione rilevata.

Geometria dei sensori infrarosso


L’interfaccia “ir” di Player
layer prevede che per ogni sensore a infrarosso sia possibile
richiederne la posizione
one in cui è montato e la direzione in cui è puntato rispetto al
robot. Questa richiesta verrà formulata con un
messaggio del tipo PLAYER_MSGTYPE_REQ e sottotipo
PLAYER_IR_REQ_POSE.. A tale richiesta bisogna
rispondere con un messaggio di tipo
PLAYER_MSGTYPE_RESP_ACK
LAYER_MSGTYPE_RESP_ACK. A questo messaggio è
stata allegata una struttura dati di tipo player_ir_pose_t
contenente le geometrie di tutti i sensori ad infrarosso
disponibili (posizione, e direzione).
direzione)
Per fare ciò è stata utilizzata la funzione Publish() della
classe Driver.

Trasmissione delle letture


Per le letture sarà necessario allo stesso modo
necessario preparare un messaggio con tipo
PLAYER_MSGTYPE_DATA e sottotipo

34
I Driver Player

PLAYER_IR_DATA_RANGES con allegata una struttura dati di tipo


player_ir_data_t.

Questa struttura dati ti deve contenere


conten tutte le ultime
letture dei sensori infrarosso compresi nell’array
rappresentato da questo driver. Nel nostro caso ci sarà
un unica rilevazione.

Driver MotoriDriver
Moto
Il driver motori ha lo scopo sia di comandare
l’azionamento dei motori sia di leggere le informazioni degli odometri per fornire
una stima della posizione del robot.
L’interfaccia player che questo driver implementa è la “position2d”.
I compiti principali
incipali di questo driver saranno di:
1. Leggere i dati odometrici dal modulo RTAI per i motori tramite la FIFO.
2. Fornire una geometria del robot, cioè la sua forma.
3. Regolare tramite la FIFO la velocità dei motori per ottenere velocità assiali
as
richieste.
4. Fornire la posizione stimata del robot sul piano.
Questo
uesto driver è stata realizzato solo in parte e quindi non sarà qui discusso.

Lo script di configurazione
Per utilizzaree il nostro robot all’interno del programma player sarà necessario
creare un script di configurazione che associa
associa al robot una serie di driver che ne
rappresentano le funzionalità e le relative configurazioni.
Nelel nostro caso dovremo definire tre driver: uno per l’array di sensori ad
ultrasuoni, uno per l’array di sensori ad infrarosso e, infine, uno per l’odometria e
il comando motori.. Il terzo driver, però, purtroppo non è stato completato per
mancanza dell’hardware.

35
I Driver Player

#imhotep.cfg
driver
(
name "2d120xdriver"
plugin "lib2d120xdriver"
provides ["ir:0"]
fifo "/dev/rtf/1"
)
driver
(
name "srf005driver"
plugin "libsrf005driver"
provides ["sonar:0"]
fifo "/dev/rtf/0"
)

36
CONCLUSIONI

Risultati raggiunti
Nell’ambito di questo progetto, si è riuscito a ricompilare il kernel del sistema
operativo TS-Linux con le estensioni real-time. E’ stato inoltre cross-compilato il
framework Player e le librerie richieste. Player, quindi, è ora eseguibile sulla
piattaforma ARM.
Si son realizzati i moduli per la lettura in real-time dei sensori e per il comando dei
motori. Sono stati sviluppati pure i driver Player che fanno uso di questi ultimi per
integrare la nostra piattaforma robotica nell’architettura di Player. Unica
eccezione per il driver Player per il controllo motori che non è stato terminato per
mancanza dell’hardware necessario.
Grazie a questi risultati, è ora possibile scrivere una logica di controllo
indipendente dalla piattaforma robotica e utilizzabile con questo robot.

Prospettive di sviluppo
Lo sviluppo di driver di alto-livello, l’analisi e la progettazione di logiche
decisionali, possono considerarsi l’evoluzione naturale di questo lavoro.
Tra questi una delle vie più dirette che può essere intrapresa sul robot è
l’integrazione dei driver wavefront per aggiungere al robot la capacità di
pianificare percorsi a lungo raggio e quindi dargli la capacità di navigazione in un
ambiente complesso. In tale ottica, sarà necessario provvedere a fornire al driver
un’informazione rispetto alla posizione del robot e una di navigazione locale, che
permetta di evitare collisioni e programmare lo spostamento tra punti vicini.
Per far ciò sono già disponibili dei driver, e in particolare:

37
Conclusioni

1. Il driver VHF che serve per dare al robot capacità di navigazione locale
secondo l’algoritmo Vector Field Histogram Plus di Ulrich e Borenstein.
Questo permette al robot di evitare gli ostacoli muovendosi su un
percorso programmato (waypoints)
2. Il driver AMCL che è un implementazione dell’algoritmo di localizzazione
adattiva monte-carlo e che serve a localizzare la posizione del robot
all’interno di una mappa fornita a priori. La localizzazione avviene a
partire dai dati dei sensori laser o sonar.
Per soddisfare i requisiti dei driver sarebbe sicuramente necessaria l’integrazione
di più sensori ad ultrasuoni sulla piattaforma. Un altro cambiamento essenziale è
costituito dalla modifica del modulo real-time in modo che provveda alla lettura di
più sensori contemporaneamente, senza dover creare un task ed occupare una
FIFO per ognuno dei sensori. Inoltre l’implementazione corrente del driver AMCL
funziona solamente con scanner laser. Sarebbe consigliabile prendere in esame la
possibilità di modificare quest’ultimo in modo che supporti anche le letture di
sensori ad ultrasuoni. Questo anche alla luce dei costi elevati che gli scanner laser
possono raggiungere.

38
APPENDICI

Redboot
Accesso a redboot
E’ possibile accedere a redboot tramite l’interruzione dell’esecuzione automatica
dello script di avvio tramite terminale seriale inviando una sequenza di escape
(CTRL-C)
In alternativa, qualora sia noto l’indirizzo IP della scheda ARM, l’accesso può
essere effettuato connettendosi alla porta 9000 tramite protocollo telnet via
interfaccia ethernet. Il tempo a disposizione per connettersi a RedBoot tramite
ethernet è una finestra di pochi istanti che si apre dopo l’accensione del sistema.

Caricamento del Kernel tramite I/O


Tramite web server:

load -v -r -b 0x00218000 -m http -h <http sever


IP> <kernel name>
Da flash:

fis load <nome partizione> -b 0x00218000


Da TFTP

load –b 0x00218000 –h 192.168.0.1 vmlinuxNFS

Scrittura/Cancellazione del kernel nella flash


Per visualizzare la lista delle partizioni della flash si usa il comando:

fis list
Per cancellare una partizione si usa il comando:

39
Appendici

fis delete <nome partizione>


Per creare una nuova partizione (dopo averla caricata in memoria)

fis create –b <base_memory> -l<lunghezza> <nome


partizione>

Esecuzione un kernel linux


Dopo aver caricato in memoria un kernel con il comando load o fis load

exec –c “parametri del kernel”

Configurazione della scheda, e del script di avvio


Per visualizzare la configurazione corrente:

fconfig –l
Per modificare la configurazione corrente:

fconfig
In particolare per fare il boot da flash si userà il seguente script:

fis load <kernelimagename>


exec –c”ttyAM0,115200 ip=<ip>
root=/dev/mtdblock/1”
per fare il boot da nfs si usarà invece:

fis load <kernelimagename>


exec –c”ttyAM0,115200 ip=<ip>
nfsroot=<ipnfsserver>:<nome condivisione>”
Dove
• <ip> è l’ip che si vuol dare all’interfaccia ethernet della scheda
• <ipnfsserver> è l’ip del server che fa da host al servizio nfs
• <nome condivisione> è il nome della condivisione nfs contenente
il root file-system da usare

40
Appendici

Setup e configurazione di un server


NFS
Per configurare un server NFS su Linux è essenziale editare il file /etc/exports e
avviare i servizi portmap e nfs.
Il file /etc/exports non è altro che un elenco dove si specifica quali risorse
condividere e con quali modalità (ad esempio readonly o read-write), e con quali
credenziali i client potranno accedere a tale risorse (ad esempio network mask
etc).
Per modificare tale file occorre essere utente root. Di seguito è riportato un
esempio del file:

#La directory /export e tutto il suo contenuto è


esportato via NFS in modalità read-
only(ro) e ai soli client con un ip
#di network uguale a 10.0.0.0/24
/export 10.0.0.0/255.255.255.0(ro)
#La directory /home/kernel e tutto il suo
contenuto è esportato via NFS in moadalità
read-write(rw) e ai soli client
#con un ip di network uguale a 10.0.0.0/24
/home/kernel 10.0.0.0/255.255.255.0(rw)
Una volta impostato correttamente il file /etc/exports, si può avviare il servizio
avviando i demoni RPC e NFS:

/etc/rc.d/init.d/portmap start
/etc/rc.d/init.d/nfs start
Nel caso in cui il servizio sia già attivo occorre semplicemente eseguire il seguente
comando per fare in modo che il file /etc/exports venga riletto e che si aggiornino
le tabelle interne di appoggio al servizio NFS:

exportfs –a
Una configurazione ottimale per un file-system può essere:

/home/damiano/armroot
192.168.0.0/255.255.255.0(rw,no_root_squas
h,insecure_locks)
Si deve poi ricordare di modificare il file /etc/fstab della partizione “ARM” in
modo appropriato, aggiungendo

<ip>:</path/to/nfsroot /> nfs exec,dev,suid 1 1


e commentando:

41
Appendici

/dev/hda1 / ext2 defaults 1 1

Yaffs File-System
Il driver Yaffs per la gestione del file-system su flash durante il boot di default
troverà 3 partizioni. La prima contenente il bootroom, la seconda il file-system del
sistema e la terza contenente il kernel del sistema operativo e il redboot
Più o meno il log di avvio del kernel si presenterà così:

Searching for NAND flash...


NAND device: Manufacturer ID: 0xec, Chip ID:
0x75 (Samsung NAND 32MiB 3,3V 8-bit)
Scanning device for bad blocks
Using static partition definition
Creating 3 MTD partitions on "NAND 32MiB 3,3V 8-
bit":
0x00000000-0x00004000 : "TS-BOOTROM"
0x00004000-0x01d04000 : "Linux"
0x01d04000-0x02000000 : "RedBoot"
Per visualizzare il log si può usare il comando dmesg

Ripristino del file-system preinstallato


Per ripristinare o installare un nuovo file-system, bisogna prima cancellare il
vecchio completamente. Per fare ciò è consigliabile eseguire il kernel su un file-
system esterno montato magari con nfs ed eseguire il comando

eraseall /dev/mtd/1
oppure
mount /dev/mtdblock/1 /mnt
cd /mnt
rm –fr

NOTA IMPORTANTE: IN QUESTO PARAGRAFO si suppone che la seconda


partizione sia quella del file-system. IL NUMERO di “/dev/mtd/1” e
“/dev/mtdblock/1” va sostituito con quello opportuno della partizione “linux”
(la numerazione parte da 0)
A questo punto si può estrarre la nuova immagine montando la partizione flash,
qualora non sia già stato fatto.

42
Appendici

mount /dev/mtdblock/1 /mnt (se non è stato già


fatto)
tar xzvf <filesystem.tar.gz> -C /mnt
umount /mnt
Si può quindi riavviare la scheda con il comando

shutdown -r now

43
RINGRAZIAMENTI

Vorrei ringraziare, in primis, i miei genitori che mi han accompagnato con una
pazienza senza limite fino a questo traguardo. Senza di voi non sarei arrivato fino
a qui.
Ringrazio il mio relatore, il prof. Massimiliano Nolich, che è stato sempre
disponibilissimo nei miei confronti , aiutandomi ogni qualvolta possibile e
dandomi la più piena libertà nell’organizzare e sviluppare il progetto.
Un grazie anche a tutti i frequentatori della mailing-list del progetto Player-Stage,
e in particolare al signor Paul Osmialowski, per l’aiuto e la disponibilità che mi han
dato e l’entusiasmo con cui mi han sempre risposto.
Ringrazio anche l’amico e collega, Lorenzo Dal Col per il supporto che mi ha dato
nella compilazione del kernel RTAI e Roberto Furlani per la l’aiuto nella revisione
della tesi.

45
BIBLIOGRAFIA

Articoli e manuali:
• La guida completa C++ - Herbert Schildt. – 2nd Edition - McGraw-Hill, 1999
• Building Embedded Linux Sistem - Karim Yaghmour - 2nd Edition –
O’Reilly, 2008
• Getting started with ts-linux – Technologic Systems, 2006
• Linux for ARM on TS-7000 User's Guide – Technologic Systems, 2006
• TS-7250 Hardware Manual – Technologic Systems, 2006
• TS ARM Linux Developer's Manual – Technologic Systems, 2004

Siti internet di riferimento:


• Player - Player User Guide
http://playerstage.sourceforge.net/
• RTAI
https://www.rtai.org/
• Technologic System
http://www.embeddedarm.com/index.php

Documentazione tecnica:
• SRF05 - Ultra-Sonic Ranger
http://www.robot-electronics.co.uk/htm/srf05tech.htm
• Sharp - GP2D120X
http://www.sharpsma.com/Page.aspx/americas/en/part/GP2D120/
• Low Current Motor Driver
https://www.zagrosrobotics.com/files/wirz203.pdf
• Agilent Technologies – Optical Encoders
http://www.zagrosrobotics.com/files/heds55xx.pdf
• Cirrus Logic EP9302
http://www.cirrus.com/en/products/pro/detail/P1066.html

47
Appendici

• TS-7250 ARM Single Board Computer


http://www.embeddedarm.com/products/board-detail.php?product=TS-
7250
• Linux for ARM on TS-7000 Series SBC's
http://www.embeddedarm.com/software/software-arm-linux.php
• Real Time Application Interface for TS-7000 series SBC's
http://www.embeddedarm.com/software/arm-linux-24-rtai.php
• Player Sonar-Array Interface
http://playerstage.sourceforge.net/doc/Player-
2.1.0/player/group__interface__sonar.html
• Player Infrared-Array Interface
http://playerstage.sourceforge.net/doc/Player-
2.1.0/player/group__interface__ir.html
• Player Position2d Interface
http://playerstage.sourceforge.net/doc/Player-
2.1.0/player/group__interface__position2d.html

48

You might also like