Introduction: Personal Compass

About: I like banjos, and whiskey in a jar. My favorite meal is brunch. In my free time, I make things, break things (usually trying to fix them), and play with electronics. In my day job, I'm a science journalist.

It's always amazing when two important events coincide - in my case, I was just starting to tinker with Arduinos around the same time as my sister's wedding. I wanted to make her and her husband a unique gift, so I immediately started trying to think of a project that would let me build something special for the two of them while learning more about Arduino coding. Some searching on Instructables gave me the perfect idea: the "Personal Compass", or a box that always points towards the park where they got engaged.


This project is based on r10n's 2011 post for a "Steampunk Geocache", a device which does more or less the same thing, but this Instructable features corrected, tested code (r10n's was un-implemented), and more details on the construction of the version I built. It would not have been possible, however, without r10n's original idea, and his original code.


You'll need:
A Wood Box (I got mine on sale at Ten Thousand villages)
Arduino Uno compatable board (sparkfun)
Micro Servo (sparkfun)
EM-506 GPS module (sparkfun)
HMC6352 module (sparkfun)**
Assorted Brass gears (ebay)
red and green mini LEDs
Male breakaway headers (sparkfun)
8 x AA Batter Holder (Adafruit)
Male DC Barrel plug 2.1mm (sparkfun)
6-wire ribbon cable (sparkfun)
Heat shrink tubing (sparkfun)

