0

Thanks in advance!

I am using a Pi 3B to detect activation of a sensor on my model railroad layout. The sensor by default only offers a rising edge detection scenario. I decided to go with gpiozero library to setup a gpiozero.Button on GPIO 17, with pull_up=False.

enter image description here

I am facing this strange situation where the button.is_active is correctly set when the sensor is active, but the button.when_activated event is not firing on the rising edge. When the sensor deactivates, both the when_activated and when_deactivated events are fired.

I wrote a test script which sets up the event handlers, and also sets up a while loop to monitor the button.is_active property.

from gpiozero import Button
from gpiozero import InputDevice
from time import sleep
from gpiozero import DigitalInputDevice
from signal import pause
from datetime import datetime

# event handlers
def activated(self):
    print(f"{datetime.now()}: Activated {str(self.pin.number)}")

def deactivated(self):
    print(f"{datetime.now()}: Deactivated {str(self.pin.number)}")

# Set GPIO 17 with pull down resistor
button = Button(17, pull_up=False,  bounce_time=0.2)

# Set up handlers
button.when_activated = activated
button.when_deactivated = deactivated

# Loop to monitor button active state
state = button.is_active
while (True):

    # Create a debounce
    condition1 = button.is_active != state
    if condition1:
        sleep(0.4)
        new_state = button.is_active
        condition2 = new_state != state
        if condition2:

            # Print states and set the stored state to new state 
            print(f"{datetime.now()}: Stored state value is {state} and Button is {new_state}")
            state = new_state

Here is the output of the code:

2022-03-12 07:52:11.679051: Stored state value is False and Button is True
2022-03-12 07:52:20.950999: Activated 17
2022-03-12 07:52:21.146104: Deactivated 17
2022-03-12 07:52:21.351971: Stored state value is True and Button is False

The button.is_active was detected in the while loop at 7:52:11, but the when_activated event fired only when the sensor deactivated and the two events (when_activated, when_deactivated) are packed along with the button.is_active detection on the falling edge.

Any thoughts what might be going on? Any help is much appreciated. This situation is driving me bonkers.

I am using a Raspberry Pi 3B+ running Raspbian Bullseye OS. The gpiozero library is 1.6.1


1
  • Thanks CoderMike. But, "self" is just a convention in Python. Its not a reserved word, like "this" in Java/C#. neopythonic.blogspot.com/2008/10/…. I will try to see if there is some issue going on with the GPIOThreadQueue. I am going through the gpiozero code base. There is a lot going on with GPIOThread and Thread queues. But, thanks for the suggestion. Commented Mar 13, 2022 at 7:42

1 Answer 1

0

Do NOT import classes you don't need from gpiozero import InputDevice - this may not hurt but wastes memory and makes the code harder to follow.

If you are using callbacks DO NOT attempt to test the state.
Button DOES NOT have a member is_active (although the base class may have you SHOULD NOT use it).

Get rid of everything after # Loop to monitor button active state and it should work.
You will need pause() or similar.
See https://gpiozero.readthedocs.io/en/v1.6.2/faq.html?highlight=pause()#how-do-i-keep-my-script-running

Your Question lacks detail about what is connected.


You said "The sensor by default only offers a rising edge detection scenario" but is an opto-isolator, which imposes no such condition.

Your circuit has a number of limitations.

  1. A bare 3.3V connection is a potential hazard, usually avoided by engineers.
  2. The internal pullup/pulldown are weak ~50kΩ and subject to interference/noise - which is to be expected where motors are involved.

I would use a low impedance circuit with an external low resistance pullup (~1kΩ).

schematic

simulate this circuit – Schematic created using CircuitLab

This should satisfy the electrical requirements, although depending on the nature of the unspecified sensor and expected function may need additional conditioning (hardware and/or software).

As no Button is in use DO NOT use the Button class use DigitalInputDevice.

4
  • Thanks Milliways for the quick response. Please see a picture of the setup I have on my model railroad. Its a current detector which has a Opto-isolator output. There is no way to make the output work other than as an active-high system. I tried with the DigitalInputDeivce and faced the same challenge of the two events firing at the deactivation of the sensor. I added the while loop only to test the system, otherwise the whole code runs as part of a TCP server on the Raspberry Pi. Commented Mar 13, 2022 at 1:38
  • Sorry Milliways, I should have added that final detail on why I said its rising-edge only. The device i use is a Quad Current Detector with Common positive for all the four opto-isolators. The collectors of all the four opto-detectors are tied together and I dont have a way to access them individually. I get access to the four emitters only. I will try to run it as a DigitalInputDevice only and see if it will help. Commented Mar 13, 2022 at 7:13
  • @SreekarKrishna It should make no difference which way it is wired, BUT running bare 3.3V wiring has the possibility of shorting the 3.3V rail - which will most likely destroy the Pi. But use sensible pulldown otherwise you are just connecting an antenna to your GPIO. You could use a small (10Ω) resistor in the 3.3V line near the Pi for protection and should not affect operation.
    – Milliways
    Commented Mar 13, 2022 at 7:28
  • Great idea. Thanks for that suggestion. I will include a small resistor for protection purposes. Commented Mar 13, 2022 at 14:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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