jueves, 27 de diciembre de 2007

Probando motores

He creado una especie de prototipo de Rabotron. El prototipo se basa en una madera donde van tres ruedas. Dos ruedas son las motrices y una tercera es una rueda loca. Supuestamente cada rueda motriz va con un motor. Para la prueba desmonté un destornillador eléctrico de 12 voltios que compré con anterioridad. Por lo que solo hay una rueda motriz, lo que hace que el robot de vueltas sobre si mismo.

Lo que no he tenido claro desde un principio es que motor poner al final. Necesito un motor que pueda ir a la velocidad de una persona andando (unos 5 km/h) y a la misma vez que pueda mover el peso del robot. El peso del robot es mas o menos:

- Batería 2 kg
- Portátil 2Kg
- Estructura ? kg (metacrilato)
- Los motores ? kg

Por lo que con esto ya tenemos las primera incógnitas, ya que no se cuanto pesa el robot, aunque supongo que unos 5-6 kg.

La prueba se hizo con el susodicho motor del destornillador que funciona a 550 rpm. Las ruedas usadas son de 5cm de diámetro. Por lo que el robot iría a una velocidad de unos 5 km/h. El cálculo esta hecho en una hoja de excel como se ve a continuación:

Diámetro rueda cm*vuelta RPM cm/minuto cm/hora m/hora Km/h
5 15,70796327 550 8639,3798 518362,788 5183,62788 5,18362788

Eso es a lo que se refiera a la velocidad. Si hablamos de la potencia, no tenemos ningún dato significativo en las instrucciones del motor, así es que en la practica pasaba lo siguiente:

De 0 a 3 kg de peso: El robot se mueve con facilidad.
De 3 a 6 Kg de peso: El robot se mueve con cierta facilidad aunque se nota una disminución de la velocidad.
Más de 6 kg de peso: Mucha dificultad (con mas de 7 presenta problemas de movimiento y se para).

En lo que se refiere al consumo, cosa que me importa también bastante para poder fabricar un puente en H acorde, los motores consumen en vacío unos 2 A (amperios). Cuando mueve cierto peso este consumo sube a unos 3 o 3 y algo. Cosa que no es muy alarmante pensando que podría ser peor.

El ejemplo que se ha comentado con anterioridad sale presentado en el siguiente vídeo, donde el robot pesa 5 kg:



Lo que quiero hacer es empezar a ver que motores son los adecuados para nuestro robot rabotron. Las ruedas lo que esta claro es que son muy pequeñas, por lo que iremos a unas de al menos 10-12 cm de diámetro. Por lo que con las formulas de antes podemos ver que con 270 rpm puede ir a la velocidad de un humano y así seguirlo:

Diámetro rueda cm*vuelta RPM cm/minuto cm/hora m/hora Km/h
11 34,55751919 270 9330,53018 559831,811 5598,31811 5,59831811

Pero la pregunta es.... ¿que motor? y sobretodo.. ¿soportará el motor el peso de rabotron? Las unidades de medida son kg/cm o mNm (miliNewton por metro) pero no las tengo del todo claro para saber si puede mover dicho peso o no.

Bueno habrá que seguir investigando.

jueves, 20 de diciembre de 2007

Instalación del proyecto Rabotron paso a paso

En este post vamos ha explicar como hemos instalado nuestro proyecto desde cero, para lo que hemos instalado... Debian, eclipse, java, gspca (spca5xx), player ( player 2.0.4 ).

Bueno comencemos:

1.- Lo primero que tenemos que hacer es descargar Debian. En nuestro caso hemos decido instalar Debian Lenny (en estos momentos testing) desde el netinstall. Para el que no se aclare mucho siempre puede descargar los ISOs de Debian completos, aun que si aquí ya andamos perdidos...

2.- Una vez instalado Debian...lo tenemos todo un poco “pelao” todavía.
Seguiremos por descargar Eclipse Classic de la página oficial.
Cuando se haya descargado Eclipse simplemente es descomprimirlo donde queramos.

Es posible que al ejecutar Eclipse nos de un error similar a este:

Error opening the editor
java.lang.ClassNotFoundException: org.eclipse.core.runtime.Plugin
...
...


Bien, que no cunda el pánico, esto es porque Eclipse no encuentra el entorno de ejecución de java (JRE). Para solucionarlo simplemente hay que instalar el JRE, hay variar soluciones.

La elegida esta vez ha sido descargar el jdk6 de la web de sun.

3.- Pasamos a instalar el driver gspca (antiguo spca5XX) necesario para la camara web. Ya explicamos como instalar tanto el driver spca como el gspca, Para mas información leer el post http://celtico-celtico.blogspot.com/2007/09/webcam-bajo-linux.html

4.- Instalar Camorama: Esto no es obligatorio, pero podemos instalarlo para ver si el driver gspca funciona correctamente (apt-get install camorama).

5.- Ya solo nos queda instalar player 2.0.4, hemos elegido esta versión por ser estable. Estuvimos probando con la versión de player 2.1.0 descargada del CVS (explicaremos como hacerlo con eclipse en otro post) pero decidimos quedarnos con la 2.0.4 por estar todavía en pruebas y en depuración de varios bugs la versión 2.1.0.

Antes de empezar con la instalación de Player 2.0.4 hay que instalar varias librerías:

- Librería “libtool” (apt-get install libtool) necesaria al hacer bootstrap para ejecutar automáticamente las ordenes:

libtoolize –force

- Instalar automake (apt-get install automake), necesaria al hacer bootstrap para ejecutar automáticamente las ordenes:

aclocal

autoheader

automake --gnu --add-missing

- Instalar pkg-config (apt-get install pkg-config), necesaria al hacer bootstrap para ejecutar automáticamente la orden:

autoconf

- Libreria “libjpeg62-dev”(apt-get install libjpeg62-dev), necesaria para que al instalar player se instale el driver cameracompress, de lo contrario este driver no aparecerá en la instalación. Esto se ve al hacer el configure, donde aparece una lista con los drivers que se instalarán y los que no.

Una vez instaladas estas librerías solo nos queda descargar player 2.0.4.

En nuestro caso hemos descomprimido el archivo y hemos añadido el driver Rabotron a la carpeta de “server/drivers/”, una vez hecho esto pasamos a la instalar Player:

./bootstrap


Si al ejecutar bootstrap nos aparece el siguiente error:

