Sohil Mehta
Sohil Mehta

Reputation: 33

Interrupts in Python

I wrote a simple code to test interrupts in Python:

import RPi.GPIO as GPIO

brakepin = 32
brake_value = 0

GPIO.setmode(GPIO.BCM)
GPIO.setup(brakepin, GPIO.IN, pull_up_down = GPIO.PUD_UP) #Brake

def brake_isr(channel):
    global brake_value 
    print ("Entered interrupt")
    brake_value = GPIO.input(brakepin)

GPIO.add_event_detect(brakepin, GPIO.RISING, callback = brake_isr)

while True:
    print("Brake_value: %d" % (brake_value))
    time.sleep(0.025)

I am using interrupts to capture when the brakes are pressed on a scooter and when they are not. Ofcourse, 1 indicates the brakes are pressed and 0 indicates they are not. I have three questions:

  1. In the line: GPIO.setup(brakepin, GPIO.IN, pull_up_down = GPIO.PUD_UP) what should I put the value of pull_up_down? UP or DOWN. Actually both are working the same way, there is no difference. The brake's default value is 0 (when not pressed) because it is connected to ground.

  2. In the line: GPIO.add_event_detect(brakepin, GPIO.RISING, callback = brake_isr) should I put GPIO.RISING or FALLING? Since I want to detect brake events (i.e. when a brake is being pressed and when it is not) I think I should use RISING only.

  3. One very weird thing is happening: When I press the brake I get output as:

Brake_value: 1 -> This is as expected. Great!

When I let go off the brake it still remains 1, i.e.:

Brake_value: 1 -> This should be 0

Why is the brake value not coming back to 0 when I let go of the brake

Edit: I modified my interrupt code block to this:

def brake_isr(channel):
    print ("Entered interrupt")
    global brake_value
    while GPIO.input(brakepin) == 1:
       brake_value = GPIO.input(brakepin)

    brake_value = 0

Well this solved the problem that I was facing with Question 3. However another weird thing is happening with the output (which was happening even before):

Brake_value: 0
.
.
.
When I press the brakes:
Entered interrupt
Entered interrupt
Entered interrupt

Brake_value: 1
Brake_value: 1
.
.
.
When I let go of the brakes:
Entered interrupt
Entered interrupt
Brake_value: 0
Brake_value: 0
.
.
.
Why is the code entering the interrupt block several times when I press the brakes (as can be seen with the multiple print statement) and why is it entering the interrupt when I let go off the brakes? This is happening for time.sleep(1) or time.sleep(0.025), deosnt matter what the delay is.

Upvotes: 0

Views: 4903

Answers (3)

Ryan
Ryan

Reputation: 126

Concerning your new issue, you might want to look into "switch debounce". This is something that can happen when you push a button and the simple answer is that cheap buttons/switches can result in multiple REALLY fast 0->1->0->1 changes for each press/release... which is why you are getting print outs when you release the button as well. Your sleeps are only pausing the print out of the current brake value, while the interrupt itself triggers it's own print out which is why the sleep duration has no effect on this message. The software fix is to have your interrupt only trigger a certain amount of time after a rising edge is detected if and only if there is no following falling edge (basically if we go from 0->1, make sure it stays at 1 for .5 seconds or something before you actually trigger the event), and then do the same thing for releasing the brake(when we go 1->0, wait 0.5 seconds to make sure it stays at 0). THAT SAID, a software solution isn't what you really want here. Switch Debouncing can be done very easily with two nand gates and a few resistors. https://electrosome.com/switch-debouncing/ has a better explanation with a few really good pictures and if you have the physical components it's the way to go, but if you don't have the actual parts you can cobble together a software solution. The software solution to this problem is sub ideal because it will introduce lag between pushing the brakes and it registering with the arduino, which in some cases you don't really care about but generally for brakes you want them to be very responsive.

Upvotes: 0

Sohil Mehta
Sohil Mehta

Reputation: 33

As suggested by @Ryan, this is what I did:

def brake_isr(channel):
    print ("Entered interrupt")
    global brake_value
    while GPIO.input(brakepin) == 1:
       brake_value = GPIO.input(brakepin)

    brake_value = 0

This solves question 3, but it will be great if someone can answer the edit I posted in my question

Upvotes: 0

Ryan
Ryan

Reputation: 126

It looks like you have an interrupt set to detect rising edges, so when the value changes from 0 to 1, but you have nothing setup to check falling edges which would be when you release the brakes. So it looks to me like you have an interrupt triggered when you push the brakes, set Brake_value = 1... but then you never setup any way to swap it back to 0 so it just stays as a 1 in your stored variable. if you were to measure the physical voltage at the GPIO pin it would change as you pressed the brake, causing the rising edge which triggers your interrupt, however within that interrupt you're just setting Brake_value = GPIOvalue which during the interrupt will always be 1.

Basically the problem is that you're trying to track the status of your GPIO pin, but instead of just reading it's value and printing that, you are setting an internal variable to be equal to the value of the GPIO pin... except you set it high on your interrupt event and then never change it back.

There are a few ways to fix this, you could set another interrupt event to occur on a falling edge for the same pin, which would make it trigger when you make a change from 1 to 0 (when you release the brakes). Additionally you could get rid of brake_value and just replace everywhere you access it with an actual read to the GPIO pin. You could also poll the GPIO pin after the 0 -> 1 interrupt occurs, essentially just having a while(GPIO == 1) in your interrupt code block which would exit as soon as the pin is set back to 0. There are probably a few other ways to do this but these are what immediately come to mind.

The above essentially answers your questions 3, question 1 is probably a datasheet question, the microcontrollers i've used needed specific values for the pullups to make the GPIO pins do different things, but I think the pi is much more forgiving and if you're not having any issues with either way you set it I wouldn't worry about it... and for question 2 rising edge will trigger an interrupt when the value at that pin goes from 0 to 1, while falling edge triggers the event when going from 1 to 0, so if you have it normally grounded, and it goes high when you pull the brakes, what you want is a rising edge. However if you normally have it tied to vcc and it goes to ground when you pull the brakes, what you want is a falling edge.

Upvotes: 1

Related Questions