I've connected the LM303 to a Arduino mega. I ran the test sketch and it appears to be reading and working fine. I just want to use it as a compass for now, so I downloaded the Adafruit example code that "converts the microTesla readings into a 0-360 degree compass heading" It's not giving me a linear 0' to 360' reading. If I point it to north with a slight back and forth the reading is 0'/360' (that seems correct). due east gives me 45', south is 90'. just slightly past south, about ssw, it jumps from 110' to 260', west is 305'
I didn't do the calibration as it states that for most applications the factory calibration is good. Plus that seems to be more if you're using the 3 axis
Here is the code I'm using
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
/* Assign a unique ID to this sensor at the same time */
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);
void setup(void)
{
Serial.begin(9600);
Serial.println("Magnetometer Test"); Serial.println("");
/* Initialise the sensor */
if(!mag.begin())
{
/* There was a problem detecting the LSM303 ... check your connections */
Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
while(1);
}
}
void loop(void)
{
/* Get a new sensor event */
sensors_event_t event;
mag.getEvent(&event);
float Pi = 3.14159;
// Calculate the angle of the vector y,x
float heading = (atan2(event.magnetic.y,event.magnetic.x) * 180) / Pi;
// Normalize to 0-360
if (heading < 0)
{
heading = 360 + heading;
}
Serial.print("Compass Heading: ");
Serial.println(heading);
delay(500);
}
All comments and suggestions most welcomed
Thanks
John
Big mistake. Whoever said that "the factory calibration is good" could not be more wrong, because magnetometers are strongly affected by any magnetic or iron containing materials in their vicinity, as well as nearby current carrying wires.
See this tutorial for the best and most effective calibration procedure.
You absolutely have to do the hard iron/soft iron calibrations for any compass chip on a breakout board, since
PCBs are covered in small parts with steel endcaps(*)! Only with the chip hanging in midair from fine copper
wires could you expect the factory calibration to be usable.
I'm trying to build an autonomous rover, so right now I just have the LM303, an Arduino and a Raspberry Pi double backed tape to a board but the board is mounted on top of the rover which is a large, metal framed, RC truck that I'm using for my testing. That frame must really be throwing it off
Well yes, you don't expect a compass to work at all on top of a steel frame. But you said metal framed,
it matters which metal. You might consider mounting it on top of a pole to get clearance. It needs
to be far from the motors and their magnets anyway, increasing the height tends to help with this.
I believe the frame is aluminium, there's 2 motors, front & back axles, ones about 10 inches away from the LM303 the other about 16 but I haven't turned them on yet. Right now it's on a stand that is on a lazy Susan so I can turn it easily. Mounting it higher is a good suggestion, eventually this will all be in a model sailboat so everything will be mounted differently, the ultimate goal is an autonomous sailboat The rover is just my test platform for now.
Wow! my head is spinning with all the info you've sent me and what I need to do to get this working, it will take awhile for it to sink in. But I do find it all fascinating and will figure it out. For now to get this working so I understand it I can take the board everything is mounted on off of the rover and just use it like that.
One of the links I followed got me to the Github of Pololu. They have a library and a calibrate sketch. It's just the basic calibrate routine where you rotate the unit on each axis and get some min/max values. I figured I start with the easy way to understand the functions of it all. So I got my min/max values. Now I have to enter them into my heading sketch to correct my readings. My problem now is I can't figure out what the Adafriut parameter, or would the correct term be arguments, to enter the values back into the sensor. Pololu also has a heading sketch where you put the min/max values in. I did that and it appears to be working but it's giving me the vector value not degrees. So I tried modifying the Adaruit sketch using the parameters names that are in the Pololu sketch but that's not working.
I looked through the Adafuit library and associated files to see if I could find those parameter names. But nothing jumped out and said here it is John. Where would I find those?
I really appreciate your help with this
Thanks again
John
For the most part I'm trying to figure this out on my own, books, videos, taking apart other people's code and a vast amount of help by people like yourself in forums. I've been programming industrial machines for over 40 years, but mostly using PLC's. I have gone through lots of lessons in CC++, Arduino, python and Process but like anything if you don't use it a lot you forget plus some of it was a bit hard for me to understand in the first place. I'm sure I've forgotten more than I know.
LOL, yes the frustration levels get pretty high sometimes but that's what makes it interesting and the satisfaction just as high when I figure it out.
I'm going to working with the Pololu Heading sketch, see below, it seems to be a better written one. I'll try to get the same output that I got from the previous sketch I posted. Then it's a simple math problem.
I truly appreciate your time and your help
Thanks
John
#include <Wire.h>
#include <LSM303.h>
LSM303 compass;
void setup() {
Serial.begin(9600);
Wire.begin();
compass.init();
compass.enableDefault();
/*
Calibration values; the default values of +/-32767 for each axis
lead to an assumed magnetometer bias of 0. Use the Calibrate example
program to determine appropriate values for your particular unit.
*/
compass.m_min = (LSM303::vector<int16_t>){-32767, -32767, -32767};
compass.m_max = (LSM303::vector<int16_t>){+32767, +32767, +32767};
}
void loop() {
compass.read();
/*
When given no arguments, the heading() function returns the angular
difference in the horizontal plane between a default vector and
north, in degrees.
The default vector is chosen by the library to point along the
surface of the PCB, in the direction of the top of the text on the
silkscreen. This is the +X axis on the Pololu LSM303D carrier and
the -Y axis on the Pololu LSM303DLHC, LSM303DLM, and LSM303DLH
carriers.
To use a different vector as a reference, use the version of heading()
that takes a vector argument; for example, use
compass.heading((LSM303::vector<int>){0, 0, 1});
to use the +Z axis as a reference.
*/
float heading = compass.heading();
Serial.println(heading);
delay(100);
}
Those two programs from Pololu perform and make use of the minimum calibration that is required, but that particular correction method may not be good enough to make a useful compass.
I'll probably start off with the easy stuff and build on that as I learn more. That's typically how I do my projects a step at a time and build off of each step. I will eventually need to have a tilt compensated compass as it will be on a sailboat and they do tilt.
I just heard from a guy I met at a Raspberry Pi meeting I went to one night. He is familiar with these, has made a self leveling robot with one, and has offered to help me.
Once again I thank you for your time and suggestions. The links you provided me have given me lots of great info.