Pack-Man manual
This is a manual for making a video game system with 5 joysticks, such as PACK-MAN
JOYSTICKS
We got out joysticks at HAPP (there are a whole lot, but we went with the cheap Ultimate Joystick, which is pictured below). You can pick between a few very primary colors, and if you order 6 or more, it’s a little cheaper per unit.

These are 4-position joysticks, which means that it is either at rest in the middle (like in the photograph) or it has been pushed UP, RIGHT, DOWN, or LEFT. There is no way to be in more than one position (for example, UP and RIGHT). It’s physically impossible.
What I mean is that there are 4 switches on the bottom (the kind you buy at an electronics store - a momentary SPDT switch, two of which can be seen in the picture). The joystick is only able to activate one switch at a time.
In order to actually use the joysticks, you need to be able to wire them; and then once you’ve wired them, you need to be able to read them and send this information onward (to a computer, to a video game console, to your stereo’s remote control, etc.) I’ll get more into wiring below, but first, think about how to mount the joysticks. It’s kind of uncomfortable to hold onto one of these in the raw. We found clear plastic containers at Super Home Mart. But maybe you just want to mount them all in a single piece of plywood. Either way, you have to cut a hole in the surface (bigger than the "stick" but smaller than that plastic ring around the stick, so it remains hidden) and then secure the joystick to the surface.
ELECTRONICS
We decided to have a microcontroller regularly (about 50 times a second) poll the joysticks; the microcontroller determined whether any of the joysticks had changed their position since the last time it polled them; and finally, it passed this information on to whoever cared to listen. We used Arduino as the microcontroller (Arduino is an AVR in a Basic Stamp-like package, kind of).
First, how do we "poll" a bunch of joysticks? Polling just means using the microcontroller to determine the position (UP, RIGHT, DOWN, or LEFT) of each of the joysticks. In words: we use 5 wires for each joystick. One wire goes to the metal part on each of the four switches (that’s 4 wires total). And one wire goes to one of the two metal parts on the end of one switch, and then it’s connected to the metal part on the end of the next switch, and then the third switch and then the fourth switch (that’s just one wire connecting the four switches together). [Image of how to wire one joystick] Those four wires are then connected to INPUT pins on the microcontroller, and the one wire is connected to an OUTPUT pin. The microcontroller sets one of the four wires to HIGH. It then reads the INPUT pin. If it reads a HIGH, then that means the joystick is pushed in that direction! If it reads a LOW, then the joystick isn’t pushed in that direction. The microcontroller continues through the other three INPUT pins in exactly the same manner.
Now, that was just for one of the joysticks. How do we check the rest of them? In exactly the same way! If you do the math, that is 5 wires for each joystick, so 5 joysticks would mean you’d need 25 pins right? Well, as it turns out, we can take a little shortcut. Those four INPUT pins can actually be shared by each of the joysticks. But each joystick needs its own OUTPUT pin. This means that five joysticks actually only uses 9 pins. There are four INPUT pins and then five OUTPUT pins (one for each joystick). Why? Well let’s say only one person is pushing UP. When we set the OUTPUT pin for that joystick to HIGH, there is 5V going to all the switches of that joystick. But since only the UP switch is activated, only the corresponding INPUT will read HIGH. If we set the OUTPUT pin for a different joystick to HIGH, instead, then none of the INPUTS will get 5V (or HIGH). Here is an image of the circuit:
So you can see that it is easy to add more joysticks. All you need to do is keep using the same 4 INPUT pins, but add an OUTPUT pin for each additional joystick.
Now, all of these wires could get pretty messy, so we used MIDI cables to carry the wires from the microcontroller to the joysticks (but you don’t have to). We’re not using real MIDI, we’re just using MIDI cables, because there are 5 wires inside of a MIDI cable we can use. So don’t let the MIDI confuse you. You could probably use phone cable if you felt like it, or ethernet. Just keep track of which wires should connect to what. Of course, if you use MIDI cables, then you’ll want to be able to plug them into something, like jacks. Then, you only have to solder wires between the jack and the joystick, and between the other jack and the microcontroller.
One thing in the schematic that I haven’t mentioned is what the resistors are doing. It is a very common technique in digital electronics, which is to "pull down" the INPUT pins to ground when the switch isn’t activated. This is necessary because the pin might "float" otherwise and the microcontroller might read unexpected HIGH values. The resistor anchors the pin to LOW, except when the switch is actually activated, at which point the INPUT pin reads a reliable HIGH.
CODE
The last part of this whole system is the code that is running on the microcontroller. The text in the section above that described how to "poll" the joysticks actually explains the what the code is doing. But here is the Arduino code to actually do it:
int joystickNum = 5; // This is a hack because I can't figure out how to access an array's length
int joystickPower[] = {2,3,4,5,6}; // which pins are connected to the power of each joystick
int joystickDirections[] = {7,8,9,10}; // which pins connect to up, right, down, left (all joysticks connect here)
byte joysticks[] = {0,0,0,0,0}; // initialize all of the joystick values
byte dataToSend;
int i,j;
byte tmp;
void readJoysticks() {
// set all output pins to low
for (i=0; i<joystickNum; i++) {
digitalWrite(joystickPower[i], LOW);
}
for (i=0; i<joystickNum; i++) { // for each one of the joysticks
digitalWrite(joystickPower[i], HIGH); // set its pin to HIGH
tmp = 0; // this is a temporary variable that will hold the direction of this joystick
for (j=0; j<4; j++) { // and then for each of the directions of the joystick
if ( digitalRead(joystickDirections[j])==HIGH ) { // check to see if it's activated
tmp = 1 << j; // do bit shifting to represent the direction (up=1<<0=1,right=1<<1=2,down=1<<2=4,left=1<<3=8)
}
}
if ( joysticks[i] != tmp ) { // check the current direction against the previous direction, which is stored in the joysticks array
dataToSend = i << 4; // put the joystick's index into the data we're about to send to the PC
dataToSend = dataToSend | tmp; // now put in the direction
joysticks[i] = tmp; // and set the previous direction to the current direction (for next time)
serialWrite(dataToSend); // finally send the data to the PC
}
digitalWrite(joystickPower[i], LOW); // we're done with this joystick, set it to LOW and do the loop again for the next joystick
}
}
// this is called once when the chip is first given power
void setup() {
for (i=0; i<joystickNum; i++) {
pinMode(joystickPower[i], OUTPUT);
}
for (i=0; i<4; i++) {
pinMode(joystickDirections[i], INPUT);
}
beginSerial(19200); // begin communication with the PC at 19200 baud (can be changed if you need to)
}
// this is called over and over and over
void loop() {
delay(10);
readJoysticks();
}
The code that’s above checks all the joysticks. But it also checks whether the joystick is in a different position than it was before. If the joystick is in a different position, then it sends its position over the serial port. One of the nice things about Arduino is that "over the serial port" actually means that it sends the data through USB to a computer. So in this case, the end recipient of the joystick control is a computer program (in PACK-MAN, it is an emulator running Pac-Man). It is entirely possible to send the data to an actual video game console too, if that’s what you want. But then you’d need to reverse-engineer how a joystick/controller to one of these consoles works and then mimick that with the microcontroller. I’ll leave that up to you!