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!