Finding degrees using a HMC5883L Compass

I was wondering how to convert the raw values of the x, y , z to get degrees like a regular compass. Do I need to use the y and z values to do this?

Here's the code.

#include <Wire.h>

#define Addr 0x1E // 7-bit address of HMC5883 compass

void setup() {
Serial.begin(9600);
delay(100); // Power up delay
Wire.begin();

// Set operating mode to continuous
Wire.beginTransmission(Addr);
Wire.write(byte(0x02));
Wire.write(byte(0x00));
Wire.endTransmission();
}

void loop() {
int x, y, z;

// Initiate communications with compass
Wire.beginTransmission(Addr);
Wire.write(byte(0x03)); // Send request to X MSB register
Wire.endTransmission();

Wire.requestFrom(Addr, 6); // Request 6 bytes; 2 bytes per axis
if(Wire.available() <=6) { // If 6 bytes available
x = Wire.read() << 8 | Wire.read();
z = Wire.read() << 8 | Wire.read();
y = Wire.read() << 8 | Wire.read();
}

// Print raw values
Serial.print("X=");
Serial.print(x);
Serial.print(", Y=");
Serial.print(y);
Serial.print(", Z=");
Serial.println(z);

delay(500);
}

First, you need to make sure that the compass is properly calibrated, or the headings will be far off. My favorite procedure is outlined here: Sailboat Instruments: Improved magnetometer calibration (Part 1)

Then, you need to implement tilt correction. Plenty of theory and code is available if you google something like "3d compass tilt correction"

1 Like

anon1337:
I was wondering how to convert the raw values of the x, y , z to get degrees like a regular compass. Do I need to use the y and z values to do this?

If the compass module lies flat on the ground with no tilt, you just need x and y for some easy calculations:

#include <Wire.h>

#define Addr 0x1E               // 7-bit address of HMC5883 compass

void setup() {
  Serial.begin(9600);
  Serial.println();
  Wire.begin();
  
  // Set operating mode to continuous
  Wire.beginTransmission(Addr); 
  Wire.write(byte(0x02));
  Wire.write(byte(0x00));
  Wire.endTransmission();
}

void loop() {
  int x, y, z;

  // Initiate communications with compass
  Wire.beginTransmission(Addr);
  Wire.write(byte(0x03));       // Send request to X MSB register
  Wire.endTransmission();

  Wire.requestFrom(Addr, 6);    // Request 6 bytes; 2 bytes per axis
  if(Wire.available() <=6) {    // If 6 bytes available
    x = Wire.read() << 8 | Wire.read();
    z = Wire.read() << 8 | Wire.read();
    y = Wire.read() << 8 | Wire.read();
  }
  // If compass module lies flat on the ground with no tilt,
  // just x and y are needed for calculation
  float heading=atan2(x, y)/0.0174532925;
  if(heading < 0) heading+=360;
  heading=360-heading; // N=0/360, E=90, S=180, W=270
  Serial.println(heading);  
  delay(500);
}

This code is great, but still I didnt solve the problem with bug. My bug is that after 2 minutes stop transmitting the heading and than after half an hour when I disconnect from the PC whole arduino uno it works again for 2 minutes. This problem I have also with the example code for HMC5883L there is a message :

"Entered scale was not valid, valid gauss values are: 0.88, 1.3, 1.9, 2.5, 4.0, 4.7, 5.6, 8.1 Setting measurement mode to continous.".

Do you have any ideas how to compel make it works ? I read something about calibration, but I am not sure...thx for all answers!