jueves, 27 de marzo de 2008

De infrarrojos y pantallas de leds

Seguimos jugando con el mando de la wii. Buscando la mejor forma de aprovechar sus características infrarrojas he dado con el proyecto de Johnny Chung Lee, en él comenta como ha utilizado las capacidades del mando, y me ha parecido muy interesante.

Usa una pantalla de aproximadamente 100 leds emisores de infrarrojo (como los que llevan incorporados las cámaras de visión nocturna) con una batería de 9v (por que si no dudo que funcione). Dentro de esta pantalla aloja el mando y utiliza un material reflectante para que el mando "vea" las señales infrarrojas. Creo que un vídeo ilustrará mucho mejor lo que acabo de contar



Y mi idea es utilizar un modelo similar. Montar una placa de dimensiones apropiadas alrededor del mando, y todo ello acoplado en el robot. Como es lógico, los objetos deberán estar forrados con un material reflectante (como el papel aluminio) y de esta forma el robot en su conjunto podrá identificar el obstáculo y evitarlo

He echo unas pruebas caseras con el mando de la tele y todo ha salido como se esperaba (nunca dejaré de asombrarme cuando las cosas me funcionan a la primera). Ahora probare a dibujar en la pantalla la fuente emisora, algo parecido a lo que hace John en el vídeo. Ya os contaré

Haciendo las pruebas me ha sucedido algo que me ha desconcertado un poco y seguro que alguno de vosotros sabe por qué sucede. Sobre "el taller" tengo un flexo con una bombilla corriente (no es de bajo consumo) y el mando recogía el flexo como fuente emisora al ser reflejada la luz en el papel aluminio. Imagino que sucede por que la luz se descompone en el papel, pero si alguno de vosotros lo sabe con certeza le agradeceré que me lo aclare. He probado con linternas y otras lámparas pero no hubo éxito, sólo con el flexo.

Documentación pyton-cwiid

A raíz de las notas que he tomado y las pruebas realizadas he escrito una breve documentación de la biblioteca cwiid para python. No está completa y seguramente contenga errores y equivocaciones, por lo que si veis alguna cosa rara o tenéis alguna sugerencia no dudéis en comentarlo.

(revisión 1.0)

cwiid.__doc__
CWiid Wiimote Interface

cwiid.__file__
/var/lib/python-support/python2.5/cwiid.so

cwiid.__name__
cwiid

Constantes

BATTERY_MAX
Indica el nivel máximo de batería, se utiliza para determinar el nivel actual de batería

BTN_UP
BTN_DOWN
BTN_LEFT
BTN_RIGHT
BTN_A
BTN_B
BTN_1
BTN_2
BTN_MINUS
BTN_PLUS
BTN_HOME
Botones del Wiimote

CLASSIC_BTN_A
CLASSIC_BTN_B
CLASSIC_BTN_DOWN
CLASSIC_BTN_HOME
CLASSIC_BTN_L
CLASSIC_BTN_LEFT
CLASSIC_BTN_MINUS
CLASSIC_BTN_PLUS
CLASSIC_BTN_R
CLASSIC_BTN_RIGHT
CLASSIC_BTN_UP
CLASSIC_BTN_X
CLASSIC_BTN_Y
CLASSIC_BTN_ZL
CLASSIC_BTN_ZR
CLASSIC_LR_MAX
CLASSIC_L_STICK_MAX
CLASSIC_R_STICK_MAX
Botones del mando clásico

CMD_LED
CMD_RPT_HOME
CMD_RUMBLE
CMD_STATUS
En la biblioteca de Python no tienen aplicación

ERROR_COMM
ERROR_DISCONNECT
Tipos de error

EXT_NONE
EXT_NUNCHUK
EXT_CLASSIC
EXT_UNKNOWN
Las distintas extensiones que soporta el mando

FLAG_CONTINUOUS
Habilita informes continuos del Wiimote

FLAG_MESG_IFC
Habilita el interfaz basado en mensajes (a través de callback)

FLAG_NONBLOCK
Provoca que get_mesg() se falle en lugar de bloquearse esperando un mensaje si la cola está vacia

FLAG_REPEAT_BTN
Se envía un mensaje por cada botón pulsado, aunque este no haya cambiado de estado

IR_SRC_COUNT
IR_X_MAX
IR_Y_MAX
Definiciones para el IR

LED1_ON
LED2_ON
LED3_ON
LED4_ON
Valores para encender/apagar los led

MAX_READ_LEN
Longitus máxima que puede leerse

