HMC6352 Compass on Baby O

I needed my solar tracker to be able to pan left/right to follow the sun’s azimuth or compass direction. The HMC6532 seemed up to the task. Here is my test implementation for the Baby O using Peter Fleury’s i2cmaster routines. For the sake of simplicity, I have eliminated adjustment to true north.

Jim Remington has a zip file containing Peter Fleury’s ic2master.c and i2cmaster.h which works with Baby O at:
http://www.uoxray.uoregon.edu/orangutan/i2c.zip

Jim’s Pololu Forum entry re. i2c was very helpful. Find it here: https://forum.pololu.com/t/i2c-master-routines-for-baby-o/332/1

Info on this module: http://www.parallax.com/Store/Sensors/CompassGPS/tabid/173/ProductID/596/List/0/Default.aspx?SortField=ProductName,ProductName

#include<i2cmaster.h>
#include<i2cmaster.c>
/*

   My suggestions on using the HMC6352 compass with the Baby O

         HMC6352
        +-------+ 
        |  o o  | 
   SDA--¦•+---+•+--VIN      
     x--¦•¦   ¦•+--x    NORTH ==>
   GND--¦•+---+•+--SCL      
        +-------+  

   put 4.7k ohm resistors between SDA and PC4, SCL and PC5

*/

float get_bearing(){
   unsigned char hi_byte, lo_byte;
   float hmc6352_bearing;

   i2c_init();
   i2c_start_wait(0x42+I2C_WRITE);
   i2c_write(0x41); // get heading
   wait(6); // takes 6000 microseconds to respond to heading command
   i2c_rep_start(0x42+I2C_READ);
   hi_byte = i2c_readAck();
   lo_byte = i2c_readNak();                   
   i2c_stop(); 
   hmc6352_bearing = (float)(hi_byte * 256 + lo_byte) / 10;

   /*
      Buy a cheap pocket compass at Wal Mart.
      Print out a compass rose with 10-degee markings such as: http://etc.usf.edu/clipart/58700/58790/58790_compass-rose_lg.gif
      Working away from electrical appliances, place the compass rose on a flat surface, align
      it with the pocket compass, and tape it down.
      Set calibration = 0
      Place hmc6352 on compass rose, then turn it until it reads 0 degrees. write the 0 in the hmc6352[] table.
      Set hmc6352_offset = (value from compass rose when hmc6352 reads 0) (to be used later during calibration)
      Turning the hmc6352 clockwise to each 10 degree mark after the first position, enter each reading
      into the hmc6352[] table until readings at all 10-degree marks have been taken.
      Enter 360 as the last entry. Your table should look something like: {0,8,18,..,360}
      Set calibration = 1
      Test the calibrated readings. The hmc6352 readings should closely match the compass rose markings.
      If the hmc6352 readings are on average over or under by a few degrees, add or subtract that amount
      from hmc_offset and test again until they are both within a couple of degrees of each other.
    */

   short calibrated = 1;

   if (calibrated)
   {
      float hmc6352_offset = 100; //mine was 105 initially, but readings were from 4-6 degrees over so I subtracted 5
      float hmc6532_tbl[]  = {0,6,21,38,52,67,78,89,97,105,115,124,135,145,155,165,175,184,194,204,214,226,237,249,261,271,281,295,307,317,325,331,337,342,344,347,354,360};
      int i=0;
      while (hmc6352_bearing >= hmc6532_tbl[i+1]) i++;
      hmc6352_bearing = (hmc6352_bearing - hmc6532_tbl[i]) / (hmc6532_tbl[i+1] - hmc6532_tbl[i]) * 10 + 10 * i + hmc6352_offset;
      if (hmc6352_bearing >= 360) hmc6352_bearing -= 360;
   }
   return hmc6352_bearing;
}

Hello.

Thank you for sharing your code with us!

- Ben

I was just on the parallax website checking out the sensors and then I see this posted, this will be awesome reference. Thanks! :slight_smile: