sábado, junio 23, 2007

Wiimote en linux

No es normal que escriba nada aquí no relacionado con los comics y mis dibujos, pero bueno, ya que tengo el blog, pues publico este manual que he escrito en un plis, para el que le interese:

Bien, este es un pequeño manual para poder sacar el máximo partido a tu wiimote, bajo linux.

Es bien sabido que el mando de la wii funciona con bluethoot, así que para poder aprovecharlo, tendremos que tener el bluethoot funcionando en nuestra maquina, y por supuesto un wiimote (el mando).

Lo primero que hay que hacer es lanzar estos modulos, uinput y evdev para que todo funcione bien, yo me he hecho un script:


#!/bin/bash

sudo modprobe uinput
sudo modprobe evdev
sudo mkdir /dev/misc
sudo ln -s /dev/input/uinput /dev/misc/uinput
sudo chmod 666 /dev/misc/uinput



Además hay que crear un enlace en /dev/misc/uinput para que el WMD sepa donde está. Dependiendo de tu distro el uinput estará en /dev/input/ o en otra parte, en ubuntu por lo menos está ahí. Buscalo y haz un enlace como lo hago yo aquí.

El segundo paso es bajarse la librería WMD (http://www.forthewiin.org/), que está en python es la que nos va a facilitar la vida. Una vez bajado el archivo (http://forthewiin.org/WMD/wmd-0.1.2.tar.gz) se descomprime:


tar -xzvf wmd-0.1.2.tar.gz


y se entra en el directorio

cd wmd-0.1.2

Una vez dentro, podremos lanzar el script que viene para ver que todo funciona bien:

python WMD.py

tenemos que sincronizar el mando, pulsando 1 y 2 a la vez, o el boton rojo que tiene de sync. No va a funcionar a la primera porque tiene puesta una mac que no va a ser la tuya y va a ser la que busque en un principio, pero no hay problema, solo tienes que esperar a que te diga: "Now trying to discover a willing Wiimote, please activate your Wiimote within 5 seconds." y entonces pulsar 1 y 2 a la vez, y así lo encontrará. Vemos que salen unas gráficas, y cuando pulsas un botón se puede ver cual has pulsado y eso.
Una vez visto que funciona, ya estamos listos para utilizar el mando como un mando a distancia. Yo voy a explicar como usarlo para manejar el mplayer, y solo voy a usar los botones, pero con el wmd también es muy fácil definir una función para gestionar los eventos de las aceleraciones en los tres ejes espaciales, otra cosa es encontrarle utilidad. También se puede manejar el ratón con el wiimote, pero esto no sé muy bien como va.

Cómo usar el wmd.

La verdad es que no sé muy bien cómo funciona, yo solo lo he tocado un poquito para poder usar el wiimote como mando a distancia, y también como joistick para algún juego, pero no me he metido más allá.

Para usar esta librería tenemos que colocar nuestro script en python en el mismo directorio que el script WMD.py. Así pues editamos nuestro fichero .py, añadiendo estas cabeceras, que son las que tiene el WMD.py:

import sys
sys.path.append('.')

from wmd.Common import *
from wmd.Config import CFG
from wmd.UI.UIManager import UIManager
from wmd.Wiimote.WMManager import WMManager
from wmd.EVDispatcher import EVDispatcher
from wmd.MotionSensing import MSManager
from wmd.Pointer import POManager
from wmd.CommandMapper import CommandMapper

yo también he usado el os, para hacer llamadas al sistema, así pues también habría que poner:

import os

definiremos una funcion wii_buttons, por ejemplo, que es la que será llamada cada vez que haya un evento de botón del mando:

def wii_buttons(buttons):

recibe un vector buttons, cuya primera componente es el nombre de la tecla pulsada, y la segunda el evento, UP o DOWN

Cada vez que se pulsa un botón, hacemos una llamada al sistema para que envie un evento de tecla pulsada. Esto lo hago con el comando xsendkeycode, al que se le pasa un keycode (se pueden ver con xev) y un evento 1 para pulsado, 0 para levantado. Para tener el comando xsendkeycode, hay que instalar el lineakd.

if buttons[1] == "DOWN":
if buttons[0] == "A":
os.popen2("xsendkeycode "+str(codeA)+" 1")

os.popen2 los que hace es crear un nuevo proceso con la llamada pasada como argumento, como si fuera lanzado desde una terminal.

Una vez definidas todas las acciones para los botones, hay que escribir el cuerpo del script:

creamos un objeto CFG, que necesita el EVDispatcher, y el WMManager

cf = CFG

creamos un objeto EVDispatcher, pasandole el CFG creado anteriormente

ev = EVDispatcher(cf)

Añadimos la función definida para los botones al EVDispatcher, con la constante WM_BT, para que llame a nuestra función cada vez que ocurra un evento de pulsación de botón

ev.subscribe( WM_BT, wii_buttons)

creamos un WMManager, connectamos, hacemos un setup, y lanzamos el bucle principal.

wm = WMManager(cf, ev)
wm.connect()
wm.setup()

wm.main_loop()

Con esto ya estaría listo nuestro script, y cada vez que pulsemos un botón será como si pulsaramos una tecla del teclado. Con esto podríamos mapear las teclas multimedia, y conseguir así un mando a distancia.

un ejemplo, con esto podremos manejar el mplayer con el mando de la wii (A play-pause, B cambiar a fullscreen, +,- subir y bajar el volumen, 1 habilitar, desabilitar osd, 2 habilitar, desabilitar subtitulos):

import sys
import os
sys.path.append('.')

from wmd.Common import *
from wmd.Config import CFG
from wmd.UI.UIManager import UIManager
from wmd.Wiimote.WMManager import WMManager
from wmd.EVDispatcher import EVDispatcher
from wmd.MotionSensing import MSManager
from wmd.Pointer import POManager
from wmd.CommandMapper import CommandMapper

def wii_buttons(buttons):
codeA = 65 #spacio
codeB = 41 #f
codeMas = 63 #*
codeMinus = 112 #/
codeH = 9 #escape
code1 = 32 #o
code2 = 55 #v
codeU = 98 #flecha arriba
codeD = 104 #flecha abajo
codeL = 100 #flecha izquierda
codeR = 102 #flecha derecha

if buttons[1] == "DOWN":
if buttons[0] == "A":
os.popen2("xsendkeycode "+str(codeA)+" 1")
elif buttons[0] == "B":
os.popen2("xsendkeycode "+str(codeB)+" 1")
elif buttons[0] == "+":
os.popen2("xsendkeycode "+str(codeMas)+" 1")
elif buttons[0] == "-":
os.popen2("xsendkeycode "+str(codeMinus)+" 1")
elif buttons[0] == "H":
os.popen2("xsendkeycode "+str(codeH)+" 1")
elif buttons[0] == "1":
os.popen2("xsendkeycode "+str(code1)+" 1")
elif buttons[0] == "2":
os.popen2("xsendkeycode "+str(code2)+" 1")
elif buttons[0] == "U":
os.popen2("xsendkeycode "+str(codeU)+" 1")
elif buttons[0] == "D":
os.popen2("xsendkeycode "+str(codeD)+" 1")
elif buttons[0] == "L":
os.popen2("xsendkeycode "+str(codeL)+" 1")
elif buttons[0] == "R":
os.popen2("xsendkeycode "+str(codeR)+" 1")

elif buttons[1] == "UP":
if buttons[0] == "A":
os.popen2("xsendkeycode "+str(codeA)+" 0")
elif buttons[0] == "B":
os.popen2("xsendkeycode "+str(codeB)+" 0")
elif buttons[0] == "+":
os.popen2("xsendkeycode "+str(codeMas)+" 0")
elif buttons[0] == "-":
os.popen2("xsendkeycode "+str(codeMinus)+" 0")
elif buttons[0] == "H":
os.popen2("xsendkeycode "+str(codeH)+" 0")
elif buttons[0] == "1":
os.popen2("xsendkeycode "+str(code1)+" 0")
elif buttons[0] == "2":
os.popen2("xsendkeycode "+str(code2)+" 0")
elif buttons[0] == "U":
os.popen2("xsendkeycode "+str(codeU)+" 0")
elif buttons[0] == "D":
os.popen2("xsendkeycode "+str(codeD)+" 0")
elif buttons[0] == "L":
os.popen2("xsendkeycode "+str(codeL)+" 0")
elif buttons[0] == "R":
os.popen2("xsendkeycode "+str(codeR)+" 0")

cf = CFG

ev = EVDispatcher(cf)

ev.subscribe( WM_BT, wii_buttons)
wm = WMManager(cf, ev)
wm.connect()
wm.setup()

wm.main_loop()

3 comentarios:

Anónimo dijo...

Muy interesante. Lo probaré en cuanto pueda. Gracias.

WiihOLiC dijo...

:O, necesito bluutuu ;)

Lord Zorel dijo...

GUAU justo lo que buscaba

en todas partes sale como conectarlo, pero no como configurarlo, muchas gracias.