Problems with Heading of HMC5883L 3 Axis Compass Module
Saravanan
Posts: 19
Dear All,
I am using a Parallax compass module "HMC5883L" with the sample code which was found in the Examples=>Sensor Folder. I changed the Pin configuration to be connected as SCL=>P3 and SDA=>P4. There is no other changes made. When I run this code there seems to be some problems with the heading. The change in heading isn't linear. Heading increases from 0 to 200 degrees just within 90 degrees of movement of the sensor and the change in degrees is very slow for the rest of the circle. I do understand that I am turning along the z axis. Hope someone can help me out on this! Below is the code that I used.
I am using a Parallax compass module "HMC5883L" with the sample code which was found in the Examples=>Sensor Folder. I changed the Pin configuration to be connected as SCL=>P3 and SDA=>P4. There is no other changes made. When I run this code there seems to be some problems with the heading. The change in heading isn't linear. Heading increases from 0 to 200 degrees just within 90 degrees of movement of the sensor and the change in degrees is very slow for the rest of the circle. I do understand that I am turning along the z axis. Hope someone can help me out on this! Below is the code that I used.
/* Test Compass HMC5883L.c Test compass with SCL connected to P3 and SDA connected to P4. Display measurement results in SimpleIDE Terminal. http://learn.parallax.com/propeller-c-simple-devices/ */ #include "simpletools.h" // Include simpletools header #include "compass3d.h" // Include compass3d header int main() // main function { int x, y, z; // Declare x, y, & z axis variables i2c *bus = i2c_newbus(3, 4, 0); // New I2C bus SCL=P3, SDA=P4 compass_init(bus); // Initialize compass on bus. while(1) // Repeat indefinitely { compass_read(bus, &x, &y, &z); // Compass vals -> variables print("%cx=%d, y=%d, z=%d%c\n", // Display compass variables HOME, x, y, z, CLREOL); float fy = (float) y; // Ints to floats float fx = (float) x; float heading = atan2(fy, fx) * 180.0/PI; // Calculate heading with floats if(heading < 0.0) // Convert -180...+180 to 0...360 heading = (360.0 + heading); print("heading = %.2f%c\n", // Display heading heading, CLREOL); pause(200); // Wait 1/2 second } }
Comments
Depending on how far away you are from a magnetic pole you can get some strange results with the sensor. Here in Idaho we have a very large component in the z axis of the magnetic field. I was still able to get good heading readings but I think a strong z component could cause trouble.
Is there any iron near the sensor? How about motors?
What values do you get for the x, y and z components as you rotate the sensor? If you shared the raw x, y and z values when the compass is oriented close to north, east, south and west, it might provide some clues on how the sensor is working.
If you're willing to try some Spin code, you could use my demo I attached to this post:
http://forums.parallax.com/showthread.php/155653-My-Version-of-a-HMC5883L-Object?p=1267049&viewfull=1#post1267049
IIRC, My version will tell you how far from horizontal the magnetic field is. The code also allows one to easily change the various registers in the sensor. This allows gain and internal averaging values to be changed.
This are the raw readings and the processed heading readings from the chip which is running the sample code.
x y z heading(Deg)
North 125 -385 -386 286
East 204 -70 -389 348.67
South -92 -7 -386 181.47
West -182 -285 -369 235.2
That doesn't look right. The y-axis stays negative?!
If your sensor got close to a large magnet it could be messed up for a while.
If your sensor is out of whack because of a magnet, I think there's a way to fix it but I don't recall what it is.
I was going to try the code with my sensor but the example code in the version of Simple IDE I had installed wasn't the same as the code you used.
I'll install a recent version of Simple IDE and try again.
My sensor also does not output good information using the example program.
I think there are other C programs available.
I haven't tried the code in this thread but I think it looks promising.
http://forums.parallax.com/showthread.php/159754-Propeller-Activity-board-C-Compass-project
I'll send a bug report to Parallax about this.
Edit: I tried the code again and it now appears to work. I'm going to test this a bit more. I'll post again later.
I changed the half second delay to a tenth of a second but the display appears to only update about one a second.
I'm trying to get a look at the library files to see if there's something limiting how frequently the sensor is read.
I know from my past experience these sensor work really well and can update quickly. I think there's something in the code which is slowing it down.
I'll try to track this down but I might not get around to it today.
I doubt there's anything wrong with your sensor.
If you have the Propeller Tool installed or some other software to load Spin programs, you might want to take a look at the code I linked to earlier.
Once these readings have been acquired, they can be entered in my online calibration program:
It will return a line like the following:
that can be inserted into a Spin program or the values copied into a C program. In my compass object (which does not use the Z axis at all, since in my app the compass will always be level), these values are named x_ampl, x_offset, y_ampl, y_offset, and a_offset.
To compute corrected xc and yc values from the raw x and y, use the following formulae:
Then the corrected compass heading (in tenths of a degree) is:
where atan2 has to return an angle in tenths of a degree.
BTW, this is all predicated upon interpreting the "heading" as pointing away from, and perpendicular to, the five-pin header of the Parallax module.
-Phil
Thanks for the information.
I've seen calibration information similar to what you use but the couple sensors I've used worked pretty well without calibration.
Apparently besides having the x, y coordinates "off center", they can also be stretched in one axis or the other. The ap note I attached to this post includes calibration techniques for overcoming these errors. I had hoped they weren't really needed but apparently I've just been lucky with the sensors I've used so far. Edit: I hadn't read Phil's post carefully enough. He already mentioned the stretch issue.
I'm not sure if I've used two or three of these sensors myself but the ones I've used were pretty symmetrical (and centered) in their output range. Though TTYTT, I haven't checked very carefully. I just checked N, S, E & W, I didn't graph a circle as you suggest.
I'm still trying to figure out why the program appears to update so slowly.
BTW, I think this is the initialization code for the compass;
I found the above code in the file "SimpleIDE\Learn\Simple Libraries\Sensor\libcompass3d\compass3d.c"
The only register changed from the default setting is the mode register which is changed to place the sensor in continuous mode. The default refresh rate is 15Hz so I don't understand why my sensor updates so slowly.
I'm out of my comfort zone when it comes to C on the Prop. I fear I could easily be missing something obvious.
I'll probably go back to the Spin demo to make sure I'm remembering the performance of the sensor correctly. It sure seems like the sensor was pretty quick to update when running the Spin code.
In case anyone else is curious about the function "i2c_out" it's located in a C file of the same name "SimpleIDE\Learn\Simple Libraries\Utility\libsimpletools\source\i2c_out.c."
I find I have a hard time finding functions used by a C program. (To be honest I haven't spent a lot of time using C on the Propeller, so I shouldn't be too surprised I'm having a hard time finding my way around the library files.)
@Andy,
The is the output when my sensor is level and aligned with magnetic north.
(Darn, SimpleIDE Terminal doesn't let me copy the output to the clipboard. I suppose I can use PST with SimpleIDE.)
Edit: I hadn't read Phil's excellent post carefully enough before replying. Phil mentioned the calibration points could form an ellipse.
I have tried your calibration technique and I got these values from the online program.
compass_corr long 295,42,288,-193,123
Then I went on to include these in my code as follows:
I now get my value for a as 1021.0 to 1023.8 when I rotate the full axis. Is there anything I have skipped or done wrong?
I don't know what's different today but the sensor is working fine. It's updating very quickly.
I don't think there's anything wrong with the C code.
I'm not following along well enough to know what's wrong. I see a mixture of integer math with floating point math but apparently you can do that with C.
I can't find my Parallax board but when I run the SimpleIDE code, I get a heading of zero when the x-axis is aligned with magnetic north. I also see your equation has a 90 degree value not present in the SIDE code.
I found Arduino example code which uses the same orientation of the sensor as you're using but IMO, having the x-axis aligned north simplifies the calculations needed to determine heading.
BTW, the y-axis on the Parallax PCB silkscreen is pointing in the opposite direction from the HMC5883L datasheet (I've seen this mentioned elsewhere on the forum).
@Saravana, The SimpleIDE code and the code Phil posted are not compatible with each other without some changes.
I can't find my Parallax board but when I run the SimpleIDE code, I get a heading of zero when the x-axis is aligned with magnetic north. I also see your equation has a 90 degree value not present in the SIDE code.
I found Arduino example code which uses the same orientation of the sensor as you're using but IMO, having the x-axis aligned north simplifies the calculations needed to determine heading.
BTW, the y-axis on the Parallax PCB silkscreen is pointing in the opposite direction from the HMC5883L datasheet (I've seen this mentioned elsewhere on the forum).
@Saravana, The SimpleIDE code and the code Phil posted are not compatible with each other without some changes.
what are the proposed changes you suggest? I am very new to parallax propeller activity board and simple IDE. What is a SPIN program?
I'll need to study Phil's code a bit and attempt to modify the example code to work with your figures.
I'll likely do this later in the day as I procrastinate my real work (which these days is programming in Spin).
Spin is the language Chip Gracey developed for use with the Propeller (Chip also designed the Propeller). The Spin interpreter resides in the Propeller's read only memory.
I was initially annoyed to have to learn Spin to use the Propeller since I previously programmed in C. I found Spin was very easy to learn after having learned some C.
I now find Spin extremely enjoyable to use.
There are links in post #3 of my index (see my signature) on learning Spin.
It would probably be a good idea for you to download the Propeller Tool (the IDE for writing Spin programs) and to give Spin a try. I'm not going to suggest you switch from using C to using Spin since Parallax is putting a lot of effort into their C tutorials and it would be a shame to miss out on Parallax's excellent tutorials.
Let us know if you need help finding the Propeller Tool to download. I don't know where to find it off hand but I'm sure I could find it if I looked.
Yes, there is a way to calibrate the compass using Simple IDE. I think I've figured this out enough to help.
You'll want to use the this set of correction factors when you first run the program:
Go through the process Phil described again with the first set of code in this post. I suggest you write down the z value as well. The z value shouldn't change much as you rotate the sensor. When I calibrated my sensor the z ranged from -584 to -603. Hopefully the z value in a low latitude will be more consistent. The calibration process is very sensitive to sensor being level.
I didn't worry about formatting the code nicely I just stuck extra code where I guessed was a good spot. A lot of the extra initialization code should probably be moved to a separate function but I just added it to the main function.
The above code sets the sensor to the highest gain sensitivity. It also have the sensor average 8 readings the number of reads has been increased from 15 a second to 30 a second. I thought my sensor performed better with these changes.
One I added Phil's calibration values, my sensor behaved pretty well.
I didn't include the "a_offset" value in the calculations. If you want to convert the magnetic heading to a true heading let us know and I'll had a correction factor back in (though it won't be the one calculated by Phil's program).
With Spin one can't really mix integers and floating point values. I treated the program as it these values couldn't mix. I don't know if this precaution was needed or not. The above code seems to work well with my sensor.
BTW, typically the a_offset value will be small. But if not, it should be used to compute the magnetic heading. Then you can add/subtract the declination on top of that to get a true heading.
-Phil
I tried the code as you said. The sensor works well now. It is very accurate! Thanks alot for helping me out.
It's basically just a Fourier analysis to compute the DC and fundamental coefficients from the sample data.
-Phil
Very cool. I hope you tell us more about the event.
Very good. I was wondering how you calculated the amplitude values. I could replicate the offset values with a spreadsheet program but my attempts to compute the amplitude values never agreed with the values provided from the output from your web page. I don't understand Perl but I think I can pick out the equations in the code. Thanks for posting it.
@Saravana, It's good to hear the sensor is working well.
the gain is set to 000 and according to the data sheet(page13) the Gain(LSb/Gauss) is 1370. Therefore to change the raw data to units of Gauss I divided the data with 1370. Is this correct?
I think this is correct.