This is a simple sketch to test out the HMC5883L based digital compass for potential inclusion in the ROV project. At present the ROV pilot has only their own spacial sense and the video feed to determine where they are and which way they’re facing. By adding in a digital compass and having it sending data to the topside control display will hopefully reduce the chance of the pilot becoming disorientated.

The HMC5883L is typically available on a small breakout board from suppliers such as DX. Depending on which port you connect to, it can be run using 3.3V or 5V. The communication protocol is i2c. It has the ability to provide a 3D heading direction based on the earths magnetic field but in this example we will only be looking at the X and Y components.

The directions are marked on the board with a set of axis. The X-axis is forward and gives the heading.

Digital Compass Directions

In this example the output is displayed on a 16x2 LCD screen. The diagram below shows the connections. If you wanted to run the device without being connected to a USB power supply, the dotted lines show where the external 5V supply should connect in.

Digital Compass Circuit Connections

The Code

You can download this sketch here: DigitalCompassv2.ino



/*
DigitalCompassv2.ino
Hamish Trolove - 13 July 2015
www.techmonkeybusiness.com
This sketch makes use of the HMC5883L based digital
compass and 16 x 2 LCD display to provide
heading readings.

The Pin assignments
LCD Display
Back light is connected to the 5V supply and Ground
therefore not controlled by the Arduino pins.
  VSS to GND
  VDD to 5V
  VO to sweep arm of 10kohm variable resistor
  RW to GND
  LCD RS - D12
  LCD E  - D11
  LCD D7 - D10
  LCD D6 - D9
  LCD D5 - D8
  LCD D4 - D7

HMC5883L Digital Compass
Connected to Ground and the 3.3V Supply pin on the Arduino
  SDA - Analogue 4
  SCL - Analogue 5
*/

#include <LiquidCrystal.h>
#include <Wire.h>  //i2c library for the Digital Compass



LiquidCrystal lcd( 12, 11, 7, 8, 9, 10 );
//Pins for the 16 x 2 LCD Display
//LiquidCrystal(rs, enable,d0,d1,d2,d3,d4,d5,d6,d7)

const int hmc5883Address = 0x1E; //0011110b, I2C 7bit address for compass
const byte hmc5883ModeRegister = 0x02;
const byte hmcContinuousMode = 0x00;
const byte hmcDataOutputXMSBAddress = 0x03;

void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.clear();  //make sure screen is clear.
  lcd.print("Compass is Go");
  delay(1000);
  Wire.begin(); // Start the i2c communication

  
  //Initialise the Digital Compass
  Wire.beginTransmission(hmc5883Address);  //Begin communication with compass
  Wire.write(hmc5883ModeRegister);  //select the mode register
  Wire.write(hmcContinuousMode); //continuous measurement mode
  Wire.endTransmission();
  
}

void loop()
{
  int x,y,z; //triple axis data.
  //Tell the HMC5883L where to begin reading the data
  Wire.beginTransmission(hmc5883Address);
  Wire.write(hmcDataOutputXMSBAddress);  //Select register 3, X MSB register
  Wire.endTransmission();
  
  //Read data from each axis
  Wire.requestFrom(hmc5883Address,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    
  }
  
  
  int angle = atan2(-y,x)/M_PI*180;
  if (angle < 0)
  {
    angle = angle + 360;
  }
  
  //Reporting the data to the LCD Screen
  lcd.clear();  //make sure screen is clear again.
  lcd.setCursor(0,0); //Top left hand corner
  lcd.print("XYZ:");
  lcd.setCursor(0,1); //Bottom left corner
  lcd.print("Dir(deg):");
  
  lcd.setCursor(4,0);
  lcd.print(x);
  lcd.setCursor(9,0);
  lcd.print(y);
  lcd.setCursor(13,0);
  lcd.print(z);
  
  lcd.setCursor(9,1);
  lcd.print(angle);
  
  delay(250);
  
}