Pages: [1]   Go Down
Author Topic: Evil Genius getEncoderTurn() Discarding some aPin and bPin Transitions?  (Read 515 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Greetings all,

Regarding getEncoderTurn() first appearing in the listing for Project 11:

int getEncoderTurn()
{
  // return -1, 0, or +1
  static int oldA = LOW;
  static int oldB = LOW;
  int result = 0;
  int newA = digitalRead(aPin);
  int newB = digitalRead(bPin);
  if (newA != oldA || newB != oldB)
  {
    // something has changed
    if (oldA == LOW && newA == HIGH)
    {
      result = -(oldB * 2 - 1);
    }
  }
  oldA = newA;
  oldB = newB;
  return result;
}

I'm clear once we test to see if a change has occurred [if (newA != oldA || newB != oldB)], but it seems to me that we then only calculate a result for the case when we are transitioning from Phase 2--->Phase 3 or Phase 1--->Phase4 [if (oldA == LOW && newA == HIGH)]. This ignores valid transitions when aPin goes from HIGH to LOW and transitions where aPin stays the same and bPin goes HIGH to LOW or LOW to HIGH, all of which are valid state changes that in this code will result in result being 0, incorrectly signalling no change in the rotary encoder at all.

I think this code drops 75% of the state transition cases, but it's possible I've lost the plot here!

Can anyone shed some light? Many thanks,
Bob
Logged

Germany
Offline Offline
Edison Member
*
Karma: 100
Posts: 1223
If you believe something is right, you won't see what's wrong (David Straker).
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Without a state diagram it is usually difficult to understand such code... Due to this fact, i draw the complete graph some months ago and derived the code from it.



From: http://code.google.com/p/m2tklib/wiki/rotenc

Sorry for not giving you more specific help.

Oliver
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you Oliver. Your state diagram is very helpful and shows my point - I've marked (*) the CW and CCW transitions which would be triggered by the IF conditional in the source code; all others would be ignored by the conditional, and result in a "no change" return value of 0.

* Rotary_Enc_Annotated.pdf (75.21 KB - downloaded 3 times.)
« Last Edit: December 31, 2012, 10:27:37 am by FoxcodeBob » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16497
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Encoder manufactures usually specify their encoders by "steps per revolution" where steps means four complete transitions of the A and B in the gray code quadrature.

So you have a choice of how to count 'steps' when using an arduino. If the encoders is rated at say 256 steps per/rev:

Count just one edge condition, say A signal rising and you will measure 256 steps/rev
Count two edge conditions, say either A or B rising and you will measure 512 steps/rev
Count all four edge condition, any change on A or B, and you will measure 1024 steps/rev

So the choice is yours to make and will dictate the decoding algorithm you use.

Lefty
« Last Edit: December 31, 2012, 10:50:54 am by retrolefty » Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can find the code I use to drive rotary encoders at https://github.com/dc42/arduino. You need to call the poll() function at least every 2ms to avoid missing transitions when the encoder is turned quickly. I normally call it from a tick interrupt or from a task scheduled to run every 2ms. When you want to know how far the encoder has moved, call getChange(). The code allows for the unfortunate tendency of some encoders to be in either of 2 states when in a detent.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Shannon Member
****
Karma: 160
Posts: 10418
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset



I'm clear once we test to see if a change has occurred [if (newA != oldA || newB != oldB)], but it seems to me that we then only calculate a result for the case when we are transitioning from Phase 2--->Phase 3 or Phase 1--->Phase4 [if (oldA == LOW && newA == HIGH)]. This ignores valid transitions when aPin goes from HIGH to LOW and transitions where aPin stays the same and bPin goes HIGH to LOW or LOW to HIGH, all of which are valid state changes that in this code will result in result being 0, incorrectly signalling no change in the rotary encoder at all.

I think this code drops 75% of the state transition cases, but it's possible I've lost the plot here!

Can anyone shed some light? Many thanks,
Bob

The code will work reliably if the direction never changes, only counting 50% of the transitions.  However when it reverses it miscounts by
1.  If it reverses several times with only a little movement it will repeatedly miscount.

The flaw with this approach is that if you only look at transitions where A changes, you must take account of both 0->1 and 1->0 transitions
of A.

Correct code would be something like
Code:
if (newA != oldA)
  result = newA ^ newB ? -1 : 1 ;
else if (newB != oldB)
  result = newA ^ newB ? 1 : -1 ;
...
Logged

[ I won't respond to messages, use the forum please ]

Pages: [1]   Go Up
Jump to: