Getting Started with a Digital Compass for Arduino Robot Navigation

Navigation is a huge topic in robotics, and there are so many things we can consider. For example, you want your robot to turn from a given angle, or go in a straight line. One component that is very helpful in robot navigation is a digital compass. This component measures the orientation of the robot compared to the Earth magnetic field. We can for example use it to determine the angular orientation of the robot at any given point in time.

In this article, we will use this kind of component on an Arduino-based robot. We will use a digital compass to precisely make the robot turn of a given angle. Of course, the principles you will learn in this article can be used in several other situations, for example to make your robot move in a straight line. Let’s dive in!

Hardware & Software Requirements

There are many Arduino-compatible robot chassis out there that we could use for a line following project, but for this project I decided to simplify things and use the latest version of the DFRobot MiniQ 2 wheels robot chassis. This chassis already comes with an onboard Arduino system, so out of the box you can make the robot move around without any other components required.

This chassis also has many sensors on board, and especially what we are interested in here is that there is already a digital compass onboard: the HMC5883 3-axis digital compass. This is the one we will be using in this project.

However, if your robot chassis doesn’t have an onboard compass, no worries: there are many external components you can use for that. For example, I recommend using the LSM303 accelerometer + compass chip. Adafruit made a nice breakout board for this chip:

The only other thing that you will need is a set of 4 AA batteries to power the robot. I chose a set of 4 AA rechargeable batteries for this project.

This is the list of all the components that were used in this article:

You will also need some Arduino libraries for this project:

To install a library, simply put the library folder into your /libraries folder of your main Arduino folder.

Hardware Configuration

The hardware configuration for this project is really simple if you are using the DFRobot MiniQ 2 wheels v2.0 robot chassis: basically all you need to do is to plug the batteries into the chassis and you are done. This is the compass chip that we will be using in this project:

If you are using an external digital compass for this project, refer to the datasheet of your sensor to know how to wire it to the Arduino microcontroller.

Writing the Code

We are now going to write the code for our project. Note that the code will be slightly different if you are using another compass than the HMC5883 chip, but the principles are the same. Usually other digital compass chips also use the I2C bus, so the code will be nearly the same as for the HMC5883 chip.

It starts by importing the correct libraries:

#include 

Then, we create an instance of the HMC5883 sensor:

Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);

After that, we define the pins on which the motors are connected. Note that this can vary depending on your robot chassis:

#define EN1 5 // Pin for run the left motor 
#define IN1 12 // Pin for control left motor direction
#define EN2 6 // Pin for run the right motor 
#define IN2 7 // Pin for control right motor direction

We also need to define some variable for the function we will use to make our robot turn:

float initial_heading;
float target_heading;
float diff_heading;
bool turn_init;
bool target_reached;

We also define some shortcuts for the left or right directions:

#define LEFT 0
#define RIGHT 1

In the setup() function, we define the motor pins as outputs:

pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(12,OUTPUT);

We also initialise the digital compass:

if(!mag.begin()) {
    /* There was a problem detecting the HMC5883 ... check your connections */
    Serial.println("Ooops, no HMC5883 detected ... Check your wiring!");
    while(1);
}

Still in the setup() function, we need to initialise the variables to make the robot turn, as we didn’t move the robot yet:

turn_init = false;
target_reached = false;

Now, in the loop() part of the robot, I used the push buttons on the robot to make the robot perform a 90 degrees turn (left or right):

int key_value = analogRead(A6);
  
// KEY1
if (key_value > 130 && key_value < 140) {
  turn(90, RIGHT);
}
 
// KEY2
if (key_value > 570 && key_value < 580) {
  turn(90, LEFT);
}

Of course, if your robot chassis doesn’t have such buttons, you can simply hard-code the behaviour into the code, for example to make the robot turn left, turn right, and then stop.

We are now going to see the details of this turn(angle, direction) function that we use to make the robot turn from a given angle using the digital compass. It starts by getting the initial heading of the robot, and calculating to which angle we want to turn:

// Get initial heading
  if (!turn_init) {
    Serial.println("Starting turn ...");
    initial_heading = get_heading();
    
    if (turn_direction) {
      target_heading = initial_heading + angle;
    }
    else {
      target_heading = initial_heading - angle;
    }
    
    Serial.print("Initial heading: ");
    Serial.println(initial_heading);
    Serial.print("Target heading: ");
    Serial.println(target_heading);
    
    turn_init = true;
    target_reached = false;
    diff_heading = 0;
  }

Then, we continuously make the robot turn by small intervals, and check if the target heading as been reached. This is done by the following piece of code:

while (diff_heading > 0 && !target_reached) {
    
    // Move & stop
    if (turn_direction) {
      right(50);
    }
    else {
      left(50);
    }
    delay(100);
    right(0);
    delay(100);
    
    // Measure heading again
    float heading = get_heading();
    
    // Calculate heading difference
    if (turn_direction) {
      diff_heading = target_heading - heading;
    }
    else {
      diff_heading = heading - target_heading;
    }
    Serial.print("Difference heading (degrees): "); Serial.println(diff_heading);
    
    // Target reached ?
    if (diff_heading < 0 && !target_reached) {
      target_reached = true;
      turn_init = false;
      diff_heading = 0;
    }
  }

Note that you can find all the code inside the corresponding GitHub repository:

https://github.com/openhardwaredrones/arduino-robot-compass

Testing the Project

It’s now time to finally test the project! Upload the code to your robot via the Arduino IDE, and then disconnect the USB cable. If you chose to test the behaviour of the robot like I did in this project (via the push of a button), you can just put the robot on a flat surface.

Then, press a button: you should see that the robot is turning from approximately 90 degrees, step by step, and then stopping. You can do the same by testing the behaviour of the robot when turning in the other direction.

How to Go Further

In this article, we used a digital compass to precisely control the movement of a small 2 wheeled Arduino-based robot. We implemented a simple behavior using this digital compass: making the robot turn on itself by a given angle.

Of course, there are many other things you can do based on this project. You can for example modify the code to improve the behaviour of the robot. You can use the digital compass to implement other kind of movements, for example always moving in a straight line.

What about you, already used a digital compass for the navigation of a mobile robot? What behaviours did you build with it? Share in the comments!