O gamepad utilizado no AD4M4ST0R é um “Gioteck VX-2 Wireless Controller” comprado na FNAC por €19.99. Qualquer modelo compatível com PC deverá funcionar, desde que use um dongle USB (os modelos por cabo USB também funcionarão mas não servem para o caso). Quando o stack bluetooth estiver funcional no ev3dev também deverão funcionar gamepads desse tipo
O gamepad é reconhecido automaticamente como um gamepad e como um disposito de classe OHCI:
root@ev3dev:~# dmesg (...) usb 1-1.4: new full-speed USB device number 4 using ohci hid-generic 0003:25F0:83C2.0001: usb_submit_urb(ctrl) failed: -1 hid-generic 0003:25F0:83C2.0001: timeout initializing reports input: Goodbetterbest Ltd Gioteck VX2 2.4G Wireless Controller as /devices/platform/ohci.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:25F0:83C2.0001/input/input2 hid-generic 0003:25F0:83C2.0001: input: USB HID v1.10 Gamepad [Goodbetterbest Ltd Gioteck VX2 2.4G Wireless Controller] on usb-ohci.0-1.4/input0
Mas a implementação USB deixa um bocado a desejar:
root@ev3dev:~# lsusb Bus 001 Device 004: ID 25f0:83c2
Bela porcaria, nem um descritivo? Vamos inspeccionar com mais detalhe:
root@ev3dev:~# lsusb -d 25f0:83c2 -v Bus 001 Device 004: ID 25f0:83c2 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 16 idVendor 0x25f0 idProduct 0x83c2 bcdDevice 3.15 iManufacturer 1 Goodbetterbest Ltd iProduct 2 Gioteck VX2 2.4G Wireless Controller iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 41 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 No Subclass bInterfaceProtocol 0 None iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 137 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0010 1x 16 bytes bInterval 10 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 1 Device Status: 0x0000 (Bus Powered)
Sendo OHCI temos também:
root@ev3dev:~# ls /dev/input/by-id/ -la total 0 drwxr-xr-x 2 root root 60 Aug 15 07:16 . drwxr-xr-x 4 root root 140 Aug 15 07:16 .. lrwxrwxrwx 1 root root 9 Aug 15 07:16 usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick -> ../event2
No Ubuntu consigo ver o estado dos vários botões e joysticks do gamepad com o comando ‘jstest’ do pacote ‘joystick’ por isso:
root@ev3dev:~# apt-get install joystick root@ev3dev:~# jstest --normal /dev/input/by-id/usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick Driver version is 0.8.0. jstest is not fully compatible with your kernel. Unable to retrieve button map! Joystick (Unknown) has 2 axes and 2 buttons. Testing ... (interrupt to exit) jstest: error reading: Invalid argument
“Not fully compatible with your kernel”… Oops!
Podemos sempre aceder directamente:
root@ev3dev:~# cat /dev/input/by-id/usb-Goodbetterbest_Ltd_Gioteck_VX2_2.4G_Wireless_Controller-event-joystick �S�z �S�z0�S�z�S�� �S��0�S��
carregar um botão apenas gerou esta sequência de caracteres estranha… pelo menos sabemos que funciona só falta entender o formato. Como sou preguiçoso fui buscar o PyGame, um módulo de python muito usado na comunidade Raspberry Pi que já faz isso – a semelhança do EV3 com o Raspberry Pi é tão impressionante que lhe podemos ir buscar ideias para quase tudo.
root@ev3dev:~# apt-get install python-pygame root@ev3dev:~# nano joystick.py root@ev3dev:~# chmod +x joystick.py root@ev3dev:~# python joystick.py
O script python ‘joystick.py’:
import traceback, os os.environ['SDL_VIDEODRIVER'] = 'dummy' from pygame import joystick, event, display def main(): try: display.init() joystick.init() js=joystick.Joystick(0) js.init() num_axes=js.get_numaxes() num_buttons=js.get_numbuttons() num_hats=js.get_numhats() print 'Axes:', num_axes print 'Buttons:', num_buttons print 'Hats:', num_hats while True: event.pump() for i in range(0, num_axes): print 'Axis %i: %6.3f' % (i, js.get_axis(i)) for i in range(0, num_buttons): print 'Button %i: %r' % (i, js.get_button(i)) for i in range(0, num_hats): print 'Hat %i: %s' % (i, js.get_hat(i)) except (KeyboardInterrupt, SystemExit): print "Exiting..." except Exception: traceback.print_exc(file=sys.stdout) sys.exit(0) if __name__ == "__main__": main()
À custa deste script fiquei a saber que o gamepad tem 4 axes (2 por cada joystick analógico), 13 buttons e 1 hat (o hat é o conjunto de 4 teclas direccionais à esquerda do gamepad) que quando accionados devolvem:
Para cada um dos 13 botões:
gatilho esquerdo = 6
botão sobre gatilho esquerdo = 4
gatilho direito = 7
botão sobre gatilho direito = 5
select = 8
start = 9
home = 12
triangulo = 0
circulo = 1
cruz = 2
quadrado = 3
botão do joystick esquerdo = 10
botão do joystick direito = 11
(o botão “Turbo’ ao centro do gamepad parece não funcionar)
Para cada um dos 4 botões do hat:
cima = (0,1)
direita = (1,0)
baixo = (0,-1)
esquerda = (-1,0)
Para o joystick da direita:
todo para cima: Eixo 3 = -1
todo para baixo: Eixo 3 = 1
todo para direita: Eixo 2 = 1
todo para esquerda: Eixo 2 = -1
=> (x,y) = (axis2,-axis3)
Para o joystick da esquerda:
todo para cima: Eixo 1 = -1
todo para baixo: Eixo 1 = 1
todo para direita: Eixo 0 = 1
todo para esquerda: Eixo 0 = -1
=> (x,y) = (axis0,-axis1)
O gamepad tem também um motor interno para vibração (force feedback?) mas que só funciona com Playstation 3. Curiosamente de vez em quando acontece-me poucos minutos depois de desligar o EV3 o gamepad desatar a vibrar.