I just got a MMC5603 magnetometer from Adafruit. However the measurements are unreliable. For example when I convert it to a heading it goes from 200° to 180° and then back to 200° if I move it radially.
2 Answers
To calibrate a magnetometer you should perform hard-iron and soft-iron calibration. There's some guides online about how to do this but I found this digikey guide to be the most informative. Adafruit also has a guide here
I had some issues getting this to work however so here's some tricks
Using an M1 macbook
Both guides recommend to use MotionCal but it hasn't been updated in several years. If you downloaded the macOS version it might not show any available ports. To fix this you need to compile it from source – you can find details in this Github Issue but the TL;DR is:
git clone git@github.com:PaulStoffregen/MotionCal.gitbrew install wxwidgets- Open the
Makefile - Comment the line
OS = LINUX - Uncomment the line
OS = MACOSX_CLANG - Under
else ifeq ($(OS), MACOSX)add-arch arm64to theCFLAGS - Run
makeand it should build
I had some issues with it not building after this which was resolved by deleting the directory and then redoing these steps
Using an Arduino UNO
Both guides say to use Adafruit Sensor Lab which is too large to fit onto an Arduino UNO's flash. Instead you can you use this code:
#include <Arduino.h>
#include <Adafruit_MMC56x3.h>
/* Assign a unique ID to this sensor at the same time */
Adafruit_MMC5603 mmc = Adafruit_MMC5603(12345);
int loopcount = 0;
// Hard-iron calibration settings
const float hard_iron[3] = {
0, 0, 0
};
// Soft-iron calibration settings
const float soft_iron[3][3] = {
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
void setup(void)
{
Serial.begin(115200);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit_MMC5603 Magnetometer Test");
Serial.println("");
/* Initialise the sensor */
if (!mmc.begin(MMC56X3_DEFAULT_ADDRESS, &Wire)) { // I2C mode
/* There was a problem detecting the MMC5603 ... check your connections */
Serial.println("Ooops, no MMC5603 detected ... Check your wiring!");
while (1)
delay(10);
}
/* Display some basic information on this sensor */
mmc.printSensorDetails();
}
void loop(void)
{
static float hi_cal[3];
// Get a new sensor event
sensors_event_t event;
mmc.getEvent(&event);
// Put raw magnetometer readings into an array
float mag_data[] = { event.magnetic.x,
event.magnetic.y,
event.magnetic.z };
// Apply hard-iron offsets
for (uint8_t i = 0; i < 3; i++) {
hi_cal[i] = mag_data[i] - hard_iron[i];
}
// Apply soft-iron scaling
for (uint8_t i = 0; i < 3; i++) {
mag_data[i] = (soft_iron[i][0] * hi_cal[0]) + (soft_iron[i][1] * hi_cal[1]) + (soft_iron[i][2] * hi_cal[2]);
}
// 'Raw' values to match expectation of MOtionCal
Serial.print("Raw:");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(int(mag_data[0] * 10));
Serial.print(",");
Serial.print(int(mag_data[1] * 10));
Serial.print(",");
Serial.print(int(mag_data[2] * 10));
Serial.println("");
// unified data
Serial.print("Uni:");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(0);
Serial.print(",");
Serial.print(mag_data[0]);
Serial.print(",");
Serial.print(mag_data[1]);
Serial.print(",");
Serial.print(mag_data[2]);
Serial.println("");
delay(10);
}
which will output the magnetometer data correctly formatted at the correct baud rate. Then you just open up MotionCal, select the right port
- 179
- 2
- 12
Richard's answer above (I'm not able to comment on his post due to 0 reputation) was very helpful since I had the same "blank ports" issue, but I needed to do a few things differently to get MotionCal to compile on an M1 pro.
- In addition to steps 4 and 5, I also needed to add "-std=c++11" to CXXFLAGS in the makefile under MACOSX_CLANG
- For step 6, the "-arch arm64" flag I think is supposed to be added to CFLAGS under "else ifeq ($(OS), MACOSX_CLANG)", not under else ifeq ($(OS), MACOSX) based on the OS setting uncommented.
- I also used "brew install llvm" to update clang. Not sure whether this was necessary or helpful.
- Even after the above, when running the make command, there is an error message stating "make: pjrcmacsigntool: No such file or directory make: [MotionCal.app] Error 1 (ignored)" which at this time I think can safely be ignored since the app appears to open and display ports as expected.
- 9
- 2