Last active
October 11, 2022 23:22
-
-
Save DaAwesomeP/4e7a8f56e25d2cd9694c to your computer and use it in GitHub Desktop.
DIY Digital Compass Sketch (for your car) http://www.instructables.com/id/DIY-Digital-Compass-for-your-car
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
Compass.ino | |
For the project here: http://www.instructables.com/id/DIY-Digital-Compass-for-your-car | |
Originally Created: August 10, 2015 | |
Written by Perry Naseck (https://perrynaseck.com/) | |
Dependencies: | |
- Cardinal (in Library Manager and at https://github.com/DaAwesomeP/arduino-cardinal ) | |
- Sparkfun Micro OLED Breakout (in Library Manager and at https://github.com/sparkfun/SparkFun_Micro_OLED_Arduino_Library ) | |
- Wire (included with IDE) | |
- SPI (included with IDE) | |
This sketch interfaces with the HMC5883 magentometer of I2C, converts degrees | |
to a heading with Cardinal, and then outputs the heading on the Sparkfun | |
Micro OLED screen. | |
Copyright 2015-present Perry Naseck (DaAwesomeP) | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
******************************************************************************/ | |
#include <Wire.h> // I2C Arduino Library for the sensor | |
#include <SPI.h> // Include SPI if you're using SPI for the screen | |
#include <SFE_MicroOLED.h> // Include the SFE_MicroOLED library | |
#include <Cardinal.h> // Cardinal library | |
// ---------------------------------------------------------- | |
// | Configuration area (edit stuff below here) | | |
// ---------------------------------------------------------- | |
/* | |
Precision types (see https://github.com/DaAwesomeP/arduino-cardinal/wiki/Types | |
for more info): | |
0: N, S, E, W | |
1: N, NE, E, SE, S, SW, W, NW | |
2: N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW | |
3: all 32 headings (N, NbE, NNE, NEbN, NE, NEbE, etc.) | |
*/ | |
int type = 1; | |
/* | |
Your declination angle is an offset that depends on your location. To find | |
out yours, go to http://www.magnetic-declination.com/ | |
Convert the degrees to radians and use it below. | |
If you don't bother to adjust this, then your compass will be a little | |
bit off. Set it to 0.0 if you don't care. | |
*/ | |
float declinationAngle = 0.0; | |
/* | |
The floatingX and floatingY values determine the 3D orientation of | |
the sensor. Shift the following values through x, y, and z until | |
the compass gices an accurate change. Note that it may not | |
actually give the right reading at this point. The Rotation offset | |
will help with that. With this settings you are ensuring that the | |
compass changes properly when it is rotated on the correct axis. | |
The default values (x, y) assumes that the commpass is flat and | |
face up. Mine ended up being (x,z). | |
*/ | |
String floatingX = "x", | |
floatingY = "y"; | |
/* | |
The rotation offset will adjust the problem where the compass gives | |
the wrong reading when your device is facing a different direction. | |
You should change this in 90 degree increments until North is North, | |
etc. Test all four cardinal directions and not just one. I needed a | |
90 degree increase. | |
This field is in radians and not degrees (so don't use 90). I've | |
included some handy measurements here: | |
0 degrees = 0.0 radians | |
90 degrees = 1.57079633 radians | |
180 degrees = 3.14159265 radians (sound familiar?) | |
270 degrees = 4.71238898 radians | |
*/ | |
float rotationOffset = 0; | |
/* | |
If you follow the same design that I had, then you'll | |
need to flip the screen virtically and horizontally. | |
*/ | |
boolean flip = true; | |
/* | |
Precision of PI. You porbably don't need to change this. Don't overdo it. | |
*/ | |
float pi = 3.1415926535897932384626433832; | |
/* | |
Zombie Mode will launch when the direction changes | |
however many times in zmodeStartAfter. Set it to 0 | |
to disable it. It will last for however many direction | |
changes as set in zmodeLength. Set zmodeLength to 0 | |
to stay on permanently. Set zmodeOnStart to true for | |
zombie mode to start immeadietly at startup. | |
*/ | |
int zmodeStartAfter = 20, | |
zmodeLength = 5; | |
boolean zmodeOnStart = false; | |
/* | |
By uncommenting the follwing line, you will enable | |
DEVMODE, which turns off the display output and | |
enable Serial output of the sensor. | |
*/ | |
//#define DEVMODE 1 | |
// ---------------------------------------------------------- | |
// | You probably don't need to edit anything below here... | | |
// ---------------------------------------------------------- | |
Cardinal cardinal; // init the Cardinal library to "cardinal" | |
#define address 0x1E //0011110b, I2C 7bit address of HMC5883 | |
// MicroOLED Definition | |
#define PIN_RESET 9 // Connect RST to pin 9 | |
#define PIN_DC 8 // Connect DC to pin 8 | |
#define PIN_CS 10 // Connect CS to pin 10 | |
#define DC_JUMPER 0 | |
MicroOLED oled(PIN_RESET, PIN_DC, PIN_CS); // SPI declaration | |
void setup(){ | |
oled.begin(); // Initialize the OLED | |
oled.flipVertical(flip); | |
oled.flipHorizontal(flip); | |
oled.clear(ALL); // Clear the display's internal memory | |
oled.clear(PAGE); | |
oled.display(); // Display what's in the buffer (splashscreen) | |
//delay(1000); // Delay 1000 ms | |
// Initialize Serial and I2C communications | |
Serial.begin(9600); | |
Wire.begin(); | |
// Put the HMC5883 IC into the correct operating mode | |
Wire.beginTransmission(address); // open communication with HMC5883 | |
Wire.write(0x02); // select mode register | |
Wire.write(0x00); // continuous measurement mode | |
Wire.endTransmission(); | |
} | |
void loop(){ | |
float direction, directionDegrees; // Init the direction data | |
String dirString, // Init the direction string | |
dirStringPrev; | |
int x,y,z, // Init triple axis data | |
zmodeStartCount = 0, | |
zmodeCount = 0; | |
boolean zmodeOn = zmodeOnStart; | |
// Tell the HMC5883L where to begin reading data | |
Wire.beginTransmission(address); | |
Wire.write(0x03); // select register 3, X MSB register | |
Wire.endTransmission(); | |
// Read data from each axis, 2 registers per axis | |
Wire.requestFrom(address, 6); | |
if(6<=Wire.available()){ | |
x = Wire.read()<<8; // X msb | |
x |= Wire.read(); // X lsb | |
z = Wire.read()<<8; // Z msb | |
z |= Wire.read(); // Z lsb | |
y = Wire.read()<<8; // Y msb | |
y |= Wire.read(); // Y lsb | |
} | |
if (floatingX == "x" && floatingY == "y") | |
direction = atan2(y, x); | |
if (floatingX == "y" && floatingY == "x") | |
direction = atan2(x, y); | |
if (floatingX == "z" && floatingY == "y") | |
direction = atan2(y, z); | |
if (floatingX == "z" && floatingY == "x") | |
direction = atan2(x, z); | |
if (floatingX == "x" && floatingY == "z") | |
direction = atan2(z, x); | |
if (floatingX == "y" && floatingY == "z") | |
direction = atan2(z, y); | |
direction += declinationAngle + rotationOffset; | |
if(direction < 0) | |
direction += 2*pi; | |
// Check for wrap due to addition of declination and rotation offset; | |
if(direction > 2*pi) | |
direction -= 2*pi; | |
// Convert radians to degrees for readability. | |
directionDegrees = 360 - (direction * 180/pi); | |
dirString = cardinal.getString(type, directionDegrees); | |
#if defined(DEVMODE) | |
// Print out values of each axis with 4 decimal places(to Serial, not the screen) | |
Serial.print("x: "); | |
Serial.print(x, 4); // X | |
Serial.print(" y: "); | |
Serial.print(y, 4); // y | |
Serial.print(" z: "); | |
Serial.print(z, 4); // z | |
Serial.print(" dRad: "); | |
Serial.print(direction, 8); // direction in Radians | |
Serial.print(" dDeg: "); | |
Serial.print(directionDegrees, 8); // direction in Degrees | |
Serial.print(" dInt: "); | |
Serial.print(cardinal.getInteger(type, directionDegrees)); // heading integer (1, 2, 3, etc...) | |
Serial.print(" dStr: "); | |
Serial.println(dirString); // heading string (N, NE, E, etc...) | |
#else | |
if ((zmodeStartCount == zmodeStartAfter) || (zmodeOn && zmodeOnStart)) { | |
zmodeOn = true; | |
zmodeStartCount = 0; | |
zmodeOnStart = false; | |
zmodeStart(); | |
} | |
if (dirString != dirStringPrev && !zmodeOn) { | |
zmodeStartCount++; | |
} | |
if (zmodeCount <= zmodeLength && zmodeOn){ | |
zombieModeDirection(dirString); | |
zmodeCount++; | |
} | |
else { | |
if (zmodeCount > zmodeLength && zmodeLength != 0) { | |
zmodeCount = 0; | |
zmodeOn = false; | |
zmodeStop(); | |
} | |
clearScreen(); | |
if (dirString.length() > 2) { | |
oled.setFontType(1); // Use font size 1 | |
} | |
else { | |
oled.setFontType(4); // Use font size 4 | |
} | |
oled.print(dirString); // Get the heading string and put it on screen | |
oled.display(); // Write to the screen | |
} | |
dirStringPrev = dirString; | |
#endif | |
delay(250); // Delay of 250 ms to reduce sensitivity and allow screen and sensor to refresh | |
} | |
void zmodeStart() { | |
oled.setFontType(1); | |
int c = 0; | |
boolean d = true; | |
String str = "ZOMBIES FOUND"; | |
while (c < 4) { | |
clearScreen(); | |
oled.invert(d); | |
oled.print(str); | |
oled.display(); | |
delay(250); | |
c++; | |
d = !d; | |
if (c == 2) { str = "ZOMBIE\n MODE\nENABLED"; } | |
} | |
} | |
void zombieModeDirection(String zdir) { | |
oled.setFontType(1); | |
int c = 0; | |
boolean d = true; | |
while (c < 2) { | |
clearScreen(); | |
oled.invert(d); | |
oled.print("ZOMBIESHEADING"); | |
oled.display(); | |
delay(250); | |
c++; | |
d = !d; | |
} | |
oled.setFontType(4); | |
clearScreen(); | |
oled.print(zdir); | |
oled.display(); | |
} | |
void zmodeStop() { | |
oled.setFontType(1); | |
int c = 0; | |
boolean d = true; | |
String str = "ZOMBIES TOO\n CLOSE!"; | |
while (c < 4) { | |
clearScreen(); | |
oled.invert(d); | |
oled.print(str); | |
oled.display(); | |
delay(250); | |
c++; | |
d = !d; | |
if (c == 2) { str = "GOING OFF!"; } | |
} | |
} | |
void clearScreen() { | |
oled.clear(PAGE); | |
oled.setCursor(0, 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment