Showing posts with label GY-271 (3-Axis Digital Compass module using HMC5883L). Show all posts
Showing posts with label GY-271 (3-Axis Digital Compass module using HMC5883L). Show all posts

Sunday, April 26, 2015

Simple Compass - Arduino Nano + GY-271(HMC5883L) + mini-OLED

Use Arduino Nano + GY-271 Digital Compass Module (with HMC5883L) + 0.96" I2C mini-OLED to implement a simple compass.


For HMC5883L library with calibration, refer LAST POST.
For u8glib library used on 0.96" I2C mini OLED, refer Hello World 0.96 inch 128X64 I2C OLED, on Arduino Uno, using u8glib library.
Connection between Arduino Nano, GY-271 and the mini OLED via I2C, refer to Arduino Nano + GY-271 (Digital Compass module) + OLED.


Nano_Compass.ino
/*
http://arduino-er.blogspot.com/

For HMC5883L_Header_Arduino_Auto_calibration library
ref: http://hobbylogs.me.pn/?p=17

For u8glib Universal Graphics Library for 8 Bit Embedded Systems
ref: https://code.google.com/p/u8glib/
*/

#include "U8glib.h"
#include <Wire.h>
#include "compass.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);

#define Task_t 10          // Task Time in milli seconds

int dt=0;
unsigned long t;
// Main code -----------------------------------------------------------------
void setup(){
  Serial.begin(9600);
  // Serial.print("Setting up I2C ........\n");
  Wire.begin();
  compass_x_offset = -48.23;  //122.17;
  compass_y_offset = 284.69;  //230.08;
  compass_z_offset = 59.87;  //389.85;
  compass_x_gainError = 1.07;  //1.12;
  compass_y_gainError = 1.09;  //1.13;
  compass_z_gainError = 1.01;  //1.03;
  
  compass_init(2);
  //compass_debug = 1;
  //compass_offset_calibration(3);

}

void loop(){
  
  t = millis();
 
  float load;
 
  compass_scalled_reading();
  
  Serial.print("x = ");
  Serial.println(compass_x_scalled);
  Serial.print("y = ");
  Serial.println(compass_y_scalled);
  Serial.print("z = ");
  Serial.println(compass_z_scalled);
  
  compass_heading();
  Serial.print ("Heading angle = ");
  Serial.print (bearing);
  Serial.println(" Degree");
  
  dt = millis()-t;
  load = (float)dt/(Task_t/100);
  Serial.print ("Load on processor = ");
  Serial.print(load);
  Serial.println("%");
  
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );

  delay(100);
}

void draw(void) {
  static int armLength = 20;
  static int cx = 64;
  static int cy = 20;
  int armX, armY;
  
  //convert degree to radian
  float bearingRad = bearing/57.2957795;
  armX = armLength*cos(bearingRad);
  armY = -armLength*sin(bearingRad);

  u8g.setFont(u8g_font_unifont);
  
  u8g.setPrintPos(0, 60);
  u8g.print("bearing: ");
  u8g.setPrintPos(70, 60);
  u8g.print(bearing);
  
  u8g.drawLine(cx, cy, cx-armX, cy-armY);
  u8g.drawCircle(cx, cy, armLength, U8G_DRAW_ALL);

}

Saturday, April 25, 2015

HMC5883L library with calibration, for Arduino

Last post I read HMC5883L (in GY-271) from Arduino Nano. Then I tried to convert to bearing by calling atan2((double)y, (double)x) * 180/M_PI. The result have very big error without calibration. Finally I found this library HMC5883L Header Arduino With Auto calibration. For detail about the functions read http://hobbylogs.me.pn/?p=17#more-17


Here is modified from Compass_header_example_ver_0_2.ino to display bearing on mini OLED.
/*
For HMC5883L_Header_Arduino_Auto_calibration library
ref: http://hobbylogs.me.pn/?p=17
*/

#include "U8glib.h"
#include <Wire.h>
#include "compass.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);

#define Task_t 10          // Task Time in milli seconds

int dt=0;
unsigned long t;
// Main code -----------------------------------------------------------------
void setup(){
  Serial.begin(9600);
  // Serial.print("Setting up I2C ........\n");
  Wire.begin();
  compass_x_offset = -48.23;  //122.17;
  compass_y_offset = 284.69;  //230.08;
  compass_z_offset = 59.87;  //389.85;
  compass_x_gainError = 1.07;  //1.12;
  compass_y_gainError = 1.09;  //1.13;
  compass_z_gainError = 1.01;  //1.03;
  
  compass_init(2);
  //compass_debug = 1;
  //compass_offset_calibration(3);

}

// Main loop 
// Main loop -----------------------------------------------------------------
void loop(){
  
  t = millis();
 
  float load;
 
  compass_scalled_reading();
  
  Serial.print("x = ");
  Serial.println(compass_x_scalled);
  Serial.print("y = ");
  Serial.println(compass_y_scalled);
  Serial.print("z = ");
  Serial.println(compass_z_scalled);
  
  compass_heading();
  Serial.print ("Heading angle = ");
  Serial.print (bearing);
  Serial.println(" Degree");
  
  dt = millis()-t;
  load = (float)dt/(Task_t/100);
  Serial.print ("Load on processor = ");
  Serial.print(load);
  Serial.println("%");
  
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );

  
  delay(100);
}

void draw(void) {
  u8g.setFont(u8g_font_unifont);

  u8g.setPrintPos(0, 15);
  u8g.print("x: ");
  u8g.setPrintPos(70, 15);
  u8g.print(compass_x_scalled);
  
  u8g.setPrintPos(0, 30);
  u8g.print("y: ");
  u8g.setPrintPos(70, 30);
  u8g.print(compass_y_scalled);
  
  u8g.setPrintPos(0, 45);
  u8g.print("z: ");
  u8g.setPrintPos(70, 45);
  u8g.print(compass_z_scalled);
  
  u8g.setPrintPos(0, 60);
  u8g.print("bearing: ");
  u8g.setPrintPos(70, 60);
  u8g.print(bearing);

}

For compass.cpp and compass.h, refer to https://github.com/helscream/HMC5883L_Header_Arduino_Auto_calibration/tree/master/Core/Compass_header_example_ver_0_2.



Next:
- Simple Compass - Arduino Nano + GY-271(HMC5883L) + mini-OLED

Friday, April 24, 2015

Arduino Nano + GY-271 (Digital Compass module) + OLED

This example show a Arduino Nano, connect with GY-271 Digital Compass module and 0.96" 128x64 OLED via a common I2C bus. GY-271 is a Digital Compass module using HMC5883L, a 3-Axis Digital Compass IC. The reading from GY-271 (x, y, abd z) is display on the OLED. Arduino Nano communicate with GY-271 via I2C bus using Wire library. Arduino Nano communicate with 0.96" 128x64 OLED via the same I2C bus, using u8glib library. I'm not sure is it 100% compatible to use both Wire and u8glib libraries, both share the common I2C bus. Anyway in this example it work.


Connection:
VCC of GY-271, OLED and Arduino Nano connect together.
GND of GY-271, OLED and Arduino Nano connect together.
SCL of GY-271 and OLED connect to A5 of Arduino Nano.
SDA of GY-271 and OLED connect to A4 of Arduino Nano.
DRDY of GY-271 no connection.
(In the following Fritzing drawing, the HMC5883 breakout not exactly my GY-271 module, just to show the connect of SCL and SDA.)


Nano_OLED_Compass.ino
#include "U8glib.h"
#include <Wire.h> //I2C Arduino Library

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

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);

int x,y,z; //triple axis data

char bufferX [20];
char bufferY [20];
char bufferZ [20];

void draw(void) {
  u8g.setFont(u8g_font_unifont);
  u8g.drawStr( 0, 20, bufferX);
  u8g.drawStr( 0, 40, bufferY);
  u8g.drawStr( 0, 60, bufferZ);

}

void setup(void) {
  x = 0;
  y = 0;
  z = 0;
  
  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(void) {
  //Tell the HMC5883 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
  }
  
  sprintf(bufferX, "x : %d", x);
  sprintf(bufferY, "y : %d", y);
  sprintf(bufferZ, "z : %d", z);

  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );
  
  delay(100);
}



Then I tried to find the bearing by calling atan2((double)y, (double)x) * 180/M_PI, but get a very big error without calibration. Finally I found a library with auto calibration, read next: HMC5883L library with calibration, for Arduino.

About 3-Axis Digital Compass IC HMC5883L:



- 3-Axis Digital Compass IC HMC5883L
- Application Note – AN226 Honeywell HMC5883L/HMC5983 3-Axis Digital Compass IC Pin Configuration for I2C Communication