Hello everyone, the Forum has changed some since I was last here, so if this in the wrong section, feel free to move it or let me know.
Anyway, I have a strange problem that I can't seem to figure out. I have a function that reads a magnetometer, applies hard and soft iron corrections, and returns a heading. Pretty straightforward stuff. During the development, I wrote the following stand-alone sketch.:
#include <LiquidCrystal_I2C.h>
#include <Adafruit_MMC56x3.h>
#include <Wire.h>
#include <EEPROMVar.h> //Used for EEPROM access
#include <EEPROMex.h> //Used for EEPROM access
//===================================================================================================================================================================
#define COMPASS_POWER 12
#define SWITCH_PIN_1 A0
#define SWITCH_PIN_2 A1
// Hard-iron calibration settings
const float hard_iron[3] = {EEPROM.readFloat(HARD_IRON_X_OFFSET_ADDRESS),EEPROM.readFloat(HARD_IRON_Y_OFFSET_ADDRESS),EEPROM.readFloat(HARD_IRON_Z_OFFSET_ADDRESS)};
// Soft-iron calibration settings
const float soft_iron[3][3] = {
{EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE1_ADDRESS), EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE2_ADDRESS), EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE3_ADDRESS)},
{EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE4_ADDRESS), EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE5_ADDRESS), EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE6_ADDRESS)},
{EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE7_ADDRESS), EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE8_ADDRESS), EEPROM.readFloat(SOFT_IRON_MATRIX_VALUE9_ADDRESS)},};
const float mag_decl = EEPROM.readFloat(LOCAL_MAGNETIC_DECLINATION_ADDRESS);
unsigned long lcdTimer;
//====================================================================================================================================================================
LiquidCrystal_I2C lcd(0x27,20,4); //0x3f
Adafruit_MMC5603 mag = Adafruit_MMC5603(12345);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
lcd.init();
lcd.backlight();
Serial.begin(115200);
pinMode(COMPASS_POWER,OUTPUT);
pinMode(SWITCH_PIN_1, INPUT_PULLUP);
pinMode(SWITCH_PIN_2, INPUT_PULLUP);
digitalWrite(COMPASS_POWER,HIGH);
if(mag.begin(MMC56X3_DEFAULT_ADDRESS, &Wire))
{
lcd.setCursor(0,0);
lcd.print("MMC5603 Compass chip");
lcd.setCursor(5,1);
lcd.print("detected.");
delay(3000);
lcd.clear();
}
else
{
lcd.setCursor(2,0);
lcd.print("No Compass chip");
lcd.setCursor(5,1);
lcd.print("detected.");
delay(3000);
lcd.clear();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
if(digitalRead(SWITCH_PIN_1) == LOW) EnterCompassCalibrationData();
if(digitalRead(SWITCH_PIN_2) == LOW) DisplayData();
static float hi_cal[3];
static float heading = 0;
// Get new sensor event with readings in uTesla and output for MotionCal
sensors_event_t event;
mag.getEvent(&event);
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(event.magnetic.x*10)); Serial.print(",");
Serial.print(int(event.magnetic.y*10)); Serial.print(",");
Serial.print(int(event.magnetic.z*10)); Serial.println("");
// Put raw magnetometer readings into an array
float mag_data[] = {event.magnetic.x,
event.magnetic.y,
event.magnetic.z};
// Apply hard-iron offsets
for (int i = 0; i < 3; i++ ) {
hi_cal[i] = mag_data[i] - hard_iron[i];
}
// Apply soft-iron scaling
for (int 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]);
}
// Calculate angle for heading, assuming board is parallel to
// the ground and Y points toward heading.
heading = -1 * (atan2(mag_data[0], mag_data[1]) * 180) / PI;
// Apply magnetic declination to convert magnetic heading
// to geographic heading
heading += mag_decl;
// Convert heading to 0..360 degrees
if (heading < 0) heading += 360;
if(millis() - lcdTimer > 500)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Heading: ");
lcd.setCursor(9,0);
lcd.print(round(heading));
lcdTimer = millis();
}
delay(10);
}
This works great. I then copied the loop code into a function in the main program as follows:
int GetHeading()
{
static float heading;
static float hi_cal[3];
sensors_event_t event;
mag.getEvent(&event);
float mag_data[] = {event.magnetic.x, event.magnetic.y, event.magnetic.z};
for (int i = 0; i < 3; i++) {
hi_cal[i] = mag_data[i] - hard_iron[i];
}
Serial.println("Soft Iron values");
Serial.print(soft_iron[0][0],3);
Serial.print(", ");
Serial.print(soft_iron[0][1],3);
Serial.print(", ");
Serial.print(soft_iron[0][2],3);
Serial.print(", ");
Serial.print(soft_iron[1][0],3);
Serial.print(", ");
Serial.print(soft_iron[1][1],3);
Serial.print(", ");
Serial.print(soft_iron[1][2],3);
Serial.print(", ");
Serial.print(soft_iron[2][0],3);
Serial.print(", ");
Serial.print(soft_iron[2][1],3);
Serial.print(", ");
Serial.println(soft_iron[2][2],3);
Serial.println("Hard Iron Corrections");
Serial.print(mag_data[0],3);
Serial.print(", ");
Serial.print(mag_data[1],3);
Serial.print(", ");
Serial.println(mag_data[2],3);
for (int 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]);
}
Serial.println("Soft Iron Corrections");
Serial.print(mag_data[0],3);
Serial.print(", ");
Serial.print(mag_data[1],3);
Serial.print(", ");
Serial.println(mag_data[2],3);
heading = 1 * (atan2(mag_data[0], mag_data[1]) * 180) / PI;
heading += declination;
heading += compassCorrection;
if (heading < 0) heading += 360;
delay(100);
return (int)heading);
The corrections are written to the EEPROM in both versions, but the serial monitor shows the following when the function is run:
Soft Iron values
0.982, -0.005, ovf, -0.005, 1.002, -0.004, 0.002, -0.004, 1.016
Hard Iron Corrections
43.219, -31.056, 54.769
Soft Iron Corrections
ovf, ovf, ovf
Sorry for the long post, but I tried to be as clear as I could. Does anyone have a reason for the overflow returns on the soft iron correction?