I was getting tired of dinging the International Space Station—not in reality, of course, but in the fantastically detailed (and free) spaceflight simulator Orbiter. Unlike most spacecraft games, Orbiter tries for as much physical realism as possible, including the need for considerable finesse when docking a spaceship at the ISS’s air lock. Unfortunately, the keyboard controls are not particularly intuitive, and most joysticks and other game controllers are designed with airplanes, cars, or avatars in mind, not spacecraft. So I decided to build my own controller.
The task was made much easier thanks to the release last summer of a new version of the popular Arduino microcontroller. The US $25 Arduino Leonardo can mimic a USB keyboard or mouse, sending keystrokes or mouse movements to a computer in response to circuitry hooked up to the microcontroller.
While this mimicking is technically possible with other versions of the Arduino, it’s a fiddly process that can require additional hardware or ditching the Arduino’s native programming software. As I’m a weekend warrior when it comes to programming, the Leonardo’s ability to transmit a keystroke with a single line of code was very appealing.
Once I’d settled on using the Leonardo for the core of my USB controller, I started working on the physical layout. Rather than trying to have a button for each of the 100 or so keyboard commands that Orbiter recognizes, I focused on the handful of commands that are most needed during busy maneuvers.
During docking, in order to align with the air lock, an Orbiter pilot must frequently switch between rotating the spacecraft along its roll, pitch, and yaw axes and moving (“translating”) the spacecraft in a vertical, horizontal, or sideways direction. A keyboard command switches the spacecraft between rotation and translation modes, which simulates the action of the small thrusters that real spacecraft use for both rotation and translation, but with different firing patterns. Another vital keyboard command stops all spacecraft rotation to prevent the spacecraft from drifting into a confusing multiaxis spin.
With this in mind, I decided on two buttons—one to switch thruster modes and the other to kill any spin—along with small left- and right-hand joysticks.
In rotation mode, the right joystick acts like a traditional airplane joystick—pushing forward pitches the nose down, pushing left rolls the spacecraft to the left, and so on. Meanwhile, moving the other joystick left and right makes the spacecraft yaw back and forth. In translation mode, pushing forward, back, left, and right on the right-hand joystick will accelerate the spacecraft in the matching direction. Moving the left joystick forward and back accelerates the spacecraft up and down.
The joysticks, made by Parallax, cost $5 apiece. These spring-loaded two-axis joysticks are essentially two potentiometers set at right angles to each other. Electrical resistance is proportional to the position of the joystick along each axis.
I also added a switch that turns the Leonardo’s ability to send keystrokes on and off (as indicated by an LED on the side of the controller). This switch means I can leave the USB controller plugged in when I’m not using Orbiter, without having to worry about, say, knocking against the device and inserting random characters into an e-mail.
Wiring up the components to the Leonardo was easy by design. The Leonardo, like all Arduinos, provides a 5-volt reference voltage and a number of built-in analog-to-digital converters for making exactly the kind of resistance measurements I needed to use the joysticks. The digital input pins can be configured to use internal pull-up resistors to prevent spurious readings, so I could connect the switch and buttons directly to the Leonardo. Digital output pins provide enough current to power my indicator LED, so the only additional component required in the whole system was a current-limiting resistor in series with the LED.
Programming the Leonardo was only slightly more difficult than wiring it up—about 100 lines of code to map the inputs from the joysticks and buttons to outgoing keystrokes, written in a version of C developed for the Arduino.
The trickiest part was constructing the controller’s enclosure. As I live in a third-floor apartment, I don’t have space for a workshop (or even a dedicated workbench). My equipment is restricted to the small hand tools I occasionally use to build scale models. So a metal enclosure, for example, wasn’t really an option.
I settled on basswood. It’s commonly used to make architectural models, so beams and strips are available from art supply stores in precut shapes and sizes. Some sawing and gluing of about $5 worth of wood produced an enclosure. The joysticks were held in place by grooves cut into supporting beams. While this arrangement probably isn’t robust enough to withstand the kind of button-mashing frenzy a first-person-shooter video game would elicit, it’s just fine for the more subtly operated Orbiter.
A micro USB cable connects the controller to the computer running Orbiter: The computer’s USB port provides all the power the controller requires, but I had to install a driver to make Microsoft Windows recognize the Leonardo. When you operate the controller, the existing keyboard and mouse remain active, so Orbiter’s full set of commands is available.
I did have to tweak Orbiter’s configuration to use the controller. Normally, Orbiter assigns the rotation and translation commands to the numeric keypad found on full-size keyboards. However, the Leonardo does not support the ability to distinguish between, say, the 8 on the keypad and the 8 in the row above the letters. Fortunately, Orbiter stores its key assignments in an easily edited text file, so a few moments’ work mapped the relevant commands onto the keystrokes I had programmed into the Leonardo.
Once that was done, I launched Orbiter and was instantly able to control my virtual spacecraft with my new controller. A quick flight around the ISS and a perfect docking confirmed the new ease in spacecraft handling—and the new ease in building custom USB hardware—provided by the Leonardo.