DIY digital compass

How to find your way?

We are going to build a DiY digital compass with the help of an Adafruit Neopixel LED ring and a HMC6352 compass module. Both are driven by an Arduino Uno

A standard Arduino Uno as microcontroller

Versatile microcontroller

This also runs on an Arduino Micro.

s

No support yet for ATtiny45/85

We are working on the support, but not yet finished.

Sparkfuns HMC6352 compass module

Digital compass module

This spark fun module is an inexpensive digital compass module.

I2C Bus

Uses the I2C Bus for easy access.

Adafruits Neopixel Ring

p

Digital compass module

12x WS2812 LEDs on a ring with controller
P

Bigger is better

Works also with the 16x and 60x NeoPixel ring. You only need to adjust the numbers of LED in the code.

The Code

#include <Wire.h>
#include <Adafruit_NeoPixel.h>

// Used Pins on the Arduino
#define PIN 6
#define SCL 5 // Analog A5
#define SDA 4 // Analog A4

// Configure NeoPixel ring of 12 Leds
#define LEDS 12
Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDS, PIN, NEO_GRB + NEO_KHZ800);

// Configure HMC6352 digital compass via I2C
int HMC6352ReadAddress = 0x41;
int HMC6352SlaveAddress = 0x42;

void setup(){
Serial.begin(9600);

// “The Wire library uses 7 bit addresses throughout.
// If you have a datasheet or sample code that uses 8 bit address,
// you’ll want to drop the low bit (i.e. shift the value one bit to the right),
// yielding an address between 0 and 127.”
// I know 0x42 is less than 127, but this is still required
HMC6352SlaveAddress = HMC6352SlaveAddress >> 1;
Wire.begin();

strip.begin();
strip.show(); // Initialize all pixels to ‘off’
theaterChase(strip.Color(32, 32, 32), 50);
}

void loop(){
// Get Data from digital compass
Wire.beginTransmission(HMC6352SlaveAddress);
Wire.write(HMC6352ReadAddress); // The “Get Data” command
Wire.endTransmission();

// Time delays required by HMC6352 upon receipt of the command
// “Get Data”. Compensate and calculate new heading : 6ms
delay(6);

// Get the two data bytes, MSB and LSB
Wire.requestFrom(HMC6352SlaveAddress, 2);

// The heading output data will be the value in tenths of degrees
// from zero to 3599 and provided in binary format over the two bytes.
byte MSB = Wire.read();
byte LSB = Wire.read();

float headingSum = (MSB << 8) + LSB; //(MSB / LSB sum)
float headingInt = headingSum / 10;

Serial.println(headingSum/10.0);

// Map heading to the LEDS length of led ring
// Find N(orth) and S(outh)
float minSweep = 0;
float sweepRange = LEDS – minSweep;
int N = (int)(sweepRange – (headingInt / 360 * sweepRange) + minSweep);
int S = N + (LEDS/2); S = ( S > LEDS ) ? S – LEDS : S;

// Display the red north and green south led dot on the ring
strip.setPixelColor(N,strip.Color(32,0,0));strip.show();
strip.setPixelColor(S,strip.Color(0,16,0));strip.show();
delay(6);
strip.setPixelColor(N,strip.Color(0,0,0));strip.show();
strip.setPixelColor(S,strip.Color(0,0,0));strip.show();
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();

delay(wait);

for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}

Have fun!