Quantcast
Channel: Chris Swan's Weblog » advmame
Viewing all articles
Browse latest Browse all 2

Raspberry Pi GPIO Joystick

0
0

After getting MAME going on my Raspberry Pi so that I could play old arcade games. I wanted to hook up a proper joystick. Back in the 80’s I had the excellent and ubiquitous Competition Pro 5000. As mine (foolishly) got sold with my Amiga stuff I got one on eBay, and it came in the original box:

The first step was to get it hooked up to the RPi general purpose input output (GPIO). I used a breadboard with my homebrew Pi Cobbler at one end and a similar connector at the other hooked up to an old PC serial card cable that has the right (male) DB9 connector for the joystick plug (female). It was then just a matter of adding some pull up resistors (10K) and some patch cables:

Since I was originally planning to use gpio-keys I used the joystick pinout to hook up to the RPi thus:

  1. Up -> 11 (GPIO 17)
  2. Down -> 13 (GPIO 22)
  3. Left -> 15 (GPIO 23)
  4. Right -> 16 (GPIO 24)
  5. n/c
  6. Fire -> 7 (GPIO 4)
  7. n/c
  8. GND
  9. n/c

Blind alley

Having already seen gpio-keys I thought I’d be using that, but when it came to the crunch I didn’t know where to start – I probably need a package of RPi kernel source. On reflection I probably really wanted gpio-mouse anyway.

After some digging around the Raspberry Pi Forums I found a comment about using Python to generate keystrokes. This got me headed in the direction of Python uinput, which is a module that can create keypresses.

sudo modprobe uinput
git clone https://github.com/tuomasjjrasanen/python-uinput
cd python-uinput
sudo python setup.py install --prefix=/usr/local

Smelling victory I knocked together some code that turns GPIO into keypresses. Sadly it seems that AdvMAME derives it’s input in such a way that completely ignores uinput for keyboard. Back to the drawing board.

The right(ish) approach

Digging around the examples for Python-uinput I found one for joystick, so I had a go at creating a GPIO connected variant:

""" rpi-gpio-jstk.py by Chris Swan 9 Aug 2012
GPIO Joystick driver for Raspberry Pi for use with 80s 5 switch joysticks
based on python-uinput/examples/joystick.py by tuomasjjrasanen
https://github.com/tuomasjjrasanen/python-uinput/blob/master/examples/joystick.py
requires uinput kernel module (sudo modprobe uinput)
requires python-uinput (git clone https://github.com/tuomasjjrasanen/python-uinput)
requires (from http://pypi.python.org/pypi/RPi.GPIO/0.3.1a)
for detailed usage see http://blog.thestateofme.com/2012/08/10/raspberry-pi-gpio-joystick/
"""
import uinput
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
# Up, Down, left, right, fire
GPIO.setup(11, GPIO.IN)
GPIO.setup(13, GPIO.IN)
GPIO.setup(15, GPIO.IN)
GPIO.setup(16, GPIO.IN)
GPIO.setup(7, GPIO.IN)

events = (uinput.BTN_JOYSTICK, uinput.ABS_X + (0, 255, 0, 0), uinput.ABS_Y + (0, 255, 0, 0))

device = uinput.Device(events)

# Bools to keep track of movement
fire = False
up = False
down = False
left = False
right = False

# Center joystick
# syn=False to emit an "atomic" (128, 128) event.
device.emit(uinput.ABS_X, 128, syn=False)
device.emit(uinput.ABS_Y, 128)

while True:
 if (not fire) and (not GPIO.input(7)): # Fire button pressed
 fire = True
 device.emit(uinput.BTN_JOYSTICK, 1)
 if fire and GPIO.input(7): # Fire button released
 fire = False
 device.emit(uinput.BTN_JOYSTICK, 0)
 if (not up) and (not GPIO.input(11)): # Up button pressed
 up = True
 device.emit(uinput.ABS_Y, 0) # Zero Y
 if up and GPIO.input(11): # Up button released
 up = False
 device.emit(uinput.ABS_Y, 128) # Center Y
 if (not down) and (not GPIO.input(13)): # Down button pressed
 down = True
 device.emit(uinput.ABS_Y, 255) # Max Y
 if down and GPIO.input(13): # Down button released
 down = False
 device.emit(uinput.ABS_Y, 128) # Center Y
 if (not left) and (not GPIO.input(15)): # Left button pressed
 left = True
 device.emit(uinput.ABS_X, 0) # Zero X
 if left and GPIO.input(15): # Left button released
 left = False
 device.emit(uinput.ABS_X, 128) # Center X
 if (not right) and (not GPIO.input(16)):# Right button pressed
 right = True
 device.emit(uinput.ABS_X, 255) # Max X
 if right and GPIO.input(16): # Right button released
 right = False
 device.emit(uinput.ABS_X, 128) # Center X
 time.sleep(.02) # Poll every 20ms (otherwise CPU load gets too high)

With that saved as rpi-gpio-jstk.py it was a simple case of running:

sudo python rpi-gpio-jstk.py &

I tested using advj, and it showed input. When I fired up AdvMAME the joystick worked – horray – time for some gaming:)

Conclusion

I now have a working classic joystick for my classic games, and it seems to perform fine. I’m not entirely happy with the Python based approach, particularly as it uses polling, but I’ve seen nastier hacks. I’d still like to get a proper kernel module working, more so if it can use interrupts rather polling. I should probably also investigate using internal pullups so that I can simplify the wiring for when I make a more permanent (dual?) joystick adaptor.

Updates

19 Aug 2012 – I changed the code (available on GitHub) to use internal pullups. Since this now means that there are no components involved (just wires between the joystick and GPIO) I’m going to see if I can make an adaptor that just uses one side of the GPIO header (as all I need is GND and 5 inputs). This will involve changing some pins. More to follow when my DB9 PCB connectors arrive from China.



Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images