Magnetic Compass
In this project, you'll learn how to connect and control the GY-273 magnetic compass module which uses the HMC5883L sensor chip to detect low magnetic fields. The HMC5883L sensor is sensitive to the earth's magnetic fields in three axes. These axes are labeled X, Y, and Z. An output is provided for each of these axes that describes the position of these axes relative to the earth's magnetic field. As illustrated, twisting or turning the device will provide the corresponding outputs.
The HMC5883L uses the I2C protocol to communicate with the Arduino.
- The 7-bit I2C device address for the HMC5883L is 0011110 (0x1E). Therefore,
- the read address is 00111101 (0x3D), and the
- the write address is 00111100 (0x3C).
| Parts needed:
|
|
| You may want to first read about the I2C protocol before you continue.
|
1
| Making the connections
- Connect the SCL pin on the compass to pin A5 on the Arduino.
- Connect the SDA pin on the compass to pin A4 on the Arduino.
- Connect Vcc to 5V.
- Connect GND to GND.
|
2
| Create a new program and type in this code.
To understand the register usage and values to read/write to the registers, you'll need to look at the datasheet for the HMC5883L sensor chip.
|
// Copyright 2017 Enoch Hwang
#include <Wire.h>
#define I2C_address 0x1E //I2C Address for The HMC5883L
float scale;
void setup(){
Serial.begin(9600);
Wire.begin();
Wire.beginTransmission(I2C_address);
// set scale to +/- 1.3 gauss
scale = 0.92; // for 1.3 gauss
Wire.write(0x01); // select register address
Wire.write(0x20); // write data
Wire.endTransmission();
Wire.beginTransmission(I2C_address);
// set continuous measurement mode
Wire.write(0x02); // select register address
Wire.write(0x00); // write data
Wire.endTransmission();
}
void loop(){
int raw_x, raw_y, raw_z; //triple axis data
float scale_x, scale_y, scale_z;
//Tell the chip what register to start reading from
Wire.beginTransmission(I2C_address);
Wire.write(0x03); //start with register 3.
Wire.endTransmission();
//Read the data. 2 bytes for each axis. 6 total bytes
Wire.requestFrom(I2C_address, 6);
if(Wire.available() == 6){
raw_x = Wire.read()<<8; //MSB x
raw_x |= Wire.read(); //LSB x
raw_z = Wire.read()<<8; //MSB z
raw_z |= Wire.read(); //LSB z
raw_y = Wire.read()<<8; //MSB y
raw_y |= Wire.read(); //LSB y
}
scale_x = raw_x * scale;
scale_z = raw_z * scale;
scale_y = raw_y * scale;
// Show Values
Serial.print("X Value: ");
Serial.print(raw_x);
Serial.print(", ");
Serial.println(scale_x);
Serial.print("Y Value: ");
Serial.print(raw_y);
Serial.print(", ");
Serial.println(scale_y);
Serial.print("Z Value: ");
Serial.print(raw_z);
Serial.print(", ");
Serial.println(scale_z);
Serial.println();
delay(1000);
}
|
3
| Run the program and open the Serial Monitor to see the X, Y, and Z values of the compass.
|
4
| Add this code to change the X, Y, and Z values to the compass direction headings.
Place the compass so that the X and Y axis of the compass are level with the ground,
and the Z axis is pointing up.
Adjust the compass reading with the declination angle for your location.
If you do not do this then your compass reading will be slightly off.
Find your declination angle here.
Convert the declination angle given in degrees minutes seconds to just degrees here.
Convert from degress to radians here.
Replace the declinationAngle constant in the code with your radians number.
|
// The X and Y values are used to calculate the heading
float heading = atan2(scale_y, scale_x);
// Add your declination angle, which is the error of the magnetic field for your location.
// The declination angle at LSU is 11 degrees 52 minutes (11* 52')
// = 11.86667*
// = 0.20711246275 radians
// If you cannot find your declination angle, comment out the next two lines,
// but the compass will be slightly off.
const float declinationAngle = 0.20711246275;
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;
Serial.print("Heading is ");
Serial.print(headingDegrees);
Serial.println(" degrees");
|
|
|
|