MESG_ACC
MESG_BTN
MESG_CLASSIC
MESG_ERROR
MESG_IR
MESG_NUNCHUK
MESG_STATUS
MESG_UNKNOWN
Tipos de mensaje recibidos

NUNCHUK_BTN_C
NUNCHUK_BTN_Z
Botones del Nunchuk

RPT_ACC
RPT_BTN
RPT_CLASSIC
RPT_EXT
RPT_IR
RPT_NUNCHUK
RPT_STATUS
Establecen los distintos tipos de informe (reporting mode) del wiimote. Cada uno determina que dispositivo está activo y que datos deben ser enviados al host. Cada flag especifica un bit, por lo que deben establecerse por medio de funciones OR

RW_DECODE
RW_EEPROM
RW_REG
Flags para los registros del wiimote

X
Y
Z
Identificadores de los distintos ejes del wiimote

Métodos

Wiimote(bt_addrs)
Parámetros
bt_addrs: Dirección Bluetooth del wiimote

Descripción
Conecta con el Wiimote especificado o con el primero que encuentre si no se especifica mando

Valor de retorno
Un objeto Wiimote si la conexión ha tenido éxito

Class Wiimote()
Una vez creado un objeto de tipo Wiimote a través de cwiid.Wiimote() disponemos de los siguientes atributos y métodos para esta clase


Atributos
state
Diccionario con el estado actual del mando

mesg_callback
Función para tratar los mensajes enviados por el wiimote. Una vez se pone a funcionar el mando en un modo RPT_XXX este envía mensajes cada vez que sucede un evento. Estos mensajes son tratados con la función indicada en este atributo (La función debe haber sido declarada anteriormente)

rpt_mode
Modo de informes del mando: RPT_ACC, RPT_BTN, RPT_CLASSIC, RPT_IR, RPT_EXT, RPT_NUNCHUK, RPT_STATUS

led
Atributo para activar/desactivar los led
Ej: wiimote.led = cwiid.LED1_ON
wiimote.led = not cwiid.LED1_ON

rumble
Atributo para activar/desactivar la vibración
Ej: wiimote.rumble = 1

Métodos

close()
Descripción
Cierra la conexión con un objeto Wiimote

enable(flags)
Parámetros
FLAG_CONTINUOUS, FLAG_MESG_IFC, FLAG_NONBLOCK, FLAG_REPEAT_BTN

Descripción
Habilita los flags indicados

disable(flags)
Parámetros
FLAG_CONTINUOUS, FLAG_MESG_IFC, FLAG_NONBLOCK, FLAG_REPEAT_BTN

Descripción
Deshabilita los flags indicados

get_acc_cal(extension)
Parámetros
EXT_NONE, EXT_NUNCHUK, EXT_CLASSIC, EXT_UNKNOWN

Descripción
Devuelve una tupla ( (X,Y,Z) , (X,Y,Z) ) con la información sobre la calibración del acelerómetro

Valor de retorno
Tupla ( (X,Y,Z) , (X,Y,Z) )

get_mesg()
Descripción
Devuelve un mensaje de la cola, estos mensajes se recuperan por medio de "callback" o de esta función

Valor de retorno
Mensaje mas antiguo de la cola

read(flags, offset, lenght)
Parámetros
flags: RW_EEPROM, RW_REG, RW_DECODE
offset: Dirección de inicio
lenght: Longitud

Descripción
Lee datos desde el Wiimote, utiliza los flags RW_EEPROM, RW_REG (mutuamente exclusivos)para leer desde la memoria EEPROM o desde el registro. El flag RW_DECODE realiza cualquier decodificación de los datos leídos si es necesario.

Valor de retorno
Los datos leídos

write(flags, offset, buffer)
Parámetros
flags: RW_EEPROM, RW_REG, RW_DECODE
offset: Dirección de inicio
buffer: Información a escribir

Descripción
Escribe datos en el Wiimote, utiliza los flags RW_EEPROM, RW_REG (mutuamente exclusivos)para leer desde la memoria EEPROM o desde el registro. El flag RW_DECODE es ignorado.


request_status()
??


Referencia
http://abstrakraft.org/cwiid/wiki/libcwiid



Canal de Youtube

Hasta ahora he publicado los vídeos a través de Google Video, pero no estoy muy contento con el servicio, ya que algunos vídeos tardan mucho en ser procesados y en ser servidos, así que he abierto un canal en youtube, ya veremos como funciona

http://es.youtube.com/user/mmartinortiz

miércoles, 26 de marzo de 2008

Mi coche de carreras

