Author Topic: Any good examples on rotary encoder library "WITH" velocity ?  (Read 27864 times)

0 Members and 1 Guest are viewing this topic.

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Any good examples on rotary encoder library "WITH" velocity ?
« on: September 13, 2013, 07:31:12 am »
The title should be clear, appreciate if you can point out some links/references on the code library that you think is proven and reliable, or at least good one. Really love to learn how to do it properly and efficiently from the experts/pros.

I don't need polling method, only ISR type, and don't worry about the cpu power, it will be used on relatively new arm m4f generation, so in term of raw power, cmiiw this should not be a problem right ?

TIA

Edit : Polling methods are also welcomed.  :P
« Last Edit: September 24, 2013, 01:11:51 am by BravoV »
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 7367
  • Country: nz
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #1 on: September 13, 2013, 07:41:52 am »
Would be pretty simple to write your own.

Use one of the hardware timers to generate a slow clock, maybe 100Hz, and use it to get a timestamp on each interrupt then calc velocity and direction.
Maybe add some filtering to the velocity.


« Last Edit: September 13, 2013, 07:46:20 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #2 on: September 13, 2013, 10:23:55 am »
Not sure what "With velocity" means.

But a typical approach to read an encoder is via a state machine. That can be easily implemented via polling or via two port-change / external interrupts. The code is almost identical in either case.
================================
https://dannyelectronics.wordpress.com/
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 7367
  • Country: nz
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #3 on: September 13, 2013, 10:55:58 am »
velocity means how fast the encoder is being rotated.

You can then do different things depending on the rotation speed.
ie,
have slow movement changing a setting by 0.1
a medium movement changing it by 1
and a fast movement changing it by 10 

Or use a function to calculate the change amount based on the speed in real time.


« Last Edit: September 13, 2013, 10:57:34 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Online Rerouter

  • Super Contributor
  • ***
  • Posts: 4393
  • Country: au
  • Question Everything... Except This Statement
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #4 on: September 13, 2013, 12:40:04 pm »
The best way to manage interrupts is to keep them short and sweet,

my approach to this would be to first capture current time, but only for the first count (do your direction math in the interrupt and make count + or -)
increment a volatile count variable, and capture the time after the reading,

then in your main loop, it reads out the counts, and the 2 times to normal variables quickly then resets the interrupt count and time, freeing it up to continue counting

this then gives you an average if you receive many on a slow loop, and for a fast loop, you would run a rolling average, to determine velocity,

 

Offline nessatse

  • Regular Contributor
  • *
  • Posts: 98
  • Country: za
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #5 on: September 13, 2013, 05:28:12 pm »
Here is a snippet that I wrote a while ago. It is specifically written for the common (cheap) rotary encoders that give four counts per detent.  The count handles two encoders and you can set independent velocity based increments for each one.  There are three velocity thresholds and associated increment values, coarse, medium and fine.


I do not use pin change interrupts, but do everything in a 1kHz timer interrupt, it makes it a lot easier in my opinion.
 
PS.  This is not a library, I just hacked bits out of my program and added a few comments, so it quite possible that I may have omitted a few pertinent bit, in which case I apologise.

PPS.  This code is for AVR & gcc, but most of it pretty generic, do it should easily translate to another architecture

Code: [Select]
// encoder 1 & 2 pins


#define SW1A PB0
#define SW1B PB1
#define SW2A PC2
#define SW2B PC3


// Timer ticks per second


#define TICKTIME 1000


// Encoder limits and increments
// 4 transitions for 1 count
#define ENDCODERSCALE 4
// Max encoder count
#define ENCODERMAX (3000)
// These are the value increments seen by the main program for the
// three velocity ranges
#define ENC1_FINE 1
#define ENC1_MEDIUM 10
#define ENC1_COARSE 50
#define ENC2_FINE 10
#define ENC2_MEDIUM 20
#define ENC2_COARSE 50


// velocity thresholds for encoders
// Speed is actually number of ticks between clicks
#define SPEED_LOW   (TICKTIME/2)
#define SPEED_MED   (TICKTIME/20)
#define SPEED_HI   (TICKTIME/50)


volatile uint32_t ticks;


// Encoder state transition table
// The table is indexed by a four bit number representing
// the previous and current state of the A&B pins of the encoder
// The value is what we should add to the current encoder count, either +1
// for forward motion, -1 for reverse or 0 for an invalid state transition
uint8_t enc_states[16] PROGMEM = {
    0, //0000
    1, //0001
    -1,//0010
    0, //0011
    -1,//0100
    0, //0101
    0, //0110
    1, //0111
    1, //1000
    0, //1001
    0, //1010
    -1,//1011
    0, //1100
    -1,//1101
    1, //1110
    0  //1111
};


// The state structure for each encoder.  This allows for
// independent velocity dependent increments.  The only bit the
// main routine needs to look at is 'value' which will vary between
// zero and ENCODERMAX


typedef struct {
    uint8_t state;
    volatile uint16_t value;
    uint16_t inc;
    uint16_t inc_fine;
    uint16_t inc_med;
    uint16_t inc_coarse;
    int8_t count;
    uint32_t speed;
    uint32_t last_tick;
} encoder_t;


// Array for the two encoder state structures
encoder_t encoders[2];


// bit 0 and 1 indicates to the main loop that the encoders have changed
// needs to be reset by the main loop after processing
volatile uint8_t encoder_flags;


// Checks if velocity thresholds crossed and adjusts the increment value
static void check_enc_speed(uint8_t enc_no)
{
    encoders[enc_no].speed = ticks - encoders[enc_no].last_tick;
    encoders[enc_no].last_tick = ticks;
    if (encoders[enc_no].speed < SPEED_MED) {
        if (encoders[enc_no].speed < SPEED_HI) {
            encoders[enc_no].inc = encoders[enc_no].inc_coarse;
        } else {
            encoders[enc_no].inc = encoders[enc_no].inc_med;
        }
    } else {
        encoders[enc_no].inc = encoders[enc_no].inc_fine;
    }
}


// Update the encoder value


static void update_encoder(uint8_t enc_no,uint8_t buttons)
{
    encoders[enc_no].count += (int8_t)pgm_read_byte(&(enc_states[buttons]));
    if (encoders[enc_no].count > 3) {
        check_enc_speed(enc_no);
        if (encoders[enc_no].value < (ENCODERMAX-encoders[enc_no].inc)) {
            encoders[enc_no].value+=encoders[enc_no].inc;
        } else {
            encoders[enc_no].value = ENCODERMAX;
        }
        encoder_flags |= 0x01 << enc_no;
        encoders[enc_no].count = 0;
    } else if (encoders[enc_no].count < -3) {
        check_enc_speed(enc_no);
        if (encoders[enc_no].value >= encoders[enc_no].inc) {
            encoders[enc_no].value-=encoders[enc_no].inc;
        } else {
            encoders[enc_no].value = 0;
        }
        encoder_flags |= 0x01 << enc_no;
        encoders[enc_no].count = 0;
    }
    encoders[enc_no].state = (buttons & 0b0011) << 2;
}


// 1 kHz timer interrupt.  Reads encoders and adjusts velocity and values.


