Make a Compass

By detecting Earth’s magnetic field, the SpinWheel can act as a compass. However, both an old-school compass with a magnetic needle and the magnetic sensor inside of the SpinWheel can be confused if you put them near a piece of iron. Here we will see how to write a program that corrects for this error, the same type of program that runs inside of smartphone apps when they give you directions.

Making a compass is done in a similar way to creating the tilt sensor. Be sure to check out the tilt sensor adventure before diving into the rest of this one.

To turn your SpinWheel into a compass, we will use the magnetic field vector components mx, my instead of the gravitational field ax, ay. This way, the SpinWheel’s display will point along the direction of Earth’s magnetic field, giving us an indication of which way is north and which way is south. This is analogous to how the tilt sensor showed us the direction of gravity, allowing us to determine whether or not a surface was flat.

However, instead of measuring only Earth’s magnetic field, the sensor will measure both Earth’s magnetic field, and the field created by objects near the sensor. This is a problem as other components near the SpinWheel’s magnetic sensor create additional magnetic fields. Using this total measured magnetic field would result in an imprecise compass, therefore we need to find a way to remove these extra magnetic fields, so that only Earth’s magnetic field remains.

Every smartphone manufacturer also faces this same problem. In addition to magnetic fields from various components inside of smartphones, temporary magnetization can also be caused by external objects, like keys kept in the same pocket. To correct for the magnetic fields caused by other nearby objects, pathfinding apps sometimes ask you to move your phone along a figure “8” to calibrate the sensors before they provide directions.

These extra magnetic fields are always present and will remain fixed with respect to the sensor. This means that even when we rotate the sensor, this component of the measured result will not change. However, such a rotation would cause Earth’s magnetic field to be oriented differently with respect to the sensor, causing the measurements to change along each axis of the sensor.

We can use this to our advantage! By rotating the device in complete circles, we can average out the Earth’s magnetic field leaving only the magnetic field caused by the device. Having this value saved, we can now subtract it from future measurements, thus leaving us only with the desired result: Earth’s magnetic field.

Below you can see a simulation of how these measurements may be taken. The SpinWheel rotates in space, taking constant measurements (each measurement is represented by a black dot). The magnetic field external to the SpinWheel caused by the Earth’s magnetic field, i.e. the red vector, is fixed. The extra magnetic field caused by the device itself, i.e. the smaller purple vector, rotates with the SpinWheel. Their sum, shown as the black vector in the second animation, is what the SpinWheel actually measures.

The magnetic fields with respect to an observer (i.e. your point of view)

The magnetic fields with respect to the SpinWheel (i.e. from the SpinWheel’s point of view):

Tilt back and forth:Tilt sideways:Rotate face:

The three axes of the SpinWheel are colored as X, Y, and Z. Also colored are the Earth’s magnetic field that we want to measure, the magnetic field caused by the SpinWheel’s metallic components, and the sum of these vectors, the total magnetic field that the SpinWheel’s sensor measures.

You can see that the cloud of measurements creates a sphere, but one not centered at the \((0,0,0)\) point. Instead, \((0,0,0)\) corresponds to the location of the magnetic field sensor on the SpinWheel, shown as the intersection of the three axes in the animation above. The center of this sphere is the tip of the purple vector, the magnetic field caused by the SpinWheel’s metallic components. If you are having trouble visualizing this, try rotating the sphere in the animation above until the orange vector points straight upwards. Below, we will introduce a procedure we can use to find the center of the sphere, or the extra magnetic field, and subtract it from all future measurements. In this way, we will just display the Earth’s magnetic field.

Reading magnetic field measurements from the SpinWheel

To begin, let’s perform some measurements with our SpinWheel. The code below, which can also be found in Examples → SpinWearables → Compass → Calibrate, will take direct measurements from the magnetic sensor and immediately send them back to your computer over your USB cable. When you upload this code, you will not see any LEDs light up on your SpinWheel. On your computer, you can use the Serial Plotter Arduino tool to observe how the magnetic field values change as you rotate the device.

If you want to refresh your memory about accessing Serial Plotter, then check out the Arduino 101 lesson. Reminder: you will see a single small LED light up in red when you use Serial Plotter or Serial Monitor.

#include "SpinWearables.h"
using namespace SpinWearables; 

void setup() {
// Ensure all of the SpinWheel hardware is on.
  SpinWheel.begin();
// Set up communication with the host computer.
  Serial.begin(9600);
}

void loop() {
// Read all sensor data.
  SpinWheel.readIMU();

// Measure the magnetic field along the three axes of the sensor.
  float x = SpinWheel.mx;
  float y = SpinWheel.my;
  float z = SpinWheel.mz;

// Report it back to the host computer.
  Serial.print(x);
  Serial.print("\t"); // Print a tab separator.
  Serial.print(y);
  Serial.print("\t"); // Print a tab separator.
  Serial.print(z);
  Serial.print("\n"); // Print a new line.
}

To visualize the cloud of points that this creates, you can also copy the data from your Serial Monitor into the text box below. Uncheck Autoscroll and Show timestamp to more easily copy and paste. The webpage will then regenerate the image based on the numbers that you provided. Currently, the text you see in the textbox contains real data we measured with one of the first SpinWheels we ever manufactured. If you rotate the plot (by dragging it), you can clearly see that the sphere of measurements is not at the center of the sphere of points. Instead, like you could see in the animation above, there is an offset that we have to correct for.

Compass with automatic calibration

Now, instead of recording all of this data and processing it in order to correct our magnetic field measurements, we can instruct the SpinWheel to continuously correct itself. Initially, such an automatic correction will be significantly off, but after a few minutes of playing with the device, it will have measured enough data in order to perform accurate corrections. This correction procedure is known as calibration.

The code below works by first storing the biggest and smallest measurements for each axis of the magnetic sensor. Then we use these maxima and minima to find the offset of the sphere along each axis and correct for it. You should see some of the small LEDs on your SpinWheel light up and point north. You can also find this code in Examples → SpinWearables → Compass → Calibrated_Compass.

#include "SpinWearables.h"
using namespace SpinWearables; 

void setup() {
// Ensure all of the SpinWheel hardware is on.
  SpinWheel.begin();
// Set up communication with the host computer.
  Serial.begin(9600);
}

float minx, miny, minz, maxx, maxy, maxz;

void loop() {
  // Read all sensor data.
  SpinWheel.readIMU();

  // Measure the magnetic field along the three axes of the sensor.
  float x = SpinWheel.mx;
  float y = SpinWheel.my;
  float z = SpinWheel.mz;

  if (x > maxx) maxx=x;
  if (y > maxy) maxy=y;
  if (z > maxz) maxz=z;
  if (x < minx) minx=x;
  if (y < miny) miny=y;
  if (z < minz) minz=z;

  float truex = x - (maxx+minx)/2;
  float truey = y - (maxy+miny)/2;
  float truez = z - (maxz+minz)/2;

  // Use this line if you want to skip the correction.
  //uint8_t angle = (-atan2(y, x)+3.1415/2)/2/3.1415*255;
  uint8_t angle = (-atan2(truey, truex)+3.1415/2)/2/3.1415*255;
  SpinWheel.setSmallLEDsPointer(angle, 800, 0xffffff);

  SpinWheel.drawFrame();
}

The main difference between the compass and tilt sensor are the lines in this style:

  if (x > maxx) maxx=x;
  if (y > maxy) maxy=y;

  float truex = x - (maxx+minx)/2;

Here we continuously update the maximal and minimal values ever measured, and then use them to correct the current measurement result.

As an extension, you can combine both the tilt and magnetic sensors. It is useful for a compass to have a tilt sensor, so that you can be sure that you are only measuring the horizontal component of Earth’s magnetic field. When you are using the SpinWheel as a compass, make sure to keep it level for best results!

Header image credit: Jack Hegarty

Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. © SpinWearables LLC (license and trademark details)