Using an Arduino Uno R3 as a Game Controller

Naturally, the Uno does not natively support keyboard strokes, unlike it’s Leonardo brother. Most of Google will tell you you need to do some firmware workarounds and ATMEGA reprogramming just to get it working and the entire ordeal is a mess. If you’re like me, you’ve found that out just after buying one. Here is how to get around all that using a bit of Java coding. The ideal solution would be to purchase an arcade or flight sim joystick button board or an Arduino Leonardo for a few bucks from China (DX.com).

You will need:
Arduino Uno
Any sort of button or switch (or multiple switches, but start off simple)
10kΩ resistor(s) (one for each button)
Eclipse (the front end for Java programming – instructions later on for install)
Arduino Software (the front end for Arduino programming)
Breadboard
Jumper wires
Patience
Any video game that you may want physical switches for (racing/flight sim)Using an Arduino Uno R3 as a Game Controller

Step 1: Installing & Testing the Software

First of, you will need Eclipse (http://www.eclipse.org/downloads/). For this tutorial, I will be using Eclipse Classic 4.2.2 – 64 Bit. If you’re running into problems during the install, refer to either Google or the FAQ. Now that Eclipse is installed, you will also need the Arduino program (http://arduino.cc/en/main/software). I’ll be using the stable 1.0.5 version.

You can skip this step if you know how to upload sketches to the Arduino. Now that you have all the software installed, we’re going to go ahead and setup Arduino first. In the Arduino software, click tools and make sure the board and port number make sense according to Device Manager. To test the board, go File>Examples>Basic>Blink then hit the arrow in the top left that says upload. If all goes right, the SMD on pin 13 should be blinking. Refer to THIS if you’re having difficulties.

Step 2: Wiring up a Basic Switch & Programming

In this step, you will be hooking up a basic switch to pin 5. Why pin 5? I have no idea but here’s the wiring diagram (Made using Fritzing). There’s two diagrams, one for (1) 2 pin switch and one for (4) 4 pin switches.

Now that you have a switch hooked onto pin 5, we begin programming in Arduino. The code I used is attached and below:

// *********************************************
// this constant won’t change:
const int  buttonPin = 5; // the pin that the pushbutton is attached to

// Variables will change:
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
// Initialize the button pin as an input:
pinMode(buttonPin, INPUT);
// Initialize serial communication:
Serial.begin(9600);
}

void loop() {
// Read the pushbutton input pin:
buttonState = digitalRead(buttonPin);

if (buttonState == HIGH) {
// If the current state is HIGH then the button
// Send to serial that the engine has started:
Serial.println(“Start Engine”);
delay (100);
}
// Save the current state as the last state,
// for next time through the loop
lastButtonState = buttonState;
}
// *********************************************

When uploaded to the Arduino, you can open up the serial monitor (Tools>Serial Monitor) and press the button. It should display “Start Engine” as long as you’re pressing the button. You may fiddle with the delay later on to suit your liking but please note this may cause issues in-game. You are now sending a serial string through tactile feedback. This is great!

Step 3: Setting up Eclipse and Installing Libraries

Now we need to do something with that serial string. A program needs to pick it up and translate it into keystrokes. This is where Eclipse comes in and things get messy. Off the bat, you will need to download and install the RXTXcomm library (http://rxtx.qbang.org/wiki/index.php/Download) into Eclipse. I used the rxtx 2.1-7r2 (stable) version. Place RXTXcomm.jar into Eclipse’s [Your workspace]/lib/jars folder as well as placing the rxtxParallel.dll and rxtxSerial.dll files into [Your workspace]/natives-win. This is where most people will go wrong if they do so feel free to ask if you have questions.

Now that you’ve installed the RXTXcomm library, we can begin coding in Eclipse. Open it up and go File>New>Project…>Java Project. For the sake of simplicity and ease, name this project SerialTest. While this may not be the proper method, there’s no reason for it not to work this way. Click finish. Under the package explorer sidebar, right click on the SerialTest folder and go New>Class we will also name this SerialTest. Make sure public static void main(string[] args) is checked on. This is a Java program in its simplest, however, we still need to import those libraries from earlier. Right click on the same project folder and go Build Path>Configure Build Path. Under the Libraries tab, click Add External JARs and navigate to where you put the RXTXcomm.jar ([Your workspace]/lib/jars) and open it. Click OK. You are now ready to begin programming Java using the serial communicating library.

If you’ve made it past this part, congratulations. You didn’t spend hours trying to figure it out like I did.

Step 4: Programming in Java to Interpret Incoming Serial & Testing

Now, bare with me because I know nobody likes working with other people’s code. It just sucks. You may have to modify the COM channel, parity, stop bits and baud (data) rate settings in the code (all of which can be determined through Device Manager but should be the same as the code). The code below works with Linux, Mac OS X and Windows. My Arduino is on the default COM1 at 9600b/s. I accidentally left some experimental code in there while making a GUI but they won’t affect anything so try to ignore understanding some of the library imports. The SerialTest folder is also attached for reference.

// *********************************************

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.util.Enumeration;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JFrame;
import java.awt.Color;

public class SerialTest implements SerialPortEventListener {
SerialPort serialPort;
/** The port we’re normally going to use. */
private static final String PORT_NAMES[] = { “/dev/tty.usbserial-A9007UX1”, // Mac OS X
“/dev/ttyUSB0”, // Linux
“COM1”, // Windows
};
/**
* A BufferedReader which will be fed by a InputStreamReader converting the
* bytes into characters making the displayed results codepage independent
*/
private BufferedReader input;
/** The output stream to the port */
private OutputStream output;
/** Milliseconds to block while waiting for port open */
private static final int TIME_OUT = 2000;
/** Default bits per second for COM port. */
private static final int DATA_RATE = 9600;

public void initialize() {
CommPortIdentifier portId = null;
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

// First, Find an instance of serial port as set in PORT_NAMES.
while (portEnum.hasMoreElements()) {
CommPortIdentifier currPortId = (CommPortIdentifier) portEnum
.nextElement();
for (String portName : PORT_NAMES) {
if (currPortId.getName().equals(portName)) {
portId = currPortId;
break;
}
}
}
System.out.println(“Port ID: “);
System.out.println(portId);
System.out.println(“”);
if (portId == null) {
System.out.println(“Could not find COM port.”);
return;
}

try {
// open serial port, and use class name for the appName.
serialPort = (SerialPort) portId.open(this.getClass().getName(),
TIME_OUT);

// set port parameters
serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

// open the streams
input = new BufferedReader(new InputStreamReader(
serialPort.getInputStream()));
output = serialPort.getOutputStream();

// add event listeners
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
} catch (Exception e) {
System.err.println(e.toString());
}
}

/**
* This should be called when you stop using the port. This will prevent
* port locking on platforms like Linux.
*/
public synchronized void close() {
if (serialPort != null) {
serialPort.removeEventListener();
serialPort.close();
}
}

/**
* Handle an event on the serial port. Read the data and print it.
*/
public synchronized void serialEvent(SerialPortEvent oEvent) {
if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
String inputLine = input.readLine();
// ENGINE START
if (inputLine.equals(“Start Engine”)) {
System.out.println(“Engine Start Engaged”);
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_S);
robot.delay(500);
robot.keyRelease(KeyEvent.VK_S);
} catch (AWTException e) {
e.printStackTrace();
}
}
// WINDSHIELD WIPERS
if (inputLine.equals(“Windshield Wipers”)) {
System.out.println(“Windshield Wipers Engaged”);
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_W);
robot.delay(500);
robot.keyRelease(KeyEvent.VK_W);
} catch (AWTException e) {
e.printStackTrace();
}
}
// PIT SPEED LIMITER
if (inputLine.equals(“Pit Speed Limiter”)) {
System.out.println(“Pit Limiter Engaged”);
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_P);
robot.delay(500);
robot.keyRelease(KeyEvent.VK_P);
} catch (AWTException e) {
e.printStackTrace();
}
}
// HEADLIGHTS
if (inputLine.equals(“Headlights”)) {
System.out.println(“Headlights Engaged”);
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_H);
robot.delay(500);
robot.keyRelease(KeyEvent.VK_H);
} catch (AWTException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
System.err.println(e.toString());
}
}
if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {

}
// Ignore all the other eventTypes, but you should consider the other
// ones.
}

Using an Arduino Uno R3 as a Game Controller Schematicpublic static void main(String[] args) throws Exception {
SerialTest main = new SerialTest();
main.initialize();
Thread t = new Thread() {
public void run() {
// the following line will keep this app alive for 1000 seconds,
// waiting for events to occur and responding to them (printing
// incoming messages to console).
try {
Thread.sleep(1000000);
} catch (InterruptedException ie) {
}
}
};
t.start();
System.out.println(“- Started -“);
System.out.println(“”);
}
}

// *********************************************

As you can see, there are 3 other buttons hooked up. Whenever Java sees the serial input of “Start Engine” , it will send out a keystroke of S. The output console will throw IO.Exceptions at you but don’t fear, it’s fixable by commenting out both System.err.println(e.toString()); lines. These errors do not interfere with anything so they’re nothing to worry about to begin with. To change what each switch does, simply change the variables that are getting written to serial in Arduino and change the respective conditional statements in Java for when it receives those serial strings. To see the list of available commands for robot in Eclipse, type robot. and a little box will pop up showing various functions. Robot is amazing, you can even assign it to move the mouse based on Arduino input.

 

For more detail: Using an Arduino Uno R3 as a Game Controller


About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top