ISR (TIMER0_COMPA_vect)
{
    uint8_t state;


    ticks++;


    // check encoder 0
    state = encoders[0].state | (PINB & (_BV(SW1A)|_BV(SW1B)));
    update_encoder(0,state);
    // check encoder 1
    // convoluted logic, but encoder 2 is on portc 2&3
    state = encoders[1].state | ((PINC & (_BV(SW2A)|_BV(SW2B))) >> 2);
    update_encoder(1,state);
}
« Last Edit: September 14, 2013, 07:46:53 am by nessatse »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #6 on: September 13, 2013, 08:01:21 pm »
This is what I would do:

Code: [Select]
#define ENC_PORT PINB     //encoder on portb
#define ENC_A       (1<<0)  //ch a on pin0
#define ENC_B       (1<<2)  //ch b on pin2

//read an encoder
//+/- indicates rotational speed
signed char enc_read(void) {
  static unsigned char enc_prev=0;  //previous values for enc. lowest 4 bits effective. A(-1) B(-1) A(0) B(0)
  //static signed char enc_count=0; //enc count, if absolute value is required
  unsigned char tmp = ENC_PORT;  //read the port

  enc_prev = enc_prev << 2; //shift enc_prev to make space for new readings
  enc_prev |= ((tmp & ENC_A)?0x02:0) | ((tmp & ENC_B)?0x01:0); //update enc_prev
  return enc_stats[enc_prev & 0x0f];  //if relative count is need
  //return enc_count+=enc_stats[enc_prev & 0x0f]; //if absolute counts are needed
}

You can run it through isrs - with minor changes but the idea is the same.
================================
https://dannyelectronics.wordpress.com/
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #7 on: September 14, 2013, 08:31:17 am »
Appreciate the replies and the algorithms.  :-+

Also to nessatse & dannyf, many thanks for the examples, now its time for this noob to digest it, this might take a while.   :P

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1060
  • Country: fi
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #8 on: September 14, 2013, 10:34:01 am »
As a quick sidenote, as your hardware seems to be pretty modern (Cortex-M4F), have you checked to see if the hardware supports reading encoders directly? It's usually a special mode of the timer/counter hardware.

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17971
  • Country: nl
    • NCT Developments
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #9 on: September 14, 2013, 11:45:29 am »
Interrupts won't work very well because the encoders can bounce pretty bad. Its better to poll using a timer interrupt unless the controller has hardware support for an encoder.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

alm

  • Guest
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #10 on: September 14, 2013, 11:55:20 am »
I wouldn't use pin change interrupts unless it was with an optical encoder which doesn't bounce.
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #11 on: September 14, 2013, 12:07:01 pm »
Interrupts won't work very well because the encoders can bounce pretty bad. Its better to poll using a timer interrupt unless the controller has hardware support for an encoder.

On MSP430 I do exactly this, since the average encoder has a nice bit of bounce in it. Have a shift register that samples the input and then debounce it. On STM32 I use the hardware support for quadrature encoders on the timer modules.
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #12 on: September 16, 2013, 03:34:23 am »
As a quick sidenote, as your hardware seems to be pretty modern (Cortex-M4F), have you checked to see if the hardware supports reading encoders directly? It's usually a special mode of the timer/counter hardware.

Yes, I'm aware of that, latest TI Tiva cortex m4f which I have has  two dedicated hardware based quadrature encoder interface (QEI) module in it, also I have the older Stellaris which they stripped down version which doesn't have that.

Its just I'm eager to learn the code/flow/algorithm from experienced fellows.


Interrupts won't work very well because the encoders can bounce pretty bad. Its better to poll using a timer interrupt unless the controller has hardware support for an encoder.
I wouldn't use pin change interrupts unless it was with an optical encoder which doesn't bounce.

Thanks for the advice. Actually I learned my hard lesson well when naively I tried with cheap mechanical encoder that bounces like hell, that made me have to add dedicated external classic 555 ics to debounce it.  |O
Currently I'm planning to use optical version.


On MSP430 I do exactly this, since the average encoder has a nice bit of bounce in it. Have a shift register that samples the input and then debounce it. On STM32 I use the hardware support for quadrature encoders on the timer modules.

Any chance I can take a peek at your code too ?
« Last Edit: September 16, 2013, 06:59:42 am by BravoV »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #13 on: September 16, 2013, 10:27:24 am »
Quote
cheap mechanical encoder that bounces like hell

Nothing a little rc filter couldn't cure. Look up its datasheet.
================================
https://dannyelectronics.wordpress.com/
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on ISR based rotary encoder library "WITH" velocity ?
« Reply #14 on: September 16, 2013, 11:38:34 am »
Any chance I can take a peek at your code too ?

For STM32 I use something like this:

quadrature_encoder.cpp
Code: [Select]
#include "quadrature_encoder.hpp"

#include "ch.h"
#include "hal.h"

QuadratureEncoder::QuadratureEncoder(void)
{
}

//
// http://stackoverflow.com/questions/15203069/stm32-rotary-encoder-config-on-tim4
// http://forum.chibios.org/phpbb/viewtopic.php?f=2&t=247&start=40
// http://tronixstuff.wordpress.com/2010/06/26/getting-started-with-arduino-chapter-eleven/
// [url]https://www.sparkfun.com/products/9117[/url]
//
// PB.4 = TIM3 CH1
// PB.5 = TIM3 CH2
//
void QuadratureEncoder::Init(void)
{
//  GPIO_PinAFConfig (GPIOB, GPIO_PinSource4, GPIO_AF_TIM3); // PB.4 = TIM3 CH1
//  GPIO_PinAFConfig (GPIOB, GPIO_PinSource5, GPIO_AF_TIM3); // PB.5 = TIM3 CH2
palSetPadMode(GPIOB, 4, PAL_MODE_ALTERNATE(2) | PAL_STM32_PUDR_PULLUP | PAL_STM32_OSPEED_HIGHEST); /* AF2 = TIM3 */
palSetPadMode(GPIOB, 5, PAL_MODE_ALTERNATE(2) | PAL_STM32_PUDR_PULLUP | PAL_STM32_OSPEED_HIGHEST); /* AF2 = TIM3 */

//  RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3, ENABLE);
    RCC->APB1ENR |= (1 <<  1); // TIM3

    //
    // RM0090, page 408
    // 011: Encoder mode 3 - Counter counts up/down on both TI1FP1 and TI2FP2 edges depending on the level of the other input.
    //
    // http://stackoverflow.com/questions/15203069/stm32-rotary-encoder-config-on-tim4
    // I have used an STM32F407 to read encoder counts from 3 optical encoders. I am using ChibiOS RTOS so the timer struct is
    // slightly different from the ST Peripheral library timer struct, but the information is basically the same. Here is how I
    // configure the registers of the actual timers:
    //
stm32_tim_t *timer = STM32_TIM3;
timer->SMCR  = 3;          // Encoder mode 3
timer->CCER  = 0;          // rising edge polarity
timer->ARR   = 0xFFFF;     // count from 0-ARR or ARR-0
timer->CCMR1 = 0xC1C1;     // f_DTS/16, N=8, IC1->TI1, IC2->TI2
timer->CNT   = 0;          // Initialize counter
timer->EGR   = 1;          // Generate an update eventcd
timer->CR1   = 1;          // Enable the counter

prev_encoder_count = GetCount();
}

int16_t QuadratureEncoder::GetCount(void)
{
return (int16_t) TIM3->CNT;
}

int16_t QuadratureEncoder::GetIncrement(void)
{
int16_t encoder_count = GetCount();
int16_t increment     = encoder_count - prev_encoder_count;
prev_encoder_count    = encoder_count;
return increment;
}

