HMC5883L 3-Axis Compass
Posted: Tue Sep 11, 2012 11:57 pm
Hey everyone
I'm very new to programming, and I mostly know how to adapt from example. So, I'm pulling my hair out trying to get the HMC5883L to work with the Pi. Since it has 3 axis's and uses the first 6 byes from the output just like the ADXL345 accelerometer, I started out by cloning most of the code I was give which works very well for that sensor. However, while I am getting values from the compass, I don't think they're correct, or I'm mis-handling them in the code or calculations to arrive at a correct heading (0-360 in degress).
Has anyone got this sensor working correctly on the Pi yet? I'm hoping someone can help me work through the problem on here, and hopefully I can learn some things along the way. Here's the code I have working so far, but as I mentioned, as I rotate the module the values do change, but they are wrong, they keep going up and down, and don't seem to make it past 90 I'd say.
Of course, as is my style, I've scoured the web for code examples, not all of them include a heading calculation, but that's really what I want. There's a correction for magnetic declination to include as well, but I figured I better get this part working correctly first. Some of the links I've been using to derive commands and code, in addition to the datasheet, are:
https://www.loveelectronics.co.uk/Tutor ... no-library
http://www.seeedstudio.com/wiki/Grove_- ... pass_v1.0b
http://dakax.googlecode.com/svn-history ... C5883L.cpp
I know it's frowned upon to ask for help without trying enough first, so I've put in about two weeks of playing around with this module and C Code tweaks, and just can't figure it out myself.
Would anyone care to assist? Even if you don't have this module yourself, maybe you can spot obvious errors in the code? Help!
I'm very new to programming, and I mostly know how to adapt from example. So, I'm pulling my hair out trying to get the HMC5883L to work with the Pi. Since it has 3 axis's and uses the first 6 byes from the output just like the ADXL345 accelerometer, I started out by cloning most of the code I was give which works very well for that sensor. However, while I am getting values from the compass, I don't think they're correct, or I'm mis-handling them in the code or calculations to arrive at a correct heading (0-360 in degress).
Has anyone got this sensor working correctly on the Pi yet? I'm hoping someone can help me work through the problem on here, and hopefully I can learn some things along the way. Here's the code I have working so far, but as I mentioned, as I rotate the module the values do change, but they are wrong, they keep going up and down, and don't seem to make it past 90 I'd say.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/i2c-dev.h>
#define HMC5883L_I2C_ADDR 0x1e
void selectDevice(int fd, int addr, char * name)
{
if (ioctl(fd, I2C_SLAVE, addr) < 0)
{
fprintf(stderr, "%s not present\n", name);
//exit(1);
}
}
void writeToDevice(int fd, int reg, int val)
{
char buf[2];
buf[0]=reg; buf[1]=val;
if (write(fd, buf, 2) != 2)
{
fprintf(stderr, "Can't write to HMC5883L\n");
//exit(1);
}
}
int main(int argc, char **argv)
{
int x, y, z;
float head;
int fd;
int buf[16];
if ((fd = open("/dev/i2c-0", O_RDWR)) < 0)
{
// Open port for reading and writing
fprintf(stderr, "Failed to open i2c bus\n");
exit(1);
}
/* initialise HMC5883L */
selectDevice(fd, HMC5883L_I2C_ADDR, "HMC5883L");
writeToDevice(fd, 0x3c, 0x70);
writeToDevice(fd, 0x3c, 0xA0);
writeToDevice(fd, 0x3c, 0x00);
usleep(67000);
writeToDevice(fd, 0x3c, 0x03);
while (1)
{
/* select HMC5883L */
selectDevice(fd, HMC5883L_I2C_ADDR, "HMC5883L");
buf[0] = 0x06;
if ((write(fd, buf, 1)) != 1)
{
// Send the register to read from
fprintf(stderr, "Error writing to i2c slave\n");
//exit(1);
}
if (read(fd, buf, 6) != 6)
{
// X, Y, Z readings
fprintf(stderr, "Unable to read from HMC5883L\n");
//exit(1);
}
else
{
x = buf[0]<<8| buf[1];
y = buf[2]<<8| buf[3];
z = buf[4]<<8| buf[5];
head = atan2 (y,x) * 180 / 3.14159265358979323846;
printf("%4.0f\n", head);
writeToDevice(fd, 0x3c, 0x03);
}
usleep(67000);
}
return 0;
}
https://www.loveelectronics.co.uk/Tutor ... no-library
http://www.seeedstudio.com/wiki/Grove_- ... pass_v1.0b
http://dakax.googlecode.com/svn-history ... C5883L.cpp
I know it's frowned upon to ask for help without trying enough first, so I've put in about two weeks of playing around with this module and C Code tweaks, and just can't figure it out myself.
Would anyone care to assist? Even if you don't have this module yourself, maybe you can spot obvious errors in the code? Help!
