Arduino Digital Compass Project

Introduction: Arduino Digital Compass Project

About: Founder and Author of, an education website in the area of Mechanical, Electrical and Computer Engineering. Tutorials, Tips, Tricks, How It Works, Projects, Examples, Source Codes, ...

Hello! In this instructable you will see how you can make a Digital Compass using an Arduino and the Processing IDE. This is quite simple but interesting and cool looking Arduino Project.

You can watch the demo example of this tutorial on the video above. You can always find more interesting videos like this on my YouTube channel as well as find a lot of electronics projects and tutorials on my website,

Step 1: Parts Required

For this project you will need just an Arduino Board and a MEMS Magnetometer, for measuring the earth magnetic field. I will use the GY – 80 breakout board which contains the MC5883L 3 – Axis Magnetometer.

Before we continue with the source code for the project If you need more details how the MEMS magnetometer works as well as how to connect and use the GY - 80 breakout board via the I2C Communication you can check my particular tutorials for that.

Step 2: Arduino Source Code

What we need to do first is to upload a sketch to the Arduino Board that will read the data from the magnetometer and it will send it to the Processing IDE. Here's the Arduino Source Code:

<p>/*   Arduino Compass <br> *      
 *  by Dejan Nedelkovski, 
* */</p><p>#include <wire.h> //I2C Arduino Library</wire.h></p><p>#define Magnetometer_mX0 0x03 #define Magnetometer_mX1 0x04 #define Magnetometer_mZ0 0x05 #define Magnetometer_mZ1 0x06 #define Magnetometer_mY0 0x07 #define Magnetometer_mY1 0x08 </p><p>int mX0, mX1, mX_out; int mY0, mY1, mY_out; int mZ0, mZ1, mZ_out;</p><p>float heading, headingDegrees, headingFiltered, declination;</p><p>float Xm,Ym,Zm;</p><p>#define Magnetometer 0x1E //I2C 7bit address of HMC5883</p><p>void setup(){ //Initialize Serial and I2C communications Serial.begin(115200); Wire.begin(); delay(100); Wire.beginTransmission(Magnetometer); Wire.write(0x02); // Select mode register Wire.write(0x00); // Continuous measurement mode Wire.endTransmission(); }</p><p>void loop(){ //---- X-Axis Wire.beginTransmission(Magnetometer); // transmit to device Wire.write(Magnetometer_mX1); Wire.endTransmission(); Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mX0 =; } Wire.beginTransmission(Magnetometer); // transmit to device Wire.write(Magnetometer_mX0); Wire.endTransmission(); Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mX1 =; }</p><p> //---- Y-Axis Wire.beginTransmission(Magnetometer); // transmit to device Wire.write(Magnetometer_mY1); Wire.endTransmission(); Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mY0 =; } Wire.beginTransmission(Magnetometer); // transmit to device Wire.write(Magnetometer_mY0); Wire.endTransmission(); Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mY1 =; } //---- Z-Axis Wire.beginTransmission(Magnetometer); // transmit to device Wire.write(Magnetometer_mZ1); Wire.endTransmission(); Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mZ0 =; } Wire.beginTransmission(Magnetometer); // transmit to device Wire.write(Magnetometer_mZ0); Wire.endTransmission(); Wire.requestFrom(Magnetometer,1); if(Wire.available()<=1) { mZ1 =; } //---- X-Axis mX1=mX1<<8; mX_out =mX0+mX1; // Raw data // From the datasheet: 0.92 mG/digit Xm = mX_out*0.00092; // Gauss unit //* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.</p><p> //---- Y-Axis mY1=mY1<<8; mY_out =mY0+mY1; Ym = mY_out*0.00092;</p><p> //---- Z-Axis mZ1=mZ1<<8; mZ_out =mZ0+mZ1; Zm = mZ_out*0.00092; // ============================== //Calculating Heading heading = atan2(Ym, Xm); // Correcting the heading with the declination angle depending on your location // You can find your declination angle at: // At my location it's 4.2 degrees => 0.073 rad declination = 0.073; heading += declination; // Correcting when signs are reveresed if(heading <0) heading += 2*PI;</p><p> // Correcting due to the addition of the declination angle if(heading > 2*PI)heading -= 2*PI;</p><p> headingDegrees = heading * 180/PI; // The heading in Degrees unit</p><p> // Smoothing the output angle / Low pass filter headingFiltered = headingFiltered*0.85 + headingDegrees*0.15;</p><p> //Sending the heading value through the Serial Port to Processing IDE Serial.println(headingFiltered);</p><p> delay(50); }</p>

Step 3: Processing IDE Source Code

After we have uploaded the previous Arduino sketch we need to receive the data into the Processing IDE and draw the Digital Compass. The compass is composed of an background image, fixed image of the arrow, and an rotating image of the body of the compass. So the values for the eart magnetic field calculated with the Arduino are used to rotate the compass.

Here's the source code of the Processing IDE:

<p>/*   Arduino Compass <br> *      
 *  by Dejan Nedelkovski, 
 *  <a href=""> <a href="" rel="nofollow">
import processing.serial.*;
import java.awt.event.KeyEvent;
import;</p><p>Serial myPort;
PImage imgCompass;
PImage imgCompassArrow;
PImage background;</p><p>String data="";
float heading;</p><p>void setup() {
  size (1920, 1080, P3D);
  imgCompass = loadImage("Compass.png");
  imgCompassArrow = loadImage("CompassArrow.png");
  background = loadImage("Background.png");
  myPort = new Serial(this, "COM4", 115200); // starts the serial communication
}</p><p>void draw() {
  image(background,0, 0); // Loads the Background image
  translate(width/2, height/2, 0); // Translates the coordinate system into the center of the screen, so that the rotation happen right in the center
  rotateZ(radians(-heading)); // Rotates the Compass around Z - Axis 
  image(imgCompass, -960, -540); // Loads the Compass image and as the coordinate system is relocated we need need to set the image at -960x, -540y (half the screen size)
  popMatrix(); // Brings coordinate system is back to the original position 0,0,0
  image(imgCompassArrow,0, 0); // Loads the CompassArrow image which is not affected by the rotateZ() function because of the popMatrix() function
  text("Heading: " + heading,40,40); // Prints the value of the heading on the screen</p><p>  delay(40);
}</p><p>// starts reading data from the Serial Port
 void serialEvent (Serial myPort) { 
   data = myPort.readStringUntil('\n');// reads the data from the Serial Port and puts it into the String variable "data".
  heading = float(data); // Convering the the String value into Float value

I hope you will like this project. If it's so you can also visit my website for more cool projects.

Be the First to Share


    • Puzzles Speed Challenge

      Puzzles Speed Challenge
    • "Can't Touch This" Family Contest

      "Can't Touch This" Family Contest
    • CNC Contest 2020

      CNC Contest 2020

    2 Discussions


    3 years ago

    Greetings Mr. Nedelkocski. I first found your project on your web site, and found this Instructable while doing searches for "import" as I'm having problems with the Java imports (I "think" these are libraries.):

    import java.awt.event.KeyEvent;


    I've done a fair amount of research and I believe the issue is that, for what ever reason, some of us simply don't have a "Java" library. My IDE is the is the most current 1.8.2 as of this date.

    Obviously because of the success of others, including Pierre on who was successful with 60 students, the question is "Why don't some of us have the Java library?"

    I have tried many searches on three different search engines and can not find this library mentioned anywhere other than in your code. I've uninstalled the Arduino IDE, then loaded the Java IDE and then reloaded the Arduino IDE to see if the Java would be picked by by the Arduino IDE without success. Do you have a record of what IDE you used and on what operating system? I would really like to solve this mystery and maybe I need to start with that IDE.. Perhaps the issue is in the English IDE?

    Thank you in advance for your time.



    4 years ago

    This is really cool! I've always been intrigued by digital compasses.