January 28, 2012

Arduino Game Port Interface

A while back I got my hands on an old analog PC joystick, and since then I have been meaning to build an adapter make the joystick work over USB.  The adapter I finally built consists of an Arduino connected to a game port I hacked off an old sound card.  The Arduino reads the analog (x and y movement) and digital (buttons) inputs and then sends them to the computer over serial.  Then a Processing script running on the computer reads the serial data, and converts it into mouse movements and clicks using the Java Robot class.

I first made an adapter to break out the connections from the joystick.  I hacked a game port off an old sound card, and wired three sets of connections to it, using the pinout I found.  Although the particular joystick I have does not use every available pin, I went ahead an included all of them.

In the picture below, the top three header pins are the 5V and ground connections (red is 5V).  The middle four are the analog connections, and the bottom four are digital, for the buttons.

Unfortunately you cannot just plug these pins directly into a microcontroller and get it go read useful information from the joystick. Pull down resistors must be added for each of the button connections.  Also, the potentiometers in the joystick do not have their third pins connected to ground, so I had to add a 100k resistor after each of the analog pins, so that the potentiometers act as a voltage divider and the Arduino can read them properly.

In the picture below, orange jumpers are analog, green digital, and the two at the bottom are for 5V and ground:

Pull down resistors:

Everything connected (minus the USB connection to the computer):

The way the code works is fairly simple.  The Arduino reads the values of the potentiometers and buttons, scales the values to under 255 (1 byte) so that they can be sent over serial, and then sends the values to the computer over the serial connection.  

The processing script running on the computer reads the sequence of numbers being received.  It compares the values form the potentiometer to the values when the joystick is centered, and then moves the mouse using the Robot.mouseMove() command based on the difference between the values.  Moving the joystick farther one direction means that the mouse will move faster.  The trigger button corresponds to left click, and the thumb button is right click.  The secondary joystick (top center) is used for scrolling, and the remaining two buttons currently adjust the sensitivity of the joystick.

Due to the speed at which the processing script runs, I had to limit the rate at which the Arduino sent data over serial, because if data was sent too quickly, it backlogged and created a huge lag when moving the joystick.  Therefore, the joystick is not quite as responsive as I hoped it would be, and you must hold down the button longer than you would a mouse for your clicks to register.  A workaround for this would be to use something like a Teensy, which can be recognized as a HID, so that the microcontroller could control the mouse directly, eliminating the need for an interpreting script.



  1. I truly didn't appreciate working with breadboard back then in college, but if it's used like this, really awesome!

  2. This project is great!!!!! but I just had a resqust can you please pst the shcamatic of the circuit.

  3. It looks like you're using pull down resistors of 82K -- grey + red x orange = 82 x 10K = 82K. Is that correct? It appears to me that the green cable is the analog inputs for potentiometers and the orange cable for the buttons. I say that because you have the 10K resistors on the orange cable where I know buttons use 10K resistors. Please explain. Also it appears that only two of four 5V pins and powered on connector. Is that ok for everyone?

  4. I chose my pull down resistors to approximately match the resistance across the outer terminals of the potentiometers in the joystick.

    Other way around. As I say "In the picture below, orange jumpers are analog, green digital"

    I found that the 5v pins were internally connected in the joystick, so I didn't bother breaking them all out.

  5. ...Also, the potentiometers in the joystick do not have their third pins connected to ground, so I had to add a 100k resistor after each of the analog pins... Is a 100k Ohm resistor or 10k, because from the photos, those resistors on the left, the third ring for me seems orange, so then is a 10k resistor. Am I right?

    1. If I buy a VGA port on the Internet, instead hacking a soundcard is the same?

    2. No, the pin configuration is different. For one, VGA has three rows of pins, while this has only two.

  6. Good, now my doubts went off; but can you have to do me a favor? If you can tell me: you divided the wires from the db15 port in three groups:5v and ground, analog, digital.Every group has 4 wires (except the 5v and ground group); There is an important order in which i have to plug them in the breadboard? If yes can you tell me which is the right order, with the pin number?(I don't think i've explained myself Clearly...)

    1. I can't think of a reason you'd have to plug them in any particular order or arrangement, as long as you keep track of which leads go to what.

  7. great tutorial....

  8. Thanks for the code + tute :) Can't seem to read any other value than 255 255 255 255 from the Analog/Joystick pins, any idea why that might be?

    12 buttons on the joystick read great via the digital pins..


  9. I think there is an accuracy improvement you can make to your voltage divider reading code; problem is that Vout is not linear; Vout = Vin * (R2 / R1 + R2), so you have to do some math to fit the Vout you get to determine the resistance value of the joystick axis, and therefore the position. This page explains it pretty well: http://www.built-to-spec.com/blog/2009/09/10/using-a-pc-joystick-with-the-arduino/

    Because of this, variable resistor gameport joysticks are a little harder to use than potentiometer joysticks like this:
    This style joystick are potentiometers with both legs of the voltage divider included, so the middle pin is a "wiper"

  10. Exactly what I was questioning! Why use pullups on the Analogues. Obvious circuit would be to use pulldowns and have a proper voltage divider.

    [pin A]
    (+5v) -> Rjoy(~) + Rpulldown -> 0v