**[NOTE: the HMC6352 board has been discontinued, but you may be able to find one elsewhere. If not, another I2C compass may work with limited tweaking of the arduino code.


Optional:
Arduino Proto Shield (Adafruit)

Step 1: Mock Up the Gears

The most important part of this project is getting the gears right. Most servos only turn about 170-175 degrees, but you'll need 365 degrees of motion to make the compass needle move correctly. In order to do that, you'll need to add a gearing system.

I bought a batch of assorted brass clock gears on Ebay, and started sorting things out by trial and error, mounting gears on a piece of scrap wood with some nails that roughly matched the diameter of their shaft holes. Ideally, you want something close to a 3:1 or 4:1 ratio - once you have that, you can fine-tune the rest in the code. The photo shows the combination I came up with (yours may be different). I decided on it partially due to aesthetic reasons, and partially practical—it's surprisingly hard to find affordable brass gears online, so I had to work with the gearing I had on hand.

Step 2: Prepare the Electronics

Get ready to rummmmble!

...or at least get your components hooked up correctly on a breadboard. Test and test again. Once everything is working, you can assemble the wiring on an Adafruit protoshield - it'll simplify soldering in the final product, and give you a lot more 5v and ground pins to work with. Here's how to hook everything up.

GPS:
The GPS comes with a 6-pin JST cable, which is way too small to easily work with (for me, at least). You'll need to buy a JST jumper cable to hook it up to the Arduino, or just make your own:

  1. Mount the GPS chip on a piece of perfboard. I used thin wire to "tie" the whole thing down.
  2. Cut the JST cable that comes with the GPS in half.
  3. Carefully strip the bare ends of the JST cable, and pass the raw wire through the perfboard.
  4. Solder the exposed ends to 6-inch strips of hookup wire to create a breakout.
  5. Hook up to Arduino
    (wires from left to right facing GPS chip)
    • 0 = unused
    • 1 = ground
    • 2 = Arduino digital pin 2
    • 3 = Arduino digital pin 3
    • 4 = VCC
    • 5 = ground

COMPASS:
Solder hookup wire into the breakout, and strip the ends.

  • 1 = SCC (Arduino analog pin 5)
  • 2 = SDA (Arduino analog pin 4)
  • 3 = VCC (3 volts! Not 5 volts!!)
  • 4 = ground

SERVO

Use hookup wire or jumper cables to attach to Arduino (should fit easily into female header already attached to servo):

  • Red wire = VCC (5v)
  • Black wire = Gnd
  • Yellow wire = PWM (Arduino digital pin 10)

LEDS

A late addition, so not shown in the photos above.

  • Green LED = Arduino digital pin 11
  • Red LED = Arduino digital pin 12

Step 3: Upload the Code

A genius electrical engineer friend helped me troubleshoot this - we ended up tweaking the code quite a bit. It's based on some hefty trigonometry, which is a bit out of my league as coding goes.

You may have to download some libraries to make this work:

TinyGPS (communicates with GPS chip)
PWMServo (lets you control a servo easily)
NewSoftSerial* (turns non-I2C pins into serial pins; you'll need this to communicate with the compass chip)
*IMPORTANT: this code was written on Arduino IDE v0023, which is a much older version than the current one. If you use a newer IDE, you'll have to tweak the code to use the built-in "softwareSerial" library rather than "NewSoftSerial."

To get started, download the arduino code below and unzip - make sure both files are in the same folder, and click on "personalCompassMAIN.ino" to open in the Arduino IDE. Upload normally to an Arduino Uno.

Step 4: Test Test Test

Once I got the code working on a breadboard, I transferred all the parts to the cigar box prototype, and tested the device out in the real world. (I unfortunately don't have any photos of that phase). When you're testing, it helps to set GPS coordinates at a recognizable landmark in your neighborhood - ideally one you can see from your window. A tall building in the distance should do.

Get your location from Google Maps by dropping a pin, then copy the exact lat-long coordinates from the little window that pops up (see screenshot). You'll have to paste each one into the code below - only change the stuff in the brackets.

<p>#define DESTINATION_LATITUDE ( [insert latitude]f * DEG_TO_RAD )<br>#define DESTINATION_LONGITUDE ([insert longitude]f * DEG_TO_RAD )</p>

You'll also have to change the servo values to match your gear ratio, so you get a reasonably accurate arc. (It won't be perfect, just in the ballpark.) Play around with the variables float servomin and float servomax, until you get a range of sweep that rotates the needle a full turn from start to finish.

////////////////// SERVO CONTROL
// change min/max values on servo sweep to match gears installed on final unit
///////////////

void PositionNeedle( const int distanceToDestination, const int directionToDestination, const int currentHeading )
{int bearing = 0;  // sweep
  if( currentHeading > directionToDestination ) 
    bearing = -(currentHeading - directionToDestination); // These two are equal. -(a-b) = -a+b
  else
    bearing = directionToDestination - currentHeading;  
       
  if( bearing < 0 ) 
    bearing += 360; // makes sure bearing is positive number; if smaller than zero, adds 360. Makes needle flip around when servo hits is rotation limit, giving illusion of 360 degree rotation  

//change values below to match gears on final product
 float servomin = 20.0f;
 float servomax = 150.0f;

Step 5: Prepare the Box

If the prototype works, you're halfway there. You just need to add all the components to the wood box.

I covered mine with painter's tape to avoid marring the finish. Extra bonus: the tape makes it easy to draw marks for centering and cutting.

To start, take the "needle" gear (the one you'll put your compass needle on), and glue a pointer to it. I used superglue and an antique clock hour hand that came with the gears I bought. Looked pretty nice.

Mark out where you want the needle gear to sit on the top of the box, and use that as a starting point to lay out where you want your other gears. Do this VERY CARFULLY—if you drill holes even slightly in the wrong place, you'll have all sorts of slop in the gears. It helps to start with the center gear and work your way outward, securing each one as you go. The final hole will be for the servo itself.

Drill an appropriately-sized hole for your servo's neck. I added a notch so it wouldn't slide around (there's a tab on the motor that fits into this), and thinned the underside of the box lid with a chisel so the top of the motor sat flush with the surface of the box.


Next, Mark where you want the GPS and compass chip to live. These should be firmly attached to the underside of the box lid so they don't shift around and give you bad readings. I carved out a small depression for the GPS antenna - you may not need to do this, but I found it helpful.

Step 6: Install Electronics

Finally, put in the electronics.

Secure the arduino/protoshield to the bottom of the box, and run your wiring to all the appropriate pins. My compass chip is free-floating (it's soldered to pretty stiff copper wire), but you could easily tape or glue this under the lid of the box. Make sure it's pointing towards the back of the box (the part facing away from you when you're holding it)

I connected everything with ribbon cable to keep things neat - you can make decent connectors by soldering male headers to ribbon cable and covering them in shrink tubing. Looks a lot nicer than a rat's nest. This is an optional detail, but I figured my sister would occasionally look inside the box when changing batteries, and it's a wedding gift, so keep it classy.

Install the GPS and servo on the underside of the lid. The GPS didn't have mounting holes, so I just used some wire twisted between a few screws. Worked like a charm,

Finally, I added the LEDs and a battery pack, and ran the pack to a power switch on the back (drill another hole for this). Initially I used a 9v, but later switched it out for 8x AA batteries. The power regulator on the Arduino can handle up to 12v, and the extra batteries last a LOT longer.

Step 7: Give It a Whirl!

If all goes well, your box should now work like this!

The red LED stays on if the satellite doesn't have a lock. Once thegreen LED comes on, you're good to go, and the servo should point towards the pre-set destination.

Be sure to give it to your loved one with a nice note! I also included an instruction manual:

"Care and feeding:

Turn me on! My power switch is on the back left side.

A red light means that I'm awake, but don't know where I am yet. I need to get my bearings. Put me in a window or someplace where I can see the sky. (Please don't put me on metal stuff - I hate metal. I also like to lay flat. I'm more comfortable that way.)

Once I'm settled and happy, my light will turn green.

Now I'm ready: as long as my green light is on, I'll always point towards [NAME OF DESTINATION]. It's a special place for you, and I want to show you how to get back there. Wherever you are in the world, I'll always show you the way."

Step 8: UPDATE: Version 2.0

A few years after making this, I decided to revisit it and build another one for a friend's wedding. While searching for ways to update it, I found Dan The Geek's website—to my amazement, he improved the original, and reworked the code to make building it a snap. Check him out at the link above!


Also: Special shout-out to my friends at PCBway, who sponsored some custom boards to get a brand-new 2.0 version up and running! Check out the demo video here: