Arduino hardware software

Adaptive User Input with a Rotary Encoder

rotary_encoderI like using rotary encoders for user input as they can provide very precise control over settings. The built-in switch is also very convenient and makes it easy to implement the push button functionality I described in a previous post. Altogether, rotary encoders have a ‘modern’ feel that makes projects seem more professional.

There is one shortcoming of these devices, though, that I have recently worked to overcome.

The downside became obvious in a recent project where the encoder was being used to select a frequency between 1Hz and 10MHz. Seven orders of magnitude is quite a range and wholly unsuitable for the ‘standard’ method of one encoder click per value – it would have simply take too long to cover the range. However, I also did not want to lose the ability to move by 1 step value if that was needed.

Somehow the user needed to express how the encoder should work by how it was being used. The most obvious way was to sense how fast the encoder was being rotated and vary the step size accordingly – precise small steps for slow turning and bigger movement steps for faster turning.

I changed my rotary encoder library (MD_REncoder) to measure a ‘speed’ parameter measured in clicks per second. I found that could get counts of 1 to around 50 with normal use of the encoder, but this was still not providing large enough steps for a good user exeperience.

I needed a logarithmic increment to give the ‘kick’ needed at faster speeds. I turned the linear readings from the encoder into a logarithmic step size by applying the formula

step = 10^(int(speed/10))

ExponentialThis meant that speed readings of 0-10 resulted in step size 1 (ie, 10^0), 10-20 step 10 (ie, 10^1), … , 40-50 step 10,000 (ie, 10^4). Given the large range to be covered this work fantastically well.

A bonus of this algorithm is that the responsiveness of the system can be tuned to requirements.

For starters, the base for the exponential does not have to be 10.  5, 3, 2 (or numbers larger than 10) can be used depending on how ‘amplified’ the steps need to be. The table on the right shows how the step size varies for each exponent base (click the chart to enlarge).

The divisor for the speed value can also be varied to give larger or smaller index values – experimentation will allow you to pick numbers that give the desired response for the particular application.

I think this is one algorithm that I will be using more in future.

Update 30 May 2017

A more efficient expression for logarithmic increments on a base 2 system (ie, a computer) is:

step = 1 << (int(speed / 10))

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s