Mike
Mike

Reputation: 411

Please suggest an algorithm to compare Gray code numbers

I have an absolute encoder which is outputting a 10 bit value (0 to 1023) in Gray code. The problem I am trying to solve is how to figure out if the encoder is moving forwards or backwards.

I decided that the “best” algorithm is as follows: first I convert the Gray code to regular binary (full credit to the last answer in: https://www.daniweb.com/programming/software-development/code/216355/gray-code-conversion):

int grayCodeToBinaryConversion(int bits)
{
  bits ^= bits >> 16; // remove if word is 16 bits or less
  bits ^= bits >>  8; // remove if word is 8 bits or less
  bits ^= bits >>  4;
  bits ^= bits >>  2;
  bits ^= bits >>  1;
  return bits;
}

Second I compare two values that were sampled apart by 250 milliseconds. I thought that comparing two values will let me know if I am moving forwards or backwards. For example:

if((SampleTwo – SampleOne) > 1)
{
  //forward motion actions
}

if((SampleTwo – SampleOne) < 1)
{
  //reverse motion actions
}

if(SampleTwo == SampleOne)
{
  //no motion action
}

Right as I started to feel smart, to my disappointment I realized this algorithm has a fatal flaw. This solution works great when I am comparing a binary value of say 824 to 1015. At this point I know which way the encoder is moving. However at some point the encoder will roll over from 1023 to 0 and climb, and when I then go to compare the first sampled value of say 1015 to the second sampled value of say 44, even though I am physically moving in the same direction, the logic I have written does not correctly capture this. Another no go is Taking the Gray code value as an int, and comparing the two ints.

How do I compare two Gray code values that were taken 250 milliseconds apart and determine the direction of rotation while taking into account the rolling over aspect of the encoder? If you are so kind to help, could you please provide a simple code example?

Upvotes: 3

Views: 807

Answers (2)

Matt Timmermans
Matt Timmermans

Reputation: 59253

Rishav's answer is correct, but it can be more easily calculated.

Let A and B be two readings made 250ms apart and converted from gray code to binary.

The difference in encoder position is just diff = ((1536 + B - A) & 1023) - 512. If you'd prefer not to use bitwise math, then diff = ((1536 + B - A) % 1024) - 512.

Note that 1536 is 1024+512, and the answer diff is determined by two constraints:

  1. diff = B-A mod 1024
  2. diff is in the range [-512, 511], which would be the normal range for a 10-bit signed number.

If your encoder is allowed/expected to go faster in one direction than the other, then you can adjust the range in (2).

To allow answers in the range [MIN,MIN+1023], use diff = ((1024 - MIN + B - A) % 1024) + MIN

If MIN is positive, add a large enough multiple of 1024 to make sure that it's positive before you do the modulus operation, since the modulus operator in most languages behaves oddly with negative numbers.

Upvotes: 3

xrisk
xrisk

Reputation: 3898

Suppose A is your initial reading, and B is the reading after 250ms.
Let's take your example of A = 950 and B = 250 here.

Let's assume the encoder is moving forwards (its value is increasing with time).

Then, the distance covered is (B - A + 1024) % 1024. Let's call this d_forward.

For this example, d_forward comes out to be (250 - 950 + 1024) % 1024 = 324.

The distance covered going backwards (d_backward) would be 1024 - d_forward; which is 700.

The minimum of d_forward and d_backward would give the direction the encoder is travelling.

This will not work if the encoder is going to travel more than 1023/2 units in 250ms. In such a case, you should decrease the intervals between taking readings.

Upvotes: 4

Related Questions