Rabenauge:
Hm-ich hatte ein Mini-Breadboard dran.
Eben hab ichs noch mal versucht, nur mit Stecker und 30cm Kabel an dem Ding-ringsum 30cm nichts- dann geht es. Rauscht aber schon enorm, bereits minimale Änderungen der Lage wirken sich gleich mal auf mehr als 90 Grad aus. Armabduhr? 
Also wenn Du eine Rolex Submariner am Handgelenk hast, und diese dann in Stahl statt in Gold, würde ich die Uhr beim Hantieren mit einem Kompass ablegen.

Ansonsten habe ich mir mal Gedanken gemacht, wie man einen eCompass kalibrieren kann und wie man korrekte Werte bekommt, trotz gleichbleibender Einflüsse aus der Montage mit Stahl-Headerstiften am Modul und ggf. auf einem Breadboard mit Stahlklammern im Innern.
Zuerst wollte ich das vermeintlich einfach machen, mit Ausrichtung des Moduls in ganz bestimmte Richtungen, messen von Werten und Errechnung simpler Korrekturwerte. Das ist alles Pustekuchen gewesen, damit bin ich überhaupt nicht auf einen grünen Zweig gekommen.
Jetzt habe die Freescale-Application-Note #AN4246 mit dem Titel "Calibrating an eCompass in the
Presence of Hard and Soft-Iron Interference" mal in einen Arduino-Sketch gegossen. Und das sieht eigentlich recht vielversprechend aus. Das Dokument ist hier im Internet nachzulesen:
http://www.freescale.com/files/sensors/doc/app_note/AN4246.pdf
Man muß mit dem eCompass einfach nur sechs verschiedene Messwerte messen, mit dem eCompass "in möglichst viele verschiedene Richtungen weisend". Und dann wird die pure Mathematik in Form von Vektor- und Matrixrechnung auf diese sechs Punkte losgelassen. Am Ende kommen drei Korrekturwerte Vx, Vy, Vz für die Korrektur der x-, y-, z-Achse dabei heraus.
Mit diesem Sketch wird das Rechenbeispiel aus dem Freescale-Dokument nachgerechnet
Entgegen des Titels wird mit dem Rechenbeispiel aber nur die Hard-Iron Kalibrierung durchgeführt:
/*
Magnetometer calibration by 'jurs' for German Arduino Forum
Created after Freescale Application Note #4246
Calibrating an eCompass in the Presence of Hard and Soft-Iron Interference
by: Talat Ozyagcilar
http://freescale.com/files/sensors/doc/app_note/AN4246.pdf
This sketch does the "hard iron" calibration only.
*/
#include <MatrixMath.h>
// Use six different measurements of magnetometer for calibration
float matrix[6][4]={
{167.4, -242.4, 91.7, 1}, // x1, y1, z1, 1
{140.3, -221.9, 86.8, 1}, // x2, y2, z2, 1
{152.4, -230.4, -0.6, 1}, // x3, y3, z3, 1
{180.3, -270.6, 71.0, 1}, // x4, y4, z4, 1
{190.9, -212.4, 62.7, 1}, // x5, y5, z5, 1
{192.9, -242.4, 17.1, 1}, // x6, y6, z6, 1
};
float matrix_transposed[4][6];
float matrix_multiplied[4][4];
float matrix_inverted[4][4];
float matrix_multiplied2[4][6];
float y_vector[6][1];
float result_beta[4][1];
float vx,vy,vz;
void calibrate()
{
Matrix.Print((float*)matrix,6,4,"matrix");
Matrix.Transpose((float*)matrix,6,4,(float*)matrix_transposed);
Matrix.Print((float*)matrix_transposed,4,6,"matrix_transposed");
Matrix.Multiply((float*) matrix_transposed, (float*) matrix, 4,6,4, (float*)matrix_multiplied);
Matrix.Print((float*)matrix_multiplied,4,4,"matrix_multiplied");
Matrix.Copy((float*)matrix_multiplied,4,4,(float*)matrix_inverted);
Matrix.Invert((float*)matrix_inverted,4);
Matrix.Print((float*)matrix_inverted,4,4,"matrix_inverted");
Matrix.Multiply((float*) matrix_inverted, (float*) matrix_transposed, 4,4,6, (float*)matrix_multiplied2);
Matrix.Print((float*)matrix_multiplied2,4,6,"matrix_inverted x transposed");
for (int i=0;i<6;i++)
{
y_vector[i][0]=0;
for (int j=0;j<3;j++) y_vector[i][0]+=matrix[i][j]*matrix[i][j];
}
Matrix.Print((float*)y_vector,6,1,"y_vector");
Matrix.Multiply((float*)matrix_multiplied2,(float*)y_vector,4,6,1,(float*)result_beta);
Matrix.Print((float*)result_beta,4,1,"result_beta");
Serial.println();
vx=result_beta[0][0]/2;
vy=result_beta[1][0]/2;
vz=result_beta[2][0]/2;
Serial.print("Vx= ");Serial.println(vx);
Serial.print("Vy= ");Serial.println(vy);
Serial.print("Vz= ");Serial.println(vz);
Serial.println();
Serial.print("Geomagnetic field strength = ");
Serial.print(sqrt(result_beta[3][0]+vx*vx+vy*vy+vz*vz));
}
void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println("Magnetometer calibration by 'jurs' for German Arduino Forum");
Serial.println();
calibrate();
}
void loop()
{
}
Die in meinem Sketch verwendete "MatrixMath" Library hänge ich als Dateianhang an dieses Posting dran.
Um selbst eine Kalibrierung für Deinen Hardwareaufbau zu ermitteln, einfach in "matrix" die Werte von sechs weitgehend beliebigen, aber möglichst verschiedenen eCompass-Messwerten eintragen.
Das müssen auch keine Werte in Mikrotesla sein, sondern Du kannst Du Datenrohwerte eines HMC5883L einsetzen.
Sechs Werte mögen insgesamt zwar ein bisschen wenig sein für eine vollständige Kalibrierung, aber für einen Kompass in der Ebene sollte es ganz gut hinhauen.
Für eine gut funktionierende Kalibrierung für einen flach liegenden Kompass zu erhalten wie folgt vorgehen:
Kompass mit dem Breadboard flach hinlegen und vier Werte ermitteln, indem jeweils um 90° in der Ebene gedreht wird. Den fünften und sechsten Wert dann durch Kippen um die eine oder andere Achse ermitteln. Und die Korrekturwerte dann in dem oben von mir geposteten Sketch zur Korrektur der ausgelesenen Rohdaten verwenden, bevor die Kompassrichtung ausgerechnet wird.
Und dran denken: Mein Sketch in Reply #1 ist KEIN Tilt-kompensierter Kompass, sondern der Code funktioniert nur bei flach liegendem Sensor! Und das gilt auch, wenn man die Rohdatenwerte vor dem Ausrechnen der Kompassrichtung noch um die Korrekturwerte Vx, Vy und Vz korrigiert! Und mit dem Sketch aus dieser Reply #5 wird auch nur die "Hard Iron" Kalibrierung durchgeführt, nicht jedoch die aufwändigere "Soft Iron" Kalibrierung.
Vielleicht kannst Du ja trotzdem etwas damit anfangen, probier's mal aus!
MatrixMath.zip (3.4 KB)