[Compass] Magnetometer Library (HMC5883)

cmopassheader

This post includes a HMC5883 Magnetometer Library for Arduino. It contains a library that makes interfacing with a compass module (for arduino) in C++ very easy. There are other libraries for the HMC5843, but they are not compatible with the HMC5843. Other libraries i found for the HMC5883 of sample codes were either inefficient or plain incorrect. You can download the library if you scroll to the bottom.

There is a breakout for this module that Seeedstudios sell for about $25, which is a great deal and includes handling of some stuff we can now ignore; like the correct voltage (it accepts like 3~6V). Anyway. You can buy it here for just $25.

This is actually a 3 axis magnetometer for arduino, and does not contain tilt compensation. For big tilts you would need tilt compensation, but it is not strictly necessary.

How does a 3 axis magnetometer work?

It reads magnitudes in X Y and Z direction. Then using sine and cosine functions you can calculate the angle between them; thus obtaining the angle between the earths magnetic force and your little module.

Example

This library is also not very efficient or versatile, but since it’s so simple, everyone understands it. It is as easy as:

  1. #include <wire.h>
  2. #include <hmc.h>
  3. int a;
  4.  
  5. void setup()
  6. {
  7.   Serial.begin(9600);
  8. }
  9.  
  10. void loop()
  11. {
  12.   int x,y,z;
  13.   delay(100); // There will be new values every 100ms
  14.   HMC.getValues(&x,&y,&z);
  15.   Serial.print("x:");
  16.   Serial.print(x);
  17.   Serial.print(" y:");
  18.   Serial.print(y);
  19.   Serial.print(" z:");
  20.   Serial.println(z);
  21.  
  22.   HMC.getAngle(&a);
  23.   Serial.println(a);
  24. }

The code is based on the Seeeduino module, which provides more info about that here.

Download magnetometer code library

Download: HMC_library.zip

Tim Zaman

Engineer from The Netherlands (1988). Living in Delft. MSc degree in Robotics. Is on a PhD research position on development of imaging devices. For contact see 'About' in the above menu.

You may also like...

23 Responses

  1. Clemens Seidenberg says:

    Hello Tim,

    I have an issue with the z-channel. It always shows the value -4096.
    I saw your post to fabio (free imu) reporting an similar problem (?).

    Do you have any explanation / solution for that problem.

    Clemens

  2. Tim says:

    Yes i have a solution: don’t use Fabio’s library as it is great fot the HMC5843; but use this one for the HMC5883: it’s not as extensive as that of Fabio’, but it is easier and fine on the other hand :). Which one are you using?

    • Clemens Seidenberg says:

      I’ve tried yours and the one published by seeeduino.garden. But always the same
      issue. I know that the sequence of the registers is different compared to the 5843. Following the datasheet -4096 indicates an ADC over- or underflow. Maybe my hardware is buggy.

      • Tim says:

        I had the same problem when there was some ferrous material (screwdriver) near. Try doing it away from all objects (do mind your speakers f.e.). Otherwise just return it…

  3. Fbo says:

    Hello Tim, thank you for your working, i use the TWIG and your library but i have something i can’t explain ! the values of x, y & z always varies (it’s not stable) even i don’t touch the sensor. Do you have an issue ?
    ie:
    x:21 y:-21 z:-235
    -93
    x:12 y:-14 z:-230
    -64
    (…)

    • Tim says:

      Actually that does not look that bad. But i think you really have to calibrate your unit a little. Check out the calibration for magnetometer post i have on this website.

      • Fbo says:

        Ok if i understand correctly your post, i must calibrate my sketch but i not sure how i must do it. i do appreciate if you can give me a sample sketch. i dont understand how your code will correct the fact that the values varies ??

      • Tim says:

        check out this post: http://www.timzaman.nl/?p=994&lang=en
        the idea is that your X+Y+Z=constant. Probably with you this is not a constant. If will represent a circle in the ideal case with 0 as its center point. Make sure 0 is the center point of a circle. Just take up some measurements of X Y and Z and draw them in a graph. make sure 0,0,0 is the center. if not: calibrate by adding or subtracting a appropraite value from X or Y or Z. easy.

      • Fbo says:

        Thank you Tim for your response, i’ll try to do it.

      • Fbo says:

        Hello Tim, I began to take some set of measurements but i have found that i can’t do more than 18 mesures by minutes ??? why it does not do faster ? ( have only this Twig connected to my seeeduino Mega).

      • Tim says:

        Hmm, well for calibrating and taking a lot of measurements (in several orientations!!) it doesnt really matter how fast it is. if you want it to go faster, you should dive in the code and rip out a delay if its in there. otherwise, doesnt really matter?

  4. Fbo says:

    Thank you Tim for the time you take,
    i use your sample code so the only delay is on the loop for 100 ms.

    This is my first set (rotating on a servo turning clockwise slowly) :
    318;-78;-373
    319;-75;-367
    (…)

    and an another set (without any movements)
    -32;-215;-264
    -18;-221;-257
    (…)

    can you see something wrong ?

    • Tim says:

      Ok lesson 1 for you: a servo contains magnets and a lot of metal: hint: STAY AWAY! compasses suck when near anything metal really, a pen or screwdriver is already too much usually.
      I have reviewed your data it seems pretty good actually, but your center point lies just a bit off at X=80, Y=100. So what you should do is add the following lines after you get the X and Y coordinates:
      X=X-80;
      Y=Y-100;
      And you’re done. The module maybe doesnt perform very well, but then again, it isnt a great module.

      • Fbo says:

        Thank you so much, but sorry i don’t understand why you fixed the 2 values (80 for X and 100 for Y)

      • Fbo says:

        Yess, i understand it in seeing your graph, it’s because the graph slide left or right for the X axis and top or bottom for Y axis is it right ?

      • Fbo says:

        here is my new value after recalibrating :
        186;-196;-294
        192;-196;-283
        179;-198;-296
        259;-136;-322
        287;-25;-362
        (…)

      • Tim says:

        That’s perfect! Good circle with 0,0 in the center! Now use this to get the angle and youre all done.

        var_compass=atan2((double)y,(double)x) * (180 / PI) -90; // angle in degrees
        if (var_compass>0){var_compass=var_compass-360;}
        var_compass=(360+var_compass);

  5. Fbo says:

    Yes Tim i also think it isn’t a great module. it’s cheaper but if you cannot trust him. so don’t buy it !
    i must, another time, tell a great thanks to Tim for his help.

  6. Fbo says:

    here is some samples values after Compass calculating :
    But how can i have a compass fixed value when i don’t move the sensor ?
    -13;66;-220
    11.14
    -12;76;-212
    8.97
    -14;79;-224
    10.05
    -24;72;-223
    18.43
    -19;75;-210
    14.22
    1;75;-213
    359.24
    -8;71;-217
    6.43
    -5;69;-224
    4.14
    -14;65;-215
    12.15
    -8;73;-215
    6.25

    • Tim says:

      Try a moving average: just add up the last three measurements and devide them by 3, that’ll give you a pretty static average.

  7. Sergio Acosta says:

    hello, where can i find the code that you are using with this magnetometer for getting the X Y Z values?

    I’d really appreciate your sharing.

    by the way this is my email.

    astaroth175@hotmail.com

  8. vahid azizi says:

    hi
    i want PCB of HMC5883 for setup,pleas help me,if you have PCB of HMC5883 pleas send in my mail.
    vahidazizi90@yahoo.com
    thanks

Leave a Reply

Your email address will not be published. Required fields are marked *


nine × 1 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">