Rotary encoder speed control, is encoder turning fast? update the counter +10 - Page 1
Forum section: electronics / general

author: ZeTeX
author_rank: Frequent Contributor
timestamp: January 13, 2017, 03:47:44 pm
content: Hi,I have a rotary encoder library that I have downloaded from the internet, and the code for reading the rotary encoder works perfectly but there is something that I would like to add to the code to make it better, what I want to add is "speed control" for the encoder, so for example, if I spin the encoder fast, instead of updating the counter once every reading of the encoder changing position, I would increase the counter x2 faster, this way if I'm using the encoder to set a value between 0-1000 instead of rotating the encoder 1000 times to get to the 1000 val I would only need to spin for example 100 times if I spin it fast, if I would spin it slow it would only update the encoder like usual, once per step.So I taught about checking if the (if) function that runs in a loop that is checking if the encoder is rotating is accomplished for 5 times at least (5 updates to the counter) in less then 250ms for example, it would update the counter by 5 every step. the numbers are not critical as I can adjust them if I find the encoder too sensitive to speed.My question is simple, How do I do this? I've tried various method like checking time elapsed and things like that, I also taught about maybe having a for loop and checking if the loop reached to 50 for example and the if statement accomplished for 5 time but I'm pretty new to arduino so I also had problems with that.This is the code:Quote

author: Kremmen
author_rank: Super Contributor
timestamp: January 13, 2017, 04:59:29 pm
content: Can be done relatively easily.All you need to do is check whether encoder pulses arrive at shorter intervals than a predefined limit. If yes then use large increment, otherwise the smaller one.Presumably the encoder is one of these mechanical type that has relatively coarse resolution? In that case the timing can be easiest achieved just by reading successive values of the millis() counter. Otherwise you can also use the Timer1 library for much more sophisticated timing.

author: BrianHG
author_rank: Super Contributor
timestamp: January 13, 2017, 05:12:19 pm
content: Keep your original counter.Time the amount of time_between_each incr, or, decr. For that timer, have a maximum limiter on it, say 100ms. (1 Sec). From that top value, subtract +1 from it:Speed_factor = 101 - (time_between_each_pulse);Now, for your position:accelerating_counter_position = ((accelerating_counter_position + counter) * speed_factor);counter=accelerating_counter_position;<<< Remember to Clear your timer whenever there is a encoder pulse>>>Whats going on here is if you are turning your encoder so slow that it's more than 100ms, the accelerating_counter_position will inc or dec by 1 for each counter inc and dec by 1.If you turn your encoder so fast that the timer is 0ms, the inc and dec of accelerating_counter_position for each pulse will be 101x per step.This would be the means if you did not want to alter your existing rotary decoder's code directly.You will need to use the CPU real time timer to make this work good.You will also need to play with my factors to achieve the acceleration curve VS rotation speed you like.Make sure that you filter out small switch debouncing noise when using a mechanical encoder in between steps. Unlike the +/-1 inc & dec which self correct, mechanical noise now may mean and additional +100, -90 or similar now that the size of the bounce can be considered different velocity, therefor, a different amount of addition and subtraction may create a spurious reaction.Good luck.

author: MarkF
author_rank: Super Contributor
timestamp: January 13, 2017, 07:28:23 pm
content: You could read your encoder at a fixed rate incrementing or decrementing a count. Then when you process the encoder inputs in your main loop, raise 10 to the power of count. in affect, you will be changing your analogValue by 1, 10, 100 or 1000 based on the count you receive from the interrupt routine. (Essentially measuring the speed the encoder is turned as others have mentioned.)Code:// PORTCbits.RC1 = encoder phase 0// PORTCbits.RC2 = encoder phase 1uint8_t currP0; // encoder phase 0 (current value)uint8_t lastP0; // encoder phase 0 (last value)int8_t en0; // encoder value (0=no change, (-)=CCW count, (+)=CW count)double analogValue=0.0;// Main entryvoid main(void){double count;// Initialize encoder variablesen0=0;lastP0=PORTCbits.RC1;// Setup interrupt here// (Recommend 50Hz or greater polling rate)// Enter main loopwhile (1) {// Encoder knob processingif (en0 != 0) {count=en0; // save counten0=0; // reset encoder value quickly// so we don't miss any changes// DO SOMETHING WITH ENCODER COUNTanalogValue += pow(10.0, count); <<<====================}// DO OTHER PERIODIC PROCESSING}}// Interrupt service entryvoid isr(void){// Read encoder knobcurrP0=PORTCbits.RC1; // encoder phase 0if (lastP0 == 0 && currP0 == 1) {if (PORTCbits.RC2 == 1) // encoder phase 1en0--; // increment CCW count for main loopelseen0++; // increment CW count for main loop}lastP0=currP0; // save current phase 0}

author: rstofer
author_rank: Super Contributor
timestamp: January 14, 2017, 04:41:11 pm
content: Quote from: MarkF on January 13, 2017, 07:28:23 pmI would think that en0 should be declared 'volatile'

author: ZeTeX
author_rank: Frequent Contributor
timestamp: January 14, 2017, 05:07:12 pm
content: Quote from: BrianHG on January 13, 2017, 05:12:19 pmHow do I time the amount between each increment?I can also use this code that includes ISR:Quoteif that would make it easier.the library is from here:http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html

author: BrianHG
author_rank: Super Contributor
timestamp: January 14, 2017, 06:35:39 pm
content: Since I've never used that library, I cannot give you a guaranteed working example, but, here is how I would modify your code so far. This should work good if every 1/4 pulse is counted from your rotary encoder and there is no signal bounce. This means every High and Low transition on both A&B inputs:Quote from: ZeTeX on January 14, 2017, 05:07:12 pmNow, this is coded messy since it is not my time driven algorithm in an earlier post you thanked me for, it is interrupt driven so you will have to work out the clock is incremented, I would recommend using a system timer which increments 10 times a second depending on your needs. Also Don't forget you can adjust the constants MAX_TIME and ACCELL_FACTOR to get the acceleration curve you like.If you setup (timer_val) properly yourself, pointing to an onchip timer which runs at the speed I recommended, with the settings I placed above, your volume should run at a step of 1 when turning it slower than 1 pulse every 0.5 seconds, smoothly ramping up to 10x per step as you rotate the encoder faster than 1/10th of a second per step.

author: 0xPIT
author_rank: Regular Contributor
timestamp: January 15, 2017, 11:43:15 am
content: My Encoder Library does what you want, in a very intuitive way: The faster you turn, the faster you'll get increments.Check my examples or other projects in my github on how to use the library.https://github.com/0xpit/encoder