quadrature_encoder.hpp
Code: [Select]
#ifndef QUADRATURE_ENCODER_HPP_
#define QUADRATURE_ENCODER_HPP_

#include "ch.h"

class QuadratureEncoder
{
private:
    int16_t prev_encoder_count;
    int16_t GetCount(void);

public:
    QuadratureEncoder(void);
    void Init(void);
    int16_t GetIncrement(void);
//    void Run(void);
//    void SetCallback(void (*cb)(void));
};

Then in main you have:
Code: [Select]
static QuadratureEncoder myQuadratureEncoder;

int main(void) {
// ..
    myQuadratureEncoder.Init();


And then in your favorite timer routine you call myQuadratureEncoder.GetIncrement().
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #15 on: September 17, 2013, 04:42:57 am »
mrflibble, thank you !  :-+

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17971
  • Country: nl
    • NCT Developments
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #16 on: September 17, 2013, 10:01:04 am »
That is pretty complicated. You just need to look for edges on one line 'A' and then check the state of line 'B'. Executing two 'if' statements is enough.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #17 on: September 17, 2013, 11:48:57 am »
TerminalJack505, wow, thank you very much for the examples, really love the state diagram too, really handy for a noob like me !  :-+

That is pretty complicated. You just need to look for edges on one line 'A' and then check the state of line 'B'. Executing two 'if' statements is enough.
Nothing at all complicated about it.  It's pretty much software development 101.

Ok, when it comes to these, just sitting quietly at the corner cause I'm too noob to comment/argue/debate which is better, just observe and learn should this turn into "quality" discussion on this routine.  :P

Nctnico, if you have any examples from your past experiences/projects related to this, really appreciate if you could share a snippet on that encoder part, no need to tidy it up, just copy & paste on the core section, I will learn to read & digest it from there.

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #18 on: September 17, 2013, 12:46:18 pm »
Quote
really love the state diagram too

You don't really need that - the 4-bit array posted earlier is a nice implementation of that.
================================
https://dannyelectronics.wordpress.com/
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #19 on: September 17, 2013, 12:57:43 pm »
Offending messages removed.
 

Offline airiclenz

  • Contributor
  • Posts: 28
  • Country: se
    • Airic Lenz
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #20 on: September 17, 2013, 01:06:40 pm »
Here is a pretty good example for the Arduino. It is well explained and can easily be ported to other systems:

http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html

Good luck,
Airic
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #21 on: September 17, 2013, 01:46:10 pm »
Offending messages removed.

Too bad you removed the FSM as well, because now the responses to that make no sense. Besides, sometimes looking at it from a state machine angle can be helpful/instructive/fun.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17971
  • Country: nl
    • NCT Developments
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #22 on: September 17, 2013, 01:56:59 pm »
Nctnico, if you have any examples from your past experiences/projects related to this, really appreciate if you could share a snippet on that encoder part, no need to tidy it up, just copy & paste on the core section, I will learn to read & digest it from there.
This is a cut down snippet which is called from a timer interrupt. In order to be get the data from the IRQ process space into the user process space without disabling the interrupts / missing steps I use two accumulators to count the cw and ccw steps. In the user process I simply calculate the difference between the current accumulator values and the previous values.

Velocity can be added by adding a counter which counts the number of calls between two edges. The variable a can be increased when the counter reaches smaller values.

static uint32_t rotation_accu_cw, rotation_accu_ccw;

void rotary_handler()
{
   static uint32_t prev_rotary_a;
   uint32_t a=1;

   if (prev_rotary_a != GET_ROTARY_A())
      {
      //edge
      prev_rotary_a = GET_ROTARY_A();
               if (prev_rotary_a==0)
         {
         //falling edge
         if (GET_ROTARY_B()!=0)
            {
            rotation_accu_cw+=a;
            }
         else
            {
            rotation_accu_ccw+=a;
            }
         }
      else
         {
         //rising edge
         if (GET_ROTARY_B()==0)
            {
            rotation_accu_cw+=a;
            }
         else
            {
            rotation_accu_ccw+=a;
            }
         }
      }
}
« Last Edit: September 17, 2013, 01:59:05 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #23 on: September 17, 2013, 02:15:28 pm »
Offending messages removed.

Too bad you removed the FSM as well, because now the responses to that make no sense. Besides, sometimes looking at it from a state machine angle can be helpful/instructive/fun.

Sorry.  That's the only time I've ever deleted any of my posts.  I know how it messes up the preceding discussion.

I thought I could add something to the discussion but apparently anything more complicated than a "Hello, World!" solution is too complicated.   |O
 

Offline Tepe

  • Frequent Contributor
  • **
  • Posts: 543
  • Country: dk
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #24 on: September 17, 2013, 02:38:39 pm »
Offending messages removed.

Too bad you removed the FSM as well, because now the responses to that make no sense. Besides, sometimes looking at it from a state machine angle can be helpful/instructive/fun.

Sorry.  That's the only time I've ever deleted any of my posts.  I know how it messes up the preceding discussion.

I thought I could add something to the discussion but apparently anything more complicated than a "Hello, World!" solution is too complicated.   |O

Are you willing to insert them in the post again?
ceterum censeo systemd-inem esse delendam
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #25 on: September 17, 2013, 02:52:59 pm »
Quote
This is a cut down snippet which is called from a timer interrupt.

That's effectively polling and consequentially not terribly efficient and may miss pulses if the encoder goes fast (aka on a motor).

The state machine approach + interrupts is really the only way to go, short of hardware encoder support.
================================
https://dannyelectronics.wordpress.com/
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #26 on: September 17, 2013, 02:57:56 pm »

Are you willing to insert them in the post again?

Alright.  Here are the attachments from my original post.

Note that they don't even address the question of "velocity."  I was just pointing out a way to implement bounce tolerance.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17971
  • Country: nl
    • NCT Developments
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #27 on: September 17, 2013, 02:59:54 pm »
That's effectively polling and consequentially not terribly efficient and may miss pulses if the encoder goes fast (aka on a motor).
The state machine approach + interrupts is really the only way to go, short of hardware encoder support.
Its not inefficient because most of the code is only executed when an edge occurs. The problem is that a mechanical encoder will bounce. Before I came up with my piece of code I tried using interrupts and a hardware counter only to find out I needed proper debouncing in software. You may call it polling but in fact the real code (not the cut down version) also does filtering by skipping edges which are to close to eachother. Whether or not you miss pulses depends on how often its called (the sampling frequency).
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #28 on: September 17, 2013, 03:32:03 pm »
That's effectively polling and consequentially not terribly efficient and may miss pulses if the encoder goes fast (aka on a motor).
The state machine approach + interrupts is really the only way to go, short of hardware encoder support.
Its not inefficient because most of the code is only executed when an edge occurs. The problem is that a mechanical encoder will bounce. Before I came up with my piece of code I tried using interrupts and a hardware counter only to find out I needed proper debouncing in software. You may call it polling but in fact the real code (not the cut down version) also does filtering by skipping edges which are to close to eachother. Whether or not you miss pulses depends on how often its called (the sampling frequency).

Wow.  And you called my code too complicated.

I do advise that if you use code similar to mine that you use an RC filter on the two encoder signals but there's no other "software filtering" required.  You don't really want the interrupt running unnecessarily and the RC filter will help in this aspect.  (Note that my code can be easily adapted to be used in a polling-type of scheme.)

With the finite state machine, if the switches bounce then the state machine just ping-pongs back and forth between two adjacent states.  It only emits a "clockwise" or "counterclockwise" action when it has reached the point where all 4 required states have been visited.  Once it emits either the "clockwise" or "counterclockwise" action then the state machine returns to the idle state.  Note how the state machine doesn't bounce between "idle" and either CW10 or CCW01 so there's no problem with false actions.
 

Offline nessatse

  • Regular Contributor
  • *
  • Posts: 98
  • Country: za
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #29 on: September 17, 2013, 04:26:32 pm »

Nice diagrams TerminalJack505.
[/size]Using a FSM is the only reliable way to read these encoders, especially the cheap mechanical ones that will bounce in weird and wonderful ways. 


That is pretty complicated. You just need to look for edges on one line 'A' and then check the state of line 'B'. Executing two 'if' statements is enough.
[/size]
This is a naive approach, it will not only count on invalid transitions, but your example also does not count all the valid transitions. 


I do however agree that polling during a timer interrupt is preferable to edge interrupts, especially when dealing  with multiple encoders.  Running your timer tick at a decent frequency, say 1000Hz, will minimise the chance of missing a step, and even if you do the FSM will recover elegantly.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 17971
  • Country: nl
    • NCT Developments
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #30 on: September 17, 2013, 04:30:36 pm »
So your statemachine approach requires a full period (two events) to determine the direction? The problem with that is that most encoders for manual input have audible/tactile feedback every half period so you need to respond to a half period otherwise the user has to advance the knob two 'clicks' to advance by 1 which is counter intuitive.

Whether you do the filtering in software or hardware depends on where you need to save something. My method also works when called from a GPIO interrupt or a timer capture interrupt. Either way the golden rule is to never ever create an interrupt from an I/O pin which has 1) no proper filtering and 2) no schmitt trigger otherwise a simple fault like a loose wire or a worn contact can make your software come to a grinding halt because it keeps servicing interrupts. All in all using GPIO inferred interrupts just costs extra hardware.

