JM9 XRCU Tutorials 0.0.1a
Learn how to program XRCU
Loading...
Searching...
No Matches
Magnetometer: QMC5883L

A magnetometer is a sensor that measures magnetic fields. The Earth is like a giant, weak magnet. So a magnetometer can feel which way is north, just like the needle of a compass. That is why we often call it a compass (or "electronic compass").

In this chapter, we will use the QMC5883L magnetometer with XRCU. It measures the magnetic field in 3 directions, called the X, Y and Z axes. The X and Y arrows are printed on the module.

On the left is the front of the module, with the chip and the X, Y and Z arrows. On the right is the back, with the names of the pins.

Note
Many modules with this sensor are sold as "HMC5883L" or "GY-271", but have a QMC5883L chip on them. The 2 chips need different code. In this chapter, the program in checkpoint 10.1 tells you whether your module really has a QMC5883L.

Wiring to a T Port

The QMC5883L talks to XRCU using I2C, just like the MPU-6050 gyro. So we connect it to a T port.

The module has 5 pins: VCC, GND, SCL, SDA and DRDY. We only need the first 4:

QMC5883L pin Connect to XRCU
VCC 3V3
GND GND
SCL T1A
SDA T1B

Leave DRDY unconnected.

Warning
Always turn OFF XRCU before you connect or disconnect a sensor. SCL must go to the A pin, and SDA must go to the B pin.

XRCU has 3 connectors called T1, and they are joined together inside XRCU. I2C lets many sensors share the same 2 wires, as long as each sensor has its own address (a number, like a house number). The QMC5883L and the MPU-6050 have different addresses. So you can plug the gyro into one T1 connector and the compass into another, and use both at the same time!

Just like the gyro, stick the module flat onto a book or a piece of cardboard, with the chip facing up.

Is the Compass There?

First, include the Qmc5883l library, and create a compass on port T1:

#include <Qmc5883l.h>
// Make a compass called compass, on port T1.
Qmc5883l compass(T1);

compass.is_mag_present() gives true if XRCU finds a QMC5883L on the port. (mag is short for magnetometer.)

#include <Qmc5883l.h>
// Make a compass called compass, on port T1.
Qmc5883l compass(T1);
void setup() {
Serial.begin(9600);
}
void loop() {
// Ask: is there a QMC5883L on port T1?
if (compass.is_mag_present()) {
Serial.println("Compass detected!");
} else {
Serial.println("Compass not present! Check the wires!");
}
delay(500);
}

Checkpoint 10.1

Turn OFF XRCU. Connect your compass module to port T1 as shown above. Turn ON XRCU, then upload the code above and run it. Open the serial monitor. Do you see Compass detected!?

If you have a gyro, turn OFF XRCU and plug it into another T1 connector too. Turn ON XRCU. Is the compass still detected?

Record a video showing the wires and the serial monitor. Submit this video to your assignment portal at checkpoint 10.1.

Feeling the Magnetic Field

Let's see what the sensor really measures. We start the compass with begin() in setup(). In loop(), update() asks the sensor for a new measurement. Then we read the strength of the magnetic field along each axis:

Code What it gives
compass.update() Get a new measurement from the sensor.
compass.get_uT_x() Strength of the magnetic field along the X axis.
compass.get_uT_y() Strength of the magnetic field along the Y axis.
compass.get_uT_z() Strength of the magnetic field along the Z axis.

The strength is measured in microtesla. In the code, we write it as uT. The Earth's magnetic field in Hong Kong is about 45 microtesla. That is very weak! A fridge magnet is hundreds of times stronger.

#include <Qmc5883l.h>
// Make a compass called compass, on port T1.
Qmc5883l compass(T1);
void setup() {
Serial.begin(9600);
// Start the compass.
compass.begin();
}
void loop() {
// Get a new measurement from the sensor.
compass.update();
// Print the field strength along the 3 axes, in microtesla.
Serial.print("x: ");
Serial.print(compass.get_uT_x());
Serial.print(" y: ");
Serial.print(compass.get_uT_y());
Serial.print(" z: ");
Serial.println(compass.get_uT_z());
delay(100);
}

Checkpoint 10.2

