SparkFun Forums 

Where electronics enthusiasts find answers.

Have questions about a SparkFun product or board? This is the place to be.
By Mee_n_Mac
#136401
Daedelus wrote:OK here is the read_compass() routine.
And the attached file is the values of magnetom_x, _y and _z
OK, I looked at the data and in general I think it looks good but :

I think there's a mixup in which sensor axes are which. In your data file I think the first to third columns are thought to be internal sensor y, internal sensor x and internal sensor z. I've ploted them out using those names. It appears to me that what you think is the sensor Y axis is really the sensor Z axis (vertical). The red plot below doesn't change as you rotate the magnetometer, just the vertical Z axis shouldn't. The other two axes look pretty good, though there's a small DC offset which might affect the fine accuracy of your heading. They both have the same + and - amplitudes (~230 counts) about that DC offset (~ -40 counts). If you started off with the sensor X axis (green plot) facing due North, then I think that's labelled correctly although I'd have thought it should have read a + number and it reads a - number. If you started off with the sensor X axis facing due South, then it would be correct. What you called the sensor Z axis (blue plot) appears to me to really be the sensor Y axis. If you started off with the sensor X axis facing due South and then rotated clockwise (as viewed from above the sensor) then this true Y sensor output makes sense (the sign is proper).

In summary I think you've got the Y and Z axes mixed up somehow. If you started with the sensors X axis facing South ... you're OK with the signs. Otherwise the signs on what I think are the true sensor X and Y axes are screwy. Hopefully my plot will attach and display below but the forum has been AFU in this regard for a while.
MagentometerData.jpg
You do not have the required permissions to view the files attached to this post.
By Mee_n_Mac
#136402
Daedelus wrote:And the compass address is:
int CompassAddress = 0x1E; //0x3C //0x3D; //(0x42>>1);
Could that be wrong?
I don't think so, the data looks like magnetometer data should (to me). Perhaps what I think is really the Z axis is some other register but I doubt it. You could read the ID registers (A,B,C) to be absolutely sure.
By Daedelus
#136403
Thank you for your analysis. Now I will see if I can comprehend all that. I have to confess to being a novice at this particular area and the code is what I have adapted from what I found on line, that was written for the 9DOF Razor. I haven't changed any axis in the code but I guess there could be differences in the way the boards were configured.
By Daedelus
#136414
Serial1322711304.08.txt
I swapped Y and Z in the Read_Compass() module. That seemed to correct the yaw to zero when pointed N. I still seem to be having a problem with converting those raw numbers to degrees.

Won't let me attach the file. I'll try again tomorrow.
By Mee_n_Mac
#136447
Daedelus wrote:Something definitely wrong with the file attach function here.
No kidding ! Sometimes it works and sometimes it doesn't. And even when it does and you try to display an uploaded pic in the post ... sometimes it will and sometimes it won't. Clicking on an attachment to D/L it often gets you the message that "XYZ is no longer available" but clicking on it again will work. AFU !

So I assume you're now trying to rotate the board and see the computed heading read like a compass would. If there's a problem there it's got to be in your code. I calculated a un-tilt un-compensated (used just X, Y data) heading from the sensor data you gave me and, after removing the offsets, it looked pretty good (I didn't do the quadrant correction stuff). If you don't remove the offsets you'll get a 5-10 degree error, depending on which quadrant it's facing. I'd attach a plot but .... :cry:
By Daedelus
#136451
Serial1322711304.08.txt
I agree, it's in 'my' code. :wink:
I'll see if I can sort it out. The end result I get is still, 0 deg. when pointing North, 22 deg pointing East, 0 again pointing South and -19 deg. when pointing West. It's consistent when the board is kept flat horizontally.

It has to be in the computation somewhere between the raw data and the final result in Degrees.
Do you know of a reference for the equations involved?
You do not have the required permissions to view the files attached to this post.
By Mee_n_Mac
#136454
Daedelus wrote:Do you know of a reference for the equations involved?
Start by removing the tilt compensation that uses the Z axis data. I think I saw words on how to do this in the code you 1'st posted. Then, using only the X and Y sensor data, compute the heading according to ...

http://www51.honeywell.com/aero/common/ ... meters.pdf

When I get a chance later today I'll do the same with the raw data your originally posted.

I've not had a chance to look at the recent batch of data. Seems I'm stuck in the "attachment XYZ does not exist anymore" loop. :shock: :cry: :evil:
By Daedelus
#136471
Success! It took some cutting and pasting from the HMC5883L_Example I also found on line.
Code: Select all
#include <HMC5883L.h>
// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;

// Added to the Compass_Heading routine.
float headingDegrees;
void Compass_Heading()


 // Retrieve the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();
  
  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);
  
  // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
  // Find yours here: http://www.magnetic-declination.com/
  // Mine is: 2 deg 37' W, which is 2.617 Degrees, or (which we need) 0.0456752665 radians, I will use 0.0457
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = -0.0782489281; // for east TN
  heading += declinationAngle;
  
  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;
    
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;
   
  // Convert radians to degrees for readability.
  headingDegrees = heading * 180/M_PI; 