@nessatse: the code I posted is just to show how to use the edges on the 'A' line in order to determine the steps. Depending on the actual hardware filtering may be required. In the real software I keep track of the number of timer ticks between the edges for de-bouncing and determining velocity. If the number of ticks is too small the edge is ignored.
« Last Edit: September 17, 2013, 05:17:16 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2094
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #31 on: September 17, 2013, 04:49:43 pm »
I do advise that if you use code similar to mine that you use an RC filter on the two encoder signals but there's no other "software filtering" required.

Hardware filters increase cost and board space, a few extra instructions usually costs nothing.
 

Offline nessatse

  • Regular Contributor
  • *
  • Posts: 98
  • Country: za
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #32 on: September 17, 2013, 05:10:52 pm »
So your statemachine approach requires a full periode (two events) to determine the direction?

I admit I haven't worked through TerminalJack505's code, but for the code I posted earlier, (which used the same FSM logic, although in a slightly different way) this is definitely not the case.  The fsm  in fact acts just like a type of software filter, preventing counters from changing during illegal state transitions that you would typically get with noisy/bouncy switches.  It will respond to every valid transition on either the A or B legs, i.e. "half" periods.

The encoders I have used all count 4 counts, i.e. a full cycle 00-01-11-10, between detents, I have been running the code I posted in a real environment, without any external hardware or further software filtering and it has been performing flawlessly.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #33 on: September 17, 2013, 05:15:05 pm »
So your statemachine approach requires a full periode (two events) to determine the direction? The problem with that is that most encoders for manual input have audible/tactile feedback every half period so you need to respond to a half period otherwise the user has to advance the knob two 'clicks' to advance by 1 which is counter intuitive.

That particular code was written for the cheap mechanical quadrature encoders that produce one pulse per detent.  One cycle for these encoders (where each detent is located) is shown on the state diagram by a dotted line.  The vast majority of the inexpensive mechanical encoders are of this variety.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #34 on: September 17, 2013, 05:22:18 pm »
"that produce one pulse per detent."

That's fairly rare: most produce 4 pulses, cheap or not.

As to the rc filter: it doesn't pay to solve a hardware problem with software. Though I have to agree with the other poster that the state machine approach is remarkably resistent to invalid pulses.
================================
https://dannyelectronics.wordpress.com/
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #35 on: September 17, 2013, 05:40:13 pm »
"that produce one pulse per detent."

That's fairly rare: most produce 4 pulses, cheap or not.

As to the rc filter: it doesn't pay to solve a hardware problem with software. Though I have to agree with the other poster that the state machine approach is remarkably resistent to invalid pulses.

That's not my experience.  Last time I went shopping for mechanical quadrature rotary encoders, the one pulse per detent type was pretty much all I could find.  Unfortunately, Digi-key doesn't have this as a parameter so you can't search by it but I remember going through page, after page of encoders looking for the half- and quarter-pulse per detent type and finding very few.

Keep in mind that I'm talking about mechanical encoders.  Optical encoders are another story.
 

Offline David_AVD

  • Super Contributor
  • ***
  • Posts: 2607
  • Country: au
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #36 on: September 17, 2013, 09:20:38 pm »
I'm implementing a rotary encoder in a current project.  Both the original one and a replacement type are mechanical and 4 pulses per click.  Both were bought from Digikey and were only a few dollars in one off quantity.
 

Offline andersm

  • Super Contributor
  • ***
  • Posts: 1060
  • Country: fi
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #37 on: September 17, 2013, 09:35:07 pm »
It may be a question of terminology, whether you count all four edges or just the full cycles.

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2094
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #38 on: September 17, 2013, 11:15:59 pm »
Still no response with any velocity sensitivity.

I have a spare time project using a Bourns PEC11 series mechanical encoder. It is working with code similar to the examples already posted here. It might benefit from some velocity sensitivity as it is used to cycle through menu options and to adjust numbers.

I will probably do some work on it eventually but I am pretty sure it will take some experimentation to get it to 'feel' right. Overshooting on number adjustment would be undesirable so the acceleration will have to 'feel' predictable.
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #39 on: September 17, 2013, 11:51:12 pm »
Heh, yeah, no velocity. If BravoV can write up a decent spec for what's needed, maybe someone will magically code it up.
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #40 on: September 18, 2013, 04:24:04 am »
Woah .. lots of updates and discussions, keep it going, ideas exchange and also different algorithms are good thing imo, especially to capture what other people are thinking on countering this matter.  :-+

Please understand, I'm still learning, and while I did write my own code (even though it sucks big time), it works though not optimal, now when it comes to integrate with "velocity" feature, everything falling apart and turned into chaos, don't ask, I'm too embarrassed to post my code, just forget it. .. LOL ...  :-DD

Also, I repeat, I may not be active in discussing this, please trust me, I'm observing this thread intensively while learning how each of you tackle it from each perspective, thats matter and valuable to me in this learning process.


Heh, yeah, no velocity. If BravoV can write up a decent spec for what's needed, maybe someone will magically code it up.
There are few previous posters already mentioned the idea like Psi did on 3 type of speeds, or nessatse's code implementing three velocity thresholds like coarse, medium and fine.

To be honest, actually I have my own very crude idea "pirated"  :P from TI tiva cortex m4f's API that handles it's hardware based QEI (Quadrature Encoder Interface). But I was hesitated to post this at the beginning since I don't want to have our hands tie up only to TI's idea/solution, and of course "ideally" the code should be easily adaptable to other platforms if possible.

But since you mentioned it, here a snippet on TI's QEI's API brief description, captured screen for your viewing pleasure without needing to download the PDF with the highlighted regions at the "velocity" feature :



Above quoted from chapter 19 at page 227, download link -> TivaWare™ Peripheral Driver Library for C Series User's Guide (PDF approx 1.8 MB)

Again, this is just my noob idea, prolly I don't know heck what I'm talking about, but for me maybe that is a good start on the idea at handling/interfacing with the "velocity" feature. And its the way how you experts/experienced people tackle it that I love to learn from.

Feel free to drop this TI's related thingy should you think this is useless, way too complicated or not feasible for easily adaptable to other different mcu architectures.  :-+

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #41 on: September 18, 2013, 04:44:54 am »
On hardware level, this is how TI QEI module handles bounces, attached the print screen from the datasheet on the QEI hardware (highlighted).

Again, just ignore this post if you think this is useless.
« Last Edit: September 18, 2013, 04:47:52 am by BravoV »
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2094
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #42 on: September 18, 2013, 05:04:38 am »
Please understand, I'm still learning, and while I did write my own code (even though it sucks big time), it works though not optimal, now when it comes to integrate with "velocity" feature, everything falling apart and turned into chaos, don't ask, I'm too embarrassed to post my code, just forget it. .. LOL ...  :-DD

Well if you wanted to do some experimentation your results might save me some effort, however, I am currently interested in cheap mechanical encoders with one pulse (or 4 edges) per dedent. So is that what you are working with?
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #43 on: September 18, 2013, 05:07:10 am »
Well if you wanted to do some experimentation your results might save me some effort, however, I am currently interested in cheap mechanical encoders with one pulse (or 4 edges) per dedent. So is that what you are working with?
Yep, dirt cheap mechanical with 4 edges, not even Bourns brand.  :P

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2094
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #44 on: September 18, 2013, 05:45:21 am »
Well if you wanted to do some experimentation your results might save me some effort, however, I am currently interested in cheap mechanical encoders with one pulse (or 4 edges) per dedent. So is that what you are working with?
Yep, dirt cheap mechanical with 4 edges, not even Bourns brand.  :P

My suggestion then would be to implement a polled scheme from a timer interrupt at about 1kHz and use the previous + current state to index into a 16 element array of count deltas like the examples in this thread.

Bounce on either input causes jitter on the LSB of the count, but, detent to detent the count changes by 4 so you should be ignoring the 2 LSBs of the count anyway. 

I think there is an issue that I have noticed (without actually investigating) where turning the encoder faster than it can track causes the count to get out of sync with the encoder dedents so I would suggest using a time out on encoder activity to set the count 2 LSBs to zero (on the assumption the encoder will be in a dedent).

For velocity a similarly triggered timeout could be used and when you see a whole pulse if the timeout is still running you would adjust the count by more than 1. You could have more than one timeout to detect more than one velocity level. That said I suspect it could 'feel' better if you don't accelerate the second pulse but delay it till the 3rd or 4th which gets more complicated.

I tend to use a lot of what I call software monostables.

if(mono)
  mono--

running at the 1kHz or whatever rate. You can trigger and re-trigger by setting mono to a value and mono being zero indicates timed out.
 

Offline nessatse

  • Regular Contributor
  • *
  • Posts: 98
  • Country: za
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #46 on: September 18, 2013, 11:28:33 am »
It may be a question of terminology, whether you count all four edges or just the full cycles.

Yes, the manufacturers seem to give different names to the same thing so I think we're probably talking about the same thing.

  1 Pulse per Detent == 4 Phase per Click == 4 edges per Detent

All of them seem to agree on the term "Pulses Per Revolution."  So if the number of pulses per revolution is the same as the number of detents per revolution then that's also the same type.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #47 on: September 19, 2013, 06:25:49 am »
Here's something I've been working on.  It's a bounce and skip tolerant rotary encoder class with support for velocity.  It's still half-baked.  The port/pin stuff is still hard coded and I haven't even run it yet.  I just bolted-on the skip handling and velocity stuff to my earlier code.

The idea behind the velocity support is to sample the number of actions (full clockwise or counter-clockwise clicks) at a period of approximately 100ms to 300ms and report this as the velocity.  This isn't the instantaneous velocity, obviously, and introduces a lag but hopefully that won't matter so long as the sampling periods are small enough.  If it works then there won't be as much data to keep track of.  I'm targeting the class toward 8-bit MCUs with limited resources--particularly SRAM.

The velocity, as reported to the user (the class user) will be the number of actions during the last complete time slice.  So, if the user (the end user) is turning a 24 pulse per rotation encoder counter-clockwise at 40 detents per second (pretty fast) and the sample period is 200ms, then velocity would be reported as -8.  How this velocity is interpreted is up to class user.

It will probably be a trick finding the best sample period size so that lag is minimized while resolution is maximized.  This method will also benefit from using encoders with a higher number of pulses per rotation.
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #48 on: September 19, 2013, 07:09:22 am »
TerminalJack505, much appreciated !  :-+

Since I'm still novice, when it comes to reading other people's code at interested topic, I always expect and really love the excitement when .. "How come I didn't think of that !" moment.  ;)

Going to print it on paper and bring it to bed later on.  ;D

Again, thanks Jack.

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #49 on: September 19, 2013, 07:22:50 am »
No problem.  I'll let you know how testing works out.  I'm sure there will be some changes.  Hopefully minor.

Note that the skip tolerance code isn't the same as the skip tolerance state machine diagram I posted earlier.  The skip logic takes the current velocity into account so that when a skip occurs it gives a bias to the current rotation direction.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #50 on: September 19, 2013, 11:12:38 am »
Quote
It will probably be a trick finding the best sample period size so that lag is minimized while resolution is maximized. 

That's futile for a generic routine, as you will never know for sure how it is to be used.

Quote
This method will also benefit from using encoders with a higher number of pulses per rotation.

High PPR can cause serious problems for complicated routines running from an isr.

Polling is just inefficient and ineffective for those situations.
================================
https://dannyelectronics.wordpress.com/
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #51 on: September 19, 2013, 01:02:24 pm »
Quote
It will probably be a trick finding the best sample period size so that lag is minimized while resolution is maximized. 

That's futile for a generic routine, as you will never know for sure how it is to be used.

Quote
This method will also benefit from using encoders with a higher number of pulses per rotation.

High PPR can cause serious problems for complicated routines running from an isr.

Polling is just inefficient and ineffective for those situations.


Yes, writing generic, reusable code for MCUs is usually a problem and not really worth the trouble.  "Reuse" on MCUs typically means cut-copy-paste-modify, especially on 8-bit MCUs.  I'm sure even if I were to reuse the code I'd likely wind-up making changes.  I'm just doing research, really.

I've attached the latest versions with a couple of fixes.  I'll likely combine the two lookup tables into one.  This will make the table bigger but the code smaller.  Hopefully with a net gain of a couple dozen bytes.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #52 on: September 19, 2013, 08:15:26 pm »
For anyone interested here's a state diagram of what I plan to implement for skip tolerance.  I've included the latest code as well but the state machine in the code hasn't been updated yet.

Say what you will about state machines but there's no way I'd ever want to try and implement that sort of behavior without one.

I've yet to actually run it and I may not get a chance for the next day or so.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #53 on: September 21, 2013, 07:49:26 am »
I finally got this thing programmed into a MCU (an ATtiny2313) and got it working.  It works pretty much like I envisioned it.  The bounce and skip tolerance works fine. 

The velocity works but I'm not sure if this particular implementation would be what a person would want for a real-world application.  It's hard to say since all I really did--so far as testing--is print out the value of the velocity. 

I'll have to come up with some kind of useability test for the velocity before I know whether or not the implementation I chose is practical.

The source code from my test project is attached for those that are interested.
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #54 on: September 21, 2013, 08:01:38 am »
Thanks for keep updating this thread !  :-+

Offline Teemo

  • Regular Contributor
  • *
  • Posts: 58
  • Country: ee
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #55 on: September 22, 2013, 10:22:46 am »
Thanks everybody for this exellent thread!

I've also been thinking to use rotary encoders with velocity control in one of my projects.
As a beeginning it seems good idea to go with those starting points:

-Use edge detect interrupts to read encoder, (paying attention to debounce).
-at every edge detect start countdown timer
-at every next edge interrupt add countdown timer remaining value+1 to the count. And restart countdown timer.

(this way turning faster results in more counting), timer running speed determines how powerful the velocity effect is.
Seems simple
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #56 on: September 22, 2013, 04:26:00 pm »
-Use edge detect interrupts to read encoder, (paying attention to debounce).

Or better yet, sample the input pins from a timer routine. More predictable results with less chance of a runaway in case of hardware failures.

As for velocity, just grab (current_count - previous_count) for the simplest case. And if you're like me and want a bit of averaging, you keep a circular buffer with the last N (for example 4) counter values, and then use that to calc average velocity.

velocity = (count[0] - count[3]) / 4 sort of thing. Preferably N in powers of 2, such that the divide is optimized to an arithmetic shift right.

 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #57 on: September 22, 2013, 04:49:23 pm »
Quote
(paying attention to debounce).

The 4-bit state machine approach posted earlier is incredibly reliable against bounces and it recovers quickly from bounces too.
================================
https://dannyelectronics.wordpress.com/
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #58 on: September 22, 2013, 05:13:31 pm »
Agreed. The state machine approach is definitely a good one if you want something rugged.
 

Offline jeroen74

  • Frequent Contributor
  • **
  • Posts: 397
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #59 on: September 22, 2013, 05:41:00 pm »
I wrote this long ago for a full quadrature cycle per detent encoder; state machine using interrupts on a mega128, with velocity sensing. Not the most efficient or beautiful code, I know...

Code: [Select]
#include <iom128v.h>
#include "main.h"

static byte encoder_a,encoder_b;
static byte encoder_flag,state,timer;

void handle_encoder(void);

// First output from encoder tied to external interrupt 4
#pragma interrupt_handler int4_isr:6
void int4_isr(void)
{
 EICRB^=(1<<ISC40);
 encoder_a^=1;

 handle_encoder();
}

// Second output from encoder tied to external interrupt 5
#pragma interrupt_handler int5_isr:7
void int5_isr(void)
{
 EICRB^=(1<<ISC50); // Toggle edge sense
 encoder_b^=1;

 handle_encoder();
}

// Set external interrupt 4 and 5 to falling edge, make sure PE4 and PE5 are set to input
void init_encoder(void)
{
 DDRE|=(1<<4)|(1<<5);     
 EICRB&=(1<<ISC40)|(1<<ISC50);
 EICRB|=(1<<ISC41)|(1<<ISC51);

 encoder_flag=0;
 state=0;
}

void handle_encoder(void)
{
 if (state==0)
  {
  if (encoder_a) state=1;
  if (encoder_b) state=4;
  }
 else if (state==1)
       {
       if (encoder_b) state=2;
        else if (!encoder_a) state=0;
       }      
 else if (state==2) 
       {
       if (!encoder_a) state=3;
       }         
 else if (state==3)
       {
       if (!encoder_b)
        {
        encoder_flag=2;
        state=0;
        }
       }
 else if (state==4)
       {
       if (encoder_a) state=5;
        else if (!encoder_b) state=0;
       }
 else if (state==5)
       {
       if (!encoder_b) state=6;
       }
 else if (state==6) 
       {
       if (!encoder_a)
        { 
        encoder_flag=1;
        state=0;
        }
       }
 else state=0;
}

byte get_encoder(void)
{
 byte f;

 if (encoder_flag)
  {
  if (timer<7) encoder_flag|=32;
  timer=0; 
  }

 f=encoder_flag;
 encoder_flag=0;

 return(f);
}

// Call this every 10ms
//
byte encoder_timer_handler(void)
{
 if (timer<200) timer+=1;
}

I guess it implements the same state machine as mentioned above :)

This particular encoder generated a lot of bounce if you held the encoder against the detent like when you carefully adjust a value. It does not continually switch between up/down in that case, even if on average that stream of up/down events is no movement at all.
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2094
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #60 on: September 22, 2013, 06:59:50 pm »
-Use edge detect interrupts to read encoder, (paying attention to debounce).

Debouncing requires you to decide when an input has stopped changing state. Kinda awkward to do that in an interrupt handler which only runs when an input changes state.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #61 on: September 22, 2013, 07:40:00 pm »
I think what I've learned from my research so far, regarding velocity, is that just having the capability to determine velocity is only half the problem.  The easy half, even.  Using the velocity in a way that actually makes for a positive user experience is the real trick.

For useability testing I emulated an interface where the rotary encoder was used to set a voltage between the values 1.250V and 30.000V.  The velocity was used to switch between adjusting the value in 1mV, 10mV and 100mV increments.  I basically had three categories of velocities.  The faster velocities controlling the larger increments.

It turns out this isn't really sophisticated enough.  If I were a user I'd despise this interface.  Some fine-tuning might help but I'm pretty sure it is just a fundamentally flawed way to go about it.

One of the biggest problems is that you have to spin the knob too fast to make large increments.  Spinning the knob fast isn't a problem.  Spinning it fast and keeping up with the changes is the problem.  I think what the user would really want is to spin the knob fast enough to get it into the large increment mode but then be able to use a slower velocity.  Some kind of hysteresis, in other words.

I'm not saying this can't be done.  I just saying it's a little more complicated to do right.
 

Offline Teemo

  • Regular Contributor
  • *
  • Posts: 58
  • Country: ee
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #62 on: September 22, 2013, 07:59:25 pm »
For useability testing I emulated an interface where the rotary encoder was used to set a voltage between the values 1.250V and 30.000V.  The velocity was used to switch between adjusting the value in 1mV, 10mV and 100mV increments.  I basically had three categories of velocities.  The faster velocities controlling the larger increments.

It turns out this isn't really sophisticated enough.  If I were a user I'd despise this interface.  Some fine-tuning might help but I'm pretty sure it is just a fundamentally flawed way to go about it.

One of the biggest problems is that you have to spin the knob too fast to make large increments.  Spinning the knob fast isn't a problem.  Spinning it fast and keeping up with the changes is the problem.  I think what the user would really want is to spin the knob fast enough to get it into the large increment mode but then be able to use a slower velocity.  Some kind of hysteresis, in other words.

I'm not saying this can't be done.  I just saying it's a little more complicated to do right.
I'd suggest that velocity control should be more smooth, simple algorithm based, not in just three 10x steps. It should add counts directly after every detent.

Isn't the gray code based encoder reading same accurate and bounce/skip proof, as full state machine as here above? (I read the example with the gray code here:http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino)
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #63 on: September 22, 2013, 08:51:32 pm »
My approach (with the large step sizes) was trying to deal with the large span of counts the user has to cover--nearly 30,000.  I don't want it to take too long to go from one end of the range to the other.

