Rotary Encoder
A rotary encoder, or more specifically a directional rotary encoder, may look similar to a potentiometer in some ways. Both have a knob that you turn to adjust a value. But unlike a potentiometer, a rotary encoder is far more flexible in the range and precision of values it can control. Our students love to use them in their projects to change the color or patterns in an LED strip.
Rotary encoders can be thought of as two concentric rings of switches that go on and off as you turn the knob. The switches are placed so that you can tell the direction of rotation by the order the two switches get turned on and off. They turn on and off quickly so we need a high-quality function to quickly detect their changes. And as we learned in the Button lab, switches can be noisy and have a complex state transition that must be debounced to get a good quality signal.
Learning How to Monitor the Rotary Switch Transitions
We will be using a low-cost ($1 USD) encoder that has five connectors, three for the direction and one for a momentary switch that is closed when you press the knob in. Here is the circuit that we will be using:
We hooked up the outer pins of the encoder to GPIO pins 16 and 17 in the lower right corner of the Pico.
Then we hooked the center pin to the 3.3 volt rail. The Pico likes to pull switches down from the 3.3 volt rail. This means that we will not be connecting any of the pins to GND.
We also hooked up the central press button to GPIO 22 and the 3.3 volt rail.
We then ran this code and turned the knob:
1 2 3 4 5 6 7 8 9 10 |
|
the results look like the following lines:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Note that the bit values the encoders switches (on or off as 0 and 1) are place next to each other on the same line. We did this by making the end of the first print statement be the null string not the default newline character.
This program prints out a LONG stream of numbers, mostly of the value 00
. The values are printed 10 times each second. Now let's take a closer look at only the values that change.
What we would like to do is now only print numbers if there is a change. To do this we will "pack" binary values into a two bit number by shifting the A pin value to the left:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Now we get values that look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
01
before the 11 frequently
Turning the know counterclockwise:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Here we see the reverse 10
pattern occur more frequently. But there is noise in the switches as they open and close due to small variations in the contacts as they move.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
The Rotary Class
Here is one rotary class:
Mike Teachman Rotary Class. This is preferred since it does not call a slow scheduler within an interrupt.
Using a Scheduler
There is another class Gurgle Apps Rotary Encoder that uses a scheduler within an interrupt which is not a best practice. However, we can show how this does work work with the one she created. The numbers incremented, but they didn't decrement. I had to change the pins to use the PULL_DOWN settings in the init method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
The following were the lines that I changed:
1 2 3 |
|
Testing Script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
Adding Plot
Now I can move the knob back and forth and get consistent values that go up and down. You can turn on the plot function of Thonny to see the values consistently go up and down.
Mysterious Runtime Error on Scheduling Queue
I did notice that the Shell output did register the following errors:
1 2 3 |
|
The error also occurred on line 32.
The following lines generated this error:
1 2 |
|
This error did not seem to impact the execution of the code. My suspicion is that this is a bug in the Micropython firmware.
As a fix, you can use the try/except block an catch any runtime error. The pass function is a no-op (no operation)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
References
- Counter get stuck on "schedule queue full" - suggest using a try/catch