Electronic Compass Arduino

Electronic Compass with the HMC5883

My friend Jac is active on 10 & 24 GHz portable. To aim his 90cm offset dish which is mounted 90 degrees tilted, the idea was born to use an electronic compass. This needs no calibration and should have an accuracy of around 2 degrees. The HMC5883 is easily found on ebay for very little money. It was Jac’s idea to have 2 buttons to calibrate his dish and to compensat for his 31 degrees of off-set because of his mounting. The code for the compass was found as opensource on the web. A few additions and an LCD were added. It required a bit of simple coding.

You have to make sure that the electronic compass is mounted levelled with the earth and that you donnot rotate it too quick. Keep it away from magnetic materials.

The code can be found below. Make sure you have the libraries in the correct place. These can be found on the Adafruit website! Check:

https://learn.adafruit.com/adafruit-hmc5883l-breakout-triple-axis-magnetometer-compass-sensor/wiring-and-test

 

/
/***************************************************************************
  This is a library example for the HMC5883 magnentometer/compass
  Designed specifically to work with the Adafruit HMC5883 Breakout
  http://www.adafruit.com/products/1746
 
  *** You will also need to install the Adafruit_Sensor library! ***
  These displays use I2C to communicate, 2 pins are required to interface.
  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!
  Written by Kevin Townsend for Adafruit Industries with some heading example from
  Love Electronics (loveelectronics.co.uk)
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the version 3 GNU General Public License as
 published by the Free Software Foundation.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ***************************************************************************/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int corr = 31;
int corraz = 0;
int incrementState = 0; //will read increment
int lastIncrementState = 0;
int decrementState = 0; //will read decrement
int lastdecrementState = 0;
byte incrementButton = 6; // the pin that the pushbutton is attached to
byte decrementButton = 7; // the pin that the pushbutton is attached to
/* Assign a unique ID to this sensor at the same time */
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
void displaySensorDetails(void)
{
  sensor_t sensor;
  mag.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" uT");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" uT");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" uT"); 
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}
void setup(void)
{
    // set up the LCD's number of columns and rows:
  lcd.begin(20, 2);
  
    // A little bit of PR
  lcd.setCursor(7,0);
  lcd.print("PE1KXH");
  lcd.setCursor(4,1);
  lcd.print("Kloat get aan!");
  delay(1000);
  lcd.clear();
  
    
  Serial.begin(9600);
  Serial.println("HMC5883 Magnetometer Test"); Serial.println("");
  
  /* Initialise the sensor */
  if(!mag.begin())
  {
    /* There was a problem detecting the HMC5883 ... check your connections */
    Serial.println("Ooops, no HMC5883 detected ... Check your wiring!");
    while(1);
     
  }
 
  
  
  /* Display some basic information on this sensor */
  displaySensorDetails();
}
void loop(void)
{
  
 
   
   
  /* Get a new sensor event */
  sensors_event_t event;
  mag.getEvent(&event);
 
  /* Display the results (magnetic vector values are in micro-Tesla (uT)) */
  Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print("  ");Serial.println("uT");
  // Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(event.magnetic.y, event.magnetic.x);
  
  // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
  // Find yours here: http://www.magnetic-declination.com/
  // Mine is: -13* 2' W, which is ~13 Degrees, or (which we need) 0.22 radians
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = 0.017453292519943; //value for JO21wd abt 1 degree in radians
  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;
  
  
  
   //Reading and counting the UP button
  
  incrementState = digitalRead(incrementButton); //read the increment button state
      if(incrementState != lastIncrementState) //compare increment button state to its last state
   {
      if(incrementState == LOW)//increment button is pressed
      {
         corr = corr + 1; //increment the corr value
         delay(10); //debounce delay
      }
   }
   lastIncrementState = incrementState;
   
     //Reading and counting the DOWN button
  
  decrementState = digitalRead(decrementButton); //read the increment button state
      if(decrementState != lastdecrementState) //compare increment button state to its last state
   {
      if(decrementState == LOW)//increment button is pressed
      {
         corr = corr - 1; //increment the corr value
         delay(10); //debounce delay
      }
   }
   lastdecrementState = decrementState;
   
  corraz = headingDegrees - corr;
  if(corraz < 0)
    corraz = (corraz + 360);
  
  Serial.print("Heading (degrees): "); Serial.println(headingDegrees);
  Serial.print("Correction (degrees): "); Serial.println(corr);
  Serial.print("Corrected Azimuth): "); Serial.println(corraz);
//first line
  lcd.setCursor(9,0);
  lcd.setCursor(0,0);
  lcd.print("Azimuth: ");
  lcd.setCursor(9,0);
  lcd.print("   ");
  lcd.setCursor(9,0);
  lcd.print(headingDegrees, 0);
  lcd.setCursor(14,0);
  lcd.print("Cor:");
  lcd.setCursor(18,0);
  lcd.print("  ");
  lcd.setCursor(18,0);
  lcd.print(corr);
  
//second line
 
 
 lcd.setCursor(0,1);
 lcd.print("Calc Az: ");
 lcd.setCursor(9,1);
 lcd.print("   ");
 lcd.setCursor(9,1);
 lcd.print(corraz);
  
  delay(500);
}