Something has to change, though, because it definitely doesn't 'feel' right.  I haven't implemented the idea of hysteresis yet.  (Entering and exiting the three velocity categories at different velocities.)  That might help.
 

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #64 on: September 23, 2013, 01:12:44 am »
.......  I basically had three categories of velocities.  The faster velocities controlling the larger increments.

It turns out this isn't really sophisticated enough.  If I were a user I'd despise this interface.  Some fine-tuning might help but I'm pretty sure it is just a fundamentally flawed way to go about it.

Thats what how I feel too when I tried using categories on the velocities, not sure how to express it, it just feels "jagged".  ???


I'm not saying this can't be done.  I just saying it's a little more complicated to do right.

This, is one of the reason the code turned my world up side down, ended up I dumped it and simply give up.  |O

Not sure if my Google Fu is lame, its just I found this topic with the velocity feature is quite rare on the net, actually at 1st I was expecting and assuming this topic should be easy to find on the net, and some code experts already written it nicely (in term of performance + tight code + elegance solution), but that is not the case.  :-//


I'd suggest that velocity control should be more smooth, simple algorithm based, not in just three 10x steps. It should add counts directly after every detent.

 :-+ , yep, agree on the smooth thingy or so called "analog" feel if this is the right wording.


Thanks for keeping this thread alive.  :clap:

Offline Crazy Ape

  • Regular Contributor
  • *
  • Posts: 181
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #65 on: September 23, 2013, 02:50:44 am »
Variable velocity user input in general is subject to the same problem, and therefore, the algorithm that provides a solution should work in all instances.

Xorg recognized and even mentioned the problem, and seem to have come up with a good solution.
My guess is that the algorithm you seek is just sitting there waiting for you find it in the Xorg source code.

Quote from Xorg site (link below):
Quote
Problems of the previous method

The previous method ('lightweight scheme') did not have a velocity concept. It is based directly on the motion report's values ('mickey'), which at best correlates to velocity. Since the brain knows about velocity, not mickeys, this is disturbing.

For polynomial acceleration: On slow movements, this code infers 3 'velocities': 1, 1.41, and 2. As 1 remains unaccelerated (or is even slowed down), we're left with just two acceleration levels. It is hard to foresee what exactly will happen.

Worse when using the simple accelerated/unaccelerated function: Acceleration either comes to effect or it doesn't, providing no predictability around the threshold. The higher acceleration, the less predictability you get.

If a system is under load, a device (or the driver/kernel) may accumulate its movement delta while the system does not query the device. This invalidates the assumed mickey-velocity relationship, causing irrational high cursor movement subsequently. This is particularly annoying when caused by focus changes during a mouse stroke (modern toolkits luckily don't exhibit this behaviour anymore).

Some people own very responsive devices, creating a need to reduce speed on precise tasks or even in general. This often required driver-side or hardware support which was missing.

With the simple acceleration scheme, acceleration is more sensitive on diagonal movements than on axis-aligned ones.

These problems result in a reduced ability for our intuition to predict a matching hand movement for desired screen movement, thus causing more correctional moves than necessary. Put simply, the mouse 'feels bad'.


Benefits of the new code

Mostly, the polynomial acceleration becomes more usable. It can be used with higher acceleration coefficients (acc > 2), still providing enough control. But also the classic acceleration should become less jumpy since it now ascends softly towards accelerated motion.

Users with too precise (or fast) devices can slow them without losing precision, independent of hardware driver support. Also, an acceleration function may decelerate on slow movements, giving (sub)pixel precision without sacrificing on pointer speed.

The code is more robust towards different devices: One could imagine a mouse reporting very often, but only 1 dot per event. Old code would not accelerate such a device at all. While this is a theoretical case, there is robustness against jitter in device event frequency (as could be caused by system load, for example). In general, the number of problematic devices (wrt acceleration) is expected to shrink significantly.
http://www.x.org/wiki/Development/Documentation/PointerAcceleration/

The original ANNOUNCE is here, it'll show you where to look in the code.
http://old.nabble.com/-ANNOUNCE--predictable-pointer-acceleration-td18980476.html

Copies of above in case it goes away (Warning at top of page suggests it will soon die)
http://lists.freedesktop.org/archives/xorg/2008-August/037734.html
http://web.archiveorange.com/archive/v/Ky751HDOYzGLgQOYcYUB
« Last Edit: September 24, 2013, 02:09:00 pm by Crazy Ape »
 

Offline Teemo

  • Regular Contributor
  • *
  • Posts: 58
  • Country: ee
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #66 on: September 23, 2013, 08:07:21 am »
For useability testing I emulated an interface where the rotary encoder was used to set a voltage between the values 1.250V and 30.000V.  The velocity was used to switch between adjusting the value in 1mV, 10mV and 100mV increments.  I basically had three categories of velocities.  The faster velocities controlling the larger increments.

Maybe to use coeficents: 1;2;4;8;16;32;64;128;..... basically powers of two instead of ten. Maybe this does the trick?
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #67 on: September 23, 2013, 11:32:06 pm »
Some thoughts on the 4-bit state machine approach: it will take about 15 us (assuming 1MIPS mcu) for interrupt latency and maybe 20 us for the actual processing. So each edge of channel A or B on the encoder will consume 35 us.

That means the max number of edges to be processed in a second is 1000000us / 35us = 28,000 edges.

At 4 edges per detent, that means 7,000 detents per second. at 16 detents or 32 detents per revolution (typically for a mechanism rotary encoder), that translates into 220 - 450 revolutions per second, far exceeding the capabilities of a mechanical encoder.

For a 500 lines (=edges) per revolution optical encoder (typical for a precision motor control application), the maximum revolution is 28000/500=~60 revolutions per second, or 3500 revolutions per minute.

That's not bad for a 1MIPS mcu, :)
================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #68 on: September 23, 2013, 11:55:16 pm »
Some rough numbers:

ISR execution (from pulse coming in to counter being updated): 41us (including 1 statement to output the encoder counter on a port),
Code size: 31 bytes,
C-statement: 1-2 statements + 1 statement to update the counter.
Using an old PICC compiler, no optimization (default optimization).
Bounce resistance: 100%, :)
================================
https://dannyelectronics.wordpress.com/
 

Offline Christe4nM

  • Supporter
  • ****
  • Posts: 241
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #69 on: September 24, 2013, 09:44:27 am »
This topic is a great read! Although I cannot submit any useful code, I did some thinking. Here are some thoughts.

One thing that keeps coming back to me is that the velocity control will probably need an exponential curve (rotation speed vs. increments). This is more based on say "professional intuition" than fact. Though there are so many things in nature that are modeled as first or second order exponential curves that it seems highly probable. It is probably explained in that you want precision as you turn slowly, but want speed as you turn quickly. As mentioned before this should feel as a smooth transition.

Another thought was this: does a user really want/like velocity control? If a user wants it, what do we need to do to make it feel right?
I recall working with the BK precision electronic load and being not used to the velocity control I turned the rotary knob big time to increase the load current (knob was set to the least-significant digit, or so I thought). Due to the velocity control with that knob, the current was at max within what felt like half a turn, though probably in reality was 1,5 turn or something. It didn't feel right. It took me a long time to get used to the control having non-constant increment depending on rotation speed. I felt I needed to be extra careful while adjusting the load with the output on, not (yet) trusting the instrument would do what I wanted.

