Handling rotary encoder signals

I’m working on a project that uses this rotary encoder to control an onscreen element. I believe I understand how rotary encoders work in that there are two pins (A & B) that produce high or low pulses based on the direction of rotation and this rotation can be used to, for example, increment or decrement a counter based on the direction and amount of rotation.

I’ve adapted this guide to Processing and it works fine as long as I’m turning the encoder slowly, however if I do a quick turn the numbers seem to change almost at random (though the tend to - on the whole - decrement.) I’m new to physical computing but my instinct is that the signals are changing faster than processing is able to register them but I’m not quite sure how to route this problem or if my current approach is even correct.

This is for an art piece so I don’t care about exact measurement, directional changes would be fine. Code below and any suggestions really appreciated :slight_smile:

import processing.io.*;

// Variables to track pulse states
int currentA;
int previousA;
int currentB;
int counter = 0;

void setup() {
  // pinA setup
  GPIO.pinMode(22, GPIO.INPUT_PULLUP);
  previousA = GPIO.digitalRead(22);

  // pinB setup
  GPIO.pinMode(27, GPIO.INPUT_PULLUP);
}

void draw() {
  currentA = GPIO.digitalRead(22);  
  currentB = GPIO.digitalRead(27);
  
  // has the A pin changed?
  if (currentA != previousA) {
    // if it has is it different than the value of pinB?
    if (currentA != currentB) {
      // if so we're turning clockwise
      counter++;
    } else {
      // otherwise we're turning counterclockwish
      counter--;
    }    
  } 
  
  // set previousA to currentA
  previousA = currentA;

  println(counter);
}

Thanks!

2 Likes

Hey,

actually this is normal behaviour of a rotary encoder. If you read the state of the pins once per frame, then you will most likeliy miss some changes. I never used GPIO before, just arduino. There you would use interrupts, to execute a function whenever the state of the pin changes. I guess it’s worth a try to look into attachInterrupt()

Regards.

3 Likes

Hello!

This topic got me interested in this!

I have never used the RPI (Raspberry Pi) for GPIO interfacing; it always seemed unjustifiable to me for some implementations and always used a microcontroller (Arduino or otherwise) and serial port (or otherwise) to transfer data when needed. It has its place for other tasks.

The 3.3V was also something to deal with but no longer an issue for me.
I have lots of these:


And there are other solutions to this as well.

However…

This topic got me interested and I will explore this further.
https://processing.org/reference/libraries/io/index.html

Processing is not mentioned here:
https://www.raspberrypi.org/documentation/usage/gpio/

Is this library stable?

:slight_smile:

I tried this on PC to see what would happen and got an expected message:

@benja - thanks! attachInterrupt() did it and resulted in much cleaner code. I can tell I’m still missing some signals but more than good enough for my purpose.

@glv - I’m new to this put have been using the Hardware I/O library for a bunch of little prototypes and it has been working well for me. Making art in processing that is controlled by physical buttons and as long as the timing doesn’t need to be strict the results are pretty good. With a little touchscreen you can make some fun stuff.

For posterity here’s a working implementation of a rotary encoder in processing:

import processing.io.*;

int currentCLK;
int currentDT;
int counter;

void setup() {
  // DT setup
  GPIO.pinMode(27, GPIO.INPUT_PULLUP);
 
  // CLK setup
  GPIO.pinMode(22, GPIO.INPUT_PULLUP);
  GPIO.attachInterrupt(22, this, "clkChange", GPIO.CHANGE);
}

void draw() {
  background(0);        
  textSize(32);
  text("counter: " + counter, 140, 100);
}

void clkChange(int pin){
  if (GPIO.digitalRead(27) != GPIO.digitalRead(22)) {
    counter++;
  } else {
    counter--;
  }    
}
3 Likes