Upload the code above and run it. Open the serial monitor.

  1. Keep the compass flat, and turn it slowly in a full circle. How do the x and y numbers change?
  2. Slowly bring each of these things close to the compass, one by one: a steel ruler or scissors, a phone, and a magnet (or a motor). How close does each one need to be before the numbers change a lot?

Record a video showing the compass, the objects and the serial monitor. Submit this video to your assignment portal at checkpoint 10.2.

Calibration

In checkpoint 10.2, did the numbers go around a circle in the middle, like -40 to 40? Probably not! The circle is usually shifted, for example from 10 to 90. This is because the module, the wires and your robot have their own little bits of magnet and iron. They turn together with the compass, so they add the same shift in every direction.

Calibration finds this shift and removes it. During calibration, you turn the compass in full circles. XRCU remembers the biggest and the smallest numbers on each axis, and uses them to find the middle of the circle.

Code What it does
compass.compass_cal() Calibrate. Keep turning the compass while it runs!
compass.save_caled_vals() Save the calibration inside XRCU.

Like the gyro, compass.begin() loads the saved calibration automatically every time your program starts.

compass_cal() keeps measuring while you turn the compass. It stops by itself when the numbers have not grown bigger or smaller for 5 seconds. So turn the compass slowly for 2 or 3 full circles, then hold it still and wait.

Warning
Calibrate the compass where you will use it, after it is fixed onto your robot. Calibration only removes magnets and iron that turn together with the compass, like the robot's motors, battery and screws. It cannot remove things that stay in the room, like steel table legs.

Here is a program that uses SW1 to start the calibration:

#include <Qmc5883l.h>
#include <Buttons.h>
// Make a compass called compass, on port T1.
Qmc5883l compass(T1);
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
// Start the compass.
compass.begin();
// Step 1: Click SW1 to start.
// This while loop waits until SW1 is clicked.
while (!button1.isClicked()) {}
// Step 2: Turn the compass flat, slowly, for 2 or 3 full circles.
// Then hold it still. The LED is ON during calibration.
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("Calibrating... Keep turning!");
compass.compass_cal();
// Step 3: Save the calibration inside XRCU.
compass.save_caled_vals();
digitalWrite(LED_BUILTIN, LOW);
Serial.println("Done!");
}
void loop() {
// Nothing to do here.
}

Checkpoint 10.3

Upload the calibration program above and run it.

  1. Click SW1. The LED turns ON.
  2. Keep the compass flat, and turn it slowly for 2 or 3 full circles.
  3. Hold it still, and wait until the LED turns OFF and the serial monitor shows Done!.

How long did you wait after you stopped turning?

Record a video showing the compass, the LED and the serial monitor during calibration. Submit this video to your assignment portal at checkpoint 10.3.

Reading the Heading

Heading means the way you are facing. compass.get_heading() gives the heading in degrees, from 0 to 359. It is a whole number, so we keep it in an int variable.

#include <Qmc5883l.h>
// Make a compass called compass, on port T1.
Qmc5883l compass(T1);
void setup() {
Serial.begin(9600);
// Start the compass. This also loads the saved calibration.
compass.begin();
}
void loop() {
// Read the heading in degrees, from 0 to 359.
int heading = compass.get_heading();
Serial.println(heading);
delay(100);
}

Heading 0 means the X arrow on the module points to magnetic north. Just like the gyro's yaw, the heading goes up when you turn the compass clockwise (to the right), and goes back to 0 after 359.

Remarks
To check your compass, use the compass app on a phone to find north. But keep the phone at least 30 cm away from your compass module! In checkpoint 10.2, you saw how a phone can disturb the sensor.

Setting a New Zero

On a robot, we usually do not care where north is. We care about where the robot should face, like the opponent's goal. Just like the gyro, compass.reset_heading() makes the way the compass faces now the new zero.

There is one big difference. The compass knows where north is, so it can remember your zero even after you turn XRCU OFF! compass.save_re_zero_heading() saves your zero inside XRCU, and compass.begin() loads it every time your program starts.

// Make the way we face now the new zero.
compass.reset_heading();
// Remember this zero inside XRCU, even after we turn XRCU OFF.
compass.save_re_zero_heading();
Warning
Only save when a button is clicked, never every time loop() runs. Saving many thousands of times can wear out the memory inside XRCU.

Checkpoint 10.4

Change the program above, so that clicking SW1 sets a new zero and saves it. (Hint: use button1.isClicked() from the Buttons chapter.)

Upload and run it.

  1. Point the compass at a door or a window, and click SW1. The heading becomes about 0.
  2. Turn the compass by a quarter turn to the right. Is the heading about 90?
  3. Turn XRCU OFF and ON again, then point the compass at the same door or window. Is the heading still about 0?

Record a video showing the compass and the serial monitor during all 3 steps. Submit this video to your assignment portal at checkpoint 10.4.

Compass or Gyro?

Both the compass and the gyro can tell your robot which way it is facing. So which one should you use? Each one has its own strengths and weaknesses:

Compass (magnetometer) Gyro (gyroscope)
Knows where north is Yes No. It starts from 0 every time.
Remembers the zero after you turn XRCU OFF Yes No. You must set the zero again.
Drifts slowly over time No Yes, a little, even after calibration.
Disturbed by magnets, motors and steel Yes, a lot No
Must be calibrated again in a new place Yes No
Gives the same result everywhere No Yes
Must be kept flat Yes No
Measures pitch and roll No Yes

Today, most robotics competition teams use a gyro. Here is why:

  • Robots are full of magnets. Every motor has strong magnets inside, and the wires to the motors carry big electric currents, which also make magnetic fields. When the motors speed up, the compass reading can jump.
  • Competition halls are full of steel. Steel table legs, steel floors, and steel bars hidden inside concrete floors all bend the Earth's magnetic field. There may also be steel pipes, steel beams and big electric cables hidden under the floor or inside the walls. You cannot see them, and you cannot move them away! The compass may say one heading in one corner of the field and another heading in the other corner. You cannot calibrate this away, because the steel does not turn with your robot.
  • You cannot test at home. Your compass may work perfectly in your classroom, then fail in the competition hall.
  • A gyro's drift is small enough. A match only lasts a few minutes. After calibration, a good gyro drifts by only a few degrees in that time. You can also set the zero again with reset_heading() between matches.

So a gyro gives the same result anywhere, while a compass depends on the place. For a robot, "the same everywhere" is usually more important than "knows where north is".

Checkpoint 10.5

This checkpoint needs the MPU-6050 gyro from the Gyroscope chapter. Make sure the gyro is calibrated first (checkpoint 9.2).

Turn OFF XRCU. Plug the compass and the gyro into 2 different T1 connectors. Stick both modules flat onto the same book, side by side.

Write a program that:

  1. Uses both Qmc5883l compass(T1); and Mpu_6050_dmp gyro(T1);.
  2. Makes the way both sensors face now the new zero when SW1 is clicked (you do not need to save it).
  3. Prints the compass heading and the gyro yaw on the same line.

Upload and run it. Click SW1, then try these tests:

  1. Turn the book by a quarter turn to the right. Do both sensors show about 90?
  2. Bring a magnet (or a motor) close to the book, and then take it away. Which sensor changes? Which sensor does not?
  3. Slide the book slowly to a steel table leg or a steel cabinet, without turning it. Which sensor changes?

Record a video showing the book, the magnet and the serial monitor during all 3 tests. Submit this video to your assignment portal at checkpoint 10.5.

Summary

Code What it does
#include <Qmc5883l.h> Lets us use Qmc5883l.
Qmc5883l compass(T1); Makes a compass called compass on port T1. Write it above setup().
compass.is_mag_present() true if XRCU finds a QMC5883L, false if not.
compass.begin() Starts the compass, with the saved calibration and zero. Call it in setup().
compass.update() Gets a new measurement for get_uT_x(), get_uT_y() and get_uT_z().
compass.get_uT_x() Field strength along the X axis, in microtesla. Also get_uT_y() and get_uT_z().
compass.compass_cal() Calibrates. Turn the compass in full circles, then hold it still.
compass.save_caled_vals() Saves the calibration inside XRCU.
compass.get_heading() Heading in degrees, from 0 to 359. Turning right makes it go up.
compass.reset_heading() Makes the way the compass faces now the new zero.
compass.save_re_zero_heading() Saves the zero inside XRCU. Only call it when a button is clicked!

Remember:

  • The compass and the gyro can share the T1 connectors.
  • Calibrate the compass after it is fixed onto your robot, in the place where you will use it.
  • Keep the compass flat, and far away from motors, magnets and steel.
  • Most teams use a gyro, because it gives the same result everywhere.