I now have the Arduino and Visual Python code working pretty close to what I expected. I still have more cleaning up to do.

Note: I ported and adapted this code from this blog: http://pranjalchaubey.wordpress.com/201 ... razor-imu/
And I used the HMC5883L library and example code from here: https://www.loveelectronics.co.uk/Tutor ... no-library
By Daedelus
#136472
Spoke too soon. I still have the yaw swinging wildly with changes in pitch and roll. Oh well back to the drawing board.
By Mee_n_Mac
#136473
Daedelus wrote:Spoke too soon. I still have the yaw swinging wildly with changes in pitch and roll. Oh well back to the drawing board.
This is where the math gets tricky. I'd have to spend a few minutes trying to re-figure it out in my own mind. Or I could look it up. IIRC I did see a pretty comprehensive explanation of all the math involved and where it comes from as part of some application note for some SF product. In fact I believe it was this very app note ...

http://www.sparkfun.com/datasheets/Sens ... ompass.pdf

:mrgreen:
By Techdetect
#149916
I was told that "The idea behind that improperly implemented code is to keep the heading between 0 and 360 degrees, or between 0 and 2 pi radians.

The action to take when heading becomes negative should be to add 2 pi radians to the value. Similarly, when the heading exceeds 2 pi, the action to take should be to subtract 2 pi. "

in reference to this code
Code: Select all
 /*
HMC5883L_Example.pde - Example sketch for integration with an HMC5883L triple axis magnetomerwe.
Copyright (C) 2011 Love Electronics (loveelectronics.co.uk)

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

The ?? or ??? is what i have added..??

*/

// Reference the I2C Library
#include <Wire.h>
// Reference the HMC5883L Compass Library
#include <HMC5883L.h>


#include <Servo.h>  //added for servo attachment on xaxis??
int val;  //added for servo attachment on xaxis??
int val2; //added for servo attachment on yaxis??
Servo myservo;  //added for servo attachment on xaxis??
Servo myservo2; //added for servo attachment on yaxis??

// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;

// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  
  
  // Initialize the serial port.
  Serial.begin(9600);
myservo.attach(9); // added for servo movement???
myservo2.attach(10); // added for second servo movement???
  Serial.println("Starting the I2C interface.");
  Wire.begin(); // Start the I2C interface.

  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); // Construct a new HMC5883 compass.
    
  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
  
  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
}

// Our main program loop.
void loop()
{
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();
  
  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);
  
  // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
  // Find yours here: http://www.magnetic-declination.com/
  // Mine is: 2� 37' W, which is 2.617 Degrees, or (which we need) 0.0456752665 radians, I will use 0.0457
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = 77.09 / 1000; //corrected for whiteland indina of 77.09 negative (west) declinationWHITELAND INDIANA
//Latitude: 39° 33' 0.2" N
//Longitude: 86° 4' 47" W
//Magnetic declination: 4° 25' WEST
//Declination is NEGATIVE
//Inclination: 67° 42'
  heading -= declinationAngle;
  
  // Correct for when signs are reversed.
  if(heading < 0)
    heading -= 2*PI;
    
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading += 2*PI;
   
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 

  // Output the data via the serial port.
  Output(raw, scaled, heading, headingDegrees);

  // Normally we would delay the application by 66ms to allow the loop
  // to run at 15Hz (default bandwidth for the HMC5883L).
  // However since we have a long serial out (104ms at 9600) we will let
  // it run at its natural speed.
  // delay(66);
  
val = raw.XAxis;  //added for servo attachment on xaxis??
val2 = raw.YAxis;  //added for servo attachment on yaxis??

val = map(val, 0, -300, 0, 300);  //added for servo attachment on xaxis???
val2 = map(val2, 0, -300, 0, 300); //added for servo;; note:will need to adjust these values to match servo movement. ??
myservo.write(val); //???
myservo2.write(val2); //???

//added for servo attachment on xaxis
}

// Output the data down the serial port.
void Output(MagnetometerRaw raw, MagnetometerScaled scaled, float heading, float headingDegrees)
{
  Serial.print("Raw:\t");
  Serial.print(raw.XAxis);
  Serial.print("   ");   
  Serial.print(raw.YAxis);
  Serial.print("   ");   
  Serial.print(raw.ZAxis);
  Serial.print("   \tScaled:\t");
   
   Serial.print(scaled.XAxis);
   Serial.print("   ");   
   Serial.print(scaled.YAxis);
   Serial.print("   ");   
   Serial.print(scaled.ZAxis);

   Serial.print("   \tHeading:\t");
   Serial.print(heading);
   Serial.print(" Radians   \t");
   Serial.print(headingDegrees);
   Serial.println(" Degrees   \t");
   
  
   
}

I have tried, yes tried to implement my own version but if you look at the comments // regarding to whiteland indiana you see what i have done and tried to compenstate for the magnetic declination.

Can you give guidance? maybe i can reply to whom i was told that this was wrong and give an explanation. I think i made the mistake by changing the values based upon the comments that were origionally presented.
Thanks to et. al.
Techdetect :clap: