element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • 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 Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • 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
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • 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 3887 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…
  • 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

    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
  • 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 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 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

    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
<
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