SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By frogboyflips
#26552
Hello,

I would appreciate some assistance with developing some code that is capable of using a MicroMag3 magneto to provide a tilt compensated heading. I have searched these forums and the net; however, I have been unable to get this to work.

My understanding is that to calculate the heading the following formulas should be used:

Xh = X*Cos(pitch) + Y*Sin(roll) * Sin(pitch) – Z*Cos(roll)*Sin(pitch)
Yh = Y*Cos(roll) + Z*Sin(roll)

Heading = arcTan(Yh/Xh)

So far, I am only able to get a heading when the device is level. My tilt values also seem accurate.

My X and Y values have been calibrated, however I am unsure on how to use the Z value, do you just use the raw sampled value? I find that tilt is sometimes compensated when the magneto is pointing in certain directions and the tilt is one way. I have played about with the roll and pitch values such that they range from 0 to 360, as well as 0 to +/- 180.

Does anyone have sample code? This is driving me crazy!

Also this is my first post and I’d just like to say I think sparkfun is great, though I think I’m getting addicted to buying new parts!
By rmillqvist
#26915
Andrew,
I had the same problem with my Mag3.
How do you get your roll and pitch values?
In my case I use a 3 axis LIS3LV02DQ from Spark Fun.
The formula I use to calculate roll & pitch:
X,Y and Z from LIS3LV02DQ
Force from gravity G= sqr(X^2+Y^2+Z^2)
Actual Pitch= -arcsin(X/G)
Actual Roll= arcsin(Y/(G*cos(pitch))
Hope this is of help to you.
TTFN
Robert
By frogboyflips
#26919
Thanks for the help...

I can see one error I've made, my calculation for roll and pitch assumed that roll was in relation the the pitch plane, rather than the ground (if that makes sense).

Though, I've changed this now, but still no joy :(

Oh and should "Actual Roll= arcsin(Y/(G*cos(pitch)) " this have read "Actual Roll= arcsin(Y/G * (cos(pitch))

My MicroMag3 has an arrow on it pointing in a direction, is this the pitch plane?

Do you have any example code I could look at?
By rmillqvist
#27072
Andrew,
Make sure the mag3's x-axis & y-axis are parallell with the axis of the device you use to measure gravity. What device is your mag3 connected to and what languge do you write in? Mine is connected to an atmega128 and I use the Bascom compiler. In Bascom you can only have one calculation per line, I'll give you my code, hopefully it will make sense.
The following variables are used:
Magx,Magy,Magz readings from Mag3 (defined as integer).
Magxm,Magym,Magzm modified readings from Mag3 (defined as integer).
Isx,Isy,Isz readings from inertial sensor (defined as integer).
Gtot,Roll,Pitch,Tmp,Tmp1,Maghead defined as singles.

Calculate Roll & Pitch:
Gtot = Isx * Isx
Tmp = Isy * Isy
Gtot = Gtot + Tmp
Tmp = Isz * Isz
Gtot = Gtot + Tmp
Gtot = Sqr(Gtot)
Pitch = Isx / Gtot
Pitch = -Asin(pitch)
Tmp = Cos(pitch)
Tmp = Tmp * Gtot
Tmp = Isy / Tmp
Roll = Asin(Tmp)

Calculate modified magnetic x & y and heading:
Tmp = Magx * Cos(Pitch)
Tmp1= Magy * Sin(Roll)
Tmp1 = Tmp1 * Sin(Pitch)
Tmp = Tmp + Tmp1
Tmp1 = Magz * Cos(Roll)
Tmp1 = Tmp1 * Sin(pitch)
Magxm = Tmp - Tmp1
Tmp = Magy * Cos(Roll)
Tmp1 = Magz * Sin(Roll)
Magym = Tmp + Tmp1
Maghead = Magym / Magxm
Maghead = Atn(maghead)
Maghead = Rad2deg(maghead)
Maghead = Abs(maghead)
If Magxm >= 0 And Magym >= 0 Then Maghead = 180 - Maghead
If Magxm >= 0 And Magym < 0 Then Maghead = Maghead + 180
If Magxm < 0 And Magym < 0 Then Maghead = 360 - Maghead
Clear as mud?
TTFN
Robert
By gussy
#29439
Wow, this thread isn't as old as I thought it was.

I am trying to do the exact same thing, tilt compensate a compass reading.

Robert, would you be able to give a bit more info on what sort of hardware you are using??
By black_hawk97
#31472
Hi guys,

Just a quick question...

To calculate Xh and Yh do you need to specify roll and pitch in degrees or in radians? And then, the heading is in deg. or rad. ?

Thanks,
James
By rmillqvist
#31506
James,
I use the bascom compiler and all calculations are done in radians,
then I covert to degrees for display.
TTFN
Robert
By black_hawk97
#31540
Robert,

Thanks for your answer. Could you also tell me what raw values should i expect for each axis? I get something from the spi but it's pretty strange... i mean i only get values from +80 to +110...

All the best-

James
By rmillqvist
#31564
James,
When the device is horizontal X&Y will return zero
and Z will return 1024 when you select the +-2g scale.
If you roll it 90 degrees X will be 1024 , Y= 0 and Z= 0.
If you both tilt and roll the three axis will be between 0 and 1024.
There is a document on this forum outlining using this device
viewtopic.php?t=4548
TTFN
Robert
By black_hawk97
#31603
Hi Robert,

I was actually talking about the micromag3. I'm sorry i was unclear...
I'm trying to read 16 bits by initiating 2 transfers... something like this:

spi_transfer (0x01); // send command to read X axis

wait_drdy();

msb = spi_transfer (0x00); //read MSB
lsb = spi_transfer (0x00); //read LSB

x_axis = ((msb << 8 ) | lsb);

Theoretically it should work... but i don't know why i get only the LSB and i guess that's why the values are so strange...

Any help is greatly appreciated.

Thanks,
James
By jasonharper
#31616
Try this instead:
Code: Select all
x_axis = ((((int)msb) << 8 ) | lsb); 
I'm assuming that lsb and msb are 8-bit variables. Some C compilers will perform all math on 8-bit values at only 8-bit resolution, causing a loss of bits when a left shift or multiplication is done. This is actually a violation of the C specification, but following the spec would lead to poor performance on 8-bit microcontrollers. Casting one of the values to the size of the desired result will fix this.

Your x_axis variable is at least 16 bits, right?
By black_hawk97
#31708
Hello !

I've tried that and it still doesn't work... I found a small bug and fixed it and now i can get values for each axis between -20 to +20.

Robert, I could really use to know what values i should expect from the micromag during normal operation. I think that the values i'm getting are way too small. If i put a strong magnet close to it it goes up to 320-350. I think it should go up to 32768...
Another strange thing is that msb is either 0 or 255 and lsb varies from 0 to 255.

Thanks,
James
By rmillqvist
#31874
James,
These are the values I get when I calibrate the mag3.
I slowly turn round on the spot while the micro takes readings.
I then use these values to calculate the offset neeeded to centre the readings. These of course are the values you get in Brisbane Australia
TTFN
Robert
X Y Z
-108 766 -1578
-63 1902 -1578
-100 1956 -1578
-83 1988 -1578
-86 1944 -1578
-104 1945 -1578
-62 2027 -1578
-81 1969 -1578
-87 1947 -1578
-96 1945 -1578
-82 1947 -1578
-94 1939 -1578
-83 1967 -1578
-83 1951 -1578
-87 1944 -1578
-73 1949 -1578
-73 1997 -1578
-87 1911 -1578
-81 1951 -1578
-83 1950 -1578
-72 1918 -1578
-85 1977 -1578
-80 1927 -1578
-70 1940 -1578
-71 1944 -1578
-74 1950 -1578
-51 1957 -1578
-66 1985 -1578
-76 1918 -1578
-69 1950 -1578
-73 1951 -1578
-57 1895 -1578
-81 1987 -1578
-66 1930 -1578
-67 1948 -1578
-90 1947 -1578
-75 1951 -1578
-52 1950 -1578
-62 1999 -1578
-72 1966 -1578
-75 1944 -1578
-77 1953 -1578
-130 1945 -1578
-74 2021 -1578
-133 1961 -1578
-99 2029 -1578
-99 1907 -1578
-98 1945 -1578
-98 1944 -1578
-74 1934 -1578
-82 1947 -1578
-115 1950 -1578
-102 2043 -1578
-104 2015 -1578
-105 2014 -1578
-102 2013 -1578
-101 1994 -1578
-125 2021 -1578
-102 2041 -1578
-107 2029 -1578
-102 2009 -1578
-102 2014 -1578
-107 2014 -1578
-86 1952 -1578
-123 1942 -1578
-106 2035 -1578
-101 2024 -1578
-103 2013 -1578
-105 2014 -1578
-104 2008 -1578
-88 1952 -1578
-118 1949 -1578
-102 2004 -1578
-103 2015 -1578
-114 2014 -1578
-101 2011 -1578
-92 2013 -1578
-87 1958 -1578
-105 1961 -1578
-101 1994 -1578
-106 2015 -1578
-148 2003 -1578
-101 1998 -1578
-82 2017 -1578
-100 1980 -1578
-101 2002 -1578
-107 2016 -1578
-104 2003 -1578
-149 2002 -1578
-88 2018 -1578
-121 1936 -1578
-101 2030 -1578
-106 1987 -1578
-101 2009 -1578
-102 2011 -1578
-131 2010 -1578
-79 2009 -1578
-117 1938 -1578
-106 2031 -1578
-102 1985 -1578
-105 2006 -1578
-106 2009 -1578
-72 1999 -1578
-120 1943 -1578
-118 2051 -1578
-103 2038 -1578
-106 2011 -1578
-107 2013 -1578
-102 2000 -1578
-78 1968 -1578
-128 1941 -1578
-102 2034 -1578
-105 2022 -1578
-106 2011 -1578
-101 2007 -1578
-100 2018 -1578
-89 1946 -1578
-118 1946 -1578
-106 2005 -1578
-105 2010 -1578
-105 2003 -1578
-106 2006 -1578
-92 2012 -1578
-81 1946 -1578
-121 1939 -1578
-102 2037 -1578
-104 2017 -1578
-103 2011 -1578
-102 2019 -1578
-113 2003 -1578
-90 1971 -1578
-125 1939 -1578
-101 2021 -1578
-104 2006 -1578
-103 2010 -1578
-107 2016 -1578
-103 2010 -1578
-83 1991 -1578
-104 1960 -1578
-103 1991 -1578
-102 2009 -1578
-135 2015 -1578
-104 2005 -1578
-81 2007 -1578
-95 1991 -1578
-105 1953 -1578
-103 2007 -1578
-108 2009 -1578
-162 2002 -1578
-96 2009 -1578
-102 1935 -1578
-79 1980 -1578
-121 1944 -1578
-105 2032 -1578
-101 2023 -1578
-103 2011 -1578
-108 2014 -1578
-102 2004 -1578
-90 1985 -1578
-127 1938 -1578
-105 2036 -1578
-106 2015 -1578
-108 2013 -1578
-102 2004 -1578
-106 2003 -1578
-95 1975 -1578
-120 1950 -1578
-105 2005 -1578
-108 2014 -1578
-103 2002 -1578
-103 2007 -1578
-91 2017 -1578
-95 1925 -1578
-104 1941 -1578
-107 1989 -1578
-109 2003 -1578
-120 2006 -1578
-105 2007 -1578
-80 2016 -1578
-104 1982 -1578
-106 1972 -1578
-106 2014 -1578
-100 2007 -1578
-142 2004 -1578
-77 2012 -1578
-125 1965 -1578
-99 2049 -1578
-103 1914 -1578
-104 2014 -1578
-103 2011 -1578
-127 2002 -1578
-65 2007 -1578
-122 1934 -1578
-103 2024 -1578
-103 1992 -1578
-105 2012 -1578
-105 2011 -1578
-131 2017 -1578
-87 2004 -1578
-118 1947 -1578
By pako1000
#32393
Hi together

I followed this thread a while and I have the same problem. But I found a source for a example in c look here:

http://robotics.ee.calpoly.edu/projects ... cpp?rev=38

the site has a problem just press reload till it opens. Based on the site I wrote my own code for an atmle it looks like this:

int MAG_READ(char axis)
{
int t;
int Data;
char dontCare; // For a reading we don't care about


PORTD &= ~(1<<PB5); //SS auf low

PORTD |= (1<<PB3); //Reset auf high
for(t=0;t<5;t++); //5 Zyklen warten
PORTD &= ~(1<<PB3); //Reset auf low


dontCare = (int)spiTransferByte(0x60+axis); // Achse + Mess. Kommando /2048

PORTD |= (1<<PB5); //SS auf high

loop_until_bit_is_set(PIND,PINB4); // Warten bis Messung fertig

PORTD &= ~(1<<PB5); //SS auf low
Data=spiTransferWord(0x00);
PORTD |= (1<<PB5); //SS auf high

return (Data);

}

I hope this helps.

Is still can't manage the compensation . I tryed the logic from this paper with and without the z guessing but still no luck

"Tilt Compensation algorithm for 2-Axis magneic Compass"
http://nesl.snu.ac.kr/publication/papers/j_int/12.pdf

Perhaps somebody has a good idea

Regards
Patrick
By Chris_P
#37552
rmillqvist wrote: Calculate Roll & Pitch:
Gtot = Isx * Isx
Tmp = Isy * Isy
Gtot = Gtot + Tmp
Tmp = Isz * Isz
Gtot = Gtot + Tmp
Gtot = Sqr(Gtot)
Pitch = Isx / Gtot
Pitch = -Asin(pitch)
Tmp = Cos(pitch)
Tmp = Tmp * Gtot
Tmp = Isy / Tmp
Roll = Asin(Tmp)

Calculate modified magnetic x & y and heading:
Tmp = Magx * Cos(Pitch)
Tmp1= Magy * Sin(Roll)
Tmp1 = Tmp1 * Sin(Pitch)
Tmp = Tmp + Tmp1
Tmp1 = Magz * Cos(Roll)
Tmp1 = Tmp1 * Sin(pitch)
Magxm = Tmp - Tmp1
Tmp = Magy * Cos(Roll)
Tmp1 = Magz * Sin(Roll)
Magym = Tmp + Tmp1
Maghead = Magym / Magxm
Maghead = Atn(maghead)
Maghead = Rad2deg(maghead)
Maghead = Abs(maghead)
If Magxm >= 0 And Magym >= 0 Then Maghead = 180 - Maghead
If Magxm >= 0 And Magym < 0 Then Maghead = Maghead + 180
If Magxm < 0 And Magym < 0 Then Maghead = 360 - Maghead
Clear as mud?
TTFN
Robert
I am following Roberts example to get a tilt compensated heading from the Micromag3. I am not sure about a couple of things and hope someone is still around to help. I have a calibration routine where I rotate the Mag3 360 degrees while on a flat surface. From that I get the max and min values of the x and y axis. As the ranges of each axis are slightly different I work out a scale factor and then work out an offset to center the ranges. So now I have eg, -1400 to +1400 for both x and y axis. Without looking at the tilt yet, I can use these values to get a heading. So now I am looking at incorporating the tilt part of the formulas but I am unsure about the z axis readings from the Mag3. Should I treat it similarly in the calibration, ie work out a scale factor and an offset so it's range is the same as the x and y axis? I'd have to tilt the micromag 90 degrees and rotate it to do that, but then if I do this the x and y readings go outside the original calibration range. Any thoughts?

Edit: I found another device that does a similar thing and they roll the device 90 degrees and rotate it 360 degrees to calibrate the z axis. I have tried this, but regardless of what I do with the z axis I am only getting a tilt compensated reading if I tilt it one direction only, towards the south. Tilting it any other direction and the heading swings a lot. If anyone can help I would greatly appreciate it.