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 https://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.



37 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

  14. 23 Kriss

    Wow. Awsome idea. Im trying to gather info enough to build a pi i have an extra of into an amiga emulator. Im wondering if it would be possible to have two joysticks hooked up at the same time ? You know. For playing two at the same time just like in the old days of amiga and C64.

    As for mouse and keyboard. A plain USB set would work right ? Id imagine somthing like putting all the amiga games on the SD card – since they dont take up alot of space in the first place. And you select with keybobard or mouse -or joystick. The game you want to play and launch it like that. Do you think that would be possible ? To begin with id need a way to connect and use two joysticks at the same time.

    • Physically connecting two joysticks shouldn’t be too much trouble, as there’s enough GPIO (especially on newer Pis), and I expect the software should be OK too. Hopefully whoever did the Amiga emulator has mapped the Linux joystick devices into the Amiga ports, in which case you should be good to go. I expect the original Pi might be a bit underpowered for emulating an Amiga, but the new Pi2 might be up to the job. USB mouse and keyboard should be just fine, and yes storage should be no issue – I remember my pimped out A1200 had a 60MB drive on it, which is smaller than the DOS boot partition on an SD card for the Pi – you can probably get every Amiga game ever written onto a modestly sized card.

    • I have two Amiga joysticks connected to GPIO now, both works in both the C64 emulator and Amiga emulator (UAE4ARM) using Retropie 3.6 with Pi3. Works really well, I used the driver described here: https://github.com/RetroPie/RetroPie-setup/wiki/GPIO-Modules

      • 26 Sean

        @witchmaster – I am also using your setup. My 9-pin joystick works with Atari ST & C64 etc, but I can’t get it to work with UAE4ARM.
        Could you give some more details as to what you did.
        As my 9-pin works with other emulators via RetroPie the drivers are working.
        Are there any configs to adjust in UAE4ARM? I am just plugging in the joystick and running UAE4ARM expecting it to work.

        Thanks,

      • @Sean – I don’t remember changing any settings, they just worked. Well, on the input tab of the menu in uae4arm I may have selected joystick: both. I did not configure the joysticks in emulationstation at all.

  15. Hi there! Excellent post! As I’m new on using GPIO inputs (I did a home automation system but only using outputs) I have two questions if you gently could help me:
    1) once I wire all the wires up in the GPIO and the joystick and within the Python script, once I run the script automatically the joystick begins to work on, for example, Stella?;
    2) is there a way to connect a second joystick?

    Sorry to bother you with this noob questions but I have a broken Atari 2600 here and my idea is to remove all the parts, put a RPi inside of it and use it like a real Atari :)

    Thanks in advance!

    regards,
    Fernando Cunha JR

    • That sounds like a great project.

      1) I’ve not used Stella, but I expect it will work much the same as with MAME. It won’t take you long to test and find out.
      2) uinput doesn’t seem to support a second joystick, this looks to me more like a Linux problem, as the traditional PC Game Port was for a single analogue joystick.

      • Thanks for answering me. So I’m connecting the cables in a DB9 connector and I’ll test I guess this week. I decided to use RetroPI instead of Stella. The other thing I didn’t understand is how do I use the script together with another application. Does it run and keep allocated inside the memory? Thanks again!

      • RetroPi is a good choice.

        The & at the end of my example command line for the script causes it to be executed in the background.

      • All the wires are OK in the DB9 connector and they are plugged in the GPIO PINs, but only the trigger works and the stick does nothing. Question: do I need to conect pins 1 to 4 to GND each of them?

        Thanks! :)

      • As you can see from the picture of the breadboard there is only one GND connection.


  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 to Chris Swan Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.