Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Friday, 13 January 2017

Round and Round (rotary encoder)

Pots are fun, but they have two limitations - firstly they have a position, which is great feedback, but if it gets out of sync with the "real" value because you've changed it for some other reason then you need a motorised pot (as we saw list time) to get it back to the correct position. The second issue is that they have limited travel - when you reach the end, then you can't go any further.

Both of these are easily fixed using a rotary encoder (which also have the advantage of being digital, so you don't need an analog input, so on a Pi they're ideal).



Our encoder has 5 pins: Gnd and +ve are obvious. SW refers to an inbuilt switch, you can press down separately from the actual rotation. The other two are clk and dt, which are the interesting ones.

make dt digital input D5
make clk digital input D6

when start
.forever
..wait until clk
..say [clk]
..wait until not clk
..say [clk]

Clock will go from high to low and back repeatedly as you turn the shaft, so to get started we wait for it to change.

when start
.forever
..wait until clk
..wait until not clk
..say [dt]

The next thing to do is to check "dt" - direction of turn. Here I've set the code up to check dt whenever the clock goes low and we conveniently find that it is true when we turn clockwise and false when we turn anticlockwise.

All that's left is to add something to keep track of the number of times we turn in each direction:

make counter number
when start
.forever
..wait until clk
..wait until not clk
..if dt
...change counter by 1
..else
...change counter by -1
..say [counter]

This works perfectly well but we can do a little better. For the encoder I got we get 15 clocks per full turn, but we can look a little closer, and get 30 half clocks by checking dt when clock goes high as well as when it goes low. When we check this we see that when we check dt at this point in the cycle it has the opposite value - its low when we go clockwise, and high anti-clockwise. Adding this in doubles the resolution of our encoder:

make counter number
when start
.forever
..wait until clk
..if not dt
...change counter by 1
..else
...change counter by -1
..say [counter]
..wait until not clk
..if dt
...change counter by 1
..else
...change counter by -1
..say [counter]

This works really well and reliably, with one gotcha. It assumes that we're actually running this code regularly. If we go off and run another script at the same time we might miss a clock change. We will spot it eventually, but by that time DT may have changed to an incorrect value - its important to check DT immedialtly the clock changes. If you're running a lot of other code at the same time, then you may need to switch back to the other version which is a little more reliable.

No comments:

Post a comment