Los requerimientos
Lo primero que tenemos que saber es que el control WiiMote se comunica de manera inalámbrica usando Bluetooth, lo cual nos lleva a tener como requisito un dispositivo Bluetooth USB compatible.
El segundo requerimiento es obviamente el emulador MAME, la version que se ejecuto al grabar este video fue instalada siguiendo las instrucciones de este sitio http://blog.sheasilverman.com/2012/06/raspberry-pi-and-mame-part-2/ , una vez instalado el emulador. necesitaremos algunas ROMS para jugar, en este enlace pueden descargar algunas de estas ROMS que son 100% legales http://www.mamedev.org/roms/ .
El siguiente requisito es cargar en memoria el módulo de kernel uinput con el siguiente comando:
sudo modprobe uinput
tras la ejecución del comando, si no están firmados en el sistema como root, les pedirá su contraseña, y una vez introducida, no se obtendrá mas salida. Para confirmar que el módulo esta cargado, ejecutamos el siguiente comando:
lsmod
este nos listará los módulos que esten cargados en memoria, y su salida será algo similar a esto:
Module Size Used by
uinput 6599 0
snd_bcm2835 16432 0
snd_pcm 77728 1 snd_bcm2835
snd_seq 53482 0
snd_timer 20110 2 snd_pcm,snd_seq
snd_seq_device 6462 1 snd_seq
snd 58744 5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device
snd_page_alloc 5169 1 snd_pcm
leds_gpio 2243 0
led_class 3570 1 leds_gpio
MAME funciona por default con el teclado, es decir, ciertas teclas se usan para control de dirección y las diferentes acciones que se requieran en el juego, por lo que necesitaremos crear un "traductor" que reciba la información del WiiMote a traves del dispositivo Bluetooth y envie al emulador el evento de teclado adecuado de acuerdo a la acción.
El Código
De nuevo recurriremos a Python para este objetivo, la libreria cwiid es la que tiene toda la lógica para la comunicación con el WiiMote, y la libreria uinput es la que nos permitirá generar los eventos de teclado para que MAME los use como entrada.
Antes de iniciar con el código, quiero darle credito a Brian Hensley por su script wiimotest.py y a Chris Swan por su script rpi-gpio-jstk.py en los cuales me basé para crear este código.
#-------------------------------------------------------------------------------
# Name: Wii Mame
# Purpose: Script that connects a Wiimote via Bluetooth using cwiid to read
# inputs and send keystrokes using uinput
#
# Author: Ismael Martinez based on scripts
# wiimotest.py by Brian Hensley and
# rpi-gpio-jstk.py by Chris Swan
#
# Created: 01/10/2012
# Copyright: OpenSource
#-------------------------------------------------------------------------------
#!/usr/bin/env python
import cwiid
import time
import sys
import uinput
def main():
events = (uinput.KEY_LEFT, uinput.KEY_RIGHT, uinput.KEY_UP, uinput.KEY_DOWN, uinput.KEY_1, uinput.KEY_5, uinput.KEY_LEFTCTRL, uinput.KEY_ESC, uinput.KEY_ENTER)
device = uinput.Device(events)
# Bools to keep track of movement
btn_a = False
btn_b = False
btn_one = False
btn_two = False
btn_pls = False
btn_min = False
btn_up = False
btn_dwn = False
btn_lft = False
btn_rgt = False
debug = False
attempt = 0
max_attempts = 3
while attempt < max_attempts:
attempt = attempt + 1
print 'Press button 1 + 2 on your Wii Remote...'
time.sleep(1)
try:
wm=cwiid.Wiimote()
break
except:
if attempt <= max_attempts:
print 'Press button 1 + 2 on your Wii Remote... attempt #', attempt,' of ',max_attempts
else:
print 'No Wii Remote found after ', max_attempts, ' attempts. Finishing execution.'
sys.exit(0)
print 'Wii Remote connected...'
print '\nPress [A]+[B] buttons to disconnect the Wii and end the application'
time.sleep(1)
wm.rpt_mode = cwiid.RPT_BTN
while True:
bitmask = bin(wm.state['buttons'])[2:].rjust(13, '0')
#print bitmask
if bitmask[-1] == "1": #wm.state['buttons'] == 1:
if debug:
print ' [2] pressed \n'
if (not btn_two) :
btn_two = True
device.emit(uinput.KEY_LEFTCTRL, 1)
else:
if btn_two:
btn_two = False
device.emit(uinput.KEY_LEFTCTRL, 0)
if bitmask[-2] == "1": #wm.state['buttons'] == 2:
if debug:
print ' [1] pressed \n'
if (not btn_one) :
btn_one = True
device.emit(uinput.KEY_LEFTCTRL, 1)
else:
if btn_one:
btn_one = False
device.emit(uinput.KEY_LEFTCTRL, 0)
if bitmask[-3] == "1": #wm.state['buttons'] == 4:
if debug:
print ' [B] button pressed \n'
if (not btn_b) :
btn_b = True
device.emit(uinput.KEY_1, 1)
else:
if btn_b:
btn_b = False
device.emit(uinput.KEY_1, 0)
if bitmask[-4] == "1": #wm.state['buttons'] == 8:
if debug:
print ' [A] button pressed \n'
if (not btn_a) :
btn_a = True
device.emit(uinput.KEY_5, 1)
else:
if btn_a:
btn_a = False
device.emit(uinput.KEY_5, 0)
if bitmask[-5] == "1": #wm.state['buttons'] == 16:
if debug:
print ' [-] button pressed \n'
if (not btn_min) :
btn_min = True
device.emit(uinput.KEY_LEFTCTRL, 1)
else:
if btn_min:
btn_min = False
device.emit(uinput.KEY_LEFTCTRL, 0)
if bitmask[-8] == "1": #wm.state['buttons'] == 128:
if debug:
print ' [Home] button pressed \n'
device.emit(uinput.KEY_ESC, 1)
time.sleep(0.25)
device.emit(uinput.KEY_ESC, 0)
time.sleep(0.25)
device.emit(uinput.KEY_DOWN, 1)
time.sleep(0.25)
device.emit(uinput.KEY_DOWN, 0)
time.sleep(0.25)
device.emit(uinput.KEY_ENTER, 1)
time.sleep(0.25)
device.emit(uinput.KEY_ENTER, 0)
time.sleep(0.25)
if bitmask[-9] == "1": #wm.state['buttons'] == 256:
if debug:
print ' [Down] button pressed \n'
if (not btn_dwn) :
btn_dwn = True
device.emit(uinput.KEY_DOWN, 1)
else:
if btn_dwn:
btn_dwn = False
device.emit(uinput.KEY_DOWN, 0)
if bitmask[-10] == "1": #wm.state['buttons'] == 512:
if debug:
print ' [Up] button pressed \n'
if (not btn_up) :
btn_up = True
device.emit(uinput.KEY_UP, 1)
else:
if btn_up:
btn_up = False
device.emit(uinput.KEY_UP, 0)
if bitmask[-11] == "1": #wm.state['buttons'] == 1024:
if debug:
print ' [Right] button pressed \n'
if (not btn_rgt) :
btn_rgt = True
device.emit(uinput.KEY_RIGHT, 1)
else:
if btn_rgt:
btn_rgt = False
device.emit(uinput.KEY_RIGHT, 0)
if bitmask[-12] == "1": #wm.state['buttons'] == 2048:
if debug:
print ' [Left] button pressed \n'
if (not btn_lft) :
btn_lft = True
device.emit(uinput.KEY_LEFT, 1)
else:
if btn_lft:
btn_lft = False
device.emit(uinput.KEY_LEFT, 0)
if bitmask[-13] == "1": #wm.state['buttons'] == 4096:
if debug:
print ' [+] button pressed \n'
if (not btn_pls) :
btn_pls = True
device.emit(uinput.KEY_LEFTCTRL, 1)
else:
if btn_pls:
btn_pls = False
device.emit(uinput.KEY_LEFTCTRL, 0)
if wm.state['buttons'] > 0 :
if debug:
print ' <-'
if wm.state['buttons'] == 12 :
print 'closing Bluetooth connection. Good Bye!'
exit(wm)
time.sleep(.02) # Poll every 20ms (otherwise CPU load gets too high)
if __name__ == '__main__':
main()
El resultado y algunos detalles acerca del orden de ejecución en el siguiente video.
Gracias por seguirme, Saludos!