Human brain is built of complex layer of structures which helps us to be a dominant species on earth. For example the entorhinal cortex in your brain can give you sense of direction helping you to navigate easily through places that you are not familiar with. But unlike us, Robots and unmanned Ariel vehicles need something to get this sense of direction so they could manoeuvre autonomously in new terrains and landscapes. Different robots use different types of sensors to accomplish this, but the commonly used one is a magnetometer, which could inform the robot in which geo-graphic direction it is currently facing at. This will not only help the robot to sense direction but also to take turns in a pre-defined direction and angel.
Since the sensor could indicate the geo-graphic North, South, East and West, we humans could also use it at times when required. So in this article let us try to understand how Magnetometer sensor works and how to interface it with a microcontroller like Arduino. Here we will build a cool Digital Compass which will help us in finding the directions by glowing an LED pointing North Direction.
i made this project. following pictures describing my project.
- Arduino Pro mini
- HMC5883L Magnetometer sensor
- LED lights - 8Nos
- 470Ohm Resistor – 8Nos
- 2 pin connector
- veroboard
- female headers
- connecting wires
i am using HMC5883L megnetometer sensor,that is here.
before we dive into the circuit, let’s understand a bit about magnetometer and how they work. As the name suggests the term Magneto does not refer to that crazy mutant in marvel who could control metals by just playing piano in the air. Ohh! But I like that guy he is cool.
Magnetometer is actually a piece of equipment that could sense the magnetic poles of the earth and point the direction according to that. We all know that Earth is huge piece of spherical magnet with North Pole and South Pole. And there is magnetic field because of it. A Magnetometer senses this magnetic field and based on the direction of the magnetic field it can detect the direction we are facing.
How the HMC5883L Sensor Module Works
The HMC5883L being a magnetometer sensor does the same thing. It has the HMC5883L IC on it which is from Honeywell. This IC has 3 magneto-resistive materials inside which are arranged in the axes x, y and z. The amount of current flowing through these materials is sensitive to the earth’s magnetic field. So by measuring the change in current flowing through these materials we can detect the change in Earth’s magnetic field. Once the change is magnetic field is absorbed the values can then be sent to any embedded controller like a microcontroller or processor through the I2C protocol.
Since the sensor works by sensing the magnetic field, the output values will be greatly affected if a metal is placed nearby. This behavior can be leveraged to use these sensors as metal detectors also. Care should be taken not to bring magnets near this sensor since the strong magnetic field from a magnet might trigger false values on the sensor.
Difference between HMC5883L and QMC5883L
There is a common confusion revolving around these sensors for many beginners. This is because some vendors (actually most) sell the QMC5883L sensors instead of the original HMC5883L from Honeywell. It is mostly because the QMC5883L is way cheaper than the HMC5883L module. The sad part is that the working of these two sensors is slightly different and the same code cannot be used for both. This is because the I2C address of both the sensors is not the same. The code give in this tutorial will work only for QMC5883L the commonly available sensor module.
To know which model of sensor you are having, you just have to look up closely at the IC itself to read what is written on top of it. If it is written something like L883 then it is the HMC58836L and if it is written something like DA5883then it is the QMC5883L IC. Both the modules are shown in picture below for easy understating.
The circuit for this Arduino based Digital Compass is pretty simple, we simply have to interface the HMC5883L sensor with the Arduino and connect 8 LEDs to the GPIO pins of the Arduino Pro mini. The complete circuit diagram is shown below
The Sensor module has 5 pins out of which the DRDY (Data Ready) is not used in our project since we are operating the sensor in continuous mode. The Vcc and ground pin is used to power the Module with 5V from the Arduino board. The SCL and SDA are the I2C communication bus lines that are connected to the A4 and A5 I2C pins of the Arduino Pro mini respectively. Since the module itself has a pull high resistor on the lines, there is no need to add them externally.
To indicate the direction we have used 8 LEDs all of which are connected to the GPIO pins of the Arduino through a current limiting resistor of 470 Ohms. The Complete circuit is powered by a 9V battery through the barrel Jack. This 9V is provided directly to the Vin pin of the Arduino where it is regulated to 5V using the on-board regulator on Arduino. This 5V is then used to power the sensor and the Arduino as well.
Programming the Arduinoi have used arduino uno to programm arduino pro mini. we can use different programmer to programm arduino pro min. other explaination is here;
Now that our hardware is ready, let us look into the program that has to be uploaded into our Arduino board. The purpose of the code is to read the data from the QMC5883L magnetometer sensor and convert it into degree (0 to 360). Once we know the degree, we have to turn on a the LED pointing a specific direction. The direction I have used in this program is north. So irrespective of where you are there will only be one LED glowing on your board and the direction of the LED will indicate the NORTH direction. Once could later calculate the other direction is one direction is known.
The complete code for this Digital Compass Project can be found at the end of this page. You can directly upload it on your board after including the library and you are ready to go. But, if you want to know more on what is actually happening in the code read further.
As told earlier we are using the QMC5883L IC, to communicate with the IC we need to know the I2C address of its registers which can be found in its datasheet. But lucky for us all of that is already done and is packaged as a library by a guy called keepworking on Github. So all you have to do is simply download the Library for QMC5883L by clicking on the link to get a ZIP file. This ZIP file can then be added into your Arduino IDE by following Sketch -> Include Library -> Add .ZIP library.
After the Library is added, we can proceed with our program. We begin the program by including the required library files as shown below. The wire library is used to enable I2C communication and the MechaQMC5883 is the one that we just added to Arduino. This library holds all the information on how to talk with the EMC5883L sensor.
#include <Wire.h> //Wire Librarey for I2C communication#include <MechaQMC5883.h> //QMC5883 Librarey is added since mine is QMC583 and not HMC5883
In the next line, we create an object name for the sensor we are using. I have used the name qmc but it can be anything you like.
MechaQMC5883 qmc; //Create an object name for the snsor, I have named it as qmc
Next, we get into the global variable declarations. Here since we have 8 Led as outputs, it is hard to refer to each one through pin name, so we are using the array option to refer to all the LEDs. The name of the array is ledPins and the variable led_count is the number of led we have. It starts with 0.
int ledPins[] = {2,3,4,5,6,7,8,9}; //Array of output pin to which the LED is connected tochar led_count = 7; //Total number of LED pins
Inside the void setup function, we initialize the I2C communication, Serial communication and the sensor as well. Then we declare all the LED pins as output pins. Since we have used an array, it is easy to refer to all the pins by using a for loop and navigating through the for loop as shown below.
void setup() { Wire.begin(); //Begin I2C communication Serial.begin(9600); //Begin Serial Communication qmc.init(); //Initialise the QMC5883 Sensor for (int thisPin=0; thisPin <= led_count; thisPin++){ //Navigate through all the pins in array pinMode(ledPins[thisPin],OUTPUT); //Declare them as output }}
In the main loop which is an infinite one, we have to get the values of x,y and z from the sensor and calculate the degree the sensor is currently facing. To read the values of x,y and z use the following line
int x,y,z;qmc.read(&x,&y,&z); //Get the values of X,Y and Z from sensor
The formulae to calculate the heading in degree is shown below. Since we are not going to rotate the compass along the z axis we do not take that value into account. This formulae can be used only if the IC flat surface is facing up like it is in our set-up. Once heading is calculated, the value will be in range -180 to 180 which we have to convert to 0 to 360 like we would find in all digital compasses.
int heading=atan2(x, y)/0.0174532925; //Calculate the degree using X and Y parameters with this formulae //Convert result into 0 to 360 if(heading < 0) heading+=360; heading = 360-heading;
The final step is to glow the LED pointing in the NORTH direction. To do that we have series of if conditions statements where we check in what range the degree is currently in and turn on the LED according to that. The code is show below
//Based on the value of heading print the result for debugging and glow the respective LED. if (heading > 338 || heading < 22) { Serial.println("NORTH"); digitalWrite(ledPins[0],HIGH); } if (heading > 22 && heading < 68) { Serial.println("NORTH-EAST"); digitalWrite(ledPins[7],HIGH); } if (heading > 68 && heading < 113) { Serial.println("EAST"); digitalWrite(ledPins[6],HIGH); } if (heading > 113 && heading < 158) { Serial.println("SOUTH-EAST"); digitalWrite(ledPins[5],HIGH); } if (heading > 158 && heading < 203) { Serial.println("SOUTH"); digitalWrite(ledPins[4],HIGH); } if (heading > 203 && heading < 248) { Serial.println("SOTUH-WEST"); digitalWrite(ledPins[3],HIGH); } if (heading > 248 && heading < 293) { Serial.println("WEST"); digitalWrite(ledPins[2],HIGH); } if (heading > 293 && heading < 338) { Serial.println("NORTH-WEST"); digitalWrite(ledPins[1],HIGH); }
The logic behind the code values can be understood by looking at the table below. Basically we calculate which direction we are facing and predict the north direction and glow the respective LED.
DirectionDegree corresponding to DirectionRange for that DirectionNORTH0° / 360°>338° or < 22°NORTH-EAST45°22° to 68°EAST90°68° to 113°SOTUH-EAST135°113° to 158°SOUTH180°158° to 203°SOUTH-WEST225°203° to 248°WEST170°248° to 293°NORTH-WEST315°293° to 338°
The final part of the program is to set how fast the result has to be updated. I have create a delay for 500 milli seconds and then made all the LED to turn off to start again form the first inside the void loop. But if you need faster updates you can reduce the delay further down.
delay(500); // update position of LED for every alf seconds//Turn off the all the LED for (int thisPin=0; thisPin <= led_count; thisPin++){ digitalWrite(ledPins[thisPin],LOW); }
You can then play with the Board by rotating it and check if the LED still points to the north direction. After that you can use a 9V battery anytime to power the set-up and check the direction you are facing. The complete working of the Digital compass can be found in the video below.
the reference video is here
Comments