ALMA MATER STUDIORUM
UNIVERSITÀ DI BOLOGNA
CAMPUS DI CESENA
SCUOLA DI INGEGNERIA E ARCHITETTURA
Corso di Laurea in
Ingegneria Informatica
LA PIATTAFORMA ROS PER LO
SVILUPPO DI APPLICAZIONI
ROBOTICHE
Elaborata nel corso di: Sistemi Operativi
Tesi di Laurea di:
DAVIDE LEARDINI
Relatore:
Prof. ALESSANDRO RICCI
ANNO ACCADEMICO 2013-2014
SESSIONE III
Parole chiave
ROS
Robot
Robotica
Piattaforma di Sviluppo
Ai miei cari
Indice
Prefazione
xi
1 Introduzione alla Robotica
1
1.1 Robotica, Breve Definizione . . . . . . . 1
1.2 Robot . . . . . . . . . . . . . . . . 3
1.2.1 Corpo . . . . . . . . . . . . . 4
1.2.2 Sensori . . . . . . . . . . . . 5
1.2.3 Effettori/Attuatori . . . . . . . .
5
1.2.4 Controllori . . . . . . . . . . . 7
2 ROS, Robot Operating System
8
2.1 Introduzione a ROS
8
2.2 Storia
. . . . . . . . . .
. . . . . . . . . . . . . . . . 9
2.3 ROS, Caratteristiche . . . . . . . . . . 10
2.4 ROS, Perchè Usarlo? . . . . . . . . . . 12
2.5 Architettura
. . . . . . . . . . . . . 15
2.5.1 Filesystem Level . . . . . . . . 16
2.5.1.1
Packages
. . . . . . . 16
2.5.1.2
Metapackages
2.5.1.3
Package Manifest . . . . 17
2.5.1.4
Stacks
2.5.1.5
Message (msg) Type . . . 18
2.5.1.6
Service (msg) Type . . . 19
. . . . . 17
. . . . . . . . 17
2.5.2 Computation Graph Level
. . . . 19
2.5.2.1
Nodi
. . . . . . . . 20
2.5.2.2
Master . . . . . . . . 21
2.5.2.3
Messaggi . . . . . . . 22
2.5.2.4
Topic
2.5.2.5
Servizi
2.5.2.6
Bag
. . . . . . . . 22
. . . . . . . 28
. . . . . . . . 32
2.5.3 Community Level
. . . . . . . 33
2.5.3.1 Distribuzioni
. . . . . . 33
2.5.3.2 Repositories
. . . . . . 34
2.5.3.3 ROS Wiki
. . . . . . . 34
3 Un Semplice Caso di Studio
35
3.1
Simulazione Robot Tramite Stage
. . .
35
3.2
Implementiamo il Movimento via Topic
3.3
Dalla Simulazione al Caso Reale . . . . 53
. 44
4 Conclusioni
54
Bibliografia e Sitografia
56
PREFAZIONE
Lo sviluppo hardware nel campo della robotica ha raggiunto negli
ultimi anni livelli impressionanti ed è in continua crescita, e di pari
passo si è espansa l’eterogeneità delle forme che può assumere, dalle
tipologie basate su movimento a terra ai droni volanti, fino a forme
più sofisticate di robot umanoidi che cercano di emularne il
comportamento. Se da un lato ora possiamo disporre di hardware
sempre più potente ed efficiente a costi sempre minori, dall’altro
programmare il comportamento che un robot deve tenere nelle
svariate circostanze in cui può imbattersi, nel poter portare a
compimento il proprio obbiettivo, risulta essere sempre più
complesso.
Dopo una breve introduzione alla robotica
e alle
difficoltà che deve affrontare e una panoramica sui robot, cosa siano e
come siano strutturati, fulcro della tesi sarà l’esposizione delle
caratteristiche principali di ROS, Robot Operating System, come
piattaforma di sviluppo software nel campo della robotica ,
e si
concluderà con un semplice caso di studio in cui ne verrà messo in
mostra concretamente l’utilizzo.
xi
Capitolo 1
Introduzione alla Robotica
1.1
Robotica, Breve Definizione
La Robotica è la branca dell’ingegneria che si occupa della
progettazione, dello sviluppo e del funzionamento dei robot, dei
sistemi informatici per l’elaborazione dei dati provenienti dai sensori e
del loro utilizzo per delineare il comportamento da tenere al fine di
eseguire compiti specifici. Il termine fu coniato nel 1920 dallo
scrittore - scienziato ceco Karel Capek e ha il significato di “ lavoro
forzato ”, e in effetti il fine ultimo di un robot è quello di riprodurre in
qualche forma il lavoro umano. Un Robot deve affrontare tutte le
difficoltà provenienti dall’interazione col mondo reale. Una semplice
salita può modificarne la velocità e la percezione della distanza
percorsa,
un
leggero
urto
può
condizionarne
la
traiettoria
irrimediabilmente. Cosi, pur avendola delineata come branca
dell’ingegneria, sono
molteplici le discipline con cui deve
confrontarsi. In primis vengono richieste conoscenze dei modelli
matematici e della fisica, soprattutto per quanto concerne tutta la
parte di acquisizione e elaborazione dei dati, essenziale per potersi
rapportare con l’ambiente con cui si interagisce.
1
Successivamente l’informatica è la disciplina cardine per tutta la parte
computazionale, e in primo luogo per quello che riguarda il controllo.
Come deve reagire il robot ai dati sensoriali? Nel caso debba eseguire
necessarimente piu azioni, quale deve essere l’ordine? Sono diverse
le architetture di controllo sviluppate al fine di ricreare una sorta di
“ intelligenza “ interna al robot, ed evidentemente il campo presenta
una complessità non affrontabile dal singolo programmatore. Nel
seguito della tesi verrà esposta una breve descrizione della struttura
tipica di un robot, e si entrerà nel dettaglio del framework ROS come
utile strumento nello sviluppo software e test di applicazioni
robotiche.
2
1.2
Robot
Definire cosa è un robot e cosa non lo è può risultare a volte triviale.
Con la parola “robot” si vuole indicare un sistema autonomo operante
nel mondo fisico, quindi con una struttura materiale, che percepisce
l’ambiente che lo circonda e che interagisce con esso, attuando
procedure al fine di perseguire l’ obiettivo per cui è stato creato.
Questa definizione contiene concetti molto importanti che distinguono
quello che vogliamo considerare robot da una semplice macchina.
Prima di tutto abbiamo chiarito che deve essere un sistema autonomo.
Deve perciò poter operare sulla base di decisioni prese per proprio
conto: pur potendo ricevere input da persone, non devono essere
controllati da essi al fine di raggiungere il proprio scopo. Un robot
deve avere una struttura fisica con cui interagire col mondo esterno e
affrontarne le sfide. Un robot che esiste solo all’interno di un
computer è solo una simulazione che non affronta la vera complessità
del mondo reale. E’ necessario che percepisca l’ambiente in cui si
ritrova ad operare. Deve montare di conseguenza sensori di vario tipo
al fine di reperire informazioni riguardo il mondo circostante, al fine
di poter rispondere in maniera adeguata agli ostacoli catturandone la
presenza nel proprio percorso. Differentemente a un robot simulato
siamo noi a dover fornire informazioni e conoscenze, e lavora di
conseguenza utilizzando dati ricavati “per magia”. Un robot deve
poter agire in risposta agli input derivanti dai sensori, montando
quelli che vengono definiti attuatori e affrontare il mondo circostante
nelle numerevoli forme in cui può presentarsi. Infine è necessario che
tutto quello che compia abbiamo come fine ultimo il perseguire un
obiettivo. Qui si entra nel campo dell’intelligenza di un robot: avere
un sistema autonomo in grado di captare gli stimoli provenienti
dall’esterno ma che agisse in maniera del tutto casuale sarebbe inutile.
3
Quello che lo differezia è il poter svolgere un task predefinito , il tutto
in maniera autonoma, la cui difficoltà può essere semplice come “ non
bloccarti” o di grado sempre più complesso come “percorri ogni
singoli centimetro di una stanza nella maniera più efficente e veloce
possibile”. Abbiamo finora descritto quali caratteristiche generali
debba avere una macchina al fine di poter essere considerata un robot,
ma per poter esistere deve presentare quattro elementi fisici che vanno
poi a rispecchiarsi nel relativo hardware: un corpo fisico, sensori,
effettori / attuatori e infine i controllori. Andremo a descriverli
brevemente a seguito.
1.2.1
Corpo
L’essere dotato di un corpo fisico è ovviamente necessario per esistere
e interagire nel mondo reale. Tuttavia lo porta a dover rispettare tutte
le leggi fisiche che esso impone, non potendo disporre dei vantaggi
presenti in simulazione. Non può cambiare le proprie dimensioni, così
come non può essere in due posti contemporaneamente. Per potersi
muovere deve sfruttare i propri attuatori, e aumentare o diminuire di
velocità richiede tempo ed è influenzato dalla topologia del mondo
circostante.
Inoltre disporre di un corpo implica la probabile
eventualità di incorrere in ostacoli e quindi di dover essere coscenti di
cosa vi è attorno. Infine il corpo impone al robot tutta una serie di
limitazioni, derivanti dalla forma e struttura del corpo stesso, che
vanno a influire sui movimenti, l’interazione con oggetti o altri robot,
il percepire l’esterno etc.
4
1.2.2
Sensori
Si identificano sotto il nome di sensori tutti i dispositivi fisici montati
su un robot in grado di ottenere informazioni dall’ambiente circostante
e permettere al robot stesso di essere “ coscente ” di ciò che lo
circonda. Il tipo di sensore montato dipende dal tipo di informazione
che viene richiesta al fine di poter portare a compimento il proprio
task. Si dividono essenzialmente in sensori passivi e attivi. I primi si
limitano a strumenti che rilevano la proprietà fisica da misurare,
mentre quelli attivi generano un segnale e sfruttano la relativa
interazione con l’ambiente circostante come proprietà da misurare.
L’uso di entrambi permette quindi al robot di essere a conoscenza del
proprio stato, ossia di una descrizione di sè stesso in un certo dato
momento, nel qual caso si parla di stato interno , e dell’ambiente
circostante in cui deve operare, e qui si parla di stato esterno. Avere a
disposizione uno stato interno risulta importante in quanto dà la
possibilità di memorizzare informazioni sul mondo in un modello o
rappresentazione. Una rappresentazione, sia essa di uno stato interno o
del mondo esterno, può assumere una grande varietà di forme e può
essere utilizzata in svariati modi da un robot. Ad esempio se
l’obiettivo fosse percorrere un labirinto, un robot potrebbe creare una
rappresentazione del percorso fatto basata sulle distanze esatte
percorse, oppure sulla sequenza di mosse eseguite in determinati punti
( gira a destra al primo angolo ). Più è complessa la rappresentazione,
maggiore è il costo in memoria utilizzata.
1.2.3
Effettori / Attuatori
Per effettore si intende ogni dispositivo fisico che ha un impatto
sull’ambiente reale su cui il robot deve operare. Sono essenzialmente
5
la controparte meccanica di quello che in biologia rappresenta una
gamba, un braccio, un dito. Il meccanismo che rende possibile ad un
effettore di compiere un’azione viene definito attuatore, e tale termine
include dispositivi di diffenti tipi di tecnologie:

Motori elettrici: i più comuni attuatori adoperati per facilità
d’uso, affidabilità e varietà di grandezze e forme in cui sono
reperibili, forniti di elettricità al giusto voltaggio permettono
di convertire l’energia elettromagnetica in energia cinetica
producendo movimento.

Dispositivi
idraulici:
consistono
in
attuatori
il
cui
funzionamento è basato sulla pressione di un fluido. Alla sua
variazione, l’attuatore inizia a muoversi. Potenti e precisi,
hanno il difetto di avere dimensioni generalmente elevate e di
essere potenzialmente pericolosi se non bene progettati.

Dispositivi pneumatici: hanno le stesse caratteristiche di
funzionamento dei dispositivi idraulici, ma anzichè essere
basati sulla pressione di un fluido utilizzano la pressione
dell’aria.

Materiali foto-reattivi: materiali che producono un lavoro
fisico in risposta all’ammontare della quantità di luce attorno a
loro. Il lavoro generato e generalmente molto contenuto, e
vengono utilizzati di conseguenza in robot di piccole
dimensioni.
6

Materiali chimico-reattivi:
materiali che reagiscono in
presenza di una sostanza chimica, come ad esempio particolari
fibbre in grado di accorciarsi in presenza di soluzioni acidi e
allungarsi con soluzioni basiche.

Materiali reattivi termicamente: tutti i materiali che hanno
una reazione di qualche tipo in presenza di un cambiamento di
temperatura nell’ambiente circostante.

Materiali piezoelettrici: materiali costituiti generalemente da
cristalli in grado di creare cariche elettriche se premuti.
1.2.4
Controllori
Sono la componente hardware e software che permettono al robot di
essere autonomo, processando gli input provenienti dai sensori o altre
informazioni come quelle contenute in memoria,
decidere quale
azione intraprendere e di conseguenza quali effettori mettere in
movimento. Costituiscono quindi la controparte robotica di quello che
è essenzialmente il cervello e il sistema nervoso. Generalmente su un
robot coesistono più controllori che operano su gruppi differenti di
sensori e effettori in modo tale da poter , nello stesso istante,
processare più informazioni e prendere decisioni differenti sulle
azione che le varie parti del robot devono intraprendere.
.
7
Capitolo 2
ROS, Robot Operating System
2.1
Introduzione a ROS
Abbiamo brevemento introdotto in cosa consista un robot, quali siano
le sue caratteritische fisiche, il suo hardware, ma d’altronde per poter
funzionare, prendere decisioni, deve disporre di un’intelligenza
artificiale costituita dal software. Di fronte al continuo progesso della
tecnologia nell’ambito della robotica e ai crescenti obiettivi sempre
più audaci che essa si pone, lo sviluppo in ambito software è divenuto
non meno difficoltoso e non triviale. Programmare un robot richiede
codice su più livelli, da software più basilare lato driver , a forme
molto complesse dedite a ricreare una forma di percezione del mondo
circostante, fino a un più alto livello in cui si va a ricreare il
comportamento voluto, ossia che il robot abbia un’intelligenza
artificiale interna in grado di reagire agli input derivanti dai sensori
secondo la metodologia di controllo più adatta al caso specifico,
Deliberative Control, Reactive Control, Behaviour-Based Control per
citarne alcune. Programmare un robot richiede abbandonare la
sicurezza dello sviluppo software classico e immergersi nel mondo
fisico e nella sua casualità, nel mondo asincrono dove la presenza di
un minimo ostacolo può deviare la traiettoria,
dove l’unica
consapevolezza di ciò che ci circonda è data dai sensori e un minimo
errore può avere grandi ripercussioni, dove le risorse in termini di
memoria, processori, energia di alimentazione sono limitate.
Programmare un robot è una sfida che va ben oltre alle capacità del
8
singolo ricercatore. D’innzanzi alle sopra citate difficoltà sono
molteplici i framework realizzati dalle varie comunità di ricercatori
per ovviare ai problemi dello sviluppo software lato robotica,
contenerne la complessità e facilitare la rapidità di rilascio di prototipi
per il testing. Un framework viene progettato con lo scopo di aiutare
lo sviluppo di un determinato tipo di software, ne consegue che non
esista “il miglior framework ” ma che ognuno sia il frutto di tradeoff
e priorità decise nel proprio ciclo di vita per far fronte a determinati
problemi. Nel seguito analizzeremo nel dettaglio ROS, progettato per
fronteggiare lo sviluppo dei cosiddetti “ large-scale service robot ”,
orientato a una programmazione parallela e general purpose.
2.2
Storia
Lo sviluppo di ROS ebbe ufficialmente inizio nel 2007 sotto il nome
di Switchyard presso lo Stanford Artificial Intelligence Laboratory a
supporto del progetto Stanford Artificial Robot ( STAIR)
programma Personal Robotics ( PR ).
e del
Nel 2008 lo sviluppo del
progetto progredisce presso il Willow Garage, ente di ricerca e
incubatore nel campo della robotica che versa il proprio contributo
approfondendo i principi con cui il progetto nasce e realizzando le
prime versioni testate. Qua assume il nome ROS, Robot Operating
System, nel 2010 viene rilasciata la prima versione stabile presentante
la maggior parte delle caratteristiche odierne, e continua lo sviluppo
fino al 2013 quando avviene la transizione presso l’ Open Source
Robotics Foundation e il Willow Garage viene assorbito dalla
Clearpath Robotics.
Rilasciato dall’inizio sotto licenza BSD (
Berkeley Software Distribution
)
è un software gratuito sia per
l’ambito di ricerca che per fini commerciali. Ciò ha favorito fin da
9
subito il suo sviluppo nel corso degli anni grazie al contributo della
comunità di ricerca mondiale ed è divenuto uno dei suoi punti di
forza.
2.3
ROS, Caratteristiche
ROS è una collezione in continua crescita di librerie software open
source e tools progettate al fine di aiutare gli sviluppatori nella
realizzazione di applicazioni robot. Acronimo di Robot Operating
System, a discapito del nome non si identifica in un sistema operativo
nel senso stretto del nome. Viene definito infatti come meta-operating
system, inglobando sì le caratteristiche tipiche di un vero e proprio
sistema operativo ( astrazione dell’hardware sottostante, gestione dei
processi, package managment,
gestione dei dispositivi ) ma
arricchendolo con elementi tipici di un middleware ( fornisce
l’infrastruttura per la comunicazione tra processi/macchine differenti
), e di un framework ( tools di utilità per lo sviluppo, debugging e
simulazione).
10
ROS opera essenzialmente su piattaforme Unix-Based, anche se sono
numerevoli le piattaforme sperimentali.
11
ROS attualmente supporta tre differenti linguaggi: C++, Phyton,
LISP.
Inoltre vengono esposte di seguito alcune delle numerose piattaforme
robotiche che supportano il framework ROS.
2.4
ROS, Perchè Usarlo?
Ci si potrebbe probabilmente chiedere perchè usare ROS e quali
vantaggi avremmo per il nostro software. D’altronde per quanto la
curva di apprendimento possa essere bassa, diventare abili nell’uso di
un nuovo framework richiede sempre tempo, tempo ben investito o
meno? In realtà sono numerevoli le situazioni in cui l’uso di ROS
12
apporta un effettivo grande contributo, situazioni che in cui ci si
scontra di continuo nella programmazione di software per robot.

Sistemi Distribuiti
Numerevoli robot ai giorni nostri contano su software basato
sulla cooperazione di molti processi spesso nemmeno
risiedenti sulla stessa macchina, ma diffusi su più computer
differenti. Alcuni possono integrare in sè più computer,
ognuno dei quali controlla un gruppo di sensori o attuatori.
Altri possono operare con un singolo computer dovente gestire
operazioni complesse con alto rischio di incorrere in errori, e
seguendo un algoritmo divide et impera suddividere il proprio
software in più parti cooperanti tra loro per raggiungere
l’obiettivo comune. Uno stesso task può essere raggiunto con
la coordinazione di più robot che devono agire all’unisono per
risolvere il problema. In tutti i suddetti casi coesiste la
necessità di poter comunicare tra processi, siano essi insiti
nello stesso robot o suddivisi tra differenti, e il middleware
garantito da ROS permette ciò tramite due meccanismi
primari, topic per una comunicazione asincrona, servizi per la
tipologia sincrona, ognuno dei quali verrà discusso piu avanti.

Standardizzazione e riuso del codice
Il rapido progresso della robotica ha portato allo sviluppo di
algoritmi sempre più complessi ed efficaci per ovviare ai tipici
problemi quali ad esempio la navigazione , il mapping di una
zona, la scelta del percorso migliore. Di pari passo avere
un’implementazione stabile di tali algoritmi senza dover ogni
13
volta si cambi sistema dover integrare con altro codice o
reimplementare risulterebbe utile. Ciò è garantito da ROS e
dalla grande comunità di ricerca che lo sostiene alle spalle.
ROS garantisce packages debuggati e testati di molti algoritmi
usati in robotica. Inoltre la sua interfaccia di comunicazione
attraverso scambio di messaggi sta divenendo una standard de
facto nell’interoperabilità del software in ambito robotica, e
interfacce ROS per le ultime versioni hardware o algoritmi
usciti sono spesso disponibili. Tutto ciò permette agli
sviluppatori di concentrarsi nella creazione di un’applicazione
sulle idee e il testing e non perdere tempo con codice
integrativo, perchè le librerie necessarie risultano già
disponibili, stabili e debuggate.

Testing
Il testing su software per applicazioni nell’ambito della
robotica richiede più tempo ed è più incline alla presenza di
errori. Per di più non sempre è disponibile fisicamente il robot
e anche se fosse accessibile spesso il processo di testing risulta
macchinoso e lento. ROS permette invece di sviluppare sistemi
in cui la parte di controllo a livello hardware sia separata dalla
gestione dei meccanismi di più alto livello, e di testare
quest’ultimi simulando l’hardware e il software di basso
livello. Inoltre ROS offre la possibilità di memorizzare i dati
ottenuti dai sensori e in fase di test in un formato che prende il
nome “ bag ”, per poi visualizzarli, analizzarli e riutilizarli più
e più volte nello stesso processo o in processi differenti.
Testato fisicamente sul robot, o su un simulatore o vengano
utilizzati dei dati di tipo bag, il software non richiede
14
integrazioni o modifiche al codice perchè tutte le modalità
forniscono uno stesso interfacciamento.
2.5
Architettura
ROS è basato su un’architettura a grafo dove il processamento avviene
nei nodi, che comunicano tra loro attraverso lo scambio di messaggi
in maniera asincrona attraverso l’uso di topic ai quali possono
sottoscrivere e/o sui quali possono pubblicare, e in maniera sincrona
con la chiamata di servizi, simili a RPC.
Strutturalmente ROS si sviluppa su 3 livelli concettuali, Filesystem
Level, Computational Level e Community Level, di cui andremo ad
esaminare gli elementi costitutivi e il loro ruolo nell’architettura .
15
2.5.1
Filesystem Level
Il Filesistem Level comprende tutte le risorse utilizzate in ROS, in
particolare Packages, Metapackages, Package Manifest, Stacks,
Message ( msg ) Type, Service (srv) Type.
2.5.1.1
Packages
In ROS il software viene organizzato in packages, che in sostanza
costituiscono dei moduli. Ogni package può contenere un nodo ROS,
un file di configurazione, un dataset, una libreria, software di terze
parti etc. Lo scopo dei packages è ottenere una maniera efficace per il
16
riuso del codice, venendo strutturati in modo tale da risultare
funzionali ma non troppo pesanti e difficili da utilizzare.
2.5.1.2
Metapackages
Costituiscono forme particolari di package che non contengono nè file
nè codice. Vengono usati per referire che più package sono legati
assieme.
2.5.1.3
Package Manifest
Fornisce tutti i metadati riguardanti un package, nome, versione
descrizione, licenza, dipendenze.
2.5.1.4
Stacks
Sono collezioni di packages con il comune scopo di svolgere un
determinato task. Così a titolo di esempio il “ Navigation Stack “ è lo
stack contenente tutti i package necessari al movimento del robot.
Ogni Stack ha associata una versione e può dichiarare dipendenze da
17
altri Stack. Sono in ROS il meccanismo primario per la distribuzione
del software.
2.5.1.5
Message ( msg ) Type
Indica il tipo di dato del messaggio, che determina di conseguenza il
contenuto del messaggio stesso. E’ strutturato come una lista di campi,
uno per linea, ognuno dei quali è definito dalla concatenazione di un
tipo di dato built-in ( come bool, string, float64 etc) e nome del
campo. Come esempio si riporta la struttura del messaggio
geometry_msgs/Twist, che verrà utilizzato più volte nell’esempio
applicativo a fine tesi:
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64
z
18
Sia “linear” che “angular” risultano essere campi composti il cui tipo
di dato è geometry_msgs/Vector3. In generale un campo composto è
semplicemente la combinazione di uno o più sotto-campi, ognuno dei
quali può essere a sua volta un altro campo composto o un campo
semplice con tipo di dato built-in.
2.5.1.6
Service ( msg ) Type
Indica il tipo di dato del messaggio scambiato nell’uso dei servizi di
ROS, che determina di conseguenza il contenuto del messaggio stesso.
Alla stessa maniera del message type, un service data type è definito
da una collezione di campi con nome come visto in precedenza.
Tuttavia la differenza consiste nel fatto che un service data type è
suddiviso in due parti. Essendo utilizzati in un modello di
comunicazione request/response, una parte dei campi sarà relativa
alla request, mentre l’altra relativa alle response.
2.5.2
Computation Graph Level
Il Computation Graph consiste nella rete peer-to-peer descritta da tutti
i processi attivi in ROS che stanno elaborando dati assieme. L’utilizzo
di una topologia peer-to-peer permette di evitare carichi di traffico di
messaggi eccessivi quali si potrebbero avere tra i componenti
periferici e ad esempio un server centrale, nel caso in cui i computer
operanti siano collegati in una rete eterogenea, ma richiede un name
service per rendere possibile ai nodi di contattarsi a vicenda nella rete.
Verrano descritti in seguito gli elementi base del Computation Graph,
nodi e master, Topic e servizi per quanto riguarda la comunicazione
con scambio di messaggi rispettivamente in maniera asincrona e
sincrona, e bag.
19
2.5.2.1
Nodi
Un nodo è un processo che compie una qualsiasi attività
computazionale all’interno del sistema ROS. Essendo ROS progettato
per essere modulare e fine-grained, tipicamente un sistema basato su
di esso comprende numerosi nodi, e in tal contesto sono interpretabili
come moduli software, ognuno dei quali incaricato di gestire un
aspetto del comportamento del robot, come ad esempio la parte
decisionale, il movimento, l’azionamento dei motori etc. Un sistema il
cui carico computazionale venga ripartito tra i vari nodi di cui è
costituito ha innanzitutto il vantaggio di una maggiore tolleranza agli
errori, potendo gestire il crash del singolo nodo. La complessità del
codice è ridotta se confrontata coi sistemi monolitici e i dettagli
implementativi sono nascosti in quanti i singoli nodi offrono
un’interfaccia composta da una API minimale. Ogni nodo in
esecuzione dispone di quello che viene definito “ graph resource
name “, un nome che lo identifica unicamente al resto del sistema, e di
un tipo che semplifica il processo di indirizzamento di un nodo
eseguibile all’interno del filesystem. Tutti i tipi sono trattati come “
package resource names”, costituiti dalla concatenazione del nome
del package e del file eseguibile del nodo.
20
2.5.2.2
Master
In un sistema basato su ROS, il Master è un server centralizzato
XML-RPC che offre ai nodi un servizio di registrazione e di naming,
similmente all’informazione data da un server DNS. Permette infatti al
singolo nodo di contattarne un secondo attraverso una metodologia
peer-to-peer. Tiene inoltre traccia per ogni singolo topic dei relativi
pubblisher e subscriber allo stesso modo gestisce i servizi. Il Master
offre anche il Parameter Server. Implementato attraverso XMLRPC,
offre un servizio di memorizzazione e consultazione di parametri a
runtime ai nodi che ne richiedono i servizi attraverso un’ API di rete.
Essendo globalmente accessibile, offre il vantaggio a tutti i tool di
sviluppo di poter analizzare in qualsiasi momento la configurazione
dello stato del sistema e modificarne i parametri se necessario.
21
2.5.2.3
Messaggi
La comunicazione tra nodi avviene tramite scambio di messaggi. In
ROS un messaggio è una struttura dati fortemente tipizzata. Sono
supportati tutti i tipi standard primitivi ( integer, floating point,
boolean etc. ) così come array di tipi primitivi
e costanti. Ogni
messaggio può essere composto da altri messaggi o array di altri
messaggi, arbitrariamente nidificati in complessità. La struttura di un
messaggio è descritta da un semplice file di testo denominato msg file,
di estensione .msg, contenuti nelle sottocartelle dei package. Un msg
file è costituito da due parti : campi ( fields) e costanti (constants ). I
campi sono i dati spediti all’interno del messaggio, mentre le costanti
sono valori numerici utili a interpretare il significato dei campi.
2.5.2.4
Topic
I topic costituiscono il mezzo di comunicazione asincrono,
unidirezionale, per lo scambio di messaggi tra nodi, secondo una
semantica di tipo publish/subscribe. Ci possono essere più publisher e
subscriber concorrenti per un singolo topic, e un singolo nodo può
pubblicare e/o sottoscriversi a più topics. In generale, publisher e
degli
altri,
disaccoppiando cosi la produzione dell’informazione dal
suo
subscriber
non
sono
consapevoli
dell’esistenza
consumo. Ogni topic è fortemente tipizzato dal tipo di messaggio che
viene pubblicato, e i nodi possono ricevere solo messaggi il cui tipo
faccia matching. Ciò determina che all’interno del topic sia possibile
scrivere o leggere un solo tipo di messaggio. Ogni nodo presenta un
URI, che corrisponde alla concatenazione host:porta del server
XMLRPC che è attivo. Tale server non trasporta topic o dati, ma viene
utilizzato per negoziare la connessione tra nodi e comunicare col
22
Master. Il master ha altresì un well-known URI accessibile da tutti i
nodi. La procedura sequenziale che permette a due nodi della rete di
poter scambiare messaggi attraverso un topic si riassume nei seguenti
passaggi:
1. Il publisher si registra al Master attraverso XMLRPC. Invia
informazioni riguardo a ciò che andrà a pubblicare, tipo dei
messaggi, nome del topic e il proprio URI.
2. Il subscriber si registra al Master attraverso XMLRPC. Anche
qui vengono inviati informazioni su tipo dei messaggi, nome
del topic e proprio URI. Il Master ritorna la lista di tutti gli
URI degli attuali publisher, e aggiornamenti di quest’ultima
qualora cambiasse.
Il Master mantiene una tabella in cui risiedono tutti i dati sia per i
subscriber che per i publisher.
3. Il Master informa il subscriber del nuovo publisher tramite
XMLRPC, comunicandogli l’URI.
4. Il subscriber contatta il publisher per richiedere la connessione
al topic e negoziare il protocollo di trasporto, sempre tramite
XMLRPC. TCP (TCPROS) è largamento usato per via della
maggior affidabilità del suo stream . I pacchetti TCP giungono
sempre in ordine, e quelli persi rimandati. Ma esistono anche
casi in cui il protocollo UDP ( UDPROS ) risulata
maggiormente
efficace,
ad
esempio
per
comunicare
simultaneamente in maniera broadcast. ROS lascia la scelta del
protocollo libera in fase di negoziazione.
23
5. Il publisher invia al subscriber la configurazione adatta al tipo
di protocollo di trasporto scelto. Nel caso TCP ad esempio
indirizzo IP e numero di porta.
6. Il subscriber si connette separatamente al publisher secondo il
protocollo scelto.
7. I successivi messaggi pubblicati dal publisher verranno inviati
al subscriber attraverso il canale aperto. Stabilita la
connessione non è più richiesto il coinvolgimento del Master
che in nessun momento è coinvolto nel flusso di dati scambiati
nel topic.
24
Il lavoro di pubblicare messaggi è eseguito da un oggetto della classe
ros::Publisher, che viene così creato
ros::Publisher pub = node_handle.advertise<message_type>(
topic_name, queue_size);
dove :

