Raspberry Pi GPIO Joystick

10Aug12

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.



26 Responses to “Raspberry Pi GPIO Joystick”

  1. 1 Reggie

    Hi, nice to see you found a workaround, if you want to do gpio-keys, I posted code on the raspberry pi website a couple of months ago.

    http://www.raspberrypi.org/phpBB3/viewtopic.php?f=50&t=8842

    You may want to look at using gpio-mouse.

    Either way you’ll get an appropriate input device in /dev/ :)

    There is also a framework for rotary encoders in the linux kernel sources, which is great for spinners.

  2. Thanks for the writeup, would love to see some video of it in action! We have featured your build over on http://www.hack247.co.uk/raspberry-pi-gpio-joystick-hack/

    • I have some PCB mount DB9 connectors on the way from China so I can make a proper adaptor board, and I’m also fighting my way through db9.c to see if I can convert it from parport to GPIO for a proper kernel driver. Once those improvements are made I’ll likely do a follow up blog post (and might try to incorporate some video).

  3. 4 stiggyworld

    Great project and using the BEST joystick ever created!

  4. 5 Joefish

    This is a great project.
    Can I suggest you take the initiative to define an extended 8-button (or more) arrangement to use as a standard for for DIY arcade control boards (6 buttons + 1UP + Coin1)? Support could then be coded into emulators or a custom driver written by some brave volunteer at a later date..?

    • This should be fairly straightforward using gpio-keys (perhaps alongside the gpio-db9 module I’m trying to hack together).

      • 7 Joefish

        Oh, yes. What I mean is, it would benefit from someone setting and publicising a precedent for what pin does what – rather than everyone having to reconfigure scripts according to their own peculiar nest of jump wires.

  5. gamecon_gpio_rpi should work fine for multisystem joysticks. db9 is only needed for TTL joysticks, e.g. Sega. Read the joystick-parport.txt documentation.

  6. Hey there, great write up, I’ve been looking for something like this for my Atari Pi project that I’m working on. I’m using the code from your original rpi-gpio-kbrd.py driver, changed it to change some of the keys, added a second joystick support and extra buttons such as select, reset and pause. I still need to build the joystick to gpio interface, but I so hope that Stella accepts uinput! http://www.raspberrypi.org/phpBB3/viewtopic.php?f=78&t=20555

  7. 10 Henrik Moller

    All people wanting to use the GPIO to uinput for controlling keypress in MAME:
    I finally found that it is NOT a blind alley you had in your above post.
    I tried all sorts of things the last month, sending keypress to PIDs, TTY etc etc. nothing worked.
    I found that your above joystick controller using uinput.KEY_5 etc will work if you just disconnect your USB keyboard!
    For some strange reason it can not handle two keyboards at the same time….
    Kind regards,
    Henrik Moller ([email protected])

  8. 11 Darko Bednjanec

    Competition Pro 5000 (aka “Kempston”) Joystick is hard to find nowadays. However, there is a clone that, somebody should try to play with.
    C64DTV (C64 Direct-to-TV) is hybrid of single-chip implementation of the Commodore 64 and C Pro 5000 joystick.
    C64DTV is sold out too, but it should be easier to find it today… beside, it is well documented.

    • Thanks for the pointer. It looks like there’s a healthy hacking community already built up around the C64DTV that has already done mods that would allow it to be used like a regular DB9 joystick.

      Of course there are also new USB versions of the Competition Pro, but judging by the reviews I’ve read the quality isn’t what it used to be (though frankly the original had its faults too – I remember modding mine to use a microswitch for one of the fire buttons as the standard leaf switch had lamed out on me).

      I live in hope that the Raspberry Pi will be enough of a success as a gaming platform that we see a return of good joysticks to the market. I’d temper that by pointing out that even though an original Competition Pro 5000 is a rarity these days, and attracts something of a premium on eBay, they’re actually cheaper in real terms than they were in the 80s.

  9. I’ve had this bookmarked for while, waiting to try.

    I just gave this a go and was very disappointed that there was no output. I even returned to using the keyboard example on the uinput site, with the same results….

    Was about to give up until I switched on the screen attached to the RPi (I’ve been running remotely) to find all of the button outputs neatly outputted in the terminal screen…yey!

    Very pleased it is working, despite my error – local buttons so local keyboard! :)

    • There probably are ways to squirt uinput to a different session, but since console games need console input I’ve had no reason to try.

      • It was just a side-effect of needing to multitask, will be perfect for direct control which is the main purpose. Thanks.

  10. Great build! I was going to mention the internal pull up resistors but I see the latest and greatest version no longer needs them. How did the custom PCB turn out?

    • I was going to just knock something up on stripboard first, but when the DB9 connectors arrived from China I found that they had the wrong pin pitch, and since then I’ve been concentrating on other projects.

  11. Hi,

    i want write the gpio kernel module driver for the raspberry pi..that is when the push button is pressed give interupt to gpio and driver is registered…That is driver..iam new to this type of drivers..please give me some guidence how to wrote the driver and how to give interupt to gpio…Please send any reference code for this…

    Thanks7Regards,
    K.Arungopal

  12. Hi,,
    Do u have any idea about this?That is Any gpio drive code is to know about this?

    Thanks&Regards,
    K.Arungopal

  13. 22 DigitalLumberjack

    Hi, i wrote a kernel space driver that maps GPIO events to a joystick device file.
    You can add up to 8 other joystick with MCP23017 (gpio extender).

    Check it at https://github.com/digitalLumberjack/mk_arcade_joystick_rpi


  1. 1 Retro games and a retro joystick | Raspberry Pi
  2. 2 Raspberry Pi GPIO Joystick #piday #raspberrypi @Raspberry_Pi « adafruit industries blog
  3. 3 Review – BeagleBone Black | Chris Swan's Weblog
  4. 4 Brighton Mini Maker Faire Raspberry Pi FAQ | Chris Swan's Weblog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

Join 98 other followers

%d bloggers like this: