Problem with data from HMC5883L magnetometer.

Hi.

I’m trying to use a magnetometer HMC5883L.
Read and re-read a lot of tutorias an I get the north pole, but the sensor show me some wrong data.

The north is correct, show me 180 degree, but the rest of point is little strange.

Follow a graphic with the data that I receive (logando is my data):

The code is:

#define HMC5883_Address 0x1E
#define HMC5883_ModeRegisterAddress 0x02
#define HMC5883_ContinuousModeCommand (uint8_t)0x00
#define HMC5883_DataOutputXMSBAddress  0x03

int regbdata    = 0x40;
float gauss     = 2.5;

int outputData[6];
int xCompass, yCompass, zCompass, regb;

void compass_setup(){
  if(gauss == 0.88){
    regb = 0x00;
  }else if(gauss == 1.3){
    regb = 0x01;
  }else if(gauss == 1.9){
    regb = 0x02;
  }else if(gauss == 2.5){
    regb = 0x03;
  }else if(gauss == 4.0){
    regb = 0x04;
  }else if(gauss == 4.7){
    regb = 0x05;
  }else if(gauss == 5.6){
    regb = 0x06;
  }else if(gauss == 8.1){
    regb = 0x07;
  }
  
  Wire.beginTransmission(HMC5883_Address);
  Wire.write(regb);
  Wire.write(regbdata);
  Wire.endTransmission();
  delay(1000);
}

void compass_loop(){
  Wire.beginTransmission(HMC5883_Address);       //Initiate a transmission with HMC5883 (Write address).
  Wire.write(HMC5883_ModeRegisterAddress);       //Place the Mode Register Address in send-buffer.
  Wire.write(HMC5883_ContinuousModeCommand);     //Place the command for Continuous operation Mode in send-buffer.
  Wire.endTransmission();                         //Send the send-buffer to HMC5883 and end the I2C transmission.
  
  Wire.beginTransmission(HMC5883_Address);  //Initiate a transmission with HMC5883 (Write address).
  Wire.requestFrom(HMC5883_Address,6); 
  
  if(6 <= Wire.available()){ // If the number of bytes available for reading be <=6.
    for(int i=0;i<6;i++){
      outputData[i] = Wire.read();  //Store the data in outputData buffer
    }
  }
  
  xCompass = outputData[0] << 8 | outputData[1]; //Combine MSB and LSB of X Data output register
  zCompass = outputData[2] << 8 | outputData[3]; //Combine MSB and LSB of Z Data output register
  yCompass = outputData[4] << 8 | outputData[5]; //Combine MSB and LSB of Y Data output register
  
  getDegrees();
}

float getDegrees(){ 
  double angle = atan2((double)yCompass,(double)xCompass) * (180 / PI) + 180;

  Serial.print("angle: ");
  Serial.println(angle);
  
  return angle;
}

Anybody get this problem any time?

Thanks.

I have a different problem with the same sensor, but its pretty easy to get it working on a flat surface. Just use this library from vareseno, https://launchpad.net/hmc58x3 and run the basic example...It ll do a calibration and then give out readings.

The main problem is that a lot of electronic components use iron and steel in their construction (resistor end caps, most surface-mount endcaps, inductors), and all the mounting hardware for circuit boards is usually steel screws etc - all of this creates magnetic fields and distort the earth's field passively too. Hence the need for this "hard iron correction" unless you mount the magnetometer away from all ferromagnetic materials (in a plastic probe for instance).

What's more the actual magnetometer has a soft ferromagnetic plate in it to concentrate the very weak field from the earth and increase its sensitivity - this may become slightly magnetised if you are not careful (some soldering irons contain magnets for instance - and all screwdrivers are routinely magnetised to help stop screws falling off the end).

In practice you cannot rely on a magnetometer inside a smartphone - these corrections are imperfect and cellphones are full of bits of metal - take a proper compass if you go hiking is my advice(!).

I had the same problem. I found that using Z,Y instead of X,Y solved it.