Cómo hacer módulos y librer´ıas para ejecutarse a bordo - Cimat

C´omo hacer m´odulos y librer´ıas para
ejecutarse a bordo del NAO
Mauricio Josafat Garc´ıa V´azquez
Abril 2011
´Indice general
1. Como hacer m´
odulos y librer´ıas para ejecutarse a bordo
NAO
1.1. T´erminos importantes . . . . . . . . . . . . . . . . . . . .
1.2. Arquitectura del NAO . . . . . . . . . . . . . . . . . . . .
1.2.1. Broker . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.2. Proxy . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.3. M´odulos locales o remotos . . . . . . . . . . . . . .
1.3. Generador de m´odulos . . . . . . . . . . . . . . . . . . . .
1.4. Compilaci´on cruzada . . . . . . . . . . . . . . . . . . . . .
1.5. Compilar una librer´ıa externa . . . . . . . . . . . . . . . .
1
del
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
2
3
3
4
5
6
7
8
Cap´ıtulo 1
Como hacer m´
odulos y librer´ıas
para ejecutarse a bordo del
NAO
1.1.
T´
erminos importantes
M´
odulo: es una unidad de c´odigo, implementada como clase C++, que
contiene c´odigo que sirve a realizar alguna funcionalidad. Como esta clase
tiene que tener ciertos m´etodos necesariamente implementados, existe un generador de m´odulos que genera autom´aticamente un esqueleto de un modulo.
Librer´ıa: est´a compuesta por trozos de c´odigo que contienen alguna funcionalidad pre-compilada. Las librer´ıas proporcionan servicios a programas
independientes (ejecutables), esto permite que el c´odigo se pueda construir
de manera modular. Los ejecutables y las librer´ıas hacen referencia entre si
a trav´es de un enlace (link).
Ejecutable: es un archivo binario que es interpretado por la computadora. Contiene instrucciones en lenguaje de m´aquina y se puede enlazar con
librer´ıas para a˜
nadir funcionalidades.
Naoqi: es el nombre del programa-servidor que corre en el robot y al cual
un programa-cliente se puede conectar para recuperar datos, o hacer una
pedida.
2
1.2.
Arquitectura del NAO
La arquitectura de Naoqi se puede observar en la figura 1.1. Es una arquitectura modular, con las varias funcionalidades encapsuladas en diferentes
unidades de c´odigo.
Figura 1.1: Arquitectura de naoqi. (Imagen extra´ıda de la documentaci´on de
naoqi.)
1.2.1.
Broker
Un broker es un ejecutable y un servidor que puede atender comandos
remotos en un IP (el de la m´aquina en que est´a corriendo) y un puerto, es
decir por red. En pr´actica, para implementar una funcionalidad en el robot,
tienes que pasar por un broker. Dos casos son posibles:
o el generador de m´odulos generar´a un ejecutable y este se conectar´a al
robot (en este caso, este ejecutable es un broker secundario),
o generar´a una librer´ıa para cargarla en el broker principal, es decir el
programa Naoqi, que es el que provee las funcionalidades b´asicas en el
robot (adquisici´on de datos por sensores, actuaci´on. . . ).
En este ultimo caso, se tiene que agregar en autoload.ini (del robot) el
nombre de tu librer´ıa. El generador de m´odulos tambi´en maneja los enlaces
y los caminos a las librer´ıas.
Hay que entender bien las implicaciones de cada una de esas dos elecciones en cuanto a tu m´odulo: en el primer caso, tu m´odulo est´a encapsulado en
3
un ejecutable diferente del ejecutable que corre las operaciones cr´ıticas en el
robot. Eso significa que en caso de que haya un gran error en tu c´odigo, tu
ejecutable podr´a fallar sin que los sistemas de control cr´ıticos del robot fallen
tambi´en. En el segundo caso, tu c´odigo compilado est´a usado por el mism´ısimo ejecutable Naoqi : en caso de problemas graves (error de segmentaci´on),
el robot puede caer. Sin embargo, en el segundo caso, ya que tu c´odigo est´a en
el mismo ejecutable que los m´odulos-core del robot, puedes acceder mucho
m´as r´apido a datos del robot (por ejemplo, la imagen de la c´amara), ya que
la memoria es compartida entre m´odulos del mismo ejecutable.
En resumen, para tu m´odulo, tienes siempre dos opciones:
correrlo en un broker separado (modo “remote”): seguro pero un
poco menos eficiente;
correrlo en el broker principal (modo “local”): arriesgado pero muy
eficiente.
En la figura 1.2 se ilustra un simple ejemplo de un m´odulo creado por
el usuario, llamado “myModule”. myModule corre como un broker separado
(modo “remote”) llamado “myBroker”que se comunica con el broker principal
sobre 127.0.0.1:9559.
Observaci´
on: Un punto importante que observar es que, en este caso particular, “Main Broker” y sus m´odulos est´an corriendo a bordo del robot,
igualmente a “myBroker”(ya que la IP especificada corresponde a la maquina
hu´esped). Pero, hubi´eramos podido muy bien correr el “myBroker” en una
m´aquina remota, especificando a este programa una IP correspondiendo a
la direcci´on del robot en la red. El desempe˜
no es en este caso limitado por las
propiedades de la red, pero permite por ejemplo correr procesamientos tal
vez m´as pesados, en tu m´aquina local m´as poderosa que la CPU del robot.
1.2.2.
Proxy
Debido a que la arquitectura software del NAO es modular, un m´odulo
no necesariamente “conoce” el c´odigo de otro m´odulo. En particular, nunca
incluimos (#include) una cabecera de otro m´odulo. En vez de esto, creamos
un objeto especial, enteramente dedicado a la comunicaci´on con otros modulos, el proxy. Es lo mismo cuando el m´odulo se ejecuta de manera local o de
manera remota. Veremos ejemplos de ellos al momento de implementar un
primer m´odulo.
4
Figura 1.2: Broker. (Imagen extra´ıda de la documentaci´on de Naoqi).
1.2.3.
M´
odulos locales o remotos
Los m´odulos, como es mencionado arriba, son clases que est´an compiladas
como librer´ıas. Para especificar que esta librer´ıa tiene que estar cargada en el
sistema, se la tiene que mencionar explicitamente en el archivo de configuraci´on autoload.ini, con el cual se instanciar´a automaticamente el m´odulo de la
clase principal. El generador de m´odulos crea una clase que ser´a comprendida
por el broker, ya sea el broker principal, o un broker creado por el usuario si
es separado/remoto.
Como hay dos tipos de m´odulos, hay tambi´en dos maneras de compilar un
m´odulo:
Como un ejecutable (m´odulo remoto): Cada paquete de m´odulo crea
un ejecutable independiente en “/path/to/aldebaran-sdk/bin/”.
Como una librer´ıa (m´odulo local): Cada paquete de m´odulo crea una
librer´ıa din´amica guardada en “/path/to/aldebaran-sdk/lib/naoqi/”.
5
Observaci´
on: En el secundo caso, para hacer que el broker principal cargue
tus m´odulos al iniciar, el archivo autoload.ini tiene que tener el nombre de
tu proyecto.
Observaci´
on: Puedes escoger si tu m´odulo va a ser remoto o local configurando la variable de CMake llamada MY_MODULE_IS_REMOTE usando ccmake.
1.3.
Generador de m´
odulos
El generador de m´odulos es una aplicaci´on incluida en el sdk, y escrita
en python. Para ejecutar el generador de m´odulos tenemos que hacer lo siguiente (en Linux, pero se har´ıa de manera equivalente en otros OS):
$∼cd /path/to/aldebaran-cpp-sdk/modules/src/
$∼python module generator.py
Figura 1.3: Generador de m´odulos
En Project Name ponemos el nombre del proyecto, este va a ser el
nombre de la librer´ıa que va a contener tus m´odulos, una sola librer´ıa puede
contener varios m´odulos.
En Modules Names ponemos el nombre de los m´odulos que queremos
generar, separados por un espacio en blanco.
El Author es opcional.
Damos click en generar y nos aparece lo siguiente:
Your project has been generated in /path/to/generator/
El generador de m´odulos nos crea un directorio donde se encuentra todo
el c´odigo generado para nuestro proyecto. En la ra´ız hay dos archivos .cmake,
que solo vamos a modificar en caso de que queramos cambiar los par´ametros
6
de compilaci´on. En src/ nos genera un archivo .cpp y un .h por cada m´odulo
que hayamos querido generar, adem´as de un archivo .cpp con el nombre del
proyecto. En ese ultimo est´a la funci´on main del ejecutable generado, si es
el caso. En cada archivo .h se define una clase heredada de ALModule, con
su constructor por default. A partir de este esqueleto, nosotros ya podemos
seguir el c´odigo y definir las variables miembro y los m´etodos que va a tener
nuestro m´odulo.
Para poder usar funciones de nuestro m´odulo mediante un proxy (usarlas en otro m´odulo o directamente), tenemos que “enlazarlas” mediante la
macro BIND METHOD. Para que esta macro funcione correctamente tenemos que llamar antes las funciones functionName, en caso que la funci´on
tenga par´ametros la funci´on addParam por cada uno y por u
´ltimo la funci´on
setReturn en caso de que tenga valor de retorno (ver ejemplo).
Por u
´ltimo en el directorio tests/ genera un archivo .py (un script python)
para lanzar m´etodos de nuestros m´odulos. Esto tambi´en lo podemos hacer
de manera an´aloga con un programa en C++.
1.4.
Compilaci´
on cruzada
Para poder correr tu c´odigo a bordo del NAO y no en tu m´aquina, tienes
que hacer una compilaci´on cruzada. Esto por el momento s´olo es posible en
linux. La compilaci´on cruzada es necesaria para asegurar que se compila con
las banderas correctas de optimizaci´on y ligas a las correctas librer´ıas.
Para hacer una compilaci´on cruzada simplemente hacemos el proceso siguiente:
$∼cd /path/to/sources
$∼mkdir buildcross
$∼cd buildcross
$∼cmake -DCMAKE TOOLCHAIN FILE=/path/to/ctc/toolchain-geode.cmake ..
$∼make
Antes de hacer la compilaci´on cruzada tenemos que definir lo siguiente:
SDK: El SDK es un directorio com´
un para todos nuestros proyectos.
Por ejemplo, las librer´ıas est´an siempre en lib/, los archivos de cabecera
en include/, los datos en share/ etc.
El archivo toolchain.cmake: Para poder usar c´odigo desde lib/cmake,
tenemos que usar el archivo toolchain.cmake. Esta es la forma de cmake para hacer compilaci´on cruzada. Para especificar un archivo tool7
chain.cmake a usar, se tiene que pasar la siguiente bandera en la l´ınea
de comandos:
cmake -DCMAKE TOOLCHAIN FILE==path/to/sdk/toolchain.cmake
As´ı es como est´a definido el archivo toolchain.cmake:
#DO NOT EDIT
#DO NOT CHANGE LOCATION, THIS FILE ONLY WORKS IN THE ROOT
#OF A FULL SDK
cmake_minimum_required(VERSION 2.6.4)
get_filename_component(_ROOT_DIR
${CMAKE_CURRENT_LIST_FILE} PATH)
set(TOOLCHAIN_DIR ’${_ROOT_DIR}/lib/’ CACHE STRING ’’ FORCE)
set(SDK_DIRS ’${_ROOT_DIR}’)
set(SDK_ARCH linux)
include(’${TOOLCHAIN_DIR}/cmake/Toolchain-generic.cmake’)
# This is a bit unusual: result of the compilation will always
# be put in this directory
set(SDK_DIR
’${_ROOT_DIR}’
)
Las principales variables son:
• TOOLCHAIN DIR: Para encontrar el c´odigo en lib/cmake.
• SDK ARCH: Para especificar si estas usando linux, windows, compilaci´on cruzada, los valores aceptados son: linux,macosx,win-vc8,
win-vc9, nao-geode. Para nuestro caso en particular debe ser naogeode.
• SDK DIRS: Una lista de posibles directorios SDK donde se buscar´an archivos de cabecera y librer´ıas creadas por el usuario.
• SDK DIR: (opcional) Es donde se pondr´a el resultado de la compilaci´on. El default es build/sdk.
1.5.
Compilar una librer´ıa externa
Para compilar una librer´ıa externa hacemos nuestra librer´ıa tal como el
generador de m´odulos lo hace:
8
$∼mkdir librer´ıa
$∼cd librer´ıa
$∼mkdir src
$∼nano bootstrap.cmake
$∼nano CMakeLists.txt
En src/ colocamos los archivos fuente (.h y .cpp) de manera similar a como el generador de m´odulos lo hace. El archivo bootstrap.cmake podemos
copiarlo tal cual de cualquier m´odulo generado. El archivo CMakeLists.txt
lo adaptamos del ejemplo siguiente1 :
###
# This is a dummy package project.
# Always put this: this won’t work if version
# is less than 2.6.4
cmake_minimum_required(VERSION 2.6.4 FATAL_ERROR)
# Name of your project: (use for the .snl filename among other things)
project(packaging)
# Always include() this: this performs a few checks, and makes
# sure everything will work.
# The bootstrap.cmake file should be at the top of your project.
# it’s always the same.
include(’${CMAKE_CURRENT_SOURCE_DIR}/bootstrap.cmake’)
# Create a library:
# first arg: the name of a CMake _target_.
# following args: list of sources, or keywords such as SHARED, STATIC ...
create_lib(world ’src/world.cpp’)
# Make the lib available for other projects:
# first arg: the name of the CMake target
# second arg: the name of the ’staged’ library
stage_lib(world WORLD)
# to use in an other project:
# use_lib(my_target WORLD)
# Create a binary using world library:
1
Del foro de academics.aldebaran-robotics.com
9
create_bin(hello ’src/main.cpp’)
use_lib(hello WORLD)
# Install rules for headers:
# WORLD is the name of the ’staged’ library, so that
# that you can also use the lib for compilation in
# an other project _after_ installation.
install_header(WORLD ’src/world.h’ SUBFOLDER ’world’)
# This is how you can install data files
install_data(hello ’data/hello.dat’)
Posteriormente hacemos el procedimiento ya mencionado para compilar.
Para poder usar esta librer´ıa, no basta con poner use lib en el archivo CMakeLists.txt de nuestros m´odulos donde la queremos usar; tenemos que incluir
el directorio sdk creado dentro de buildcross/ en nuestra librer´ıa en el archivo
toolchain.cmake de la siguiente manera: en la parte
#it’s possible to add more sdk here
set(SDK_DIRS
"${OE_CROSS_DIR}/staging/geode-linux/usr/")
debemos agregar:
set(SDK_DIRS
"/path/to/the/library/buildcross/sdk")
Esto lo hacemos por cada librer´ıa que queramos cargar en nuestros m´odulos,
por u
´ltimo compilamos la librer´ıa.
10