Está en la página 1de 22

Manual de vision en robotica

Jose M. Ca
nas
Universidad Rey Juan Carlos
jmplaza@gsyc.escet.urjc.es
version 1.5

Resumen
Este manual describe diferentes aspectos relevantes del manejo de im
agenes en
rob
otica, incluyendo su captura, su procesamiento y su visualizaci
on. Est
a orientado a
servir de gua al programador que se enfrenta a estas tareas, y en este sentido se incluye el c
odigo de ejemplos b
asicos que pueden servir de base. En la parte de captura se
describe el estandard que se ha extendido en el mundo linux: la interfaz Video4Linux,
y el m
as reciente v4l2. La hemos probado con una c
amara convencional m
as tarjeta
digitalizadora BT878, y sobre una c
amara USB. En la parte de procesamiento se describe la librera Gandalf, de software libre, que ofrece manejo de matrices. En la parte
de visualizaci
on comentamos Tambien varias herramientas para programar interfaces
gr
aficas: la librera XForms y la librera Qt

Indice
1. Introducci
on

2. Captura de im
agenes
2.1. Dispositivos hardware . . . . . . . . . . .
2.2. Instalacion de video4linux . . . . . . . . .
2.2.1. Digitalizadoras BT878KHF en PC
2.2.2. Utilizar webcams USB en debian .
2.3. Video4linux API . . . . . . . . . . . . . .

.
.
.
.
.

2
2
2
3
3
5

3. Procesamiento de im
agenes
3.1. Librera Gandalf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.1.1. Instalacion en el PC de la librera Gandalf . . . . . . . . . . . . . . .
3.1.2. Compilacion de un programa que usa la librera Gandalf. . . . . . .

7
7
8
9

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

4. Visualizaci
on en interfaces gr
aficas
4.1. X-Window system . . . . . . . . . . . . . . . . . . . . . . . .
4.2. Librera XForms . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.1. Elementos graficos de XForms . . . . . . . . . . . . . .
4.2.2. Construccion visual de la interfaz grafica con XForms
4.2.3. Interaccion de XForms con el programa . . . . . . . .
4.3. Librera Qt . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.1. Instalacion de Qt Free en Linux . . . . . . . . . . . . .
4.3.2. Hola mundo . . . . . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.

12
12
13
14
15
16
19
19
20

Agradecimientos
Este manual ha sido realizado en parte por los alumnos del grupo de robotica de la
URJC. Contribuciones importantes se deben a ellos: Francisco Valverde, David Lobato y
Marta Martnez.

1.

Introducci
on

La vision es un sensor mas que los robots pueden utilizar para inferir el estado de su
entorno. Es un sensor muy complejo que entrega un flujo continuo de imagenes, pero es
difcil extraer de ese flujo informacion directamente u
til para la accion del robot.
Hoy da hay en el mercado camaras disponibles a precios razonables. Las imagenes que
la camara proporciona se pueden capturar en un ordenador y poner disponibles a los programas de control. En el grupo de robotica1 de la Universidad Rey Juan Carlos tenemos
varios escenarios tpicos donde utilizamos las imagenes capturadas por una camara. En el
primero la camara hace de ojo del robot. Por ejemplo en el robot pioneer esta conectada al
ordenador portatil de a bordo, que toma decisiones de movimiento basandose en las imagenes. Del mismo modo el robot EyeBot desarrolla comportamiento sigue-pelota utilizando
su camara local. En el segundo marco tenemos una camara cenital situada encima de un
tablero de ping pong donde unos robots EyeBot juegan al futbol. En este caso se utiliza
basicamente como sensor de posicion para todos los jugadores.
Normalmente en aplicaciones roboticas ademas de capturar imagenes querremos visualizarlas. Resulta muy u
til por ejemplo para depurar los algoritmos perceptivos o los
programas de control. En esta lnea describimos varias libreras que permiten desarrollar
interfaces graficas en maquinas linux: XForms y Qt.
1

http://gsyc.escet.urjc.es/robotica/

2.

Captura de im
agenes

Para ordenadores personales y portatiles que corren sobre el sistema operativo linux se
ha desarrollado la interfaz video4linux. Esta interfaz homogeneiza el acceso a las imagenes
con independencia de la camara concreta que se trate. Al ser generico los programas o
aplicaciones pueden funcionar sobre camaras o digitalizadoras de distintos fabricantes sin
necesidad de recodificacion. Antes de su existencia cada fabricante entregaba un driver
especfico para su camara o capturadora, que entregaba su imagen de un modo no estandarizado. Por ejemplo si nuestra aplicacion funcionaba sobre una digitalizadora Matrox
Meteor tenamos que instalar el driver correspondiente y utilizar en nuestro codigo sus
funciones especficas para capturar las imagenes.

2.1.

Dispositivos hardware

Camaras USB, Tarjetas digitalizadoras.

2.2.

Instalaci
on de video4linux

