Introduction: Personal Compass
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:
- Mount the GPS chip on a piece of perfboard. I used thin wire to "tie" the whole thing down.
- Cut the JST cable that comes with the GPS in half.
- Carefully strip the bare ends of the JST cable, and pass the raw wire through the perfboard.
- Solder the exposed ends to 6-inch strips of hookup wire to create a breakout.
- 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.
Attachments
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:
14 Comments
Question 4 years ago
Hi! Is there a possibility to add a button for set new direction?
Answer 4 years ago
Yeah, I think that would be possible - you’d just have to put in code that refreshes the value of the lat/lon variables with your current coordinates. It’d just be a matter of assigning them whatever coordinates the GPS chip is spitting out at the time you press the button. Let me know if you try it - that’d be a cool feature to reset the box to a new location!
5 years ago
Hi, I've been trying to update the code so that it works with the current IDE version and have successfully received the required data from the GPS and Compass pins, and the code is also calculating the different variables such as bearing, etc accurately but the servo refuses to move. Is it possible to run the code using the default Servo.h library instead of the PWMServo or is there another fix for this?
Thanks
Reply 5 years ago
Good question - a lot of features that were driven by external libraries in the past have been incorporated into the new IDE. I would try using SoftwareServo.h (included now) instead of PWMservo... I think it was designed to play nicely with interrupts.
FYI, Arduino Playground notes that it might mess with the angular position of the servo a bit, so keep that in mind—depending on the gearing ratio you use for the compass needle, any difference will be amplified by at least 2x. It's still a pretty small effect, so maybe not a huge deal.
Other than this project, I don't have a lot of experience dealing with interrupts, so your milage may vary...
5 years ago
Has someone managed to update the code so that it works with the latest Arduino IDE?
Reply 5 years ago
Not to my knowledge - maybe you're that guy! Feel free to tweak the code however you'd like... would love to see what you come up with. At minimum, it would need the code changed to match the output of whatever digital compass and gps you're using. Also, you'd likely need to update all the libraries/calls to the latest versions in order to work with the latest IDE. That'd mean replacing all the "NewSoftSerial" calls with "SoftwareSerial", since it's now one of the built-in Arduino libraries, swapping the "PWMservo" library out for the latest build, and possibly replacing TinyGPS with the newer TinyGPS++ library as well.
http://arduiniana.org/libraries/newsoftserial/
http://arduiniana.org/libraries/tinygpsplus/
http://arduiniana.org/libraries/pwmservo/
Another option might be just downloading an older version of the IDE so all the existing code compiles!
5 years ago
that's a great project!!
Reply 5 years ago
Thanks! Glad you liked it.
6 years ago
Wow wasn't expecting this when I clicked on your tutorial. Awesome idea, very clean presentation too :)
Reply 6 years ago
Thanks! It was a blast making this - glad you enjoyed it!
6 years ago
Very cool! I love this idea!
Reply 6 years ago
Thanks! btw - saw your "perfect workbench" instructable the other day - fits all my criteria for a good bench as well. I may have to give it a try...
Reply 6 years ago
I'd love to see any pictures and feedback if you decide to make one yourself!
6 years ago
Nice idea. But I don't really need a compass pointing to the high school loos !