Same input works different on different code - python

I have 2 different codes for the same input. The most basic one(knoptest.py(translate to buttontest.py)) works as intented. When i press the button the terminal writes "aan"(translate to "on") until i let go. However, in my more difficult code(discodouch.py(translate to discoshower)) the terminal writes "uit"(off) for a couple of times, somewhere between 1 and 20 times aprox. After then it "aan"(on) once and stays there, even without me pressing the button.
I've tried fixing it on the hardware side without any result. I've also tried copying the lines from the test file to the real file to check for spelling/other writing errors
knoptest.py:
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(38, GPIO.IN)
while True:
if GPIO.input(38) == 1:
print('aan')
discodouch.py:
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(38, GPIO.IN)
GPIO.setup(16, GPIO.OUT)
tijd = 0
GPIO.output(16, 0)
while True:
GPIO.output(16, 0)
tijd = 0
print('uit')
if GPIO.input(38) == 1:
GPIO.output(16, 1)
print('aan')
while tijd <= 2:
time.sleep(60)
tijd = tijd + 1
print('1 minuuten voorbij')
No error messages when compiling or running. However the code is supposed to jump to the "on state" when i press the button. Not after somewhere between 1 and 20 cycles at random.

TL;DR
I can't run your code on my laptop (requires a RasPi), but it sounds like you are experiencing a phenomenon called button-bouncing. Currently, your code does not handle this problem.
End TL;DR
Essentially, the button you are expecting is an ideal button. An ideal button only presses once when you push down on the button. A realistic button (the one you have) "bounces" up and down before tapering off in the depressed position. There are more discussions about this topic on the Arduino stack exchange that elaborate on this subject in much more detail.
Basically, you need to de-bounce the button so that it reads like an ideal button. You need to either use an IC (Integrated Circuit) that specifically solves this problem, some software logic, or a simple (tiny) capacitor** in series of the signal input to properly read the value of the button.
There are many different ways of solving this problem, and I haven't paid too much attention to your code, but I know, with %100 certainty, that you need to take care of button debouncing before you can reliably write programs that use buttons, and I don't see that in your code. I should mention that debouncing only matters if you care about sensitivity and timing, but I don't know the application requirements to recommend you otherwise.
Basically, without knowing the hardware configuration, that is the best I (or anybody) can give you.
** A capacitor would automatically add a delay, but it would prevent a bunch of readings of both high and low before choosing a polarity. I suggest you hook up an oscilloscope and see for yourself how the output of the button reacts.

Related

How to speed up while loop with PyAutoGui?

I am making a very simple spambot for Discord just for pranking my friends. But the while True: command is very slow. Is there a faster alternative?
import PIL
import pyautogui, time
time.sleep(5)
pyautogui.FAILSAFE = True
while True:
pyautogui.hotkey("command", "v")
pyautogui.press("enter")
if (pyautogui.locateOnScreen("av.png")):
(pyautogui.click(pyautogui.locateCenterOnScreen("av.png")))
From the documentation:
Like the enchanted brooms from the Sorcerer’s Apprentice programmed to keep filling (and then overfilling) the bath with water, a bug in your program could make it go out of control. It’s hard to use the mouse to close a program if the mouse cursor is moving around on its own.
As a safety feature, a fail-safe feature is enabled by default. When a PyAutoGUI function is called, if the mouse is in any of the four corners of the primary monitor, they will raise a pyautogui.FailSafeException. There is a one-tenth second delay after calling every PyAutoGUI functions to give the user time to slam the mouse into a corner to trigger the fail safe.
You can disable this failsafe by setting pyautogui.FAILSAFE = False. I HIGHLY RECOMMEND YOU DO NOT DISABLE THE FAILSAFE.
The tenth-second delay is set by the pyautogui.PAUSE setting, which is 0.1 by default. You can change this value. There is also a pyautogui.DARWIN_CATCH_UP_TIME setting which adds an additional delay on macOS after keyboard and mouse events, since the operating system appears to need a delay after PyAutoGUI issues these events. It is set to 0.01 by default, adding an additional hundredth-second delay.
Therefore, if you want to "speed up" your loop, you can reduce the pyautogui.PAUSE value. However, keep in mind, this will prevent you from having time to activate the failsafe if you need it.

An idle video/still frame that seamlessly transitions into a short animation, then back?

Putting together an interactive effect for my basement tiki bar using a Pi 3 B+. Total newbie to Python as of this morning, so I apologize for the inevitably dumb questions I'll be asking.
I have a PIR sensor that is working great, and is properly triggering a single audio/video with omxplayer, however I want to be able to go from an all-black screen that seamlessly transitions into an effect video when the sensor is triggered, then go back to that idle all-black screen after the effect video ends.
I planned to make the idle all-black video very long (hour or two) so that there was no risk of it ending while people were in the bar. Ideally, I'd like to be able to re-start this effect at any given time before that idle video file would theoretically end.
Right now my issues are about 1 second or so where we return to the Desktop before the idle file (file1) begins. I'd prefer this be completely seamless during the transition. Alongside that issue, I cannot restart the effect until file1 ends.
This is my current code:
from gpiozero import MotionSensor
import os
pir = MotionSensor(4)
file1 = "idle.mp4"
file2 = "effect.mp4"
while True:
pir.wait_for_motion()
print ("Effect Start")
os.system("omxplayer -o 'local' " + file2)
pir.wait_for_no_motion()
print ("Effect End")
os.system ("omxplayer -o 'local' " + file1)
Thanks in advance!
Sorry I wont be able to write you some code for this as I am working on my own project.
Idea to help you:
Have a variable set to 0 when PIR activates that variable changes to a 1. Change your While statement to an IF statement to play different vids.
If 1 then,
Play Selected Video
Else;
Play Black Video

How to disable Raspberry Pi GPIO event for certain time period after it runs in Python?

I am creating an event whenever my Raspberry Pi's GPIO pin has a falling edge. However, I want to disable this event for a certain amount of time (5 seconds for example) after each time it runs. I want the event to be enabled again after that time period.
My first thought was just to use sleep(5) within the actual event function. But I believe this will not work due to the event being ran in a separate thread.
Can anyone point me in the right direction to what I am trying to accomplish? This is not as straightforward as I imagined it would be.
import RPi.GPIO as GPIO
import time
from time import sleep
# wait 1 second at startup
sleep(1)
# event function
def event(ev=None):
print("Event was triggered! Should not run again for 5 seconds.")
# sleep(5)
# initialize GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# setup the pin and the event
GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(21, GPIO.FALLING, callback=event)
while 1:
continue
There is a switch bounce effect which happens when we use simple cheap buttons with just two contacts connected to GPIO.
During the press and depress alot of analogue stuff happens which do not belong to digital domain.
There are two ways to solve those bounces :
hardware way (adding RC filters)
software way - wait for some time to filter out those analogue world effects (this could be "dummy delay", "usage of state machines", "temporary disable interrupt")
Fortunaly python GPIO library supports software implementation for debouncing.
When you define callback for such "interrupt" you can specify the time for which listener go deaf to any changes on specified pin.
It does not really matter whether you use "bad"( noisy) button or not.
You can use this debouncing built-in function to achieve what you need:
GPIO.add_event_detect(21, GPIO.FALLING, callback=event, bouncetime=5000 )

RPi.GPIO.wait_for_edge(4, GPIO.FALLING) detects both press and release of button

I've read the documentation for RPi.GPIO, and searched Google as well as SO, but can't quite find a solution to what is probably a very dumb problem. I'm trying to ONLY detect the edge of my button being pressed. But regardless of whether I specify to look for a "falling" or "rising" edge, the Pi will execute a command on both press and release of my button. Sometimes it executes the code a bunch of times. My code:
import RPi.GPIO as GPIO
buttonPin = 4 # this is the pin for the button
GPIO.setmode(GPIO.BCM) # pinmode
GPIO.setup(buttonPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) #setting up my pin to be input w/ pullup resistor
if __name__ == '__main__':
while True: # loop
GPIO.wait_for_edge(buttonPin,GPIO.RISING) # looking for a rising edge
print('Edge detected') # this happens regardless of my button being pressed or released
Quite sure I'm missing something fundamental here, any help greatly appreciated.
You can solve it programmatically with parameter bouncetime but, you have to use
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)
or
GPIO.add_event_callback(channel, my_callback, bouncetime=200)
instead of GPIO.wait_for_edge(channel,GPIO.RISING)
or with additional hardware: add a 0.1uF capacitor across your switch,
or you can use combination of both.
More in Documentation
Peace
Your code is mostly fine, but you need some hardware knowledge...
With common switches and buttons, there's a thing called jitter.
One solution is to check for button state after a short period, usually a few milliseconds, and act based on the delayed result.

Break out of loop if GPIO doesn't toggle in time

I'm changing some inputs to a device with relays, and I'm expecting at some point to break the firmware. The question is, when will this happen?
So, to determine if the firmware breaks, I'm monitoring some LEDs that normally blink during normal operation. I know that they will lock up in whatever state they're currently in when the firmware breaks. So, my bright idea was to simple feed that signal back into a Raspberry Pi and watch the that GPIO for a change-state. If I see the state change, then go ahead and flip the relays...Then look at the LEDs and make sure they're still blinking...rinse, repeat.
However, I would normally check this with an interrupt or something in C, but I'm writing this in Python...
What's the Python way for handling this? I know that if I don't see any blinking for 2 seconds or so, the test is over, but I'm not sure how to do this without invoking something like sleep...to which, I wouldn't be able to watch for pin changes.
From the gpio module, create a threaded callback function that fires every time a rising (or falling, etc...) edge is detected.
Then using signal within this function call signal.alarm() to reset an alarm whenever the pin changes.
Finally use signal.signal() to register a function for what should happen when the alarm is not reset in time (ie, firmware has broken)
this won't work if you're using windows unfortunately... you would need to implement your own alarm system with threading if you are

Categories