Hello All. I am a bit of a noob, but please bear with me.
I'm trying to use Honeywell's HMC5883L as a digital compass. I've compiled a piece of code from random sites on the internet to drive it, and output x, y and z values down the serial. That part works satisfactorily. However, I've been trying to make additions to that code that calculates a vector (only from the x and y at this point, although I'd like z too) as an angle and a magnitude.
It also should calculate which of eight outputs to use, to light up some LED's.
I'm having a problem with the numbers, though- for some inputs the output numbers get stuck on 0.00, or values like -0.79. If I change the number types up the top (I've been experimenting with having m, a and o as long or float numbers) it can get stuck on -2147483648.
Why is this? It's really annoying. Also, does anyone know how I could integrate the z axis, and how I could make the arduino output to the relevant LED?
Here is the code I am using. Only the comments that directly mention me are mine, I am aware some of them hide code, or are in stupid places. Also attached is a representation of my magnetometer and arduino setup. I am using a duemilanove with a 328, via Mac OSX 10.6.8.
// HMC5883L Arduino Sketch, compiled on 22/06/2012 by Marlo Webber from other people's code
#include <Wire.h>
#define address 0x1E //0011110b, I2C 7bit address of HMC5883
//defining numbers. I added m, a, and o here.
int cnt=0;
int x,y,z;
long xx,yy,zz;
long m,a,o;
void setup(){
//Initialize Serial and I2C communications
Serial.begin(9600);
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(){
//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);
while(Wire.available() < 6);
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
//if(zz>4800)
//corrections?
float heading=atan2(yy,zz); //zz instead of xx
//Print out values of each axis
Serial.print("x: ");
Serial.print(x);
Serial.print(" y: ");
Serial.print(y);
Serial.print(" z: ");
Serial.print(z);
//repeatable within 1 deg, but off by 90 deg?
//The code I've added
m = sqrt((x*x) + (y*y));
a = atan2(y,x);
o = (a/(4/PI));
Serial.print(" m: ");
Serial.print(m);
Serial.print(" a: ");
Serial.print(a);
Serial.print(" o: ");
Serial.println(o);
if (zz > 4800)
{ //near level 5200 max down, in MA
//Serial.print(xx);Serial.write(32);Serial.println(yy);
float heading=atan2(yy,xx);
heading*=(180/M_PI);
//declination here degrees
if(heading<0)heading+=360;
if(heading>360)heading-=360; //for + declination only
//upside down on board so...
heading=360-heading;
Serial.println(heading);
}
delay(50); //50 or 150 more acc 3s
}
boolean avgxyz(){
const int N=20; //matches delay 20*50=1s
boolean b;
cnt++;
if(cnt%N==1)xx=yy=zz=0;
xx+=x;
yy+=y;
zz+=z;
if(b=!(cnt%N)){
xx=xx*10/N;yy=yy*10/N;zz=zz*10/N; }
return(b);
}