Tras la desesperación de anoche y la angustia de esta mañana he ido a pasar frío y correr durante un buen rato para aclarar las ideas. Con mucha paciencia y la ayuda de IDLE (el enésimo IDE para python que he probado) he escrito una breve documentación para cwiid. Tengo intención de subirla, por si le resulta útil a alguien.

Gracias a la gente de CRySOL y a la demo escrita en python que viene junto al paquete de cwiid he escrito un pequeño programa para conducir mi propio coche teledirigido utilizando la cruceta del mando. Manejarlo con golpes del mando no es mucho mas complicado, habría que manejar unos eventos en lugar de los otros y los vídeos que he visto con ese manejo no son tan elegantes. Os adjunto un par de vídeos para que veáis el resultado.



En este vídeo se ve la cruceta del mando



Y esta es una foto con parte del taller que tengo montado (no viene a cuento, lo se)



martes, 25 de marzo de 2008

Jugando con la Wii

¡Al fin tengo un mando para la Wii!. después de mucho corretear por Talavera he encontrado una tienda en la que si tenían mandos (de hecho tenían dos mandos, ahora sólo uno). Lleno de alegría e ilusión he puesto camino a casa, con mucho mimo he sacado el mando y le he puesto las pilas (en la caja pone que es un mando, pero a mi me da que esto es un vibrador)

Lo primero, ver si funciona, y como no tengo una Wii, pues a conformarme con el programa de prueba que trae el driver que estoy usando, cwiid (odio profundamente a las personas que desarrollan una API completa y no escriben una puñetera línea de documentación), lo ejecuto y "me llena de orgullo y satisfacción" ver como reconoce el mando a la primera, los botoncitos lucen, el acelerómetro va bien y el infrarrojos... bueno, el infrarrojos no funciona por que no tengo un emisor de infrarrojos, pero a esto ya le encontraremos solución mas adelante.



Ahora que se que funciona el mando, vamos a buscar la biblioteca para python que tengo ganas de caharrear con él. Después de ir y venir, de apt-cachear y pedir ayuda a San Google, encuentro el paquete para ubuntu (python-cwiid) que sólo está disponible para la versión Hardy de Ubuntu, así que toca actualizar algún que otro paquete para poder instalarla.

Bien, ya tenemos la biblioteca, ¡vamos a jugar!, después de fijarme en el código que viene escrito en python para comprobar que el mando funciona, escribo un pequeño script para recuperar la información de acelerómetro. Recuperar... la recupero. Antes dije que odiaba mucho a los desarrolladores que no escriben una jodida (digo jodida por no decir puta, que suena muy mal) línea de documentación para aliviar los sufrimientos del prójimo, pues bien, ahora los odio mucho mas.

Algo que no he contado antes, mas que nada por que no viene a cuento, es que empecé escribiendo código utilizando geany (bueno y ligero), pero le falta completar el código, algo que me resulta enormemente útil cuando no hay documentación alguna (se que los hombres y mujeres de verdad no utilizan estas mariconadas, que con vi es suficiente, pero es que yo no soy ni un hombre ni una mujer de verdad). Luego me pasé a Editra, que mola mazo, pero... le faltan muchas cosas que si ofrece Geany, así que sigo buscando y ahora estoy probando openkomodo, que es muy pesado y me recuerda a mi querido NetBeans. Todo esto, que no tiene mayor importancia, viene por que llevo cerca de dos horas dando vueltas, buscando un método o función que me permita recuperar valores del mando de la wii sin tener que leerme todo el código

Y hoy, hasta aquí. Noto que la neurona patina un poco y creo que será mejor mirar un rato al infinito para que descanse. Mañana volveré a la carga

lunes, 24 de marzo de 2008

¡Cuidado con el perro!

Leyendo las cosas de barrapunto he encontrado este vídeo de un cuadrúpedo desarrollado por Boston Dynamics. Me encanta como recupera el equilibrio después de recibir el golpe.




domingo, 16 de marzo de 2008

El valor de la sencillez

La semana pasada estuve hablando con Javi, que me pasó un par de artículos para salir de mi atolladero de diseño. A parte de esto, decidimos jugar con un robot que siguiese un haz de luz (una linterna, el móvil...).

Entre artículo y artículo, se me ocurrió una idea genial. Construir una cabeza giratoria que buscase el haz de luz a lo largo de giros completos de 360 grados en caso de perderlo, para sincronizar esta cabeza con las ruedas podría utilizarse un par de mandos de la wii, pero este problema se afrontaría mas adelante. De momento mi mente había tenido una idea genial y había que construirla.

Manos a la obra, un par de horas el sábado y otras tantas el domingo para construir una preciosa cabeza giratoria en pos de la luz. Henchido de orgullo pruebo mi creación, ¡fabuloso!. Las ruedas dentadas danzan elegantemente con un suave ronroneo de fondo, la mecánica es maravillosa, el movimiento se transforma a lo largo del espacio para que el sensor de luz explore su entorno.

Y entonces... me doy cuenta de mi gran error, un error catastrófico, que se lleva al garete mi obra. Como no voy a desarmar tan elegante creación de la mecánica sin dar testimonio de ella, os dejo un vídeo de su funcionamiento para que veáis "la enorme cagada" de este soleado fin de semana.



Y desde un poco mas cerca...



¿Lo veis?, no he tenido en cuenta que el sensor de luz hay que conectarlo, y para eso hay un cable que está anclado en la base del robot, estática en relación a la cabeza, así que el cable se retorcería hasta impedir el movimiento de la cabeza y con ello su funcionalidad.

La solución es sencilla, que el sensor de luz sea estático con relación al cuerpo, y que sea todo el cuerpo el que se mueva para encontrar el haz de luz perdido. Esta solución no mola tanto como la cabeza giratoria, pero es mas sencilla de montar, de implementar, de probar... vamos, que esta solución es mas sencilla y mas elegante, es mejor.

lunes, 10 de marzo de 2008

Sin sabor y sin sustancia

Hoy he decidido aparcar de momento la aplicación que estaba desarrollando (el "viewer"), ya que me he dado cuenta que no está bien enfocada y su desarrollo no tiene un final feliz. La idea de los módulos no me parece extensible o generalista, por lo que desarrollar esta aplicación con esta filosofía es una pérdida de tiempo.

Para encontrar un nuevo enfoque he vuelto ha jugar con el robot, buscando un nuevo camino para programarlo y encontrar así una fórmula mágica aplicable a cualquier problema. Así que he jugado con hilos, con subprocesos, con señales y temporizadores, lo he sofrito todo a fuego lento en una sartén con dos cucharadas de aceite virgen extra, un poquito de especias y... ha quedado una pasta sin sabor alguno.

Si ya de por sí la biblioteca de python para el NXT está mal documentada, me encuentro con un extraño síntoma que no se como buscar en "san google". El ladrillo, después de dos o tres ejecuciones se queda silbando y con los motores en un estado epiléptico en el que quieren rodar cada uno en un sentido, así que es necesario reiniciarlo para que funcione bien.

Y después de varios días sin recoger frutos ni ver un campo fertil me surge una duda existencial, ¿de verdad se programar?, ¿es python un lenguaje de programación?, ¿será mi robot un cabecilla en la rebelión de las máquinas?

martes, 4 de marzo de 2008

Caminando en silencio

He estado demasiado callado estos días, y es que lo poco que avanzo no es visible. Sigo desarrollando la aplicación Nxt Viewer y ahora estoy bastante atascado, los problemas vienen a la hora de detener los procesos 'hijo' ejecutados (los módulos) ,no consigo capturar la señal SIGCHLD para que tengan una muerte limpia (y hayá donde vayan tengan una feliz estancia). Así que estoy pensando en dejarlos en estado zombie por el resto de los tiempos... algo que atenta contra todo lo aprendido en sistemas operativos (y la ética)


Por si alguien ve algo que yo no consigo ver, os comento la situación:

La aplicación permite ejecutar otros programas, y cuando estos mueren, las buenas formas dicen que el proceso padre (en este caso mi aplicación) debe recoger los restos de su hijo para que este tenga un funeral digno. Para esto, el sistema operativo me envía la señal SIGCHLD ante el fallecimiento de un proceso hijo. Para capturarla python me proporciona la función signal(signal, manejador). Hasta aquí todo bien, pero... cuando se lanza esta señal por parte del sistema operativo lo que capturo es una SIGINT, y a pesar de ignorarla o asociarla a funciones de tratamiento absurdas, siempre mata a la aplicación (tratamiento por defecto).

¿Alguna sugerencia?

domingo, 2 de marzo de 2008

NXT Viewer - Versión de desarrollo

Sigo con el desarrollo de la aplicación, desde la toma de contacto que representa la versión 0.1 he aprendido unas cuantas cosas. He remodelado el aspecto gráfico de la aplicación, ahora dispone de dos partes diferenciadas

La parte superior está destinada a la conexión con un brick (de momento sólo con uno) y a mostrar información acerca de este ladrillo

La parte inferior permite cargar módulos que ejecutar en el brick conectado, administrándolos de forma simultánea o por separado

Según tenga versiones funcionales intentaré publicarlas por si queréis echarle un vistazo al código