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