I’ve recently been immersed in a space sim called Elite:Dangerous. (It’s in Gamma and will be out shortly 12/16/2014.) I play with a small casual group that’s not about to build a ship cockpit in our living rooms or all splurge for a dev kit VR Oculus Rift. Some of us have played Elite on the Oculus and the first thing you miss is “head look”. The game is designed for it, and once you use it dog-fighting in an asteroid field, watching your enemy turn sharp high above you while you cut power and rotate at the same time whilst avoiding giant floating rocks, you don’t want to give it up. This is one of those games (much like a flight simulator) that takes 30 minutes just to map your controller(s).
My brother linked me to a UK group that was doing head tracking with an Arduino (SparkFun Pro Micro) and a Gyroscope / Accelerometer (MPU-6050) over at edtracker.org.uk, “Can you build this?” he asked.
“I can build a better one.” – and you can too.
- No drift – Use hardware that incorporates a magnetometer (compass)
(The new edtracker 9150 version uses a magnetometer to remove drift) - No calibration GUI – Place flat on table when powering on
- No PCB – Four connections. SCL, SDA, +5, GND
Here’s what makes up the easier better IMU head tracker:
- MiniIMU-9 by Pololu OR, IMU Breakout by Adafruit
- L3GD20H is a 3-axis gyroscope
- LSM303 is a 3-axis accelerometer AND 3-axis magnetometer
- Teensy 2.0 – Fantastic Arduino clones from PJRC
- 2 pins + 2 wires for VCC & GND
The first thing I noticed was the drift problem. The EDTracker guys have since put out a second version with magnetometer compensation, but they didn’t have it from the start and the hardware difference is around $6. I picked an IMU hardware package that has a great tested library for it. The calibration and angle calculation built into the Pololu libraries – specifically the code from Michael Baker Pololu_Open_IMU (Inertial Measurement Unit) as it uses the Madgwick algorithm is particularly brilliant. It outputs pitch, yaw, and roll angles. Watch a video of the Madgwick algorithm in action.
I knew from past experience that the Teensy 2.0 can emulate many types of USB devices right out of the bag. “Joystick.X(value);” was simple to integrate and the device needs no emulation software or additional CPU to work. It just shows up in joy.cpl as a Joystick. You wouldn’t think that an Arduino could handle complex Euler angles and lots of float math on its own, but it has no problem. With the Teensy Joystick, the X,Y, and Z can be directly mapped 0 – 1023.
Lastly there are PCB boards being built for this, and I’m really not sure why. These are not PCB’s with components on them like an ATMEGA32U4’s and the 9 Degree of Freedom hardware already built in. These are PCB’s just to connect a 9-DOF board with an Arduino. This is all of 4 connections, and the two pins on the Teensy 2.0 are D0 (SCL) & D1 (SDA) and they line up fine on both the Adafruit and Pololu breakouts for an above mount setup.

With the hardware finalized, I mounted it in a small box with a dab of hot glue and a cut-out for the mini-usb. Here’s the test:
[youtube=”http://youtu.be/tsXhuh09hko”]
For the head tracking code I used Fscale to scale map the angles to the joystick. This is the part where you amplify a tiny amount of head movement into a larger amount of in-game head-look movement. I settled on a 50° angle for pitch and roll, and an 80° angle for left and right (yaw). You’re more than welcome to try a different scale by changing the low and high Fscale numbers (-25 & 25 = 50° of movement translates into -90° & 90° of game movement) Everything else is directly from Michael Baker mikeshub/Pololu_Open_IMU. Such a tiny amount of code here is from me that I don’t even want credit for it. 😛 I’m just a lowly hardware guy that can smash out some C#. Example:
if (pitch < 0){pitch = fscale(-25, 0, 0, 512, pitch,0);} else {pitch = fscale(0, 25, 512, 1023, pitch,0);}
Joystick.Y(pitch);
Here’s a list of what you will need for software:
- Arduino Software
- Teensy Loader
- L3G Libray 1.2.2
- The ‘older’ LSM303 Library 1.4.4
- Michael Baker’s Pololu Open IMU
- Code you see here – Kris’s Version Pololu_Open_IMU_joystick
The device calibrates when it it powered on, make sure it’s flat and motionless. After that it takes an initial heading reading and starts to blink. 20 more seconds of being on, and that heading is locked in. I commented out all of the serial outputs and zip tied it to my headset:
[youtube=”http://youtu.be/55OkfPZCeCg”]
Results: After playing for 3 hours I had zero drift. It stays pointed at the direction of your monitor forever. I considered adding a curve to the scaling to provide a “dead zone”, but the game has a dead zone setting built-in and I’d rather just output 100% and let the game / user control the settings. I also mapped the roll axis and one could use it to fire the roll thrusters in the game. For ~$45 you now have a cool little IMU that you can experiment with!
Update: If you would like to configure it to work with Opentrack (supports TrackIR games), you will need to map the axis 1:1 with the joystick output and then set all your curves and config up in Opentrack.
fscale(-90, 0, 0, 512, your_axis,0)
fscale(0, 90, 512, 1023, your_axis,0)
Update 1/16/2016: Uploaded code and working with Grégory Paul over on hackaday.io
https://hackaday.io/project/8952-elite-dangerous-headtracker