mardi 12 février 2013

HMC5883L Compass + Arduino + Processing


You will find below the Arduino and ProcessingCode. I used the arduino example code found into the library, and adaped it a bit.
The Processing code is from a code that I found on internet and adapted and changed some graphic details.
You will find also a link to download the library that I use.

Since the video, I have solved the angle issue, now performing 90 degrees angle with the compass will ouput correctly a +/- 90 degrees on the serial port.

HMC5883L Library:
http://dl.free.fr/q9O0J0cXe


Arduino code:


// Reference the I2C Library
#include <Wire.h>
// Reference the HMC5883L Compass Library
#include <HMC5883L.h>

// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;

//rounding angle
int RoundDegreeInt;

int PreviousDegree = 0;

// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  // Initialize the serial port.
  Serial.begin(9600);

  Wire.begin(); // Start the I2C interface.

  compass = HMC5883L(); // Construct a new HMC5883 compass.
 
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));

  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
}

// Our main program loop.
void loop()
{
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();

  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);

  // 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: 2� 37' W, which is 2.617 Degrees, or (which we need) 0.0456752665 radians, I will use 0.0457
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = 0.009 ;
  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;

  //correcting the angle issue
  if (headingDegrees >= 1 && headingDegrees < 240)
  {
    headingDegrees = map(headingDegrees,0,239,0,179);
  }
  else if (headingDegrees >= 240)
  {
    headingDegrees =  map(headingDegrees,240,360,180,360);
  }

  //rounding the angle
  RoundDegreeInt =round(headingDegrees);

  //smoothing value
  if( RoundDegreeInt < (PreviousDegree + 3) && RoundDegreeInt > (PreviousDegree - 3) ) {
    RoundDegreeInt = PreviousDegree;
  }

  Output(RoundDegreeInt);

  PreviousDegree = RoundDegreeInt;

  // Normally we would delay the application by 66ms to allow the loop
  // to run at 15Hz (default bandwidth for the HMC5883L).
  // However since we have a long serial out (104ms at 9600) we will let
  // it run at its natural speed.
  // delay(66);
}

// Output the data down the serial port.
void Output(int RoundDegreeInt)
{
   //Serial.println();
   Serial.println(RoundDegreeInt);
 
   delay(150);
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Processing Code:

import processing.serial.*;

Serial myPort;
PFont b;

int lf = 10;    // Linefeed in ASCII
String myString = null;
float angle;

void setup(){
  size(600,400);
  b = loadFont("Arial-BoldMT-48.vlw");
  myPort = new Serial(this, "COM3", 9600);
}

void draw(){

background(255);

while (myPort.available() > 0) {
    myString = myPort.readStringUntil(lf);
    if (myString != null) {
  //print(myString);  // Prints String
    angle=float(myString);  // Converts and prints float
    println(angle);
    }
  }
  translate(160, 50);

  // draw the compass background
  ellipseMode(CENTER);
  fill(50);
  stroke(10);
  strokeWeight(2);
  ellipse(150,150,300,300);

  // draw the lines and dots
  translate(150,150);  // translate the lines and dots to the middle of the compass
  float CompassX = -angle;
  rotate(radians(CompassX));
  noStroke();
  fill(51, 255, 51);

  int radius = 120;

  for( int degC = 5; degC < 360; degC += 10) //Compass dots
  {
    float angleC = radians(degC);
    float xC = 0 + (cos(angleC)* radius);
    float yC = 0 + (sin(angleC)* radius);
    ellipse(xC,yC, 3, 3);
  }

  for( int degL = 10; degL < 370; degL += 10) //Compass lines
  {
    float angleL = radians(degL);
    float x = 0 + (cos(angleL)* 145);
    float y = 0 + (sin(angleL)* 145);
 
    if( degL==90 || degL==180 || degL==270 || degL==360) {
     stroke(51, 255, 51);
     strokeWeight(4);
    }
    else {
      stroke(234,144,7);
      strokeWeight(2);
    }
    line(0,0, x,y);
  }

  fill(102, 102, 102);
  noStroke();
  ellipseMode(CENTER);
  ellipse(0,0, 228,228); //draw a filled circle to hide the lines in the middle

  b = loadFont("Arial-BoldMT-48.vlw");
  textAlign(CENTER);

  // Draw the letters
  fill(250);
  textFont(b, 32);
  text("N", 1, -90);
  rotate(radians(90));
  text("E", 0, -90);
  rotate(radians(90));
  text("S", 0, -90);
  rotate(radians(90));
  text("W", 0, -90);
  rotate(radians(90));
 
  textFont(b,40);
  textAlign(CENTER);
  //text((angle), 20, 20);
  println(angle);

  //draw the needle

  rotate(radians(-CompassX)); //make it stationary
  stroke(234,144,7);
  strokeWeight(3);

  triangle(-10, 0, 10, 0, 0, -85);
  fill(234,144,7);
  triangle(-10, 0, 10, 0, 0, 60);

}











10 commentaires:

  1. could you give me the video link that solved the angle issue?

    RépondreSupprimer
  2. hy,
    under what license is your code - just for public use ?
    got it running - very nice !

    RépondreSupprimer
  3. please help with processing code? do i just paste it in a new sketch

    RépondreSupprimer
  4. For correct measurement with HMC5883L magnetometer you should calibrate it. Use the MagMaster software for magnetometer calibration. Article about this: http://diydrones.com/profiles/blogs/advanced-hard-and-soft-iron-magnetometer-calibration-for-dummies

    RépondreSupprimer
  5. after I try to take the HMC5883L Library:http://dl.free.fr/q9O0J0cXe;
    But the file was no longer there, can you give me a help ?

    RépondreSupprimer
  6. If your declination angle is 0.0457rad, why are you using "float declinationAngle = 0.009"?
    Is there any math I'm missing?

    RépondreSupprimer
  7. The link for the library download is broken... can u solve it? Thanks!

    RépondreSupprimer
  8. am i around here that have problem at compass setScale
    when i verify it say, 'class HMC5883L' has no member named setScale.
    i dont think the problem with the code, because i just try above code and same problem occur.
    please help me. i am newbie

    RépondreSupprimer
    Réponses
    1. I too have the same problem. I hope that author give us answer quickly

      Supprimer
    2. try to change to setscale with small litter

      Supprimer