element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Sensors
  • Technologies
  • More
Sensors
Sensor Forum Help with 5883L crazyness.
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Sensors to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Suggested Answer
  • Replies 16 replies
  • Answers 1 answer
  • Subscribers 342 subscribers
  • Views 4263 views
  • Users 0 members are here
  • 5883l
Related

Help with 5883L crazyness.

screamingtiger
screamingtiger over 10 years ago

shabaz

jw0752

 

I have collected data and cannot get it to point to the correct heading.  Its off quite a bit and I cannot adjust as the amount it is off is non-linear.  For example, at 0 degrees it shows 100 degrees.  But at 45 degrees it shows 170 degrees.  Z axis is level and remain constant for the most part.

 


Here is the data I collected, does it makes sense?  I used a compass on my phone and compared to the readings I am getting.

 

 

 

0 degrees North
X 0
Y 155
Z -530

 

Calculated heading: 100

 

 

90 degrees east

 

X -165
Y 100 (shouldn't this read 0 since it is pointing in same direction X was just at?)
Z -530
Calculated Heading: 224

 


180 degress South
X: 0
Y: -290
Z: -540

 

Calculating Heading: 286

 

 

 

270 degrees West

 

X: 250
Y: -100
Z: -550
Calculated Heading: 252

 


One thing I am thinking is odd, if at 0 degrees north X axis reads 0, if I rotate 90 degrees to right, would Y axis now read 0?

 

I am not sure what the axis is measuring, I thought it was force and it I point x axis in one direction, then Y axis in same direction, they would show the same reading...

 

X and Y are 90 degrees in parallel plane.
I ordered another magnometer hoping a different brand will help.  Its still 5883L but different maker of breakout.

  • Sign in to reply
  • Cancel

Top Replies

  • shabaz
    shabaz over 10 years ago in reply to screamingtiger +2
    Hi Joey, I took your code and added ALG_TEST stuff to it and modifying the declinationAngle variable: //#include "heading.h" #include <stdio.h> #include <iostream> //#include <wiringPi.h> //#include…
  • jw0752
    jw0752 over 10 years ago +1
    Hi Joey, This may be off base but if I treat your X and Y data as vectors and calculate Result = Sqrt( X^2 + Y^2) I get a Result that is at least in the ball park for the headings that you listed. Like…
  • jw0752
    jw0752 over 10 years ago +1
    Ok now you can see I really don't grasp it quickly as that is exactly what you were doing. No wonder my calculations matched yours. I will put my thinking cap back on and let you know if something better…
  • screamingtiger
    0 screamingtiger over 10 years ago in reply to screamingtiger

    Been trying real hard to calibrate the compass, the self test don't make sense to me

     

    This document here:

    http://www.jameco.com/Jameco/Products/ProdDS/2150248.pdf

     

    is WAY different than the current version of the spec sheet Honeywell provides.  So I am going to go over it and come back.  I am almost ready to just use some source code from Ardupilot and use the calibration code there.  I am not fond of cheating though.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • screamingtiger
    0 screamingtiger over 10 years ago in reply to screamingtiger

    Looks like out has to be calibrated and it's not trivial. 

    http://hobbylogs.me.pn/?p=17#more-17

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • screamingtiger
    0 screamingtiger over 10 years ago in reply to screamingtiger

    Here is the code I am using:

    int main()
    {
    short int x, y , z;
            wiringPiSetup();
            //Setup I2C
            memsBoard = wiringPiI2CSetup(0x1e);
    //Not needed was just expirmenting
            int memsBoardRead = wiringPiI2CSetup(0x3D);
            int memsBoardWrite = wiringPiI2CSetup(0x1C);
    
    //exit self test in case
    //cerr << wiringPiI2CWrite(memsBoard,0x3c) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x00) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x70) << endl;
    
    //step 1 self test mode
    //cerr << wiringPiI2CWrite(memsBoard,0x3c) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x00) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x71) << endl;
    //step 2 set gain 192=6 (11000000)
    //cerr << wiringPiI2CWrite(memsBoard,0x3c) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x01) << endl;
    cerr << wiringPiI2CWrite(memsBoard,192) << endl;
    
    //step 3 set continuous mode
    //cerr << wiringPiI2CWrite(memsBoard,0x3c) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x01) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x02) << endl;
    usleep(10000);
    while(1)
    {
    //step 5a loop 1
    //cerr << wiringPiI2CWrite(memsBoard,0x03d) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x06) << endl;  //Not sure what this does
            x  = wiringPiI2CReadReg8(memsBoard,0x03) << 8;
            x |=   wiringPiI2CReadReg8(memsBoard,0x04);
            z = wiringPiI2CReadReg8(memsBoard,0x05) << 8;
            z |=   wiringPiI2CReadReg8(memsBoard,0x06);
            y =  wiringPiI2CReadReg8(memsBoard,0x07) << 8;
            y |=   wiringPiI2CReadReg8(memsBoard,0x08);
    //step 5b       loop 2
    //cerr<< wiringPiI2CWrite(memsBoard,0x3c) << endl;
    cerr << wiringPiI2CWrite(memsBoard,0x3) << endl;  ///point to register X MSB, not needed
    cout << "x: " << x << endl;
    cout << "y: " << y << endl;
    cout << "z: " << z << endl;
    usleep(79000);
    }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • screamingtiger
    0 screamingtiger over 10 years ago

    So I am trying out the self test procedure found at

    http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/HMC5883L_3-Axis_Digital_Compass_IC.pdf

     

    I am trying to understand the procedure.  I am confused about step 2, it says that 0a0 sets a gain of 5?  that hex value is 160..

    EDIT:  Nevermind I got this, the 3 MSB of the byte of that register are the gain.  So 160 is 10100000b so 101 is 5  image

     

    Also step 5, how many times do I loop or does it matter?

     

    The other odd thing is the first step of the loop "Send 0x3D 0x06 (Read all 6 bytes)"  Am I suppose to read x,y and z the same way as when in normal mode, if so what does the send step do?

     

    Finally, I get negative values, does it matter which way the sensor is oriented?

     

    Thanks!

     

    1. Write CRA (00) – send 0x3C 0x00 0x71 (8-average, 15 Hz default, positive self test measurement)

    2. Write CRB (01) – send 0x3C 0x01 0xA0 (Gain=5)

    3. Write Mode (02) – send 0x3C 0x02 0x00 (Continuous-measurement mode)

    4. Wait 6 ms or monitor status register or DRDY hardware interrupt pin

    5. Loop

    Send 0x3D 0x06 (Read all 6 bytes. If gain is changed then this data set is using previous gain) Convert three 16-bit 2’s compliment hex values to decimal values and assign to X, Z, Y, respectively. Send 0x3C 0x03 (point to first data register 03) Wait about 67 ms (if 15 Hz rate) or monitor status register or DRDY hardware interrupt pin

    End_loop

    6. Check limits – If all 3 axes (X, Y, and Z) are within reasonable limits (243 to 575 for Gain=5, adjust these limits basing on the gain setting used. See an example below.) Then  All 3 axes pass positive self test  Write CRA (00) – send 0x3C 0x00 0x70 (Exit self test mode and this procedure) Else  If Gain<7 Write CRB (01) – send 0x3C 0x01 0x_0 (Increase gain setting and retry, skip the next data set) Else At least one axis did not pass positive self test Write CRA (00) – send 0x3C 0x00 0x70 (Exit self test mode and this procedure) End If


    Below is an example of how to adjust the “positive self” test limits basing on the gain setting: 
    1. If Gain = 6, self test limits are:  Low Limit = 243 * 330/390 = 206 High Limit = 575 * 330/390 = 487 
    2. If Gain = 7, self test limits are:  Low Limit = 243 * 230/390 = 143 High Limit = 575 * 230/390 = 339

     

     

    When I run this I get this output (the zeros are "Success writes"

    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    x: -546
    y: 211
    z: -130
    0
    0
    x: -548
    y: 212
    z: -128
    0
    0

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • screamingtiger
    0 screamingtiger over 10 years ago in reply to shabaz

    shabaz  Sorry man I got side tracked.  I will be working on this today.  Thanks for your help, I'll post back.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • shabaz
    0 shabaz over 10 years ago in reply to screamingtiger

    Hi Joey,

     

    I took your code and added ALG_TEST stuff to it and modifying the declinationAngle variable:

    //#include "heading.h"
    #include <stdio.h>
    #include <iostream>
    
    
    //#include <wiringPi.h>
    //#include <wiringPiI2C.h>
    #include <math.h>
    
    
    using namespace std;
    
    
    // comment out the next line if there is a WiringPi library
    #define NO_WIRING
    
    
    #define SENSORS_GAUSS_TO_MICROTESLA       (100)
    #define     PI 3.1415926535897932384626433832795
    #define HEADINGADDRESS          0x1e
    #define HEADINGDEADBAND 2
    #define ALG_TEST 1
    
    
    
    
    static float _hmc5883_Gauss_LSB_XY = 1100.0F;
    static float _hmc5883_Gauss_LSB_Z  = 980.0F;
    
    
    
    
    
    
    class Heading
    {
      public:
      int memsBoard;
      int address;
      float fx,fy,fz;
      short int x,y,z;
      float currentHeading,previousHeading;
    
    
      Heading(int address);
      int Initialize();
      float GetHeading();
      bool HeadingReached(double);
    
    };
    
    
    
    
    Heading::Heading(int address)
    {
      this->address = address;
    }
    
    
    
    
    int Heading::Initialize()
    {
      cout << "HEADING INIT here" << endl;
      int t;
      if (ALG_TEST)
      {
      cout << "Heading::Initialize()" << endl;
      return(0);
      }
    
    
    #ifndef NO_WIRING
      memsBoard = wiringPiI2CSetup(address);
      t = wiringPiI2CWriteReg8(memsBoard,0x02,0x00);
      if(memsBoard < 0)
      return memsBoard;
    
    
      if(t < 0)
      return t;
    
    
      t = wiringPiI2CWriteReg8(memsBoard,0x01,0x20);
      if(t < 0)
      return t;
    #endif
      return 0;
    
    }
    
    
    
    
    float CorrectHeading(float heading)
    {
      float _0to90 = -100;
      float _91to180 = -136;
      float _181to270 = -100;
      float _270to360 = 20;
    
    
      if(heading >=100 && heading <= 100+90)
      return heading + _0to90;
    
    
            if(heading >= 91 && heading <= 180)
                    return  heading + _91to180;
            if(heading >=181 && heading <= 271)
                    return  heading + _181to270;
            if(heading >=271 && heading <= 360)
                    return  heading + _270to360;
    
    
      return heading;
    
    
    
    
    
    
    }
    
    
    float Heading::GetHeading()
    {
      if (ALG_TEST)
      {
      cout << "Heading::GetHeading" << endl;
      x=-238; // this is 0xff12
      y=-342; // this is 0xfeaa
      z=-479; // this is 0xfe21
    
    
      }
    #ifndef NO_WIRING
      x  = wiringPiI2CReadReg8(memsBoard,0x03) << 8;
            x |=   wiringPiI2CReadReg8(memsBoard,0x04);
    
    
      z = wiringPiI2CReadReg8(memsBoard,0x05) << 8;
            z |=   wiringPiI2CReadReg8(memsBoard,0x06);
    
    
      y =  wiringPiI2CReadReg8(memsBoard,0x07) << 8;
            y |=   wiringPiI2CReadReg8(memsBoard,0x08);
    #endif
      fx = x;
      fy = y;
      fz = z;
    
    
      float heading = atan2(fy,fx);
    
    
            float declinationAngle = 0.0404; //0.22;
      heading += declinationAngle;
      if(heading < 0)
        heading += 2*PI;
      if(heading > 2*PI)
        heading -= 2*PI;
    
    
      previousHeading = currentHeading;
      currentHeading = heading * 180/M_PI;
      //currentHeading = CorrectHeading(currentHeading);
    
    
      return currentHeading;
    
    
    
    
    
    
    
    
    }
    
    
    
    
    
    
    bool Heading::HeadingReached(double heading)
    {
            double b = GetHeading();
            if(fabs(b - heading) <= HEADINGDEADBAND)
                    return true;
            else
                    return false;
    }
    
    
    Heading *magHeading;
    
    
    int
    main(void)
    {
      float heading;
    
    
      magHeading=new Heading(1);
      heading=magHeading->GetHeading();
    
    
      printf("Heading is %lf\n", heading);
      if (ALG_TEST)
      {
      printf("Expected value is 237.48\n");
      }
      return(0);
    }

     

    You can compile it on any Linux machine by saving it to a file (called say mag-test.c) and then typing g++ mag-test.c and then you can run it by typing ./a.out

    This is the result I get:

    Heading::GetHeading
    Heading is 237.480469
    Expected value is 237.48

     

    So, the algorithm appears working (the code uses the values 0xff12, 0xfeaa and 0xfe21 for the x, y and z values it pretends to read from the sensor,

    and expects the output to be around 237.48 because that was the value in the example on the web page I mentioned ( Creative Electronic!: Arduino: simple compass with HMC5883L + Library ).

    So, if it doesn't work, then either the code on that site is giving incorrect values (it is a possibility, even though the author claims it works, we must never assume!),

    or I2C values read are incorrect.

    The latter could occur with faulty or long wiring perhaps, or faulty/counterfeit sensor IC/module for example.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • screamingtiger
    0 screamingtiger over 10 years ago in reply to shabaz

    Go to https://github.com/screamingtiger/QuadCOP

    And look at head.h and heading.cpp

     

    I think I have missed a stip.  there is some code that is setting up gains

    static float _hmc5883_Gauss_LSB_XY = 1100.0F;
    static float _hmc5883_Gauss_LSB_Z  = 980.0F;

    I'm not using these but I did think I confirmed I am getting same values as the arduino I was using.

    Anyways have a look at the code if you will.  Its pretty simple actually.

     

     

    The god news is that I can still have a test auto flight today.  Because my magnometer is consistent, I can use it to fly in a square pattern.  I think that will be a good test.  But would love to have this working.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • shabaz
    0 shabaz over 10 years ago

    Also, if you can post the code then I can give it a visual inspection, in case anything seems odd.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • shabaz
    0 shabaz over 10 years ago

    Hi Joey,

     

    This is how I'd try to troubleshoot this - unfortunately I've not used this sensor before, but there is a typical process I would use for sensors:

    Basically, try to find known values (e.g. a worked example in the datasheet), and then plug those values into your code so that the data from the sensor

    is overwritten with your known values, so you can see if the rest of the coded algorithm behaves as expected. I do it something like this:

     

    #define ALG_TEST 0
    ... code...
    i2c_read(buf); // read into buffer the actual sensor data
    if (ALG_TEST)
      {
       buf[0]=0x11;
        buf[2]=0x22;
        buf[3]=0x33;
      }
    ... data processing ..
    ... remainder of your code ..

     

    Basically at any point during your code development you can set ALG_TEST to 1 to quickly confirm the algorithm is not broken, and set it back to 0 to go back to normal operation.

     

    The problem is finding some known values and the correct computed value. To do this, perhaps use this arduino compass web page which (about half-way down)

    has a screenshot of captured raw values, and the computed results. You could plug the raw values into your code, and check if the result matches.

    Another way I frequently use is to come up with some raw values and the expected result by checking if the datasheet has a worked example (in your case unfortunately

    the datasheet doesn't have this) or by inventing some sensor values, and writing some formula to generate the output, using (say) Excel.

    Then, at any point during testing, I can plug the raw sensor values into the spreadsheet and see what value I expect. This really helps to confirm the coded algorithm is

    working well. I do this a lot with virtually any IC. For example, here is my 555 spreadsheet:

    image

    I can plug in values into the green cells, and the red cells show the expected output for the 555. I'd suggest a similar thing

    with the IC you're using. It takes a while to create, but worth it in the long run.

    Also, with the two modules you have, do they both give similar values that match each other?

    How are they connected to the RPI - short(ish) wires? What resistors are you using for pull-ups for the I2C -

    are these already on the board, or external? Could you attach a photo of the set-up if possible?

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • jw0752
    0 jw0752 over 10 years ago

    Here is the last thought before I quit for the night. Does it make a difference for your equations which axis the chip is rotated around. From your readings it seems to me that the field is practically perpendicular to the Z sensor and that you rotated around the axis of the Z sensor. Does that make any sense?

    John

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube