Troubleshooting HMC5883L Model GY-273 Magnetometer

Hello,

I am working on a project that needs a magnetometer (HMC6883L GY-273) hooked up to an Arduino Uno to read a certain heading and manipulate a servo motor to orient in a particular heading. However, I can't seem to get the magnetometer to work. I've used multiple codes found online and downloaded a couple libraries and still get the same problem. That is, I get either zeros as a return value or a constant value as a heading (i.e. 23 degrees)

But to streamline the post, this is the original code given by my instructor to test a magnetometer.

#include <Wire.h> //I2C Arduino Library

#define address 0x1E //0011110b, I2C 7bit address of HMC5883


void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(9600);
  Wire.begin();

  
  //Put the HMC5883 IC into the correct operating mode
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.write(0x02); //select mode register
  Wire.write(0x00); //continuous measurement mode
  Wire.endTransmission();
}

    void loop(){
  
  int x,y,z; //triple axis data

  //Tell the HMC5883L where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x03); //select register 3, X MSB register
  Wire.endTransmission();
  
 
 //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
  if(6<=Wire.available()){
    x = Wire.read()<<8; //X msb
    x |= Wire.read(); //X lsb
    z = Wire.read()<<8; //Z msb
    z |= Wire.read(); //Z lsb
    y = Wire.read()<<8; //Y msb
    y |= Wire.read(); //Y lsb
  }
  
  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);
  
  delay(250);
    
  }

In this code, the only numbers that are returned are zeros, I run the Serial Monitor for a good 30 seconds and that is the only result.
(i.e. x:0 y:0 z:0)

My instructor suspected it could be the address for the magnetometer is wrong, so he updated the code and gave us the following to calibrate the magnetometer:

#include <Wire.h> //I2C Arduino Library

#define address 0x0D //0011110b, I2C 7bit address

// Magnetometer variables
int xRaw, yRaw, zRaw;

// Calculated maximum value for each variable
int xMax = -32765;
int xMin = 32765;
int yMax = -32765;
int yMin = 32765;

// Printing variables
bool printStartingInstructions = true;
unsigned long lastTimeUpdatePrint = 0;
unsigned long timeUpdateInterval = 5000; // interval to print time update

// Calibration time in milliseconds
unsigned long calibrationTime = 30000;

unsigned long timeNow;

void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(9600);
  Wire.begin();
  
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.write(0x09); //select mode register
  Wire.write(0x0D); //continuous measurement mode
  Wire.endTransmission();

  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.write(0x0B); //select Set/Reset period register
  Wire.write(0x01); //Define Set/Reset period
  Wire.endTransmission();
}

void loop(){
  timeNow = millis();
  // If it is the first iteration, print the intructions to use this calibration program
  if(printStartingInstructions)
  {
    printInstructions();
    printStartingInstructions = false;
  }

  // If time is not up, update magnetometer and get values
  if (timeNow < calibrationTime)
  {
    updateMagnetometerData();
    xMax = max(xRaw, xMax);
    xMin = min(xRaw, xMin);
    yMax = max(yRaw, yMax);
    yMin = min(yRaw, yMin);

    // Check if it is time to print the elapsed time
    if ((timeNow - lastTimeUpdatePrint) > timeUpdateInterval)
    {
      printTimeUpdate();
      lastTimeUpdatePrint = timeNow;
    }
  }

  // If time is up, print the results and stop the program
  else
  {
    printResults();
    while(1);
  }
  delay(10);
}

void updateMagnetometerData()
{
  //Tell the magnetometer where to begin reading data
  Wire.beginTransmission(address);
  Wire.write(0x00); //select register 0, X MSB register
  Wire.endTransmission();
  
  //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
  if(Wire.available()>=6){
    xRaw = Wire.read(); //x lsb
    xRaw |= Wire.read()<<8; //x msb
    yRaw = Wire.read(); //y lsb
    yRaw |= Wire.read()<<8;; //y msb
    zRaw = Wire.read(); //z lsb
    zRaw |= Wire.read()<<8; //z msb
  }
}