Como con todos los dispositivos hardware de un ordenador, si queremos que funcione el
kernel del sistema debe incluir soporte para el. Esto se puede conseguir de varias maneras.
Por ejemplo se puede patchear el codigo fuente del kernel para que incluya drivers especficos. En dispositivos con mejor soporte esos drivers vienen con la propia distribucion del
kernel, e incluirlos en el kernel puede ser tan sencillo como activar una opcion al recompilar,
o cargar como modulo en tiempo de ejecucion.
Hemos probado dos configuraciones.
Dos programas muy buenos para probar si la instalacion ha sido buena son xawtv y
vic. Xawtv es un programa muy completo que digitaliza las imagenes de una camara y
las muestra por pantalla, permitiendo una total configuracion del dispositivo de captura.
La pagina de referencia para este programa es http://bytesex.org/xawtv/2 , aunque en
las versiones mas recientes ya viene como paquete debian que se puede instalar por el
procedimiento estandard de debian (sin traerse el fuente comprimido tar.gz y compilarlo
en local). Vic es un programa que se utiliza para transimitir y recibir audio y video desde
otras maquinas remotas. La parte u
til en este entorno es la que configura el dispositivo de
video, captura imagenes y muestra una version reducida en local.
2.2.1.

Digitalizadoras BT878KHF en PC

Esta tarjeta tiene un chipset de la familia BT8x8 de Book Tree. Es con diferencia la
mas difundida en el mundo linux, y por ello tiene amplio soporte software. El modulo con
su driver se llama bttv.
2

http://bytesex.org/xawtv/

La configuracion exitosa se hizo sobre un kernel 2.2.17, utilizando el modulo bttv-0.5.35.


El primer paso fue recompilar el kernel activando varias opciones como modulos:
1.

videoforlinux (en character devices), como modulo.

2.

bt848 video for linux, como modulo.

3.

CONFIG SOUND=y

4.

CONFIG SOUND ES1371=y (es de la tarjeta Creative Ensoniq, muy popular)

5.

CONFIG SOUND OSS=y

2.2.2.

Utilizar webcams USB en debian

Para que una camara USB funcione sobre linux (1) el kernel debe ofrecer soporte para
el bus USB. Ademas (2) el driver concreto de la camara debe incluirse tambien, bien dentro
del kernel compilado, bien como modulo.
Desde la version 2.2.7 empezo el soporte USB de modo experimental dentro del kernel
y se ha estabilizado en las versiones 2.4.*, ofreciendo ya soporte completo. Los modulos
implicados son usbcore, usb-uhci, usb-ohci.
En cuanto a las distintas camaras del laboratorio, hemos probado las siguientes:
C
amara Terratec : ov511

C
amaras Philips : pwc Una pagina muy u
til para las camaras Philips es http://www.smcc.demon.nl/webcam
Obtener el kernel Lo primero es conseguir un kernel con soporte para USB, los 2.2.x
tienen soporte desde la version 2.2.18, pero es preferible utilizar un 2.4.x, ya que aun teniendo tambien soporte para video4linux en el que estan basados la mayora de los programas
que utilizan los drivers de las camaras USB, tiene ademas muchas mas camaras soportadas
a parte de las compatibles con ov511. Para realizar este documento se ha utilizado el 2.4.14.
Bien, para conseguir un kernel, hay 2 opciones: bien instalar la imagen que vendra en los
CD de la distribucion que tengas, bien bajartela de ftp://ftp.kernel.org/pub/linux/kernel/v2.4.
Si vas a instalar la imagen desde los CDs, abre un terminal y ejecuta dselect (es una
herramienta para instalar paquetes en debian, mucho mas sencillo que hacerlo directamente
con apt-get), selecciona select pulsa space para pasar la introduccion, entraras en un
men
u con todos los paquetes de la distribucion, ahora pulsa /.aparecera en la esquina
inferior izquierda search:pon kernel-source. Cuando encuentres la que buscas pulsa
+e intro, a continuacion volveras al men
u inicial. Ahora selecciona install y dale los
CDs que vaya pidiendo. Esto instala la imagen en el directorio /usr/src.
El u
nico problema es que las fuentes que en mi distribucion (potato r4) son las del 2.2.19
y a no ser que tengas una woody no creo que vengan las 2.4.x por lo tanto recomiendo la
4

opcion del FTP. Para ello conectate a ftp://ftp.kernel.org/pub/linux/kernel/v2.4 y


bajate el kernel (.tgz) que mas te guste al directorio /usr/src y descomprmelo (tar xvzf
kernel-source-2.x.y.tgz o bzip2 -dc kernel-source-2.x.y.tar.bz2 2>/dev/null
| tar tvvf -).
Compilando e instalando el kernel Hay muchas formas de recompilar el kernel, en
este documento no vamos a extendernos demasiado en este tema, si quieres mas informacion (otros dispositivos) puedes mirar el kernel-HOWTO en debian.org o el del directorio
/usr/share/doc/HOWTO en el que encontraras documentacion sobre el kernel y otras cosas
interesantes.
Una vez en la carpeta del kernel descomprimido hacemos make xconfig y aparecera una
ventana con un men
u, en este men
u hay una pesta
na en la que pone video4linux support(en la 2.2.19 dentro de C
haracter devices) pincha en ella y activa la opcion para que
soporte dispositivos de vdeo (pinchando en ). Ahora cierra esta ventana (Main Menu)

y pincha en USB
support.activa support for USB si has activado la opcion video4linux

podras seleccionar USB


ov511 camera support. Pincha en Save and exit en el terminal
pon make dep, luego make clean para compilar finalmente el kernel hay 2 opciones:
2

1.

Si no estas muy convencido de lo que le has metido a tu kernel puedes hacer make
bzdisk, con esto compilaras el kernel y meteras la imagen en un diskette. Una vez
compilado reinicia el sistema con el diskette y si todo ha ido bien prueba con la
siguiente opcion.

2.

make bzImagecon esto compilaras el kernel en el directorio /usr/src/kerne-source2.x.y/arch/i386/boot .

Copia el archivo bzImageen /boot y edita el archivo /etc/lilo.conf y a


nade las siguientes lineas y cambia la lnea default=Linux por default=LinuxUSB.
image=/boot/bzImage
label=LinuxUSB (o como quieras que se llame tu imagen)
read-only
optional
Guarda los cambios y ejecuta lilo y lilo -q. Con esto la proxima vez que reinicies
tu sistema lo haras con tu nuevo kernel (si quieres volver a utilizar tu viejo kernel vuelve
a cambiar el default=Linux y haz lilo y lilo -q).

Ultimos
retoques Ahora ya tienes soporte para tu webcam, pero si ejecutas cualquiera
de los programas que existen puede suceder que aparezca el siguiente mensaje no such file
or device: /dev/videoesto significa que no se crearon los enlaces en /dev, si esto pasa debemos hacerlo a mano. ejecuta esto: mknod /dev/video0 c 81 0, mknod /dev/video1 c 81
5

1,ln -s video0 video finalmente chmod 666 /dev/video /dev/video0 /dev/video1.(mira


man mknod, man ln man chmodpara mas informacion). Con esto ya tienes totalmente configurado el dispositivo.
MAKEDEV video.
2

Figura 1: Imagen tomada con el interfaz video4linux

2.3.

Video4linux API

Para capturar imagenes utilizando v4l previamente hay que abrir e inicializar el dispositivo correctamente.
Por convenio los dispositivos de video en linux aparecen en los ficheros /dev/video0,
/dev/video1,.... En esta inicializacion se especifican cosas como el tama
no de la imagen
digitalizada, el formato en el que queremos que se entregue (RGB,YUV...), y la configuracion de la propia tarjeta de captura. Por ejemplo es tpico que las tarjetas capturadoras
tengan varias entradas de video analogico (conector S-Video, conector RCA...) y que admita se
nales de entrada en distintos formatos (PAL,SECAM,NTSC,etc). En esta etapa se
puede especificar que nos interesa digitalizar las imagenes que vienen por la entrada RCA,
que vienen en PAL.
Una vez inicializado se pueden leer las imagenes con una simple llamada al sistema
read(). Sin embargo este modo de leer imagenes es relativamente lento. Cuando se desea
capturar a un ritmo mayor es conveniente preparar una zona de la memoria para que el
driver deje ah las imagenes que va capturando. Normalmente estas transferencias se hacen
por DMA desde la tarjeta a la memoria que le indiquemos. Para que nuestra aplicacion
pueda leer de la zona de memoria (del kernel) donde el driver recoge las imagenes es
necesario solicitarlo al kernel con la llamada mmap(). En este u
ltimo caso es necesario
preparar la captura con alguna funcion adicional, tal y como muestra el siguiente ejemplo:
struct video_mmap gb;
static struct video_mbuf gb_buffers;
6

fd = open(video, O_RDWR);
...
gb_buffers.frames=2;
if (cap.type & VID_TYPE_CAPTURE) {
/* map grab buffer */
if (-1 == ioctl(fd,VIDIOCGMBUF,&gb_buffers)) {
perror("ioctl VIDIOCGMBUF");
}
map = mmap(0,gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if ((char*)-1 != map) printf("Error\n");
else
{perror("mmap");
close(fd);
exit(-1);
}
}
gb.frame=0;
gb.width=win.width;
gb.height=win.height;
gb.format=vpic.palette;
Con ioctl(fd,VIDIOCGMBUF,&gb buffers)) se le pregunta al driver por la configuracion de la tarjeta, tama
no de imagenes, etc, que deja en la variable gb buffers, para luego
pedir la comparticion del tama
no adecuado.
Con map = mmap(0,gb buffers.size,PROT READ|PROT WRITE,MAP SHARED,fd,0); se
le pide al sistema operativo compartir la zona, y este entrega su direccion, si todo va bien.
Una vez configurada la captura por memoria mapeada tenemos al driver que constantemente estara volcando en esa zona las imagenes recien capturadas. En realidad no
estara continuamente, sino que ira volcando imagenes en el buffer hasta que se llene. Una
vez que esta saturado no sigue capturando, sino que espera a que el proceso del usuario lea
alg
un frame. En el ejemplo actual se han configurado memoria para dos cuadros. Mientras
el usuario esta leyendo en uno el driver esta rellenando el otro, de manera que si el lector
es suficientemente rapido no se detiene nunca la captura.
for(;;)
{
gb.frame=(gb.frame+1)%2;
if (-1 == ioctl(fd,VIDIOCMCAPTURE,&gb)) {
perror("VIDIOCMCAPTURE");
7

}
/* "libera" ese frame para que el driver pueda cargar ahi nueva imagen.*/
if (-1 == ioctl(fd,VIDIOCSYNC,&gb.frame)) {
perror("VIDIOCSYNC");
}

3.

Procesamiento de im
agenes

3.1.

Librera Gandalf

Gandalf es una librera de C dise


nada para soportar el desarrollo de aplicaciones informaticas en el campo de la vision. Esta librera esta compuesta por cuatro paquetes:
COMMON : Este paquete define distintos tipos de datos y funciones para usar en los
otros paquetes incluidos en Gandalf. Dispone de diversas funciones para memoria
dinamica, listas enlazadas, arrays, varias funciones numericas y permite el manejo de
excepciones.
LINEAR ALGEBRA : Contiene distintas funciones para el manejo de vectores y matrices. Para aquellos con tama
no 2, 3 y 4 dispone de unas funciones predefinidas,
pero tambien dispone de otras mas generales para el manejo de matrices y vectores
de cualquier tama
no.
IMAGE : Permite la manipulacion de imagenes de cualquier formato y tipo. Soporta
imagenes en los diferentes niveles de gris, imagenes en RGB con o sin canales Alpha;
y distintas profundidades de pxeles.
VISION : Este paquete es mas completo que el anterior y posee funciones para la identificacion de bordes, lneas o esquinas de una figura.
3.1.1.

Instalaci
on en el PC de la librera Gandalf

Para la instalacion de la librera conviene seguir los siguientes pasos:


1.

Bajar el fichero gandalf-1-1.tgz de la pagina http://gandalf-library.sourceforge.net


. Tambien conviene bajarse el tutorial incluido en dicha pagina, que explica el contenido de los paquetes de la librera y las funciones que contienen. A continuacion
descomprimimos el fichero, con lo que se crea el directorio gandalf.

2.

Dentro de este directorio habra un fichero INSTALL que contiene los pasos a seguir
para la instalacion, que a continuacion describimos.

3.

Compilamos y construimos la librera Gandalf, para ello ejecutamos los siguientes


comandos:
cd gandalf
./configure
make

4.

Instalamos las cabeceras y los ficheros de la librera:


make install

5.

Comprobamos si esta bien instalada la librera ejecutando:


cd gandalf/TestFramework
make
./cUnit -all
Esto te comprobara de una sola vez si los cuatro paquetes se han instalado satisfactoriamente, pero si por el contrario, queremos mirar como se ha instalado un
determinado paquete, por ejemplo, el common, lo que haramos sera:
cd gandalf/common
make all
./listtext
Esto es as, porque cada paquete posee su propio test. El programa TestFramework/cUnit.c
lo que hace es compilar y enlazar los tests de cada paquete.

3.1.2.

Compilaci
on de un programa que usa la librera Gandalf.

A la hora de compilar un programa que usa la librera Gandalf, lo hemos de hacer


mediante el uso de un Makefile. El modo de usarlo es el siguiente, supongamos que tenemos
el siguiente programa, que se llama prueba.c:
/*********************************************************************/
/*
PROGRAMA PRUEBA QUE USA LA LIBRER
IA GANDALF
*/
/*
*/
/* Este programa pide al usuario los datos de 2 matrices, y muestra */
/* ambas matrices por pantalla, luego las suma, las resta,
*/
/* multiplica y halla su determinada traspuesta y su inversa si la */
/* tuviera.
*/
9

/*********************************************************************/
#include <gandalf/common.h>
#include <gandalf/linalg.h>
#include <stdio.h>
int

main (){

/* Declaramos las variables */


int i, j;
Gan_Matrix33 m33A, m33B, m33C;
double dDetA, dDetB;
float A[3][3];
float B[3][3];
/* Pedimos los datos por teclado */
printf ("Introduzca los datos de la matriz A: \n");
for (i=0;i<3;i++){
for (j=0;j<3;j++){
printf ("Introduzca A(%d,%d): ", i,j);
scanf ("%g", &A[i][j]);
}
}
printf ("Introduzca los datos de la matriz B: \n");
for (i=0;i<3;i++){
for (j=0;j<3;j++){
printf ("Introduzca B(%d,%d): ", i,j);
scanf ("%g", &B[i][j]);
}
}
/* Definimos las matrices */
gan_mat33_fill_q (&m33A,A[0][0], A[0][1], A[0][2], A[1][0],
A[1][1], A[1][2], A[2][0], A[2][1], A[2][2]);
gan_mat33_fill_q (&m33B, B[0][0], B[0][1], B[0][2], B[1][0],
B[1][1], B[1][2], B[2][0], B[2][1], B[2][2]);
printf ("\n");
/* Escribimos por pantalla las matrices */
gan_mat33_print (&m33A, "Matriz 1", 3, "%f");
gan_mat33_print (&m33B, "Matriz 2", 3, "%f");
10

printf ("\n");
/* Sumamos y escribimos por pantalla el resultado */
m33C = gan_mat33_add_s(&m33A, &m33B);
gan_mat33_print (&m33C, "Suma", 3, "%f");
printf ("\n");
/* Restamos y escribimos por pantalla el resultado */
m33C = gan_mat33_sub_s(&m33A, &m33B);
gan_mat33_print(&m33C, "Resta", 3, "%f");
printf ("\n");
/* Multiplicamos y escribimos por pantalla el resultado */
/* C = A*B */
m33C = gan_mat33_rmultm33_s (&m33A, &m33B);
gan_mat33_print(&m33C,"Multiplicaci
on", 3, "%f");
printf ("\n");
/* Hallamos el determinante de A y B y lo sacamos por pantalla */
dDetA = gan_mat33_det_q (&m33A);
printf ("El determinante es: %g\n", dDetA);
dDetB = gan_mat33_det_q (&m33B);
printf ("El determinante es: %g\n", dDetB);
printf ("\n");
/* Tasponemos las matrices A y B y lo sacamos por pantalla */
gan_mat33_tpose_i(&m33A);
gan_mat33_print(&m33A, "Transpuesta de A", 3, "%f");
gan_mat33_tpose_i(&m33B);
gan_mat33_print(&m33B, "Transpuesta de B", 3, "%f");
printf ("\n");
/* Invertimos las matrices A y B (si se pueden invertir, y
sacamos el resultado por pantalla */
gan_mat33_tpose_i(&m33A);
if (dDetA!=0){
gan_mat33_invert_i (&m33A);
gan_mat33_print(&m33A, "Inversa de A", 3, "%f");
} else {
printf ("El determinante de A es 0, por lo que no se puede hallar su inversa. \n");
}
11

gan_mat33_tpose_i(&m33B);
if (dDetB!=0){
gan_mat33_invert_i (&m33B);
gan_mat33_print(&m33B, "Inversa de B", 3, "%f");
} else {
printf ("El determinante de B es 0, por lo que no se puede hallar su inversa. \n");
}
return 0;
}
Pues bien, este programa digamos que esta situado en el directorio ejemplo. Y el directorio gandalf que creamos cuando instalamos la librera esta en /users/pepe, el Makefile
quedara as:
# Generated automatically from Makefile.in by configure.
CC = gcc
PNG_LIBS = -lpng -lz
JPEG_LIB = -ljpeg
TIFF_LIB = -ltiff
LAPACK_LIBS =
OPENGL_LIBS = -lglut -lGLU -lGL -lXmu -lX11
X_LIBS = -L/usr/X11R6/lib
include /users/pepe/gandalf/Make.inc
include /users/pepe/gandalf/config
PACKAGE = ejemplo
TOPLEVEL = /users/pepe/gandalf
EXECUTABLES = prueba
targets: $(EXECUTABLES)

prueba: prueba.c
libtool $(CC) $(INCLUDES) $(CFLAGS) -static prueba.c -o prueba $(LIB) $(EXTERNAL_LI
GARBAGE += $(EXECUTABLES)
include /users/pepe/gandalf/make.targets

12

Figura 2: Arquitectura cliente/servidor en una maquina (izquierda) y en una red (derecha)

4.

Visualizaci
on en interfaces gr
aficas

Un aspecto relevante de nuestras aplicaciones es su interfaz grafica. A traves de ella el


robot muestra los valores de los distintos sensores de un modo grafico. De este modo para
el usuario resulta sencillo interpretar lo que se le esta mostrando por pantalla. Esta interfaz
grafica tambien ofrece herramientas para que usuario humano pueda mover el robot a su
voluntad.
X-Window es el sistema de ventanas escogido para desarrollar nuestras interfaces, por
ser el mas extendido dentro del mundo Unix-Linux y ajustarse a nuestras necesidades.

4.1.

X-Window system

El sistema X-Window [X.Org] fue desarrollado a mediados de los a


nos 80 en el MIT,
movido por la necesidad de dotar al sistema operativo Unix de una interfaz grafica de
usuario. X-Window es el encargado de visualizar la informacion de manera grafica y es
totalmente independiente del sistema operativo (los sistemas Unix-Linux no necesitan de
X-Window para funcionar, pudiendo trabajar en modo texto).
Es el sistema grafico mas extendido en el mundo Unix-Linux. La casi totalidad de las
aplicaciones graficas desarrolladas para Linux han adoptado este sistema llegando a convertirlo en el estandar. As pues Linux ofrece todas las libreras necesarias para desarrollar
aplicaciones y generar salidas graficas conforme a ese estandar.
La gran diferencia entre X-Window y la interfaz grafica de otros sistemas operativos es
que X-Window distribuye el procesamiento de aplicaciones, especificando un enlace clienteservidor. El cliente X especificara que hacer al servidor X, que se encargara de como
hacerlo. El servidor X es un programa que se ejecuta en una maquina. A este servidor
le llegan solicitudes de clientes X para generar la salida grafica de una aplicacion en la
pantalla que administra el servidor, que puede ser la de la maquina que ejecuta el cliente
o la de otra maquina remota.
El sistema X-Window oculta las peculiaridades del sistema operativo y del hardware
asociado al mismo, simplificando la labor del desarrollador y proporcionando una alta
portabilidad de las aplicaciones cliente.
La gran ventaja de X-Window es que el servidor X de una aplicacion y el cliente X
13

donde se trabaja no tienen por que estar en la misma maquina. Se puede utilizar X-Window
en una maquina y conectarse a otra remota, ejecutar un programa en esta maquina remota
y visualizar e interactuar con este programa en la maquina local.
Esta caracterstica de X-Window permite utilizar la interfaz grafica en cualquier maquina que soporte este sistema grafico, consiguiendose as una implementacion adicional a la
perseguida, que es la posibilidad de hacer una teleoperaci
on remota sobre el robot. Esto
implica que el operario de la interfaz grafica no ha de estar obligatoriamente delante del
ordenador donde se ejecuta el programa cliente, sino que puede conectarse a este desde
cualquier ordenador y teleoperar el robot.
En cuanto a la programacion, la librera Xlib ofrece funciones para crear ventanas
sencillas y visualizar en ellas imagenes, siempre que tengan un formato adecuado. Ese
formato debe entenderlo el servidor X, y en el fondo, la tarjeta de video.

4.2.

Librera XForms

El sistema X-Window es un sistema relativamente complejo, que ofrece varias interfaces


de acceso a su funcionalidad, desde las de mas bajo nivel hasta otras mas elaboradas que
ocultan al programador detalles que normalmente no necesita. Las interfaces de bajo nivel
permiten maxima flexibilidad y control de los detalles de la interaccion grafica, pero suelen
resultar demasiado complicadas para la mayor parte de aplicaciones.
En esta direccion han surgido paquetes software que se montan encima del sistema XWindow ofreciendo distintos objetos graficos y un repertorio de patrones de interaccion y
visualizacion. Esta reduccion de la flexibilidad total del bajo nivel disminuye la complejidad
de uso sin recortar excesivamente la funcionalidad que las aplicaciones normales pueden necesitar, facilitando de este modo la programacion de interfaces graficas. La librera XForms
[Zhao] es uno de estos paquetes, precisamente el que se ha elegido para desarrollar las
interfaces graficas que necesitemos. Este paquete cuenta con varias ventajas:
Es software de libre distribucion, completamente gratuito para uso no comercial (accesible en http://bragg.phys.uwm.edu/xforms).
Ademas ofrece un repertorio extenso de elementos graficos (botones, diales, canvas,
etc.), suficiente para las necesidades que tenemos. Oculta mucha complejidad asociada
a las ventanas graficas, mostrando una interfaz de uso facil y coherente.
XForms esta en perfecta sintona con el entorno informatico disponible. Se ejecuta
sobre sistema X-Window, con lo que la visualizacion remota es posible, y esta escrita
en C.
Tambien ofrece una herramienta visual, llamada fdesign , muy sencilla, para crear la
interfaz grafica del programa aplicacion.

14

Figura 3: Elementos graficos de XForms: Botones, diales y canvas


4.2.1.

Elementos gr
aficos de XForms

La librera ofrece un amplio repertorio de objetos graficos con los que confeccionar
el frontal grafico seg
un se desee, cada uno de ellos con un determinado comportamiento
y funcionalidad. Estos elementos son sensibles a la interaccion con el usuario a traves
del raton y del teclado. Por otro lado son accesibles y manipulables desde el codigo del
programa aplicacion. As permiten la comunicacion bidireccional: al usuario comunicar
cosas al programa y al programa mostrar cosas al humano, es decir, la interaccion grafica
entre ambos.
Para la implementacion de la interfaz grafica del teleoperador el programa cliente necesita utilizar los siguientes elementos graficos:
Bot
on que el usuario puede pulsar. De diferentes tipos seg
un su comportamiento cuando
se pulsa con el raton: los hay que notifican el evento al pulsarlo, que lo notifican
cuando se suelta, otros se quedan en estado pulsado hasta que se pulse otra vez y
los hay que vuelven inmediatamente a su estado de reposo.
Dial (slider si no muestra el valor, varslider si lo indica) con los que el usuario puede fijar
un valor dentro de un rango lineal.
Canvas que permite al programa pintar sus propias imagenes, puntos, rectas, etc. Nuestro
programa pinta en este canvas las lneas de los infrarrojos, la silueta del robot,...
dependiendo de lo que el operario quiera visualizar. Tambien permite volcar a pantalla
imagenes reales obtenidas con la camara.
Posicionador que permite conocer la posicion x y que se ha seleccionado con el raton
gracias al movimiento de unas trazas sobre un area. De este modo se especifican 2
valores con un solo click de raton. Este elemento lo utilizaremos para crear el joystick
visual.

15

Figura 4: XForms: Posicionador


4.2.2.

Construcci
on visual de la interfaz gr
afica con XForms

Una vez que se tiene en mente el dise


no se construye el frontal grafico con la herramienta

visual que proporciona XForms. Esta construccion conlleva la seleccion de los distintos
elementos graficos que conforman la interfaz, su tama
no, su posicion y sus atributos.
El propio paquete XForms ofrece una herramienta visual para construir el frontal grafico
de la aplicacion. Esta herramienta se llama fdesign y crea una ventana vaca sobre la cual
permite ir incorporando distintos elementos graficos del repertorio (botones, diales, cuadros
de texto, canvas...), que se van situando rellenando el frontal grafico. Fdesign tambien
permite configurar estos elementos: color, tipo de letra, aspecto, color cuando el raton lo
pulsa, tama
no, forma, etc.
La posicion se decide con el raton, seleccionando dentro del repertorio el elemento que
queremos insertar, arrastrando hasta donde queremos situarlo en el frontal y soltandolo
all. El tama
no tambien se vara visualmente con el raton, del mismo modo que el tama
no
de las ventanas de X-Window. Otro tipo de propiedades como color, etiquetas, etc. se
configuran cambiando las propiedades del objeto, tambien visualmente en gran medida,
pulsando entre las distintas posibilidades.
Una vez acabado el dise
no del frontal la herramienta genera tres ficheros: nombre.fd
en el que guarda todos los elementos con sus atributos y los ficheros nombre.h y nombre.c
que son los equivalentes en lenguaje C. Gracias a estos u
ltimos los programas del usuario
pueden iniciar la visualizacion del frontal, acceder a los distintos elementos del mismo y
manipularlos a voluntad. Los objetos graficos tienen asociadas gran cantidad de funciones
que permiten muestrear y fijar su estado, acceder y cambiar sus valores, hacer un repintado,
etc.

16

Figura 5: Fdesign

Figura 6: Construccion de una interfaz grafica con Fdesign

17

4.2.3.

Interacci
on de XForms con el programa

La librera XForms ofrece un modelo de interaccion basado en eventos. Se asocia un area


de la ventana a los elementos graficos y se genera eventos cuando el raton pasa por encima,
cuando el raton se pulsa o se suelta en ese area, etc. El paquete permite definir callbacks, que
son funciones enganchadas a cierto evento sobre un objeto. Estas funciones son invocadas
cuando ese evento se produce en el objeto asociado. El enganche entre el evento y la funcion
se realiza en el momento de construir la interfaz grafica, el programador no debe vigilar
de nada, salvo definir esa funcion, la librera se encargara de llamar al callback cuando
proceda.
La librera XForms permite dos modos de operacion. En el primero toma completamente
el control del flujo de ejecucion y deja todo el funcionamiento del programa en modo
reactivo, respondiendo a los eventos que el usuario genera. El segundo esquema permite
muestrear , de modo no bloqueante, el estado de la interfaz y mantener el control del flujo de
ejecucion en el programa de la aplicacion, que decide cuando muestrear y como responder

al estado en que se encuentre la interfaz [Canas01]. Este


es el esquema que hemos seguido
en nuestra aplicacion, con una hebra periodica que muestrea el estado del frontal 4 veces
cada segundo.
El muestreo de los elementos del frontal recorre los distintos objetos de los que consta.
La funcion fl check forms() devuelve el elemento que ha sido modificado refiriendose a el
como fd nombredelForm -> elemento. Ademas de saber el elemento que ha sido modificado,
tambien es posible saber el estado en el que se encuentra y, si se desea, modificar dicho
estado. Por ejemplo, si se trata de un boton, se puede saber si esta pulsado con la funcion
fl get button (fd nombredelForm -> bot
on ) , los valores que devuelve esta funcion son
PUSHED si el boton esta pulsado y RELEASED si no lo esta. Para modificar el estado del
boton se utiliza la funcion fl set button (fd nombredelForm -> boton, ESTADO ), siendo
el valor de ESTADO igual a PUSHED o RELEASED seg
un lo que se desee.
Para un posicionador tambien es posible conocer el valor xy del punto donde sus trazas
se cruzan. El valor x se obtiene con la funcion fl get positioner xvalue (fd nombredelForm ->
posicionador ) y el valor y se obtiene con fl get positioner yvalue (fd nombredelForm -> posicionador). Para situar el posicionador en un punto se utiliza la funcion fl set positioner xvalue
(fd nombredelForm -> posicionador, valor x) para indicarle la componente x de la posicion,
y con la funcion fl set positioner yvalue (fd nombredelForm -> posicionador, valor y) se le
indica la componente y.
Para conocer el valor actual del elemento dial se utiliza la funcion fl get slider value
(fd nombredelForm -> slider ). Tambien es posible determinar su valor desde el programa
con la funcion fl set slider value (fd nombredelForm -> slider, valor).
Sobre el elemento canvas se pueden utilizar funciones que corresponden a la librera
Xlib. Esta librera esta un nivel por debajo de XForms. Para dibujar una lnea se utiliza la
funcion XDrawLine. En la llamada a esta funcion hay que especificar el canvas donde se
desea pintar y las posiciones xy dentro de dicho canvas de los puntos de principio y final del

18

segmento. Para dibujar puntos se utiliza la funcion XDrawPoints. A esta funcion tambien
hay que indicarle el canvas donde se desea dibujar los puntos, as como las posiciones de
dichos puntos. En el elemento canvas tambien es posible representar una imagen. Para ello
se utiliza la funcion XPutImage, indicandole la imagen que se desea visualizar, el tama
no
de la misma y la posicion que va a ocupar dentro del canvas.
Tambien es posible hacer un repintado de un elemento de un form con la funcion
fl redraw object (fd nombredelForm -> elemento)
La interfaz grafica se inserta en el modelo de programacion multitarea descrito como
dos tareas mas: por un lado muestrea si el usuario ha pulsado alg
un boton o slider y
por otro periodicamente refresca la imagen que se le esta mostrando. Cuanto mas corto
sea el periodo de muestreo de los botones antes se entera el programa de la interaccion
demandada por el usuario y el sistema sera mas reactivo.
Si la tarea de refresco se llama muy frecuentemente la visualizacion sera muy vivaz, pero
puede consumir mucho tiempo y ralentizar al resto de las tareas, lo cual no es deseable.
Se ha decidido hacer un refresco cada segundo y resulta ser un buen compromiso entre la
viveza de presentacion requerida y el ahorro de recursos computacionales que se necesita.

4.3.

Librera Qt

Esta seccion describe el uso basico de la libreria QT. Esta permite el desarrollo de
interfaces graficas muy sencillas y vistosas. El lenguaje de programacion que utiliza es
C++.
Qt es una libreria C++ que proporciona un toolkit para el desarrollo de interfaces
graficas multiplataforma. Qt esta totalmente orientado a objetos, es facilmente extensible, y
proporciona verdadera programacion de componentes mediante el mecanismo SIGNALSSLOTS.
Qt es la libreria nativa de KDE, el popular entorno de escritorio de Linux.
Qt es multiplataforma Una de las principales caracteristicas de Qt, es sin duda, su
orientacion multiplataforma. De esta manera, podemos escribir aplicaciones portables a
MS/Windows, Unix/X11, Mac y sistemas embebidos, con un minimo de restricciones inerentes a las diferencias entre sistemas ( nombres de ficheros, llamadas al sistema, concurrencia, . . . ).
Versiones de Qt Qt es un producto de la compa
nia noruega trolltech (www.trolltech.com),
y se distribuye en diferentes versiones.
Estas son:
Qt Enterprise
Qt Professional

19

Qt Free
Qt/Embedded Free
Las dos primeras, permiten la costruccion de software comercial, e incluyen actualizaciones y soporte tecnico.
La tercera, Qt Free, es la version de Qt para Unix/X11 para el desarrollo de software
gratuito y abierto. Esta version esta bajo licencia GPL.
La u
ltima permite el desarrollo de software gratuito, y tambien se acoge a la GPL.
4.3.1.

Instalacion de Qt Free en Linux

Una vez obtenido el paquete qt-free-x11-XXX.tar.gz de la pagina de trolltech lo descomprimiremos en /usr/local/qt-free-x11-XXX, y crearemos el enlace qt-qt-free-x11-XXX. Definiremos las variables de entorno QTDIR=/usr/local/qt, LD LIBRARY PATH=QTDIR/lib,
MAN PATH=QTDIR/doc/man y PATH=QTDIR/bin.
Tras esto, configuraremos la libreria con ./configure ( desde el directorio QTDIR ). En
este punto podremos modificar las opciones por defecto que se aplican a la libreria, para
ver todas las posibles configuraciones ./configure -help.
Y por u
ltimo, compilamos com make, proceso que llevara almenos 20 o 30 minutos.
Probablemente sea necesario actualizar el fichero /etc/ld.conf.so y ejecutar ldconfig
para qu la libreria sea accesible. Para mas indicaciones sobre el proceso de instalacion
debemos mirar el fichero INSTALL del directirio QTDIR.
4.3.2.

Hola mundo

Por supuesto, el primer programa que se presenta es el tradicional Hola Mundo. En


este primer programa, veremos como crear una peque
na ventana que contiene la cadena
Hola Mundo.
El codigo es el siguiente:
1 #include <qapplication.h>
2 #include <qlabel.h>
3
4 int main( int argc, char* argv[] )
5 {
6
QApplication myapp( argc, argv );
7
8
QLabel* mylabel = new QLabel( <Hola Mundo!, 0 );
9
mylabel->resize( 120, 30 );
10
11 myapp.setMainWidget( mylabel );

20

12 mylabel->show();
13 return myapp.exec();
14 }
Para compilarlo simplemente ejecutamos:
c++ -I$QTDIR/include -L$QTDIR/lib -lqt -o holamundo holamundo.cpp
El resultado de la ejecucion lo vemos en la figura 7( el marco depende del gestor de
ventanas ).

Figura 7: Ejecucion de holaMundo


A continuacion describire el codigo linea a linea. En las primeras lineas tenemos las
inclusiones de las cabeceras necesarias. Por lo general, existe una relacion uno a uno entre
las cabeceras y las clases que declaran. En nuestro ejemplo necesitamos las decleraciones de
las clases QApplication y QLAbel, contenidas en qapplication.h y qlabel.h respectivamente.
En la primera linea de la funcion main, tenemos la creacion del objeto myapp de la clase
QApplication, que sera el encargado de llevar el flujo de ejecucion de la aplicacion y de
manejar las principales opciones de la aplicacion ( fuentes, paleta, . . . ). Dicho objeto recibe
los argumentos de la linea de comandos, por lo que si queremos utilizar alguno de los
argumentos debemos hacerlo antes de crear el objeto.
En la siguiente linea, creamos un objeto QLabel3 , el cual representara nuestra cadena
Hola Mundo. QLabel es un widget( como la gran mayoria de las clases de Qt ), y por
ello tiene una representacion grafica que atiende a su estado.El segundo argumento pasado
al constructor, se refiere al padre del widget, que en nuestro caso no existira por lo que
bastara con pasarle un 0.Con esto la aplicacion se encargara de destruirlo cuando ya no
sea necesario.
La linea 9 indica al widget el tama
no inicial con el que aparecera por pantalla, si nos
basta con que sea visible todo su contenido( Hola Mundo ), podemos eliminar dicha
instruccion, ya que Qt elige el tama
no mas adecuado por defecto.
La linea 11, indica a la aplicacion cual sera el widget principal, lo que significa que la
aplicacion seguira ejecutando hasta que cerremos dicho widget. Para el caso de aplicaciones
sin widget principal( multiples ventanas ) debemos utilizar otras tecnicas.
3

El hecho de haberlo creado en el heap( usando new ) no es casual, si no, que por norma sera la manera de
crear los widgets.La raz
on es, que cada widget tendra un padre, de manera que cada widget sera destruido
por su padre. De esta manera evitamos el desperdicio de memoria.En nuestro caso particular, el segundo
parametro pasado al constructor QLabel indica que no tiene padre, y la aplicacion se encargara de su
destruccion.

21

A continuacion, debemos mostrar los widgets creados, que por defecto permanecen
ocultos.Para ello basta con llamar al metodo show() comun a todo widget.
Por u
ltimo, lanzamos el bucle de eventos con el metodo exec() del objeto QApplication.De esta manera la aplicacion pasa a procesar los eventos recividos hasta que destruyamos el widget principal( cerrando la ventana ).

Referencias
[Zhao] T.C. Zhao and Mark Overmars, Forms Library: a graphical user interface toolkit
for X,http://world.std.com/ xforms/.
[X.Org] X.Org, X-Window System, http://www.x.org.
[Canas01] Jose M. Ca
nas, Manual del robot m
ovil Hermes, Informe Tecnico, Instituto de
Automatica Industrial, Julio 2001.

22

También podría gustarte