0

I'm using an encoder KY040 with a Raspberry ZERO W. I want to catch every single step of my encoder. If I miss any steps, it is a problem because I have to plug on this encoder a button with figures on it.

Below it is the code I use (I found it on the web). When I rotate too fast the axis of my encoder I miss some steps. This is a big problem. Would you have an idea to avoid missing any steps ? Aside from to rotate slowly the axis.

import RPi.GPIO as GPIO
import threading
from time import sleep

#GPIO ENCODEUR 1                # GPIO Ports
Enc1_A = 32                 # Encoder input A: input GPIO 4 
Enc1_B = 36                     # Encoder input B: input GPIO 14

#GPIO ENCODEUR 2                
##Enc2_A = 11               
##Enc2_B = 12

#GPIO ENCODEUR3


#GPIO RELAI
Relay = 16


# CODE
Enc1_code = 4
Enc2_code = 18


#REFERENCES
Rotary_counter = 0              # Start counting from 0
Current1_A = 1                  # Assume that rotary switch is not 
Current1_B = 1                  # moving while we init software

##Rotary_counter_2 = 0              # Start counting from 0
##Current2_A = 1                    # Assume that rotary switch is not 
##Current2_B = 1                    # moving while we init software

LockRotary = threading.Lock()       # create lock for rotary switch


# initialize interrupt handlers
def init():
    GPIO.setwarnings(True)
    GPIO.setmode(GPIO.BOARD)                    # Use BCM mode

    #SETUP ENCODEUR 1                                       # define the Encoder switch inputs
    GPIO.setup(Enc1_A, GPIO.IN)                 
    GPIO.setup(Enc1_B, GPIO.IN)                             
                                            # setup callback thread for the A and B encoder  # use interrupts for all inputs
    GPIO.add_event_detect(Enc1_A, GPIO.RISING, callback=rotary_interrupt_1)                 # NO bouncetime 
    GPIO.add_event_detect(Enc1_B, GPIO.RISING, callback=rotary_interrupt_1)                 # NO bouncetime


    #SETUP ENCODEUR 2                                       
##  GPIO.setup(Enc2_A, GPIO.IN)                 
##  GPIO.setup(Enc2_B, GPIO.IN)
##  GPIO.add_event_detect(Enc2_A, GPIO.RISING, callback=rotary_interrupt)               
##  GPIO.add_event_detect(Enc2_B, GPIO.RISING, callback=rotary_interrupt)   


    #SETUP RELAI
    GPIO.setup(Relay, GPIO.OUT) 
        GPIO.output(Relay, GPIO.LOW) 


    return



# Rotarty encoder interrupt:
# this one is called for both inputs from rotary switch (A and B)
def rotary_interrupt_1(A_or_B):
    global Rotary_counter, Current1_A, Current1_B, LockRotary
                                                    # read both of the switches
    Switch1_A = GPIO.input(Enc1_A)
    Switch1_B = GPIO.input(Enc1_B)
                                                    # now check if state of A or B has changed
                                                    # if not that means that bouncing caused it
    if Current1_A == Switch1_A and Current1_B == Switch1_B:     # Same interrupt as before (Bouncing)?
        return                                      # ignore interrupt!

    Current1_A = Switch1_A                              # remember new state
    Current1_B = Switch1_B                              # for next bouncing check


    if (Switch1_A and Switch1_B):                       # Both one active? Yes -> end of sequence
        LockRotary.acquire()                        # get lock 
        if A_or_B == Enc1_B:                            # Turning direction depends on 
            Rotary_counter += 1                     # which input gave last interrupt
        else:                                       # so depending on direction either
            Rotary_counter -= 1                     # increase or decrease counter
        LockRotary.release()                        # and release lock
    return                                          # THAT'S IT


def destroy():
  GPIO.output(Relay, GPIO.LOW)   # led off
  GPIO.cleanup()                  # Release resource



# Main loop. Demonstrate reading, direction and speed of turning left/rignt
def main():
    global Rotary_counter, LockRotary


    Volume = 0                                  # Current Volume    
    NewCounter = 0                              # for faster reading with locks



    init()                                      # Init interrupts, GPIO, ...

    while True :                                # start test 
        sleep(0.1)                              # sleep 100 msec

                                                # because of threading make sure no thread
                                                # changes value until we get them
                                                # and reset them


        LockRotary.acquire()                    # get lock for rotary switch
        NewCounter = Rotary_counter         # get counter value
        Rotary_counter = 0                      # RESET IT TO 0
        LockRotary.release()                    # and release lock

        if (NewCounter !=0):                    # Counter has CHANGED
            Volume = Volume + NewCounter*abs(NewCounter)    # Decrease or increase volume 
            if Volume < 1:                      # limit volume to 0...100
                Volume = 20
            if Volume > 20:                 # limit volume to 0...100
                                Volume = 1
                        if Volume == 4:
                                print 'gagne'
                                GPIO.output(Relay, GPIO.HIGH)
                                sleep(3)

                                GPIO.output(Relay, GPIO.LOW)
                                destroy()
                                sleep(1)
                break
            print NewCounter, Volume            # some test print








try:
    main()
except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
    destroy()
# start main demo function
FrancNovation
  • 349
  • 6
  • 20
  • `sleep(0.1)` this means you have an update interval of only 10Hz, anything faster then that, will cause some data-loss. Either figure out how to use interrupts, or loop faster. – Matt Clark Jun 13 '18 at 19:14
  • a) edit your question and get your python code indented properly because at the moment it is not readable b) how do you know (or, why do you believe, which is different) you are missing steps? – DisappointedByUnaccountableMod Jun 15 '18 at 13:48

1 Answers1

0

Finally I have been advised to use the library PIGPIO, see the link http://abyz.me.uk/rpi/pigpio/

Their is a clean example which is working. Search for the encoder rotary example here http://abyz.me.uk/rpi/pigpio/examples.html

FrancNovation
  • 349
  • 6
  • 20