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

0 Members and 1 Guest are viewing this topic.

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • 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: 1310
  • 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: 1310
  • 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: 1310
  • 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.
 

Offline BravoVTopic starter

  • Super Contributor
  • ***
  • Posts: 7547
  • Country: 00
  • +++ ATH1
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: 2051
  • 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: 8221
  • 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: 2051
  • 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: 396
  • 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: 2095
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: 1310
  • 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: 1310
  • 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.
 

Offline BravoVTopic starter

  • Super Contributor
  • ***
  • Posts: 7547
  • Country: 00
  • +++ ATH1
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: 8221
  • 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: 8221
  • 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: 252
  • 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: 1310
  • 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: 99
  • 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: 1310
  • 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: 2095
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: 8221
  • 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/
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf