0

I'm sampling an encoder and this sample has a value between the interval [30, 230]; I have to use this value to define two output counter variables (one increasing counter and one decreasing counter).

The problem is that sometimes when there is a rollover, which means that the encoder passes from 230 to 30 or vice versa, the sampling is too slow and I lose the direction of the movement (counterclockwise or clockwise) and this results in a wrong behaviour.

Example:

If the encoder is on the 220 value and I move it really fast in clockwise direction, my next value is for example 100 and that means that the value passed through 30 (rollover): the direction should be clockwise. But the software thinks that I moved the encoder from 230 to 100 and it gives me a counter clockwise movement.

Remind that I cannot encrease the sampling speed, it is steady.

It's in a real-time enviroment.

L. Vee
  • 13
  • 4
  • Hi, welcome to stack overflow. Please post your code and take a look at how to ask good questions: [ask] – terence hill Apr 05 '16 at 09:11
  • Just an idea you could elaborate on: refering to your example: you could remember the last detected direction, and when you pass from 220 to 100 _and_ the _last_ detected direction was _clockwise_, you assume that the direction is still _clockwise_. – Jabberwocky Apr 05 '16 at 09:23
  • You should think to use a _16 bit variable_ to count suck a signal. In case you haven't got this opportunity you could think to install a interrupt read signal that detect a the rollover (_reed signa_l). Otherwise you should define the _max variation_ between 2 reads of encoder value and, based on this _max gap_, determine if the direction is the same of the precedent read or is inverted direction. – LPs Apr 05 '16 at 10:29
  • @terencehill I'm sorry, I didn't read that post! – L. Vee Apr 05 '16 at 11:38
  • @L.Ventriglia don't worry but I suggest you to take an overview of the help pages, if your questions are well asked there are more chances that you will get an answer. – terence hill Apr 05 '16 at 11:54
  • Some code would be useful - if only to understand your polling frameworks and the the encoder read function . – Clifford Apr 05 '16 at 17:23
  • This is a common problem with encoders and multi-turn potentiometers: there is no direction indicator. It seems mighty fishy that you have a sampling speed which is much slower than humans, though. – Lundin Apr 06 '16 at 06:24
  • Btw is the output from the encoder digital or analog? If it is analog, you could possibly solve this with an analog comparator that triggers an interrupt. Some MCUs have it built-in. Overall, this is a hardware design problem, not a software problem. – Lundin Apr 06 '16 at 06:27
  • Thanks @Lundin, probably you are right on both your comments! Thanks again. – L. Vee Apr 06 '16 at 06:43

1 Answers1

1

If you cannot guarantee that the encoder will not move more then half the range in one polling period, then the problem cannot be solved. If you assume that it will not move that far, then it is solvable - you simply assume that the movement between two polling events was the shortest of the two possible directions.

You don't explain, why your encoder range starts from non-zero, but the arithmetic is easier to follow (and code) if you remove that offset and work with a range 0 to 200 by subtracting the offset.

Given an encoder read function uint8_t ReadEnc() for example:

#define ENCODER_RANGE 200
#define ENCODER_OFFSET 30  // remove offset for range 0 to 200
static unsigned ccw_counter = 0 ;
static unsigned cw_counter = 0
static uint8_t previous_enc = ReadEnc() - ENCODER_OFFSET ;

uint8_t enc = ReadEnc() - ENCODER_OFFSET ;
signed enc_diff = enc - previous_enc ;
previous_enc = enc ;

// If absolute difference is greater then half the range
// assume that it rotated the opposite way.
if( enc_diff > ENCODER_RANGE / 2)
{
    enc_diff = -(ENCODER_RANGE - enc_diff)
}
else if( enc_diff < -(ENCODER_RANGE / 2) )
{
    enc_diff = (ENCODER_RANGE + enc_diff)
}

// Update counters
if( enc_diff < 0 )
{
    // Increment CCW counter
    ccw_counter -= enc_diff ;
}
else
{
    // Increment CW counter
    cw_counter += enc_diff ;
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Thanks @Clifford this is very enlightening! How do you think I can also get the direction of the rotation with this algorithm? – L. Vee Apr 06 '16 at 06:13
  • Is enc_diff signed or unsigned? @Clifford – L. Vee Apr 06 '16 at 09:43
  • I think there is something wrong with this algorithm. I'll give you an example. If my encoder is in 210 and I move it to 180, this should be a counterclockwise movement but your algorithm increments the clockwise counter. What do you think? @Clifford – L. Vee Apr 06 '16 at 09:52
  • Another example: if you suppose that the encoder is in 210 and you move it to 220: this should results in an increment of the clockwise counter of 10 tick. Instead it will be increase of 210 ticks. – L. Vee Apr 06 '16 at 10:01
  • @L.Vee : Sorry; `enc_diff` is necessarily signed - edited. The direction is determined by the sign of `enc_diff` which is used to update the CW and CCW counters as you required. I am not sure however why you keep a separate counter rather then a single signed value (which would be just `counter += enc_diff` I have not tested the algorithm; it is a general idea. I have however walked through it with your examples and cannot see a problem. – Clifford Apr 06 '16 at 13:51
  • For example for the change 210 to 180, `enc == 150`, `previous_enc == 190` and `enc_diff == 150 - 190 == -30`, `enc_diff < 0` so `ccw_counter = ccw_counter - -30`, i.e. the CCW counter is incremented by 30. – Clifford Apr 06 '16 at 13:51
  • Of course, but before it passes through the first if-else and there enc_diff will be changed. – L. Vee Apr 06 '16 at 13:55
  • @L.Vee : Its a typo, the second else should be negative - fixed. As I said it is illustrative of a general idea. The comment for that block makes the error obvious perhaps. Apologies. – Clifford Apr 06 '16 at 14:02