server/libplayerdrivers/Makefile.am:26: shell find $(top_builddir: non-POSIX variable name

server/libplayerdrivers/Makefile.am:26: (probably a GNU make extension)

hay que instalar la versión 1.9 de automake (apt-get install automake1.9) y volver a ejecutar bootstrap.

Una vez termine, ejecutamos el comando:

./configure

Al ejecutar configure nos dice los drivers que se instalarán y los que no serán instalados junto con la causa por la cual no pueden ser instalados:

The following device drivers will be included:

acts, amtecpowercube, aodv, bumpersafe, nd, cameracompress, camerav4l, canonvcc4, clodbuster, cmucam2, cmvision, dummy, er1, fakelocalize, festival, flockofbirds, garminnmea, iwspy, khepera, laserbar, laserbarcode, lasercspace, laserposeinterpolator, laserrescan, lasersafe, laservisualbarcode, laservisualbw, linuxjoystick, laserposeinterpolator, logfile, mapcspace, microstrain, obot, p2os, erratic, wbr914, ptu46, relay, rflex, sicklms200, sicknav200, sickpls, sicks3000, sphere, sonyevid30, urglaser, vfh, vmapfile, roomba, rabotron, wavefront, insideM300, skyetekM1, mica2

The following device drivers will NOT be included:

acoustics -- disabled by default; use --enable-acoustics to enable
amcl -- couldn't find (at least one of) gsl/gsl_version.h
artoolkitplus -- couldn't find required package artoolkitplus >= 2.0.2
...

Como vemos, en drivers instalados, aparecen los drivers de cameracompress y rabotron.

El siguiente paso es ejecutar las ordenes:
./make
./make install

Ya tenemos instalado Player!!. Ahora para ejecutarlo simplemente habrá que ejecutar:

./player ficheroCfg.cfg

Ahora CUIDADO, puede que nos de un error similar al siguiente al intentar arrancar player:

player: error while loading shared libraries: libplayerdrivers.so.2: cannot open shared object file: No such file or directory

En este caso hay que exportar el path:

export LD_LIBRARY_PATH=/usr/local/lib

Un consejo es que se ponga en el fichero “.bashrc” para que cada vez que se habrá un terminal se ejecute automaticamente.

Ya podemos ejecutar player en nuestro sistema:

./player ficheroCFG.cfg

* Part of the Player/Stage/Gazebo Project [http://playerstage.sourceforge.net].
* Copyright (C) 2000 - 2006 Brian Gerkey, Richard Vaughan, Andrew Howard,
* Nate Koenig, and contributors. Released under the GNU General Public License.
* Player comes with ABSOLUTELY NO WARRANTY. This is free software, and you
* are welcome to redistribute it under certain conditions; see COPYING
* for details.

Listening on ports: 6665

Ahora solo nos quedaría arrancar el proyecto y verlo rular...

Adicionalmente recordar que subimos un post en el que indicábamos como grabar video de nuestro escritorio Linux con el programa “recordMyDesktop”: http://celtico-celtico.blogspot.com/2007/11/grabacin-de-vdeo-en-linux.html

viernes, 14 de diciembre de 2007

Camino hacia la integración

Voy a permitirme hacer una analogía entre nuestro proyecto y una situación de la vida real que podría ocurrir.

Supongamos que existe una gran cordillera que separa dos países. Por intereses económicos y comerciales se quieren comunicar ambos países. Por lo que se decide hacerlo mediante un camino que atravesará con un túnel la gran cordillera.

Para que los dos países tengan los mismos gastos y esfuerzos, se decide que el país A haga un túnel hacia el país B y viceversa. La intención no es crear dos túneles distintos, sino que más bien es encontrarse los dos túneles a la mitad de la cordillera, formando así uno único.

¿Que os parece?
¿fácil?
¿difícil?

El que haya contestado debería de reflexionar sobre algunos aspectos clave que no han sido presentados. Por ejemplo, ¿de que países estamos hablando? No es lo mismo que se quieran comunicar dos países del tercer mundo con economías muy limitadas, que lo hagan dos superpotencias con sus ingenieros de caminos y sus excavadoras. ¿Y si hablamos de en que año situamos esto? Quizás hemos pensado en una época actual, pero si pensamos en cuando el cavernicola iba con un taparabos y una lanza para cazar... se nos viene a la cabeza la palabra utopía.

Hablando meramente del proyecto. Los dos componentes hemos empezado por polos opuestos (cada uno a un lado de la cordillera). }TOR{ ha estado programando en JAVA peleándose con la visión y ha ido bajando de niveles tocando el servidor de player. Por otro lado, celtico ha ido desde lo más bajo hacia arriba, soldando la placa de motores, programando los microcontroladores y creando el driver que se integra en player.

Ahora si que es el momento. Es el momento de la integración, si todo ha ido bien los túneles se encontrarán sin problemas, sino tendremos que ir buscando soluciones. Ahora hago la misma pregunta que antes sobre la integración de nuestro proyecto Rabotron....

¿Que os parece?
¿fácil?
¿difícil?

Pues la contestación es, como antes se ha explicado ... "depende". Tenemos que tener en cuenta que hablamos de tecnologías en constante desarrollo (player y javaclient), hablamos de hardware creado por estudiantes, de escasa información en la red.... Todo esto nos hace tener un cumulo de sensaciones de posibilidad de éxito en esta etapa o de fracaso.

Nunca se sabe, es el momento. Vamos.

miércoles, 5 de diciembre de 2007

Vista general de Rabotron

Como se puede observar ya hay gran cantidad de posts sobre el trabajo que se está realizando. Pero a veces no estoy seguro si la gente tiene claro la ubicación general del proyecto y más despues de hablar esta tarde con mi colega skool. Es por ello que quiero comentar brevemente la visión general del proyecto.

Rabotron se compone basicamente de un portatil en el que va instalado un servidor llamado PLAYER (en nuestro caso la version 2.1.0 compilada desde el cvs). Hemos tenido que compilarla manualmente nosotros ya que necesitamos gestionar una placa de motores para el movimiento de rabotron.

Es por ello que creamos un driver en lenguaje c , lo integramos en player y lo compilamos. No ocurre igual con la camara web (para la vision) ya que ya existe un driver creado v4l (video for linux) y es el que vamos a usar.

El servidor lo manejará un cliente creado a partir de Javaclient 2.0 (programamos en java). Dicho cliente tambien va instalado en el mismo portatil y se comunica con player a traves del puerto 6665.

Los perifericos usados es una camara web a traves de usb y una placa diseñada y creada integramente por nosotros encargada de gestionar el movimiento del robot. La placa es la que contiene el pic16f876 que programada en emsamblador se comunica por rs-232 con el driver de player.

Dicho esto, una secuencia logica de funcionamiento es: la camara web recibe una imagen y la envia de forma vertical (segun el dibujo de mas abajo) hasta javaclient2. Aqui la valoramos y decidimos el movimiento de rabotron segun las necesidades del entorno. El movimiento se le indica a player a traver del puerto 6665, gracias al driver creado se comunica con la placa por puerto serie y esta es la que lo trasforma en impulsos para las ruedas del robot.

Espero que todo haya quedado un poco más claro. Os dejo un dibujo aclaratorio:

Aplicando filtro Equalize (¿mejorando?)

El filtro realiza una mejora sustancial de la imagen capturada bajo circunstancias pobres de luz ó exponiendo a la víctima de Rabotron a una luz que no sea blanca, mientras que si realizamos en filtro en campo abierto no es tanta la ganancia que podamos llegar a tener comparada con la pérdida de tiempo que tenemos al aplicar la función anterior. El tiempo dirá si realmente merece la pena que realizamos el filtro, para empezar lo que hemos hecho es optimizar un poco el código para que la función tarde menos en ejecutarse, el código actual tarda un tiempo (calculado mediante pruebas) aproximado del 30% al 40% menor al código inicial de la función equalize.

El código en java del filtro de ecualizado optimizado es el siguiente:
public int [] filtroEqualizeTOR()
{
double max=255;
double[] binR= new double [tamano/3];
double[] binG= new double [tamano/3];
double[] binB= new double [tamano/3];
int [] binAux = new int [tamano];

double maxiR=0,maxiG=0,maxiB=0;
double miniR=255,miniG=255,miniB=255;
int aux=1;

//sacamos valor del pixel minimo y maximo para cada componente RGB
for (int k = 0; k < tamano/3; k++) { aux= k*3; binR[k] = imageRGB[aux]; binG[k+1] = imageRGB[aux+1]; binB[k+2] = imageRGB[aux+2]; } Arrays.sort(binR); Arrays.sort(binG); Arrays.sort(binB); maxiR=binR[(tamano/3)-1]; maxiG=binG[(tamano/3)-1]; maxiB=binB[(tamano/3)-1]; miniR=binR[0]; miniG=binG[0]; miniB=binB[0]; for (int k = 0; k < tamano/3; k++) { aux=k*3; binAux[aux]=(int)(((imageRGB[aux]-miniR)/(maxiR-miniR))* (double)max); binAux[aux+1]=(int)(((imageRGB[aux+1]-miniG)/(maxiG-miniG))*(double)max); binAux[aux+2]=(int)(((imageRGB[aux+2]-miniB)/(maxiB-miniB))*(double)max); } return binAux; }

Al estar trabajando con imágenes de 320x240 no es excesivo el tiempo ganado, pero todo lo que podamos recortar es tiempo que ganamos a la hora de ejecutar la orden a Rabotron para que se mueva. Para la demostración de este filtro voy a poner solamente un par imágenes de la ejecucion: En la parte superior de la ventana se ve la imagen captura sin aplicarle ningún tipo de filtro Mientras que en el canvas de abajo de la ventana se ve la misma imagen pero aplicándole el filtro de ecualización. En esta primera imagen podemos ver como al mejorar filtrar la imagen también mejoramos el binarizado de la misma al buscar a nuestra víctima, en este caso el color a buscar es el de la mano.

- Imagen 1-

En la segunda imagen ( Imagen 2 ) simplemente se ve la mejora realizada sobre el color de la imagen (Arriba sin aplicar filtro, Abajo tras aplicar el filtro), no mostramos el binariza:


-Imagen 2-

martes, 4 de diciembre de 2007

cambio comunicacion puerto serie

Hola a todos,

He cambiado el protocolo de comunicación del puerto serie. Lo he hecho mas que nada pensando en un mejor rendimiento de la comunicación. Antiguamente enviaba carácter a carácter desde el puerto serie del ordenado a la placa controladora de motores y el pic era el que daba confirmaciones de envío.


El esquema como recordatorio es algo así:


El cambio reside pues en la forma de envío. A partir de ahora no se hará de carácter a carácter, sino que se enviará una trama entera y es el pic el encargado de interpretarla, definiendo así nuestro propio protocolo.

La trama enviada tiene tres limitadores. Primero una "d" indicando que se refiere al motor derecho, despues va un numero (negativo o positivo) de 0 hasta 127 que indica la potencia del motor derecho. Luego hay un limitador "i" indicando que se refiere al motor izquierdo, al igual que antes después aparece un numero que indica la potencia de dicho motor. El ultimo carácter de la trama es el limitador "f", que indica que la trama ha finalizado.

Un ejemplo de trama:

d

2

5

i

-

6

4

f


Por supuesto que la longitud de la trama es variable, ponemos la máxima dimensión y la mínima:

d

-

1

1

5

i

-

1

2

7

f

d

5

i

7

f


Por ultimo y si por si es de ayuda os posteo el código del pic para recibir las tramas, interpretarlas y crear los impulsos necesarios para el control de los motores:


/*
----------------------------------------------------------------------
#include <16f876a.h> // Definiciones del PIC 16F876A
#include // Para el atoi
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de siempre
#use delay(clock=4000000) // Oscilador a 4 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estándar



// CONSTANTES /////////////////////////////////////////////////////////////////

int const lenbuff=12; // Longitud de buffer--> Ajustar



// VARIABLES EN RAM ///////////////////////////////////////////////////////////

int motder,motizq;
int sentido, sentidoder, sentidoizq;
int xbuff=0x00; // Índice: siguiente char en cbuff
char cbuff[lenbuff]; // Buffer
char rcvchar=0x00; // último carácter recibido
int1 flagcommand=0; // Flag para indicar comando disponible
char arg[lenbuff]; // para pasar el negativo
int cont=0; // contador de recibidos




// Declaración de Funciones ///////////////////////////////////////////////////

void inicializa(void);
void inicbuff(void); // Borra buffer
int addcbuff(char c); // añade carácter recibido al buffer
void procesa_comando(void); // Procesa comando
int aentero(void); // Pasa el buffer a un entero
int procesatrama(void); // Procesa una trama recibida


// INTERRUPCIONES /////////////////////////////////////////////////////////////


#int_rda

void serial_isr() // Interrupción recepción serie USART
{
while ( cbuff[cont-1]!='f' ) // entramos al bucle while
{
if ( kbhit () )
{
cbuff[cont]=getc(); // en la variable keypress se guardan los caracteres
cont++;
}
}
printf("Recibo: %s ",cbuff);
cont=0;
flagcommand=1; // Comando en Main
procesatrama(); //procesa la trama
inicbuff(); // Borra buffer
}




// Desarrollo de Funciones ////////////////////////////////////////////////////


void inicializa()
{
motder=motizq=0;
sentido=sentidoder=sentidoizq=0;
xbuff=0x00; // Índice: siguiente char en cbuff
inicbuff(); //char cbuff[lenbuff]; // Buffer
rcvchar=0x00; // último carácter recibido
flagcommand=0; // Flag para indicar comando disponible
}


void inicbuff(void) // Inicia a \0 cbuff -------------------
{
int i;

for(i=0;i Recibo d: %c ",cbuff[contador]);

contador++; //1

if(cbuff[contador]=='-')
{
sentidoder=0;
contador++;
printf("PT--> Recibo negativo der");
}
else
sentidoder=1;

i=0;

do
{ // Extraemos argumento D del buffer
arg[i]=cbuff[contador];
i++;
printf("PT--> Recibo num der: %c ",cbuff[contador]);
}while(cbuff[++contador ]!='i'); // hasta que llegue I


motder=atoi(arg); //valor motor derecha

printf("PT--> Mot der: %d ",motder);

//inicbuff(); //iniciamos el buffer de arg

for(i=0;i Recibo i: %c ",cbuff[contador]);

contador++; //en izq

if(cbuff[contador]=='-')
{
printf("PT--> Recibo negativo izq");
sentidoizq=0;
contador++;
}
else
sentidoizq=1;

i=0;

do
{ // Extraemos argumento D del buffer
arg[i]=cbuff[contador];
i++;
printf("PT--> Recibo num izq: %c ",cbuff[contador]);
contador++;
}while(cbuff[contador]!='f' && cbuff[contador]!=0x00); // hasta que llegue F


motizq=atoi(arg); //valor motor derecha

printf("PT--> Mot izq: %d ",motizq);

retorno = 1;
return retorno;
}


// Programa Principal /////////////////////////////////////////////////////////

void main()
{

setup_ccp1(CCP_PWM); //ccp1 modo PWM
setup_ccp2(CCP_PWM); //ccp2 modo PWM

setup_timer_2(T2_DIV_BY_16, 127, 1); // 488Hz (con XT=4MHz) esta frecuencia la podes variar cambiando los valores, fijate en el datasheet del micro que uses, que vienen las relaciones para calcular lo inherente a la frecuencia y al duty.
inicbuff(); // Borra buffer al inicio

printf("Soy el Pic y estoy activo\n");
enable_interrupts(int_rda); // Habilita Interrupción RDA
enable_interrupts(global); // Habilita interrupciones

do {

if(flagcommand) procesa_comando(); // Si hay comando pendiente
// de procesar ... lo procesa.

} while (TRUE);

}

// Procesador de Comandos /////////////////////////////////////////////////////

void procesa_comando(void)
{

flagcommand=0; // Desactivo flag de comando pendiente.

printf ("procesa comando: %d\n",motder);
printf ("procesa comando: %d\n",motizq);

if(sentidoder!=0)
{
printf ("Enciende DER\n");
output_high(PIN_C3);
}
else
{
printf ("Apaga DER\n");
output_low(PIN_C3);
}

set_pwm1_duty(motder); // Se cambia el ancho con el valor obtenido en canal 0.

if(sentidoizq!=0)
{
printf ("Enciende IZQ\n");
output_high(PIN_C4);
output_high(PIN_C5);
}
else
{
printf ("Apaga IZQ\n");
output_low(PIN_C4);
output_low(PIN_C5);
}

set_pwm2_duty(motizq); // Se cambia el ancho con el valor obtenido en canal 0.

inicializa(); // Borra buffer
}

----------------------------------------------------------------------
*/


martes, 27 de noviembre de 2007

Off-topic: Ingenieros Informaticos

Lo mal que está hoy en día el trabajo de ingeniero en informático no es ningún descubrimiento.

Buscando por el youtube he encontrado 1 vídeo ( referenciado por la profesora de BDA) que creo que puede ser bastante interesante a la vez que divertido.

Es triste que nos tengamos que reír de algo que nos afecta directamente y que además no tiene ninguna pinta de cambiar. Pero bueno, a mal tiempo buena cara.

Os dejo aquí el enlace al vídeo a ver si os gusta. Por desgracia lo que dice de forma sarcástica es realidad:

http://es.youtube.com/watch?v=mdP7noUwbR4

domingo, 25 de noviembre de 2007

Fotos placa gestion motores



Hola a todos

Como os dije he tenido un poco de tiempo para hacer unas fotos a la placa que gestionará los motores del nuestro robot rabotron. Como podemos ver en la primera imagen tenemos una bateria de 12 v voltios de entrada, aunque es regulada a 5 voltios por el 7805. Tambien podemos ver como a nuestra placa le hemos conectado una placa de pruebas de esas blancas donde hemos conectado leds y resistencias para poder ver a ojo el funcionamiento de la placa (indica direccion y fuerza de cada uno de los motores):



En esta foto podemos ver con más detalle los elementos que hay soldados en nuestra placa. Basicamente están todos menos el puente en H (l293) que lo soldaremos mas adelante, ya que aun no es de vital importancia:



En la siguiente imagen podemos ver las soldadoras por la cara de atrás de la placa ( es un poco rustico):


Por ahora la placa se va a quedar así y voy a ponerme a programar un driver para linux y player/stage que gestione dicha placa, y esta placa que gestione los motores.

jueves, 22 de noviembre de 2007

Primeras pruebas de visión

Una vez decido el formato de color elegido para la identificación de nuestra víctima, hemos de empezar con las primeras pruebas sobre el reconocimiento del objetivo a seguir. Para lo cual ya explicamos en un post anterior que usaríamos el modelo de color HSV (Hue, Saturatión, Value) también conocido como HSB debido a la mayor efectividad que obteníamos analizando colores en comparación con el formato de imagen RGB.

Para una correcta muestra del funcionamiento de nuestra captura de imagen, hemos decidido crear una ventana en la cual mostramos:
-La imagen original en el modelo de color RGB que está recibiendo nuestra cámara
-Una imagen binarizada que representa los puntos que realmente nos interesan de la imagen que estamos capturando.


Actualmente para calcular la imagen binarizada aplicamos un filtro del color que queremos buscar sobre la imagen original en formato HSB, analizando el matriz, la saturación y el brillo de cada píxel de la imagen.

El color que nuestro robot debe localizar lo calculamos a partir de una imagen de la víctima, a través de la cual obtenemos el perfil de matiz, saturación y brillo de nuestra víctima para poder realizar el posterior seguimiento.

Como demostración subiremos un primer vídeo del reconocimiento de una persona basándonos únicamente en el color de la ropa de la misma, para que vayamos haciendo nos una idea del objetivo que vamos persiguiendo en la zona de visión.

Como se puede apreciar hay ruido en la imagen y algunas zonas no reconocidas por problemas de sobras por el ángulo de incisión de la luz sobre la ropa y las arrugas de la misma.

Grabación de Vídeo en Linux

Para poder mostrar al publico externo a la Universidad de Alicante como actúa la visión del robot Rabotron, que mejor manera de realizar algún vídeo con el resultado de alguna de las pruebas que estamos realizando.


Para la captura de vídeo bajo linux de nuestro escritorio de trabajo hemos decidido utilizar el programa “recordMyDesktop”. El software se puede adquirir desde su página web o mediante los repositorios de Debian / Ubuntu.


En nuestro caso hemos optado por la segunda opción:


apt-get install recordmydesktop


Como el software dispone de una versión gráfica y cómoda de usar hemos decido también instalarla


apt-get insta gtk-recordmydesktop


Más rápidamente podemos realizar la instalación conjunta


apt-get install recordmydeskto gtk-recordmydesktop


Una vez realizada la instalación tenemos un acceso directo al software de grabación en: Aplicaciones / Sonido y Vídeo / gtk-recordMyDesktop


Mediante el uso de la versión gráfica podemos seleccionar una sola ventana o la parte del escritorio sobre la que queremos realizar la grabación, así mismo también podemos modificar la calidad de sonido y audio de nuestro vídeo, el uso es realmente sencillo.


Nota: El vídeo grabado por defecto por el software recordmydesktop es en formato OGG.


Como transformar los video OGG a formato AVI:

Estamos teniendo bastante problemas al subir vídeo en formato OGG a youtube, por lo que hemos decido pasarlo al formato AVI antes de subirlos.

Para covertir video en formato OGG al formato AVI usaremos en nuestro caso el software MEncoder, el cual se instala al instalar el Mplayer.

Antes de instalar Mplayer debemos instalar primero el encoder de vídeo mp3 Lame, sino no será posible realizar la conversión de videos con Mplayer, muy importante instalar primero los codecs, sino no compilaremos el Mplayer sin la librería libmp3lame y nos dará un error al realizar la transformación del vídeo.

Para instalar Lame debemos seguir las siguientes pautas: (descargamos la versión 3.97)

# wget http://ufpr.dl.sourceforge.net/sourceforge/lame/lame-3.97.tar.gz
# gunzip -c lame-3.97.tar.gz | tar xvf -
# cd lame-3.97/
# ./configure && make && make install

Ahora llega el momento de instalar el Mplayer, en nuestro caso hemos descargado de la web oficial de Mplayer la versión Mplayer-1.0rc1, la instalación es bastante sencilla:

# tar xvjf MPlayer-1.0rc1.tar.bz2
# cd Mplayer-1.0rc1/
# ./configure
# ./make
# ./make install

Una vez instalado todo simplemente tenemos que ejecutar la orden para convertir nuestro vídeo en OGG a AVI:

# mencoder video_entrada.ogg -ovc lavc -oac mp3lame -o video_salida.avi

martes, 20 de noviembre de 2007

Programa de control del puerto serie / motores

Ya tengo la placa que gestiona los motores soldada. Todo menos el puente en H (L293), con lo que por ahora tengo las salidas del microcontrolador (pic 16f876) enganchadas a unos leds, con resistencias de 220 ya que la salida es de 5v. Con esto consigo ver el funcionamiento del pic y el pueroto serie de una forma gráfica.

En cuanto pueda subiré unas fotos de como va la placa que gestiona los motores y si me da tiempo algun video. Por ahora os voy a comentar el programa en c que he creado en el PICC para recibir datos desde el puerto serie (rs232) y transformarlo en señales para los motores.

Lo primero que queria comentar es que el codigo me he basado en uno que hay hecho por Internet. Y he ido modificando cosas para poder aplicarlo a mi caso (que ha sido bastantes modificaciones).

Basicamente hay una funcion principal que activa los dos pwm(RC1 y RC2):

setup_ccp1(CCP_PWM); //ccp1 modo PWM
setup_ccp2(CCP_PWM); //ccp2 modo PWM

Inicializamos el TIMER2 y activamos dos interrupciones, las interrupciones globales y la de RDA que es cuando recibe datos por el puerto serie.

Despues el programa se queda en un bucle infinito esperando que hayan datos que procesar.

La interrupcion de rda (serial_isr();) se activa cuando llega algo por el puerto serie, conforme va recibiendo datos los va acumulando en un buffer para despues procesarlos.

Por funciones tenemos:

Inicializa --> que inicializa todas las variables globales de nuestro programa.

inicbuffer --> inicializa el buffer de caracteres leidos y lo pone todo a 0x00. Indispensable limpiarlo despues de usarlo, ya que se puede quedar basura que haga un funcionamiento anomalo.

addcbuffer --> Va añadiendo caracteres al buffer, en el caso de que un caracter sea un intro (0x0D) o un espacio (0x20) se corta la ejecucion para procesar los comandos.

aentero --> Convierte la cifra obtenida en caracteres a numero entero, aqui tambien vemos si el valor es negativo, en dicho caso el motor irá en sentido contrario.

procesa_comando --> Una vez que se han introducido los comandos esta funcion es la encargada de sacar los valores (iluminar leds) correspondientes que más adelante moverán los motores.

La forma de usar el programa es pasando valores por el puerto serie de la siguiente forma:
valor1 (espacio) valor2 (intro)

Por ejemplo para mover los motores hacia adelante de una forma continua podria ser:
50 50

Para mover un motor hacia adelante despacio y otro hacia atras muy rapido sería:
8 -100


A continuacion os pego el codigo entero del pic:



//-----------------------------------------------------------------

#include <16f876a.h> // Definiciones del PIC 16F876A
#include <
stdlib> //stdlib.h para el atoi
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT // Los Fuses de siempre
#use delay(clock=4000000) // Oscilador a 4 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estándar



// CONSTANTES /////////////////////////////////////////////////////////////////

int const lenbuff=5; // Longitud de buffer, Ajustar
// a lo que desees (o te sea posible)


// VARIABLES EN RAM ///////////////////////////////////////////////////////////

int motder,motizq;
int sentido, sentidoder, sentidoizq;
int xbuff=0x00; // Índice: siguiente char en cbuff
char cbuff[lenbuff]; // Buffer
char rcvchar=0x00; // último carácter recibido
int1 flagcommand=0; // Flag para indicar comando disponible
char arg[lenbuff]; // para pasar el negativo



// Declaración de Funciones ///////////////////////////////////////////////////

void inicializa(void);
void inicbuff(void); // Borra buffer
int addcbuff(char c); // añade carácter recibido al buffer
void procesa_comando(void); // Procesa comando
int aentero(void); // Pasa el buffer a un entero



// INTERRUPCIONES /////////////////////////////////////////////////////////////

#int_rda
void serial_isr() { // Interrupción recepción serie USART

rcvchar=0x00; // Inicializo carácter recibido
if(kbhit())
{ // Si hay algo pendiente de recibir ...
rcvchar=getc(); // lo descargo y ...
addcbuff(rcvchar); // lo añado al buffer y ...
printf("Recibo: %c ",rcvchar);
}
}



// Desarrollo de Funciones ////////////////////////////////////////////////////


void inicializa()
{
motder=motizq=0;
sentido=sentidoder=sentidoizq=0;
xbuff=0x00; // Índice: siguiente char en cbuff
inicbuff(); //char cbuff[lenbuff]; // Buffer
rcvchar=0x00; // último carácter recibido
flagcommand=0; // Flag para indicar comando disponible
}


void inicbuff(void) // Inicia a \0 cbuff -------------------
{
int i;

for(i=0;i Habilita Flag para procesar
flagcommand=1; // Comando en Main
motizq=aentero(); // Paso a entero
sentidoizq=sentido;// Cambio sentido
inicbuff(); // Borra buffer
break;

case 0x20: // Espacio
motder=aentero(); // Paso a entero
sentidoder=sentido;// Cambio sentido
inicbuff(); // Borra buffer
break;

default:
cbuff[xbuff++]=c; // Añade carácter recibido al Buffer
}
}


int aentero () //pasa el buffer a un entero
{

int retorno,i;


if(cbuff[0]=='-')
{
sentido=0;

i=1;

do{ // Extraemos argumento del buffer
arg[i-1]=cbuff[i]; // copiamos a arg sin el '-'
}while(cbuff[++i ]!=0x00);

retorno=atoi(arg);
}
else
{
sentido=1;
retorno=atoi(cbuff);
}
printf("A entero: %d\n",retorno);

return retorno;
}

// Programa Principal /////////////////////////////////////////////////////////

void main()
{

setup_ccp1(CCP_PWM); //ccp1 modo PWM
setup_ccp2(CCP_PWM); //ccp2 modo PWM

setup_timer_2(T2_DIV_BY_16, 127, 1); // 488Hz (con XT=4MHz) esta frecuencia la podes variar cambiando los valores, fijate en el datasheet del micro que uses, que vienen las relaciones para calcular lo inherente a la frecuencia y al duty.
inicbuff(); // Borra buffer al inicio

printf("Soy el Pic y estoy activo\n");
enable_interrupts(int_rda); // Habilita Interrupción RDA
enable_interrupts(global); // Habilita interrupciones

do {

if(flagcommand) procesa_comando(); // Si hay comando pendiente
// de procesar ... lo procesa.

} while (TRUE);

}

// Procesador de Comandos /////////////////////////////////////////////////////

void procesa_comando(void)
{

flagcommand=0; // Desactivo flag de comando pendiente.

printf ("procesa comando: %d\n",motder);
printf ("procesa comando: %d\n",motizq);

if(sentidoder!=0)
{
printf ("Enciende DER\n");
output_high(PIN_C3);
}
else
{
printf ("Apaga DER\n");
output_low(PIN_C3);
}

set_pwm1_duty(motder); // Se cambia el ancho con el valor obtenido en canal 0.

if(sentidoizq!=0)
{
printf ("Enciende IZQ\n");
output_high(PIN_C4);
output_high(PIN_C5);
}
else
{
printf ("Apaga IZQ\n");
output_low(PIN_C4);
output_low(PIN_C5);
}

set_pwm2_duty(motizq); // Se cambia el ancho con el valor obtenido en canal 0.

inicializa(); // Borra buffer
}

--------------------------------

Espero que os sea de ayuda.
UN SALUDO

jueves, 8 de noviembre de 2007

Ya va el puerto serie

Por fin puedo escribir para dar buenas noticias. Como recordáis os comenté que tenia problemas porque aparentemente la placa con la gestión de los motores debería de funcionar perfectamente y no lo hacía. Pues bien después de mucho esfuerzo, sudores y tres intentos de suicidio he conseguido que funcionara.

Voy a explicar los problemas que localicé. La primera lección chicos para el éxito del proyecto es la siguiente premisa: "No meteré 12 voltios donde van 5". Sí, como oís, al meter mas voltaje me cargué varios componentes de la placa (¿varios? queria decir casi todos). Como ya comenté la otra vez comprar componentes en Alicante es como buscar un balneario en Somalia. El PIC 16F876 fui a comprarlo a una tienda que lo ofertan en el catalogo en inet y recibieron con un: ¿que quieres piratear? Yo flipando. Es como si vas a la ferreteria a comprar un cuchillo y te preguntan ¿A quien vas a matar? Bueno en fin.... Despues de patearme toda alicante he encontrado un sitio donde si que lo tenian, y les he comprado todos los que le quedaban, o sea 5.

Una vez resuelta la papeleta de los componentes, resulta que tenia retorno las pistas de enviar y recibir, Rx Tx. Despues de comerme muchos dias la cabeza resulta que comprendí que la pasta de soldadura es conductora. Toda mi desesperacion se fué en cuanto limpié toda la pasta.

Conclusiones: tengo la placa funcionando a la perfeccion. Al final resulté ser una chorrada. Pero una chorrada que me ha llevado bastante tiempo. Espero poder quedar con mi "jefe de proyecto" para enseñarle los resultados.

El siguiente paso será programar el driver.

miércoles, 31 de octubre de 2007

Problemas con el proyecto

Como habéis podido comprobar llevo un tiempo sin escribir nada. Puede parecer que haya desertado el proyecto como un cobarde, jejej. No es el caso, por lo menos por el momento. Pero si que he sufrido una serie de contratiempos.

Os comento que llevo soldado de la placa que controlará los motores, el conector rs-232, el max232 (cambio de niveles) y el pic16f876. He estado programando algunas rutinas para comprobar que la trasmisión serie funciona. En estas rutinas he conseguido que el pic mande datos al PC y viceversa.
Aunque no se que pasa que a veces pierdo datos, no se si es por el oscilador o por algo.

También comentaros que he pasado de programar en ensamblador a hacerlo en C. He encontrado una herramienta llamada PICC que es un compilador de C para los PIC. Creo que este paso puede acortarme las tareas de programación, como así ha sido.

Bueno paso a comentar los contratiempos. El problema que tengo es que antes de soldar toda la movida lo tenia en dos placas distintas (placas experimentales de esas blancas que no hace falta soldar) y muy tonto de mi cuando fui a conectar la alimentación le metí 12V donde iban 5V. El efecto fue casi inmediato ya olia a quemado y salió una pequeña nube de humo. A pesar de los signos evidentes de "petada" el chip seguia funcionando, pero era solo un espejismo, porque cuando fui a grabarlo de nuevo comprobé que habia muerto.

Como vivo en alicante y esto es lo mas parecido al tercer mundo hablando tecnológicamente pues me ha costado dios y ayuda encontrar un PIC16f876. Vamos que estaba rellenedo un pedido a una tienda de valencia cuando por fin encontré una en Alicante de la cual no me da la gana poner su nombre y darle publicidad.

El tema es que ayer por fin pude probar las rutinas para el puerto serie y parece que medio funcionaban, solo medio porque aun me hacen extraños, pero como la alimentación la tengo con dos cables en un movimiento me saltó una chispa y creo que creé un cortocircuito, por lo que ahora no va nada. ¿es posible que sea el 7805? lo que tengo claro es que el 16f876 no es ya que he comprobado que funcione y grabe y todas esas movidas.

El resumen es que por unas cosas o otras no estoy consiguiendo avanzar al ritmo que tenia previsto y el que seria idóneo para la finalización de la practica. Es posible que empiece a mirar alguna placa hecha para gestion de motores y sobretodo los precios, aunque me congratularia mucho mas poder terminarla yo con mis propias manos. A ver si alguien se anima y me escribe algun consejo o algun animo, porque hoy estoy encendidisimo jejejej.

jueves, 18 de octubre de 2007

Diagrama electronico drivers motores (II)

He tenido que rectificar el diagrama electrónico del driver de motores de nuestro robot. En el anterior están mal enganchadas las patillas de comunicación del pic con el puerto serie. Anteriormente su colocación ha sido arbitraria y después me he dado cuenta que tienen que enchufarse obligatoriamente a los pines RC6 para el Tx y RC7 para el Rx.

El problema reside en que el puerto C ya lo tenia ocupado con el control de los motores, ya que los pines de PWM también están en dicho puerto. Por lo que no me cabe las dos cosas en el mismo puerto.

Para cada motor gestionado por el L293 van dos señales que le indican la dirección que debe de tomar (positivo y negativo) o (negativo y positivo), pero nunca (negativo y negativo) o (positivo y positivo) ya que el motor no se moveria. Como una señal es siempre la contraria que la otra podemos insertar un negador que nos lo haga automáticamente. El negador es el 7404 como se muestra en la imagen:

Gracias al negador conseguimos ahorrarnos 2 patillas, por lo que podemos usar la usart del PIC y el control de los motores con el mismo puerto. Dejando otros puertos para futuras ampliaciones del robot rabotron. Sobretodo el puerto B.

El esquema queda de la siguiente forma:

viernes, 12 de octubre de 2007

Probando el MAX232

Una vez diseñada la placa para el driver de motores para nuestro robot, solo tenemos que empezar a soldarla tal como se ha indicado en el esquema anterior.

El primer paso es el del max232 (en nuestro caso el st232). El MAX232 es un circuito integrado que convierte los niveles de las líneas de un puerto serie RS232 a niveles TTL y viceversa. Esto nos es imprescindible para la comunicación entre el microcontrolador (pic16f876) y el ordenador (rs232).


Del puerto serie solo necesitamos los pines TX y RX. TX es la señal de transmisión de datos, RX es la de recepción (RTS y CTS se utilizan para establecer el protocolo para el envío y recepción de los datos). Para la comunicación con nuestro robot vamos a utilizar lo que vulgarmente llamamos “modem nulo”. Es decir, que tan solo vamos a tener en consideración las señales de RX (recepción) y la de TX (trasmisión) para realizar la comunicación.


Por ultimo podemos ver el video como indicando que el funcionamiento es correcto:

-12V/-9V --> 5V
12V/9V --> 0V
y viceversa


martes, 9 de octubre de 2007

Reconociendo colores: ¿Por que HSV (HBS) y no RGB?

Una vez conseguido capturar imágenes con Linux para nuestro robot, tenemos que pasar a examinar dichas imágenes para así conseguir el objetivo deseado: que rabotron reconozca a nuestra “víctima” mediante visión (webcam). En los inicios el modelo de color empleado fue el conocido RGB (Red, Green, Blue), en este modelo al representarse cada color como una tupla de tres elementos, en nuestro caso lógicamente colores: rojo, verde y azul, esto acarrea un problema a la hora de reconocer un color, en un ambiente de luminosidad variado un color puede tener varios tonos, por ejemplo, podemos tener un amarillo, amarillo oscuro o un amarillo claro (todo dependiendo del nivel de luz que incida sobre nuestro objeto y la webcam que usemos para la captura):

Por lo tanto para reconocer un mismo color con distintas intensidades se nos plantea el problema de tener que crear un filtro de rangos a la hora de localizarlo.

Para solucionar este pequeña pega consideramos mas conveniente usar el modelo HSV (Hue, Saturation, Value) ( también conocido como HBS (Hue, Saturation, Brightness), en este modelo cada color esta representado por una tonalidad, una saturación y un brillo:

Por lo tanto a la hora de localizar un color en concreto nos bastará saber su tonalidad para saber si podría ser el color buscado en la imagen que recibe nuestro robot.

Por tanto para el reconocimiento de nuestra “victima” usaremos el modelo de color HSV.



Diagrama electrónico drivers motores

Vamos a comentar brevemente el diseño de lo que a posteriori será el circuito impreso de nuestro driver de motores.

La comunicación con el pc (con player/stage) se efectuará mediante el puerto serie, usando los pines 2 y 3 que son los de Tx(trasmision) y el Rx (recepcion) y el pin 5 de tierra. Los niveles del puerto serie (-12V para un 1 lógico y 12V para un 0 cero lógico) no coinciden con los que necesita el microcontrolador (5V para un 1 lógico y 0V para un 0 cero lógico). Por ello vamos a utilizar un max232 que es el encargado de convertir los niveles de las líneas de un puerto serie a niveles TTL y viceversa.

Una vez que tenemos trasformadas las tensiones conectamos con el microcontrolador, como ya hemos comentado anteriormente será un PIC16F876. Este microcontrolador es el encargado de recibir las ordenes del pc (cabeza pensante del robot) y manejar los motores.

Para manejar los motores (ya que vamos a usar motores de corriente continua) utilizamos un L293 que basicamente es un circuito puente en h. Las entradas metemos la direccion en que giran los motores y la interrupcion para dejar que giren o pararlos. El circuito se alimenta con 5v pero dejaremos pasar 12 v que son lo que alimentan a los motores (usamos motores dc de 12 v).


Con esto podemos crear nuestro diagrama electrónico para el driver de motores que despues soldaremos en una placa. El diagrama queda de la siguiente manera:


Podriamos haber puesto un inversor (un 7400) para no tener que replicar algunas salidas del pic16f876 con el l293. Pero no se como voy a ir de espacio en la placa y como me sobran pines en el microcontrolador voya gestionarlo por "software", espero no equivocarme.

martes, 2 de octubre de 2007

Modulacion de ancho de pulso (PWM)

Entrando en materia, tenemos que tener presente como vamos a utilizar los motores para el movimiento de nuestro robot. Las variables que nos va a pasar el player/stage a los motores serán la velocidad lineal y la velocidad angular. Con estas dos variables el robot debe de poder moverse de un lado a otro con distintas velocidades.

La primera solucion para ello era utilizar motores paso a paso, ya que con ello podemos seleccionar los pasos que den los mismos tanto haccia adelante y hacia atras. Consultando con un pas de la universidad de alicante me acondejó que no lo hiciera así, ya que son motores muy bruscos y no muy recomendables para el movimiento de un robot, aunque si para la posición de algo.

A si es que he preferido meterme con el "tinglao" de motores de corriente continua (motores dc), es podible que eso sea lo que necesita nuestro robot. El problema reside es que para realizar los giros, un motor debe de ir a distinta velocidad que el otro. Para hacer esto recurrimos al pwm (pulse width modulation) modulacion del ancho del pulso.

PWM es una técnica en la que se modifica el ciclo de trabajo de una señal periódica. De esta manera conseguimos que trabaje mas o menos tiempo un motor. El microcontrolador trabajará por nivel alto, cuanto mas tiempo este en nivel alto más velocidad:

Para usar esto necesitamos un microcontrolador de gama media (no lo mas baratos), el elegido en nuestro caso es el del robot (pic 16f876) con dos salidas moduladas con pwm.

Para probarlo nhemos creado un programita que aumenta el % de nivel alto hasta el 100% y despues disminuye poco a poco hasta el 0% y así indefinidamente. El codigo del microcontrolador para esta tarea lo programamos de la siguiente manera:

;Includes
LIST P=16f876
RADIX HEX
INCLUDE "P16F876.INC"

;Configuracion quitar
; __CONFIG _PWRTE_ON & _WDT_OFF & _HS_OSC & _LVP_OFF


cont1 equ 0x0E ; Numero de ticks a esperar
cont2 equ 0x0F ; Numero de ticks a esperar
cont3 equ 0x10 ; Numero de ticks a esperar

ORG 0x00

GOTO INICIO

ORG 0x05

; Initialisierung
INICIO

; Preparacion del PWM
; Predivisor 16:1 y Timer2 on
BSF T2CON, T2CKPS1 ; Preescalador 16:1
BSF T2CON, TMR2ON ; Activa el Timer2


; Frecuencia a 1,22 KHz
BSF STATUS, RP0 ;Cambio al banco 1
MOVLW D'255' ;255 en decimal
MOVWF PR2 ;1.22 kHz
BCF STATUS, RP0 ;Cambio al banco 0


; Ponemos la potencia al 50%
MOVLW D'127' ;127 en decimal
MOVWF CCPR1L ;50%

; RC2/CCP1 salida
BSF STATUS, RP0 ;Banco 1
BCF TRISC, 2 ;RC2 salida
BCF STATUS, RP0 ;Volvemos al Banco 0

; Inicializamos el modo PWM de CCP1
CLRF CCP1CON ;Limpiamos reg CCP1
BSF CCP1CON, CCP1M3 ;CCP1 en modo pwm 11XX
BSF CCP1CON, CCP1M2

;Aumento

AUMENTO
CALL RETARDO
INCFSZ CCPR1L,1 ;Incrementamos uno
GOTO AUMENTO ;Va aumentando
GOTO DECREMENTA ;Toca decrementar

;decrementa
DECREMENTA
CALL RETARDO
DECFSZ CCPR1L,1 ;Decrementamos uno
GOTO DECREMENTA ;Va decrementando
GOTO AUMENTO ;Toca aumentar


;************************************************************
;* Rutina de espera.
;* ENTRADA:
;* -W: Numero de ticks a esperar. Cada tick es de 10ms
;************************************************************

RETARDO
movlw D'2'
movwf cont3
CICLO3 movlw D'20'
movwf cont2
CICLO2 movlw D'33'
movwf cont1
CICLO decfsz cont1,1
goto CICLO
decfsz cont2,1
goto CICLO2
decfsz cont3,1
goto CICLO3


RETURN ; Si, terminar


; FIN
end

A continuación podemos ver un video de la ejecucion del programa. La prueba se hace con un led. Cuanto mas pwm el led se ilumina mas y cuando vamos bajando vemos como el led disminuye su iluminacion hasta apagarse y luego al reves. Además podemos contemplar los voltages como aumenta y disminuye acorde con el led:

viernes, 28 de septiembre de 2007

Webcam bajo linux

Como es de esperar , la visión de nuestro robot se hará mediante una camara web que captura el entorno para que más tarde sea player quien procese dicha imagen.


Para hacer las pruebas he cogido la mía, una logitech un poco reventada. He estado buscando por inet y he encontrado dos drivers distintos: el spca5xx y el gspca. La verdad es que no se aun la diferencia entre ambos. En un principio entendí que el spca5xx era mas moderno y lo instalé. Más tarde lei en otra pagina web que era al revés y entonces instalé el gspca. El caso es que ahora conviven los dos en mi lenny, por ahora sin problemas.

La forma de instalar spca5xx fue esta:

#apt-get install spca5xx-source

Se nos instalara en /usr/src, por tanto vamos a esa ruta, y lo descomprimos:

laos:/home/usuario# cd /usr/src/
laos:/usr/src# ls spca5xx-source.tar.bz2
laos:/usr/src# unp spca5xx-source.tar.bz2
modules/ modules/spca5xx/
modules/spca5xx/debian/
modules/spca5xx/debian/rules
modules/spca5xx/debian/control.modules.in
modules/spca5xx/debian/control
modules/spca5xx/debian/compat
modules/spca5xx/debian/copyright
modules/spca5xx/debian/changelog
modules/spca5xx/cutlog.py
modules/spca5xx/LICENSE
modules/spca5xx/CHANGELOG
modules/spca5xx/INSTALL
modules/spca5xx/drivers/
modules/spca5xx/drivers/usb/
modules/spca5xx/drivers/usb/spca500_init.h
modules/spca5xx/drivers/usb/spcaCompat.h
modules/spca5xx/drivers/usb/spca5xx.h
modules/spca5xx/drivers/usb/pac207.h
modules/spca5xx/drivers/usb/spcausb.h
modules/spca5xx/drivers/usb/sonix.h
modules/spca5xx/drivers/usb/tas5130c.h
modules/spca5xx/drivers/usb/cxlib.h
modules/spca5xx/drivers/usb/spca508_init.h
modules/spca5xx/drivers/usb/sp5xxfw2.h
modules/spca5xx/drivers/usb/spcadecoder.c
modules/spca5xx/drivers/usb/pb0330.h
modules/spca5xx/drivers/usb/cs2102.h
modules/spca5xx/drivers/usb/dummy_cam.h
modules/spca5xx/drivers/usb/spcadecoder.h
modules/spca5xx/drivers/usb/pas106b.h
modules/spca5xx/drivers/usb/cx11646.h
modules/spca5xx/drivers/usb/sn9cxxx.h
modules/spca5xx/drivers/usb/hdcs2020.h
modules/spca5xx/drivers/usb/spcagamma.h
modules/spca5xx/drivers/usb/hv7131b.h
modules/spca5xx/drivers/usb/hv7131c.h
modules/spca5xx/drivers/usb/spca500.dat
modules/spca5xx/drivers/usb/jpeg_header.h
modules/spca5xx/drivers/usb/spca501.dat
modules/spca5xx/drivers/usb/icm105a.h
modules/spca5xx/drivers/usb/spca501_init.h
modules/spca5xx/drivers/usb/jpeg_qtables.h
modules/spca5xx/drivers/usb/spca505.dat
modules/spca5xx/drivers/usb/spca505_init.h
modules/spca5xx/drivers/usb/spca508.dat
modules/spca5xx/drivers/usb/et61xx51.h
modules/spca5xx/drivers/usb/ov7630c.h
modules/spca5xx/drivers/usb/tv8532.h
modules/spca5xx/drivers/usb/zc3xx.h
modules/spca5xx/drivers/usb/spca506.h
modules/spca5xx/drivers/usb/spca561.h
modules/spca5xx/drivers/usb/mr97311.h
modules/spca5xx/drivers/usb/spca5xx.c
modules/spca5xx/drivers/usb/sp5xxfw2.dat
modules/spca5xx/README-TV8532
modules/spca5xx/README-SONIX
modules/spca5xx/Makefile
modules/spca5xx/README-KERNEL-UPTO-2.6.16
modules/spca5xx/RGB-YUV%2fmodule-setting
modules/spca5xx/README

Ahora lo tendremos en la carpeta modules, vamos a élla y lo compilamos:
laos:/usr/src# cd modules/spca5xx/

instalar el source del kernel:
laos:/usr/src/modules/spca5xx# apt-get install linux-source-2.6.21
laos:/usr/src/modules/spca5xx# apt-get install linux-tree-2.6.21
laos:/usr/src/modules/spca5xx# apt-get install linux-headers-2.6.21-2-all-i386

otros paquetes necesarios:
laos:/usr/src/modules/spca5xx# apt-get install gcc

make
make install
laos:/usr/src/modules/spca5xx# lsmod |grep spca5xx
spca5xx 658224 1
videodev 25952 2
spca5xx usbcore 123272 5 spca5xx,usbhid,ehci_hcd,uhci_hcd


Con esto ya conseguí que se viera la cámara perfectamente. Luego más tarde por un problema con una cámara intenté instalar el otro driver, el gspca. De la siguiente manera:

laos:/home/usuario# apt-get install module-assistant
laos:/home/usuario# apt-get install gspca-source
laos:/home/usuario# m-a prepare (abreviatura de module-assistant)
laos:/home/usuario# m-a a-i gspca
laos:/home/usuario# modprobe gspca
laos:/home/usuario# lsmod |grep spca5xx
spca5xx 658224 0
videodev 25952 3
gspca,zc0301,spca5xx usbcore 123272 9 gspca,usbhid,zc0301,snd_usb_audio,snd_usb_lib,spca5xx,ehci_hcd,uhci_hcd

Podemos ver como ahora carga los dos drivers y sigue yendo igual. Para probarla podeis usar cualquier programa que use la webcam o usad el camorama:

apt-get install camorama
camorama

Os pego una imagen de mi propio sistema operativo.

cámara funcionando.

sábado, 1 de septiembre de 2007

Mi proyecto

Como todo en la vida, las cosas tienen un principio, un desarrollo y un final. Mi carrera universitaria no iba a ser menos, a si es que me encuentro casi al final del trayecto. Para terminar necesito hacer el proyecto de fin de carrera. Para esto cuento con la inestimable ayuda de mi compañero de andadas (por lo menos en los ultimos 3 años), mi amigo victor.

Como Victor le da relativamente igual el proyecto a realizar, he decidido elegir yo por él. Quizás esto sea bastante peligroso, ya que es muy probable que nos metamos en un verdadero berengenal. Pero bueno creo que hemos salido de situaciones peores, o sea que esto no nos da miedo y seguro que sale adelante (Intento convencerme a mi mismo).

La idea es hacer un robot. Vaya tela ¿no?. La verdad es que hace tiempo hice uno bastante sencillo que se trataba de un sigue-lineas. Con un PIC 16F84 y unos cuantos sensores infrarrojos de corto alcance (CNY70) conseguí terminarlo y la verdad es que funcionaba bastante bien. Pero te das cuenta que no tiene muchas posibilidades un microcontrolador para crear un robot "semi-inteligente". La segunda toma de contacto queria que fuera con una fpga pero eso fue tan desastroso que ni lo cuento.Lo que pasa es que como los ingenieros, o los informaticos, o simplemente yo, siempre queremos superarnos he seguido investigando. Y creo que ya se el berengenal que voy a hacer.

La idea es crear un robot "inteligente". Lo de inteligente no se refiere a que sea einstein, ni nada parecido, me conformo con que tenga alguna conducta inteligente. En un principio lo hablé con un profesor de la universidad y pactamos algo tan simple como seguir a una persona dada. Ese es el objetivo aunque me gustaria sobrepasarlo.

El problema tiene dos partes diferenciadas, por un lado el montaje del robot (mecanicamente y electronicamnente) y por otro lado la programacion del mismo y la instauracion de inteligencia artificial. Lo que me lleva a no poder hablar solo con un departamento, sino que tendré que ir pidiendo ayuda de al menos dos. Aunque el departamento encargado seguramente será el de inteligencia artificial.

En la parte del montaje tengo un amigo que trabaja con metacrilato, por lo que en plan de retales creo que podré montarlo, aunque aun me queda hacer el diseño. Pero la verdad es que llevo un lio con que motores ponerle y como gestionarlos. Supongo que unos motores paso a paso para medir los cm que avanza y la gestion haré alguna placa. Por otro lado pondré una camara web para la vision del robot. ¿Qué camara? Aun no se. por ahora uso una logitech bastante antigua, aunque he leido que la websphere de logitech va bien.

Por el lado del software la idea es meterle un portatil entero con player/stage instalado que sea el que gestione todo y que interactue con el hardware. La verdad es que nunca he usado player/stage pero estoy viendo que no es dificil y da posibilidades. Creo que la IA se la daré a mi compi Victor y yo me dedicaré al montage y a la electronica.

No se como saldrá esto. Espero que dios reparta suerte y espero vuestros comentarios tambien.

viernes, 24 de agosto de 2007

Bienvenida

Siempre he estado entrando a distintos blogs por internet. Pero ahora ha sido el momento de hacer uno. jejeje.

Intentaré escribir aqui mi proyecto de final de carrera (aunque aun no esta decidido) y algunas otras hierbas que crea que son interesantes.

Un saludo