I have a rotary encoder with 64 pulses per revolution and am trying to run it at a variety of speeds with a max of 10000 rpm. I think the Raspberry Pi can handle these rotation rates and pulses and I am using the pigpio rotary encoder library/module but I am not getting the right counter/speed readouts. I get the same number (around 8000) regardless of the speed I run the motor at. It seems as though the counter simply counts time instead of actual pulses and I cannot figure out why? I believe this might be because the counter is not updating every time it there is a pulse. Is there any way to use interrupts on the Raspberry pi so I can count every single encoder pulse?

Alternatively, would appreciate any ideas or solutions as to why the speed readouts are inaccurate.

Thanks so much!

Motor control and encoder reading code:


import RPi.GPIO as GPIO
import time
import pigpio
import rotary_encoder
import wiringpi

#Pins for Motor Driver Inputs
Motor1A = 24 # header 18, wpi 5
Motor1B = 23 # header 16, wpi 4
Motor1E = 13 # header 33, wpi 23
encA, encB = 27, 22 # these are BCM pins, headers 13 and 15, wPi 2 and 3

last_pos, curr_pos = 0, 0
start = 0
LOOP_TIME = .1 # how often RPM is calculated
CPR = 64 # 64 pulses per revolution
G = 6.3 # gear ratio on the motor

pi = pigpio.pi()

def callback(way):
    global curr_pos
    curr_pos += way

def setup():
    wiringpi.wiringPiSetupGpio() # this sets all the pin inputs to wPi mode (as opposed to BCM or headers)

    wiringpi.pwmSetRange(500) # arbitrary max value
    GPIO.setmode(GPIO.BCM) #GPIO Numbering
    GPIO.setup(Motor1A,GPIO.OUT) #All pins 2as Outputs
    wiringpi.pinMode(Motor1E, wiringpi.GPIO.PWM_OUTPUT)
    global pi
def loop():

    global start
    global last_pos
    global decoder
    decoder = rotary_encoder.decoder(pi, encA, encB, callback) 

    # reading the encoder data and measuring RPM
    dt, dpos = time.time() - start, curr_pos - last_pos
    if dt > LOOP_TIME:
        start, last_pos = time.time(), curr_pos
        rpm = (dpos*60)/(G*CPR*dt)
        print("RPM = {}".format(rpm))

    wiringpi.pwmWrite(Motor1E, 480)

def stop():
    wiringpi.pwmWrite(Motor1E, 0)

def destroy():
if __name__=='__main__': # Program start from here
        while True:
    except KeyboardInterrupt:
  • you may be using the encoder in an incorrect way ... do you really need to measure the angular position of the motor shaft? ... do you need to measure which direction is the motor shaft spinning? ... do you only need to know how fast the motor shaft is spinning?
    – jsotola
    Oct 13 '21 at 22:58

I suggest you simplify your code and do everything with pigpio.

Currently you are also using RPi.GPIO and wiringPi.

Interrupts will not help. pigpio samples faster than the Pi can supply a continuous stream of interrupts.

If your figures are correct you are swamping the system.

10000 RPM
64 steps per revolution
4 edges per step.

In a minute that is 10000 * 64 * 4 or 2560000 edges.

In a second that is 42667 edges. A Pi4B/Pi400 would probably work reasonably well.

An obvious problem is you are repeatedly creating the encoder in the loop. It should be created once outside the loop.

You really need to refactor your code.

  • Hi joan, thanks for the advice. I am very much a beginner to this and I think I will definitely need to hone the code more and get rid of wiringpi and RPi.GPIO. It seems that I actually fixed the problem by adding delays and moving the decoder definition out of the loop, thanks for the suggestion!
    – paprikum
    Oct 13 '21 at 20:08
  • That's good. Well done to get it working.
    – joan
    Oct 13 '21 at 20:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.