void printInstructions()
{
  // Print the instructions to use the calibration
  Serial.println("Rotate your robot in a slow rate to one direction until it has been rotate 360 degrees.");
  Serial.println("Rotate it to the other direction for another 360 degrees.");
  Serial.println("Keep rotating it until calibration time is up.");
  Serial.println("Make sure you keep the robot leveled during the calibration!");
}

void printTimeUpdate()
{
  // Print elapsed time in the claibration process
  Serial.println();
  Serial.print("Elapsed time: ");
  Serial.print(timeNow/1000);
  Serial.print("s of ");
  Serial.print(calibrationTime/1000);
  Serial.println("s");
}

void printResults()
{
  // Print the results of the calibration
  Serial.println();
  Serial.println();
  Serial.println("Finished calibration!");
  Serial.println("Copy the following numbers to your main magnetometer code:");
  Serial.print("xMin: ");
  Serial.print(xMin);
  Serial.print("\txMax: ");
  Serial.print(xMax);
  Serial.print("\tyMin: ");
  Serial.print(yMin);
  Serial.print("\tyMax: ");
  Serial.println(yMax);
}

But this too has the same effect of returning nothing but zeros.

I've run this code and others multiple times to get the same result.

Is there anything that can be done? Or is my magnetometer broken?
Please note, I bought a new magnetometer of the same make and model, and it too gives the same result (that is, a constant value as a heading in the Serial Monitor)

I have also attached a photo of the wiring. That is, how I hooked up the magnetometer to my Arduino Uno.
Note: I have swapped the two yellow wires between Analog Pin 4 and 5 each time I run the code as well as the recommended wiring found on the internet (this was done on the recommendation of my instructor)

Thank you!

Try running the I2C scanner program to see if it recognizes the device, at the proper address.

Perhaps your wiring is wrong, or you do not have pullup resistors on the I2C pins. The photo doesn't show anything useful.

jremington:
Try running the I2C scanner program to see if it recognizes the device, at the proper address.

Perhaps your wiring is wrong, or you do not have pullup resistors on the I2C pins. The photo doesn't show anything useful.

Hi! Thank you for replying.

I ran the I2C program you suggested, and both magnetometers (old and new one that I bought) aren't registering as an I2C device on my Serial Monitor. But I was wondering if I wired it correctly to the Arduino Uno for the program to work?

I've attached a wiring diagram that is exactly what I hooked my magnetometer up as. (e.g. there are no resistors involved, just a direct connection)

Post a link to the module you have.
It seems you use a board with voltage regulator.
And are powering it from 3.3volt instead of 5volt.
Leo..

Wawa:
Post a link to the module you have.
It seems you use a board with voltage regulator.
And are powering it from 3.3volt instead of 5volt.
Leo..

The new magnetometer I have is this:

https://www.amazon.com/SMAKN-GY-273-HMC5883L-Compass-Magnetometer/dp/B0141UFZTU/ref=sr_1_3?ie=UTF8&qid=1496098654&sr=8-3&keywords=hmc5883l

I've used both 3.3 V and 5 V to see if it will work with the magnetometer, both give the same result.

There is no voltage regulator shown in the picture of the module you linked, so it is 3.3V maximum. The vendor is lying, by claiming the pictured module is 3-5V operation.

The module will be (and probably has been) destroyed by connecting it to 5V.

I recommend buying sensors from Pololu, who stand by their products and provide excellent support. This one is excellent, and outperforms the HMC5883L.

Even thou its an old post - maybe will stumble across this solution:

The problem is that many GY-273 modules do contain the QMC5883L chip instead of the expected HMC5883L.

Adresses and registers are different that is why the QMC will not work with the HMC libraries.

Adress is 0x0D as found by the I2C Scanner - not an issue of Pull ups. Same for the 3V and 5V, a regulator is onboard and the logic is 5V compatible.

Luckily there is a QMC5883 library that works great: --> MechaQMC5883

Install the library and all works fine!

Greetz

Mike

1 Like

Thanks a bunch, it worked it was labeled as an HMC but in fact, it was a QMC I used the following link to help me out

http://osoyoo.com/2017/09/14/qmc5883l-electronic-compass-for-arduino/

I hope it helps

1 Like