Node_handle è un oggetto della classe ros::NodeHandle, una
cui istanza generalmente viene creata a inizio programma.

Message_type è il tipo del messaggio che vogliamo pubblicare

Topic_name è il nome del topic su cui pubblicare.

Queue_size è la grandezza della coda dei messaggi in uscita.
Per pubblicare il messaggio è sufficiente poi utilizzare il metodo
publish(msg)
dell’oggetto ros::Publisher. Invocare la funzione
publish() serializza il messaggio in un buffer, il quale successivamente
viene messo in coda. Tale coda viene processata il prima possibile in
maniera asincrona da uno dei thread interni di roscpp, il package
contenente le librerie per l’interfacciamento coi topic e service. Il
messaggio serializzato contenuto è spostato, dal thread , per ogni
subscriber connesso al topic in una coda ad esso associata. Il numero
di messaggi che questo secondo set di code può contenere prima che i
vecchi siano scartati è definito dal parametro queue_size della
funzione advertise() di cui abbiamo parlato in precedenza. Infine i dati
serializzati
sono
inviati
sulle
connessioni
degli
subscriber.
25
Diametralmente dall’altro lato della comunicazione avremo un nodo
subscriber. La differenza importante rispetto a un publisher consiste
nel fatto che il nodo subscriber non è a conoscenza di quando il
messaggio
effettivamente
arriverà.
Per
fronteggiare
ciò,
va
implementato il codice che risponda ai messaggi in entrata in una
funzione di callback,
che verrà chiamata per ogni messaggio in
arrivo. Tipicamente una funzione di callback ha la seguente signature:
void function_name(const package_name::type_name &msg) {
...
}
I parametri “package_name” e “type_name” sono gli stessi del
publisher, in quanto si riferiscono alla classe del messaggio per il
topic a cui miriamo sottoscrivere. Il corpo della funzione di callback
ha accesso a tutti i campi dei messaggi in arrivo, e può decidere
liberamente se utilizzare, scartare o memorizzare i dati contenuti. Il
ritorno della chiamata è void in quanto è ROS a gestire la chiamata
alla funzione. I Messaggi in arrivo vengono messi in una coda fino a
quando ROS ha la possibilità di eseguire la callback. La grandezza
della coda viene definita nella costruzione del subscriber, che andiamo
ora ad analizzare.
Per creare un ros::Subscriber si utilizza la seguente signature
ros::Subscriber sub = node_handle.subscribe(topic_name,
queue_size, pointer_to_callback_function);
26
dove:

Topic_name è il nome del topic in format stringa al quale
vogliamo sottoscrivere

Queue_size è appunto l’integer che va a definire la grandezza
dell coda in cui alloggiare i messaggi non ancora processati. In
caso di arrivo di un nuovo messaggio e coda piena, il più
vecchio viene scartato.

Pointer_to_callback_function è il puntatore alla funzione di
callback
Non è menzionato il tipo del messaggio in quanto il compilatore lo
recupera dal tipo di dato del puntatore a callback che gli viene
fornito.ROS esegue le chiamate di callback solo quando lato user
viene esplicitamente detto di farlo.
Ciò avviene utilizzando due
differenti funzioni:

ros::spinOnce() ordina a ROS di eseguire tutte le callback
pendenti da tutte le sottoscrizioni del nodo e ritorna il controllo
.

ros::spin() ordina a ROS di attendere e processare callback
finchè il nodo risulta attivo, entrando in un loop simile a quello
che si otterrebbe da
while(ros::ok()) {
ros::spinOnce();
}
27
In conclusione, usare i topic risulta molto efficiente in situazioni in
cui si ha un flusso continuo di dati, come quelli derivanti dai sensori o
parametri relativi allo stato del robot.
2.5.2.5
Servizi
I servizi rappresentano il mezzo di comunicazione sincrono secondo
una semantica di tipo request / reply, implementando in ROS
funzionalità di RPC. Andranno cosi a definirsi nella rete nodi che
svolgeranno funzione di service provider e nodi client. Esistono
funzioni per verificare la presenza di un service provider nella rete . Il
nodo client invierà dei dati che prenderanno il nome di request a un
nodo server, aspettando la risposta di quest’ultimo. Il nodo server una
volta ricevuta, processerà la request del client a cui inviere come
risposta dei dati col nome di response. Un nodo client che voglia
usufruire
di
un
servizio
inizializza
un
oggetto
di
tipo
ros::ServiceClient che ha il compito di inoltrare la chiamata, e la cui
signature è
ros::ServiceClient client = node_handle.serviceClient<service_type>(
service_name);
dove:

Service_type
è il service data type utilizzato nella
comunicazione

Service_name è il nome passato come stringa del servizio che
si vuole chiamare
28
Successivamente si creano gli oggetti Request e Response
package_name::service_type::Request
package_name::service_type::Response
ed essendo lato Client riempita la Request coi dati da inviare al nodo
server.
La chiamata al servizio
bool success = service_client.call(request, response);
effettua infine il lavoro di localizzare il nodo server, trasmettere la
Request, attendere l’arrivo della risposta e magazzinarne i dati ricevuti
nei campi dell’oggetto Response creato in precedenza. Il ritorno è di
tipo booleano indicandoci se la chiamata ha avuto successo o meno.
Lato server, come accadeva per i subscriber, ogni servizio che il nodo
offre deve essere associato a una funzione di callback con signature
bool function_name(
package_name::service_type::Request &req),
package_name::service_type::Response &resp)
){
...
}
29
Ros esegue la funzione di callback relativa una volta per ogni
chiamata al servizio che il nodo riceve, il cui compito è
essenzialmente riempire i campi dell’oggetto Response.
Successivamente si associa la funzione di callback col nome del
servizio attraverso
ros::ServiceServer server = node_handle.advertiseService(
service_name,
pointer_to_callback_function
);
dove:

Service_name è il nome in formato stringa del servizio che si
va ad offrire.

Pointer_to_callback_function è il puntatore alla callback prima
definita
Come visto coi topic, anche qui ROS non eseguirà nessuna callback
finchè non sarà esplicitato con ros::spin() o ros::spinOnce():
Il protocollo di accesso a un servizio può essere riassunto nei seguenti
passaggi:
1. Registrazione del servizio nel Master.
2. Richiesta di un determinato servizio al Master da parte di un
client.
30
3. Creazione di una connessione TCP/IP al servizio da parte del
Client.
4. Scambio tra Client e servizio di un Connection Header, il quale
contiene importanti metadata sulla connessione che andrà a
crearsi.
5. Invio del messaggio di request serializzato da parte del Client.
6. Invio del messaggio di response serializzato da parte del
servizio.
Di default, le connessioni a un servizio sono stateless, e per ogni
chiamata il Client desideri fare va ripetuto il protocollo sopra citato
per ottenere una nuova connessione al service. Ciò permette un
approccio più robusto e che un nodo che svolga la funzione di service
provider possa venire riavviato, col tradeoff di un maggiore overhead.
ROS tuttavia presenta anche una forma di connessione persistente a un
service in cui viene mantenuta aperta al fine di permettere al client
31
ripetuti invii di request. A un maggiore throughput, il tradeoff da
pagare consiste nel fatto che nel caso in cui appaia un nuovo nodo
provider del servizio a sostituzione del precedente, la connessione non
verrà ugualmente interrotta, mentre se la connessione dovesse cadere
per motivi tecnici non ci sarebbero tentativi di ripristino.
2.5.2.6
Bag
E’ un formato file, con estensione .bag, utilizzato in ROS per la
memorizzazione di dati di tipo ROS message. Viene creato dal tool
rosbag, il quale si iscrive a uno o più topic e memorizza in un file i
messaggi in forma serializzata. E’ il meccanismo sfruttato da ROS
per fare il logging nelle comunicazioni topic.
32
2.5.3
Community Level
Comprende tutte le risorse che permettono a comunità separate di
ricercatori di poter interagire scambiando software.
2.5.3.1
Distribuzioni
Sono collezioni di stacks versionati pronti all’installazione. Fino ad
ora sono state otto le distribuzioni rilasciate, delle quali l’ultima è
ROS Indigo Igloo.
33
2.5.3.2
Repositories
Per ROS è stato scelto un modello di repository federato del codice:
anzichè utilizzare un medesimo server centrale in cui depositare il
codice, ogni gruppo di ricercatori può creare il proprio repository di
ROS sui propri server mantenendo il pieno controllo e tutti i diritti sul
codice ivi depositato. Decidendo poi di renderlo pubblico,
otterrebbero tutti i riconoscimenti e i crediti per i propri
conseguimenti, e i feedback tecnici utili al miglioramento come in
ogni progetto software open-source.
Questa metodologia di
condivione del codice ha enfatizzato e massimizzato la partecipazione
della comunità internazionale al progetto, rendendo ROS tra i
framework piu utilizzati a livello mondiali nell’ambito dello sviluppo
di applicazioni per robot, dalle più semplice ai grandi sistemi di
automazione industriali.
2.5.3.3
ROS Wiki
E il forum princiale per documentarsi su ROS. Dopo una veloce
registrazione, si può contribuire alla crescita della comunità scrivendo
tutorial, offrendo aiuto, correzioni, update.
34
Capitolo 3
Un Semplice Caso di Studio
3.1
Simulazione Robot Tramite Stage
In seguito verrà proposto un esempio applicativo di utilizzo di topic
per trasmettere informazioni e permettere il movimento casuale di un
robot in un ambiente con ostacoli. Verrà utilizzato a tal proposito
Stage. Stage è un tool di simulazione che permette di simulare robot
muniti di sensori in una mappa in due dimensioni. Essendo stato
progettato nell’ambito della ricerca per i sistemi multi-agente
autonomi,
fornisce, dei molti dispositivi emulati, un modello
computazionale piuttosto semplice. Tuttavia pur non simulandoli con
grande fedeltà, sono numerosi i sensori che permette di utilizzare a
bordo dei robot, laser, bouncer, dispositivi a infrarossi fra questi.
Stage è implementato attraverso lo Stage Stack, il quale contiene il
nodo Stageros che fornisce le funzionalità del simulatore utilizzando
ROS. Ricrea l’ambiente definito in un file di estensione .world, che
contiene tutti i dettagli implementativi su sensori utilizzati, struttura
del robot, composizione della mappa e ostacoli. Il codice del .world
file che verrà utilizzato al fine della simulazione è il seguente:
define block model
(
size [0.5 0.5 0.5]
gui_nose 0
)
35
define robot_laser ranger
(
Sensor
(
range [ 0.0 5.0 ]
fov 40.25
samples 1081
)
color "green"
size [ 10 10 20 ]
)
define robot position
(
size [0.35 0.35 0.25]
origin [-0.05 0 0 0]
gui_nose 1
drive "diff"
robot_laser(pose [ 0.050 0.000 0 0.000 ])
)
define floorplan model
(
color "gray30"
boundary 1
gui_nose 0
gui_grid 0
gui_outline 0
gripper_return 0
fiducial_return 0
36
laser_return 1
)
resolution 0.02
interval_sim 100
window
(
size [ 745.000 448.000 ]
show_data 1
rotate [ 0.000 -1.560 ]
scale 28.806
)
floorplan
(
name "test_map"
bitmap "autolab.png"
size [54.0 58.7 0.5]
pose [ 0 0 0 90.000 ]
)
robot ( pose [ 5 -5 0 180.000 ] name "bot" color "red" )
Senza analizzare nel dettaglio il codice in ogni singola riga, viene
caricata la mappa “autolab.png” e posizionato nel punto voluto il
robot, descritto da:
define robot position
(
size [0.35 0.35 0.25]
37
origin [-0.05 0 0 0]
gui_nose 1
drive "diff"
robot_laser(pose [ 0.050 0.000 0 0.000 ])
)
Sarà quindi un differential wheeled robot, ossia la classica tipologia
che monta per il movimento due ruote, ciascuna su uno dei due lati del
corpo, permettendo alla base mobile di curvare variando la velocità
relativa di rotazione delle singole ruote.
Inoltre monterà in testa un laser di 5m di range per individuare la
presenza di ostacoli onde evitarli, le cui caratteristiche sono descritte
da:
38
define robot_laser ranger
(
Sensor
(
range [ 0.0 5.0 ]
fov 40.25
samples 1081
)
color "green"
size [ 10 10 20 ]
)
Avviando il simulatore tramite riga di comando
rosrun stage_ros stageros $(rospack find stage_ros)/world/map.world
si aprirà la nostra mappa con al centro il robot emulato come in figura:
39
In realtà quello che accade a livello di codice è la creazione del nodo
Stageros, che a sua volta sottoscrive a/ pubblica su diversi topic,
visualizzabili attraverso il comando
rostopic list
che mostra la seguente lista:
Nel dettaglio quello che Stageros esegue a livello di topic è:

sottoscrivere il topic cmd_vel da cui riceverà informazioni di
comando per la velocità lineare e angolare del robot
sottoforma di messaggi di tipo geometry_msgs/Twist di
struttura:
geometry_msgs/Twist twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
40
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z

Pubblicare informazioni odometriche sullo stato del robot sui
topic /odom e /base_pose_ground_truth attraverso messaggi di
tipo nav_msgs/Odometry con struttura:
Header header
uint32 seq
time stamp
string frame_id
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/Pose pose
geometry_msgs/Point position
float64 x
float64 y
float64 z
geometry_msgs/Quaternion orientation
float64 x
float64 y
float64 z
float64 w
float64[36] covariance
geometry_msgs/TwistWithCovariance twist
41
geometry_msgs/Twist twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
float64[36] covariance

Pubblicare i dati ottenuti dalle scansioni del laser sul topic
base_scan attraverso messaggi di tipo sensor_msgs/LaserScan
con struttura :
Header header
float32 angle_min
# angolo iniziale di scan [rad]
float32 angle_max
# angolo finale di scan [rad]
float32 angle_increment # distanza angolare [rad]
float32 time_increment # tempo tra le misurazioni [s]
float32 scan_time
# tempo tra ogni scan [s]
float32 range_min
# range minimo [m]
float32 range_max
# range massimo [m]
float32[] ranges
# range dei dati [m]
42
float32[] intensities
# intensità del dato
Ne consegue che Stageros presenterà la seguente configurazione:
Andremo in seguito a creare un nodo che permetterà al robot simulato
di muoversi e un nodo che pubblicherà semplicemente le informazioni
odometriche di base, velocità lineare e velocità angolare, sul topic
/rosout, lo “standard output” di ROS per visualizzare messaggi di
logging su console.
43
3.2
Implementiamo il Movimento via Topic
Affinchè il robot simulato possa muoversi nella mappa in cui è stato
posizionato, avendo cura di evitare gli ostacoli, è necessario instaurare
una comunicazione tra il nodo stageros e un nodo che andremo a
creare ( e che chiameremo per comodità Walker ) che si sviluppi nel
seguente modo:
1. Walker sottoscrive il topic /base_scan.
2. Stageros pubblica i dati metrici provenienti dalle scansioni
laser
sul
topic
/base_scan
sottoforma
di
messaggio
sensor_msgs/LaserScan
3. Walker riceve i dati, li processa e ricava velocità lineare e
angolare da impartire
4. Walker pubblica velocità lineare e angolare sul topic /cmd_vel
( al quale Stageros è sottoscritto ) sottoforma di messaggio
geometry_msgs/Twist.
5. Stageros riceve le informazioni e il robot in simulazione
inizializza il movimento.
44
Viene proposta ora di seguito il codice del nodo Walker, che verrà poi
commentato nelle sue parti:
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
#include "sensor_msgs/LaserScan.h"
#include <cstdlib>
#include <ctime>
#define FORWARD_SPEED 1
#define ROTATE_SPEED 1.4
#define REVERSAL_ROTATE_SPEED -1.4
45
class Walker {
public:
Walker(ros::NodeHandle& nh) {
commandPub=nh.advertise<geometry_msgs::Twist>("cmd_vel",1);
laserSub=nh.subscribe("base_scan",1,&Walker::commandCallback,
this);
};
void move(double linearVel, double angularVel) {
geometry_msgs::Twist msg;
msg.linear.x = linearVel;
msg.angular.z = angularVel;
commandPub.publish(msg);
};
void commandCallback(const sensor_msgs::LaserScan::ConstPtr&
msg) {
float closestRange = msg->ranges[0];
for( int x = 0; x< msg->ranges.size(); x++){
if(msg->ranges[x] < closestRange){
closestRange
=
msg->ranges[x];
46
}
}
ROS_INFO_STREAM("Range: " << closestRange);
if (closestRange < 2){
srand(time(NULL));
int random;
random = rand() % 2 + 1;
if (random > 1){
move(0, ROTATE_SPEED);
}else{
move(0, -REVERSAL_ROTATE_SPEED);
}
}else{
move(FORWARD_SPEED, 0);
return;
}
};
ros::Publisher commandPub;
ros::Subscriber laserSub;
};
int main(int argc, char **argv) {
ros::init(argc, argv, "Walker");
ros::NodeHandle n;
Walker walker(n);
ros::spin();
47
return 0;
}
Partiamo analizzando il main. Dopo aver, attraverso l’invocazione di
ros::init(argc, argv, "Walker");
ros::NodeHandle n;
inizializzato il nodo e assegnatogli il nome “Walker” ( che deve
essere univoco all’interno di ROS ) , creiamo l’oggetto “Walker” che,
come si evidenzia dal costruttore
public:
Walker(ros::NodeHandle& nh) {
commandPub=nh.advertise<geometry_msgs::Twist>("cmd_vel",1);
laserSub=nh.subscribe("base_scan",1,&Walker::commandCallback,
this);
};
Esegue due chiamate di funzione:
commandPub=nh.advertise<geometry_msgs::Twist>("cmd_vel",1);
Connette il nostro nodo al ROS Master indicando che pubblicherà
messaggi di tipo geometry_msg/Twist nel topic /cmd_vel e che avrà
come grandezza della coda dei messaggi in uscita un solo messaggio,
garantendoci che verrà pubblicato sempre l’ultimo messaggio
generato.
48
laserSub=nh.subscribe("base_scan",1,&Walker::commandCallback,
this);
Sottoscrive il nostro nodo al topic /base_scan e imposta come
funzione di callback il nostro metodo di classe commandCallback
passato come puntatore, che verrà chiamata ogniqualvolta arriverà un
nuovo messaggio da quel topic. A questo punto il nostro nodo è
sottoscritto al topic /base_scan dove arriveranno le informazioni
relative al puntatore laser, e pubblica i comandi di velocità nel topic
/cmd_vel.
Invocando
ros::spin();
Mandiamo il nostro nodo in un loop infinito. Fino allo shutdown del
nodo, ordiniamo a ROS di attendere e processare tutte le callback da
tutti i nodi sottoscritti, nel nostro caso /base_scan. Quindi ad ogni
49
nuovo messaggio in arrivo, verrà lanciata il nostro metodo di callback
di cui il codice:
void commandCallback(const sensor_msgs::LaserScan::ConstPtr&
msg) {
float closestRange = msg->ranges[0];
for( int x = 0; x< msg->ranges.size(); x++){
if(msg->ranges[x] < closestRange){
closestRange = msg->ranges[x];
}
}
ROS_INFO_STREAM("Range: " << closestRange);
if (closestRange < 2){
srand(time(NULL));
int random;
random = rand() % 2 + 1;
if (random > 1){
move(0, ROTATE_SPEED);
}else{
move(0, -REVERSAL_ROTATE_SPEED);
}
}else{
move(FORWARD_SPEED, 0);
return;
}
};
La nostra callback eseguirà un ciclo for dove analizzerà il messaggio
LaserScan, in particolar modo analizzerà ogni punto della scansione e
50
memorizzerà in una variabile quello di distanza inferiore. Dopodichè
se tale valore risulterà inferiore a una certa soglia, verrà impartito il
comando di ruotare casualmente a destra o sinistra, in caso contrario
di continuare ad avanzare dritto. I comandi per la rotazione o il
proseguimento sono inoltrati attraverso la funzione move() di cui il
codice:
void move(double linearVel, double angularVel) {
geometry_msgs::Twist msg;
msg.linear.x = linearVel;
msg.angular.z = angularVel;
commandPub.publish(msg);
};
Tale funzione compila un messaggio di tipo geometry_msgs/Twist
con informazioni riguardo la velocità lineare o angolare a seconda che
si voglia far proseguire diritto o far curvare il robot simulato, e lo
pubblica sul topic /cmd_vel dove Stage_ros è in ascolto. Il risultato
finale sarà il movimento randomico all’interno della mappa del nostro
robot simulato, che proseguirà dritto innanzi a se fino a quando il laser
non rileverà un ostacolo in un range inferiore ai due metri , dopodichè
casualmente ruoterà a destra o sinistra finchè il laser accerterà che non
ci siano ostacoli inferiori a tale soglia e infine proseguirà il cammino.
51
52
3.3
Dalla Simulazione al Caso Reale
Stage emula le caratteristiche di un robot, dal movimento ai sensori,
creando un nodo che sottoscriva e pubblichi sui topic necessari in base
alla configurazione data al robot stesso, e mostrando a video la
simulazione. In un caso di esempio reale è necessario invece
interfacciarsi al robot fisico. Mantenendo il codice redatto inalterato,
per poterlo utilizzare per il movimento reale del robot deve essere
costruito quello che in terminologia ROS prende il nome di Base
Controller.
Un base controller non è altro che un nodo di
interfacciamento che comunica direttamente con l’elettronica del
robot, e in particolare con la base mobile. La sua funzione consiste
quindi nel convertire i messaggi geometry_msgs/Twist relativi alla
velocità, avendo sottoscritto il topic cmd_vel, in comandi motore da
inviare alla base mobile. Essendo strettamente dipendente dal tipo di
piattaforma robotica utilizzata,
ROS non ne fornisce una forma
standardizzata. La configurazione che ne risulterebbe sarebbe la
seguente:
53
Capitolo 4
Conclusioni
Lo scopo della tesi è stato introdurre
il lettore nel campo della
robotica e presentare ROS come framework per lo sviluppo di
applicazioni. ROS non è di certo il framework migliore in assoluto,
poichè tutte le difficoltà e i casi differenti che un campo così
complesso come la robotica
offre non possono essere risolti
certamente con un’unica soluzione, nè la sua architettura risulta
sempre la più adatta ai differenti casi. Tuttavia è ormai uno standard
de facto all’interno della comunità di sviluppo di applicazioni
robotiche.
Perchè tutto questo successo, e perchè non usare altri
framework quali OROCOS, YARP o Microsoft Robotics Studio? A
prescindere da tutti gli aspetti strutturali precedentemente presentati, il
primo punto forte di ROS è il fatto di aver avuto come obbiettivo la
riusabilità del codice, combattendo la tendenza a rendere algoritmi e
driver potenzialmente riutilizzabili in altre applicazioni difficili da
estrarre dal contesto originale. In che modo?
Incoraggiandone lo
sviluppo in librerie standalone prive di dipendendenze da ROS,
contenenti virtualmente tutta la complessità, e creando solo piccoli
eseguibili che ne espongano le funzionalità a ROS stesso. Inoltre
l’essere stato rilasciato sotto licenza BSD, quindi totalmente free e
open – source, ha certamente contribuito alla crescita della forte
comunità di ricercatori
che può vantare alle spalle, e che ne
costituisce un altro grande punto di forza. Grazie ad essa ROS è in
continuo sviluppo, col rilascio di sempre nuove distribuzioni, e sono
sempre maggiori di numero le piattaforme robotiche a supportarlo.
54
Parlando tuttavia dei limiti che ROS impone, è necessario citare che
non sostituisce un sistema operativo ma vi lavora a un livello
superiore. Ciò implica la difficoltà di importarlo su sistemi di piccole
dimensioni, dove la disponibilità in termini di memoria e risorse è
strettamente limitata. Inoltre il fatto di funzionare su sistemi Linux –
based lo taglia dalla corposa fetta di mercato operante su sistemi
Windows. Per il futuro , la vera sfida di ROS risulterà così essere lo
sviluppo di una versione adatta ai sistemi embedded .
55
Bibliografia e Sitografia
[1] A Gentle Introduction to ROS , Jason M. O’Kane
[2] Is ROS Good for Robotics?
http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=6213
236
[3] ROS by Examples INDIGO – Vol 1, R. Patrick Goebel
[4] ROS: an open-source Robot Operating System,
http://cs.stanford.edu/people/ang/?portfolio=ros-an-opensource-robot-operating-system
[5] ROS Wiki, http://wiki.ros.org/it
[6] Sito Ufficiale, http://www.ros.org
[7] Stage,
http://playerstage.sourceforge.net/index.php?src=stage
[8] The Robotics Primer , Maja J Mataric,
56
Scarica

Documento PDF - AMS Tesi di Laurea