So what think is that you need some clear feedback to the user that is more than just the numbers on the display increasing. The change in the displayed value is probably not really intuitive if you're used to look at a certain digit changing, or looking for a constant change, as you rotate the control knob. Maybe if velocity control kicks in you should indicate in real time which digit is increased so you aren't 'overwhelmed' by the way your value changes. (Is it clear what I mean here?)

P.S. read for increasing also decreasing, but i.m.o. that's just a matter of rotation direction.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #70 on: September 24, 2013, 11:11:00 am »
Some rough numbers:

ISR execution (from pulse coming in to counter being updated): 41us (including 1 statement to output the encoder counter on a port),
Code size: 31 bytes,
C-statement: 1-2 statements + 1 statement to update the counter.
Using an old PICC compiler, no optimization (default optimization).
Bounce resistance: 100%, :)

BBM.  It's bounce resistant up to the point that both channels are bouncing simultaneously.  If that happens then all bets are off.
 

Offline nessatse

  • Regular Contributor
  • *
  • Posts: 98
  • Country: za
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #71 on: September 24, 2013, 12:52:47 pm »
BBM.  It's bounce resistant up to the point that both channels are bouncing simultaneously.  If that happens then all bets are off.


If both channels bounce simultaneously your encoder is probably broken.  This is in effect Gray code, remember.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #72 on: September 24, 2013, 12:57:38 pm »
BBM.  It's bounce resistant up to the point that both channels are bouncing simultaneously.  If that happens then all bets are off.


If both channels bounce simultaneously your encoder is probably broken.  This is in effect Gray code, remember.

I'd be worried that this is going to be a common failure mode when these things reach their end-of-life.
 

Offline Rufus

  • Super Contributor
  • ***
  • Posts: 2094
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #73 on: September 24, 2013, 01:13:46 pm »
BBM.  It's bounce resistant up to the point that both channels are bouncing simultaneously.  If that happens then all bets are off.

If both channels bounce simultaneously your encoder is probably broken.  This is in effect Gray code, remember.

When you turn a mechanical switch encoder faster than it can track simultaneous bounce on both channels is about all you are going to see.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #74 on: September 24, 2013, 01:51:14 pm »
Quote
both channels are bouncing simultaneously.

Or both channels are not pulsing at all, :)

You have to stop somewhere and engineering against every possible fault leads to a useless product.
================================
https://dannyelectronics.wordpress.com/
 

Offline jeroen74

  • Frequent Contributor
  • **
  • Posts: 397
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #75 on: September 24, 2013, 06:22:19 pm »
One Philips/Fluke function generator (PM5139 I think) I once took a cursory peek at, at a previous job, had a nice big knob that was apparently quite heavy and undamped. Give it a good spin and it keeps on spinning for like a minute :) I wonder how well that worked.
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #76 on: September 24, 2013, 06:38:05 pm »
I finally got things in my little research project to the point where I would consider it "not terrible."

Just to remind everyone, for useability testing I have a mock interface to change a voltage between the values of 1.250V and 30.00V, using just a 20PPR rotary encoder.  The challenge here is to give the user the ability to change the setting as conveniently as possible--avoiding overshoots and not requiring the user to spend a lot of time spinning the encoder just to make large changes.

One of the important changes I made was to basically throw away half of the actions (=clockwise or counter-clockwise click) and turn the encoder into a 10PPR encoder instead of a 20PPR encoder.  The problem was that it is actually too hard to control at 20PPR.  It's too hard to keep up with the changes, that is.

Note that, from the standpoint of calculating velocity, I still count the actions that are otherwise thrown away.  This gives better resolution.

I still have the three step sizes that I had earlier: 1mV, 10mV and 100mV.  The problem with my earlier implementation was that I required the user to maintain the velocity to stay at particular step size.  This meant that the user (=me) couldn't keep up with the changes for the larger step sizes and would, more often then not, overshoot.

I changed it so that the user can slow down once they have stepped-up the speed.  The step size can now only increase once the user starts spinning the encoder.  That is, they can step up but not down.  The encoder has to come to a complete stop before the step size returns to the 1mV size.  This actually works out pretty good for this particular mock environment.  (Setting an output voltage.)

Another change that helps a lot is that when the step size is 10mV then the last digit of the setting is always "0", and if the step size is 100mV then the last two digits are always "00".  This helps the user focus on what is actually changing.  (Like Christe4nM suggested.)

There are two velocity thresholds to enter into the 10mV and 100mV step sizes.  The user has to be fairly determined to pass these thresholds.  Once they are passed, however, the user can slow down and catch back up and regain control.  Control is one of the keys. 

Predictability is another key.  So far as the user having a pretty good expectation as to when they are going to "step up."  That doesn't seem too bad currently but could use some improvement.
 
The following users thanked this post: ilium007

Online BravoV

  • Super Contributor
  • ***
  • Posts: 6253
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #77 on: September 25, 2013, 03:36:12 am »
Uhmm ... another new one, geezz ... I haven't finished digesting your previous codes yet.  :-[

Really appreciate that Jack.  :-+

Offline Teemo

  • Regular Contributor
  • *
  • Posts: 58
  • Country: ee
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #78 on: September 25, 2013, 07:49:48 am »
Another idea: probably it is better to use undented rotary encoder with smooth turning. The detents kind of screw up the user experience, because they trick the brain to instinctively thinking that one step with detents should mean one step of adjustment.

Our kitchen radio have volume knob with undented encoder(with velocity) and it feels so natural that most users even do not know it has this magnificent feature. It is possible to turn the volume from 0 to max (or form max to 0) in only half turn when turning really fast.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8229
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #79 on: September 25, 2013, 10:31:04 am »
another way to measure velocity is to measure frequency of the pulses and adjust increments based on that.
================================
https://dannyelectronics.wordpress.com/
 

Offline TerminalJack505

  • Super Contributor
  • ***
  • Posts: 1205
  • Country: 00
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #80 on: September 25, 2013, 11:58:55 am »
Uhmm ... another new one, geezz ... I haven't finished digesting your previous codes yet.  :-[

Really appreciate that Jack.  :-+

The only file that changed since the last version I posted is main.cpp.  All the other files are the same.

I probably won't be playing around much more with the project.  I don't have an immediate need for an encoder with velocity.  I just thought it sounded like something interesting to research.

Another idea: probably it is better to use undented rotary encoder with smooth turning. The detents kind of screw up the user experience, because they trick the brain to instinctively thinking that one step with detents should mean one step of adjustment.

Our kitchen radio have volume knob with undented encoder(with velocity) and it feels so natural that most users even do not know it has this magnificent feature. It is possible to turn the volume from 0 to max (or form max to 0) in only half turn when turning really fast.

The encoder I'm using has no detents.  I agree that you wouldn't want them for this sort of application.
 

Offline mrflibble

  • Super Contributor
  • ***
  • Posts: 1947
  • Country: nl
Re: Any good examples on rotary encoder library "WITH" velocity ?
« Reply #81 on: September 25, 2013, 10:28:02 pm »
The encoder I'm using has no detents.  I agree that you wouldn't want them for this sort of application.

That might also be a matter of both taste and the particular application.

The affordable ones on ebay do have the detent. And while I would like to have the detent be a little less forceful they are good enough. Incidentally, does anyone know of a cheap source of decent knobs for these things?

Regarding distinct 10/100/1000 mV steps vs continuous, I prefer the distinct steps. Precisely because that gives me some predictable behavior in step size.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf