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.