Compass Turns Counter

Discussion in 'Embedded Systems and Microcontrollers' started by eugene.ee13, Jan 30, 2013.

  1. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    Hi, im working on a mini project which focuses on counting complete turns either clockwise or counter-clockwise using a compass and I'm having problems on finding the correct algorithm for it.

    This is the flow of the program...

    1. Read the initial bearing from the digital compass and save it
    2. In the loop, read the current bearing
    3. Compare the current bearing with the initial bearing
    4. If they are equal, add/subtract a count depending on the direction of turn

    The problem is determining the direction of full turn on angle 359 to 0.
    There's a code for determining the bearing difference for the direction of turn but this is only applicable on half turn applications.

    Can anybody help me with this? Thanks!
     
  2. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Read each update, add 360 to reading. Compare to last. get difference between new and old reading, if it is negative, subtract from counter, if it is positive, add to counter.

    Once counter reaches -360 or 360, one revolution has been made.

    Alternatively, start count at 360, and when it reaches 0 or 720, 1 revolution has been made, and the counter is re-initialized to 360.
     
  3. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    Did you mean like this?

    Code ( (Unknown Language)):
    1. heading = 0;
    2. last_heading = 0;
    3. counter = 0;
    4. revolution = 0;
    5.  
    6. void setup()
    7. {
    8.     last_heading = compassRead();
    9.     last_heading += 360;
    10.        
    11. }
    12.  
    13. void loop()
    14. {
    15.     heading = compassRead();    
    16.     heading += 360;
    17.  
    18.     head_difference = heading - last_heading;
    19.    
    20.     counter = counter + head_difference;
    21.  
    22.     if(counter == 360)
    23.     {
    24.       revolution++;
    25.       counter = 0;    
    26.     }
    27.     elseif(counter == -360)
    28.     {
    29.       revolution--;
    30.       counter = 0;
    31.     }
    32.     else
    33.  
    34.     last_heading = heading;
    35.        
    36. }
     
  4. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    If you are initializing variables to 360, though I'm not sure why you are using += rather than =, then your test should be for 0 or 720, rather than -360 and +360
     
  5. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    you,ve told earlier to add 360 to the reading. :)

    heading += 360 is just the same to heading = heading + 360

    For example,
    At initialization.
    1. I turn on the system and I m facing at 40 deg.
    2. So, I will be getting a result of 400 for adding the reading of the compass and 360

    At loop
    1. I will be getting new value of compass, (i.e. 90 deg)
    2. adding 360 again will yield 450
    3. So subtracting the new reading with the last will count to 50.

    so whenever i turn right im getting positive values that will be added to the counter.

    is that right?
     
  6. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    This project is a home made ROV, and Im making a turns counter using the compass. so it rotates not on just one direction, it turns left and right, I need this to protect the cable from tangling. There's a problem when you at a point on 359 deg and 0 deg
     
  7. thatoneguy

    AAC Fanatic!

    Feb 19, 2009
    6,357
    718
    Look for a trend, if the past two measurements were increasing toward 259, then assume a reading of 2 is 362 rather than 0.
     
  8. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    could you please post a sample code of yours? It will be greatly appreciated. I m finding it difficult when the compass is at a point between 0 and 359

    Thank you thatoneguy
     
  9. atferrari

    AAC Fanatic!

    Jan 6, 2004
    2,648
    764
    The trick is to use a counter.

    I would consider what is the maximum number of turns (well, degrees) allowed, say, for example, 1 and 1/2 turn to each side which is 540 degrees.

    I would then start that master counter with exactly that number (for the "initial heading" condition) that would be decreased / increased until reaching the 0 or 1080 limits.

    Please note that your "initial heading" (compass) could be of any value.

    With the counter you can forget actual heading and focus your algorithm on the limits. For the purpose of your request, the last and current (compass) readings are relevant just to know how much you have to decrease / increase the counter.

    Been there, done that. IIRC I used something like +/-270º sectors.

    Depending of how frequent your readings are you could have (or not )the surprise that you actually altered you course by 270 instead of 90!
     
  10. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    hi atferrari, what do you mean by using +/- 270º sectors?
     
  11. atferrari

    AAC Fanatic!

    Jan 6, 2004
    2,648
    764
    Starting at a certaing heading it was acceptable to turn for a maximum of 270º to each side. But that was in my design for that specific platform.


    Do not take that value as a reference for your calculations or algorithm. Is just a reference.
     
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,606
    This is not any kind of trivial problem. There are real devils in the details that need to be accounted for. I wanted to comment when I saw the post but knew I would miss something.

    Consider this series of readings for a device driving in a northerly direction:
    {0, 5, 356, 3, 358, 0}

    Now consider this series of readings for a device spinning in tight circles:
    {0, 5, 356, 3, 358, 0}

    There is no way to tell these apart! So the first thing we need is more data so we never get that large a difference between 2 readings.

    How large is too large? Over 180 degrees... then we can always pick the smallest difference between 2 readings as the true angle of change. So three variables need to be maintained:

    Start_Angle: The first compase reading to mark our beginning rotation. signed int, will range 0 to 359

    Last_Angle: preserve the value of the last reading. signed int, will range 0 to 359

    Current_Angle: computed position for where we are now. signed int, will range -359 to +719

    Then you need two functions:

    Init_Rotation() will set Start_Angle, Last_Angle, and Current_Angle to the current reading

    Get_Rotation() will take the current reading, compute the Current_Angle, then update Last_Angle, and Current_Angle

    Now the angle of change is the tough part! Here lays the devil, I played with some numbers in excel and by guess and by gosh worked out an algorithm that worked. Compute the difference in angle between last and current (Current_Pos - Last_Angle), then constrain it to the range of -180 to +180. This constraint follows from our "assumption" we will call Get_Rotation() before an angle of greater then 180 has occurred.

    You then just add the corrected angle to the Current_Angle, update Last_Angle and you're good.

    Keep in mind that Current_Angle has a very large range, perhaps as much as -720 to +720 degrees. Why? If you start at a heading of 359, do the hokey pokey and turn yourself about you'll be at 359 + 360 = 719.

    Here's the code I tested this with:

    Code ( (Unknown Language)):
    1.  
    2. int Start_Angle;    // The first compass reading to mark our beginning rotation.
    3.                     // signed int, will range 0 to 359
    4. int Last_Angle;     // preserve the value of the last reading.
    5.                     // signed int, will range 0 to 359
    6. int Current_Angle;  // computed position for where we are now.
    7.                     // signed int, will range -720 to +720
    8.  
    9. void Init_Rotation(int Current_Pos);
    10. void Get_Rotation(int Current_Pos);
    11.                                    
    12. void main(void)
    13. {
    14.   Init_Rotation(10);
    15.   Get_Rotation(20);
    16.  
    17.   Init_Rotation(10);
    18.   Get_Rotation(350);
    19.  
    20.   Init_Rotation(90);
    21.   Get_Rotation(271);
    22.  
    23.   Init_Rotation(20);
    24.   Get_Rotation(10);  
    25.  
    26.   Init_Rotation(350);
    27.   Get_Rotation(10);  
    28.  
    29.   Init_Rotation(271);
    30.   Get_Rotation(90);  
    31. }
    32.  
    33. void Init_Rotation(int Current_Pos)
    34. {
    35.   // set Start_Angle, Last_Angle,
    36.   // and Current_Angle to the current reading
    37.   Current_Angle = Last_Angle = Start_Angle = Current_Pos;    
    38. }
    39.  
    40. void Get_Rotation(int Current_Pos)
    41. {
    42.   // will take the current reading,
    43.   // compute the Current_Angle,
    44.   // then update Last_Angle, and Current_Angle
    45.   int Delta;
    46.  
    47.   // compute delta angle
    48.   Delta = Current_Pos - Last_Angle;
    49.  
    50.   // put Delta into range of
    51.   // -180 <= angle <= 180
    52.   if (Delta > 180) Delta -= 360;
    53.   if (Delta < -180) Delta += 360;
    54.  
    55.   // update Current_Angle
    56.   Current_Angle += Delta;
    57.  
    58.   // update last reading with our current reading
    59.   Last_Angle = Current_Pos;    
    60. }
    61.  
    62.  
     
  13. eugene.ee13

    Thread Starter New Member

    Jan 30, 2013
    7
    0
    yup, this is not any kind of those problems. Thanks for understanding what I m trying to say about the problem of computing the compass turns. About the devil I m trying to ignore in the code.

    Thanks for commenting on this post. I will tell you as soon as this thing works. This is much appreciated.
     
Loading...