Compass Turns Counter

Thread Starter

eugene.ee13

Joined Jan 30, 2013
7
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!
 

thatoneguy

Joined Feb 19, 2009
6,359
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.
 

Thread Starter

eugene.ee13

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

Rich (BB code):
heading = 0;
last_heading = 0;
counter = 0;
revolution = 0;

void setup()
{
    last_heading = compassRead(); 
    last_heading += 360;
    	
}

void loop()
{
    heading = compassRead();     
    heading += 360;

    head_difference = heading - last_heading;
    
    counter = counter + head_difference;

    if(counter == 360)
    {
      revolution++;
      counter = 0;    
    } 
    elseif(counter == -360)
    {
      revolution--;
      counter = 0;
    }
    else

    last_heading = heading;
        
}
 

thatoneguy

Joined Feb 19, 2009
6,359
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
 

Thread Starter

eugene.ee13

Joined Jan 30, 2013
7
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?
 

Thread Starter

eugene.ee13

Joined Jan 30, 2013
7
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
 

thatoneguy

Joined Feb 19, 2009
6,359
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
Look for a trend, if the past two measurements were increasing toward 259, then assume a reading of 2 is 362 rather than 0.
 

Thread Starter

eugene.ee13

Joined Jan 30, 2013
7
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
 

atferrari

Joined Jan 6, 2004
4,770
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!
 

atferrari

Joined Jan 6, 2004
4,770
hi atferrari, what do you mean by using +/- 270º sectors?
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.
 

ErnieM

Joined Apr 24, 2011
8,377
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:

Rich (BB code):
int Start_Angle;    // The first compass reading to mark our beginning rotation. 
                    // signed int, will range 0 to 359
int Last_Angle;     // preserve the value of the last reading. 
                    // signed int, will range 0 to 359
int Current_Angle;  // computed position for where we are now. 
                    // signed int, will range -720 to +720

void Init_Rotation(int Current_Pos);
void Get_Rotation(int Current_Pos);
                                   
void main(void)
{
  Init_Rotation(10);
  Get_Rotation(20);
  
  Init_Rotation(10);
  Get_Rotation(350);
  
  Init_Rotation(90);
  Get_Rotation(271);
  
  Init_Rotation(20);
  Get_Rotation(10);  
  
  Init_Rotation(350);
  Get_Rotation(10);  
  
  Init_Rotation(271);
  Get_Rotation(90);  
}

void Init_Rotation(int Current_Pos)
{
  // set Start_Angle, Last_Angle, 
  // and Current_Angle to the current reading
  Current_Angle = Last_Angle = Start_Angle = Current_Pos;    
} 

void Get_Rotation(int Current_Pos)
{
  // will take the current reading, 
  // compute the Current_Angle, 
  // then update Last_Angle, and Current_Angle
  int Delta;
  
  // compute delta angle
  Delta = Current_Pos - Last_Angle;
  
  // put Delta into range of 
  // -180 <= angle <= 180
  if (Delta > 180) Delta -= 360;
  if (Delta < -180) Delta += 360;
  
  // update Current_Angle
  Current_Angle += Delta;
  
  // update last reading with our current reading
  Last_Angle = Current_Pos;    
}
 

Thread Starter

eugene.ee13

Joined Jan 30, 2013
7
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.
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.
 
Top