My question is: GPIO.add_event_detect() is detecting a false Rising edge continuously in an infinite loop and running the call_back function() infinitely even though I do not press the push-button connected to GPIO 25 even once But the call_back function() keeps executing.
Here is my code, where I want to call the call_back function x1() which contains the function WhatsApp(lat_o,long_o) only when the button is pressed but WhatsApp(lat_o,long_o) keeps executing without me pressing the button. Also, I put WhatsApp(lat_o,long_o) inside x1() to remove the problem of passing arguments to the call_back function.
# INTERRUPTS (NOT WORKING)
# Sample Coordinates
lat_o=33
long_o=72
# Import Libraries
import RPi.GPIO as GPIO
from time import sleep
def x1(channel):
WhatsApp(lat_o,long_o)
# Configure GPIO of Rpi
GPIO.setwarnings(False) # Ignore warning for now
GPIO.setmode(GPIO.BCM) # Use GPIO pin numbering
button1 = 25 # For WhatsApp
# Setup GPIO for Whatsapp
GPIO.setup(button1, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) # Set GPIO 25 (pin 22) to be an input pin for WhatsApp
# Detect button1-press
GPIO.add_event_detect(button1 ,GPIO.RISING, callback = x1)
try:
while True : pass
except:
GPIO.cleanup()
Please help!
I don't want to execute WhatsApp(lat_o,long_o) using Polling (i.e., using if-else in a while loop) in my Final Code for my Final Year Project because I want GPIO to detect button press continuously and using Polling here will drain a lot of power of my Raspberry Pi 4.
According to this discussion on the raspsberrypi discussion
A rising edge will be detected at approx. 1.25V. However, when the
voltage lowers again and the input voltage drops below the 1.16V
level, a stream of interrupts will start, and continue until the level
is below 1.12V.
This is most dramatic when slower rising or falling edges are present,
as an example, when excessive anti-debounce measures have been taken.
This is the given solutuion
In software, I use two other techniques to get rid of the false hits.
First, after the edge has been recognized by the system, we don't know
if it is the one we expect. By waiting for 5mSec, and then reading the
input again but now with a Logic Level command, we can determine if
the edge is indeed what we expect and we then avoid and discard all
other (false) edges.
And finally the code for rising edge
import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BCM)
Input_Sig = 23 # any plain GPIO pin
# if there is no external pull, use the internal one (pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(Input_Sig, GPIO.IN)
def interrupt_service_routine(Input_Sig):
sleep(0.005) # edge debounce of 5mSec
# only deal with valid edges
if GPIO.input(Input_Sig) == 1:
print("RISING")
return
# define the event; bountime of 5mSec means that subsequent edges will be ignored for 5mSec
GPIO.add_event_detect(Input_Sig, GPIO.RISING, callback=interrupt_service_routine, bouncetime=5)
def main():
try:
while True:
pass # your code
except KeyboardInterrupt:
pass
finally:
print("\nRelease the used pin(s)")
GPIO.cleanup([Input_Sig])
if __name__ == '__main__':
main()
Related
This simple piece of code crashes (the window is not responding) after a few seconds (around 5).
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 24)
#clock = pygame.time.Clock()
#font = pygame.font.Font(None, 32)
cycles = 0
while True:
screen.fill(0)
# text = font.render('Cycles : %d' % cycles, True, (255, 255, 255))
# screen.blit(text, (100, 100))
cycles += 1
pygame.display.update()
If I uncomment the commented lines, I can clearly see the program going out of control when displaying values between 47 and 50.
I use python 2.7 and pygame 1.9.2, Windows 8 (64 bits) and Eclipse + PyDev.
Call pygame.event.get() at the beginning of the while loop.
You need to regularly make a call to one of four functions in the pygame.event module in order for pygame to internally interact with your OS. Otherwise the OS will think your game has crashed. So make sure you call one of these:
pygame.event.get() returns a list of all events currently in the event queue.
pygame.event.poll() returns a single event from the event queue or pygame.NOEVENT if the queue is empty.
pygame.event.wait() returns a single event from the event queue or waits until an event can be returned.
pygame.event.pump() allows pygame to handle internal actions. Useful when you don't want to handle events from the event queue.
The window does not respond (freeze), because you do not handle the events. You have to handle the events by either pygame.event.pump() or pygame.event.get(), to keep the window responding.
See the documentation of pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
Add an event loop, for instance:
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
Alternatively just pump the events:
while True:
pygame.event.pump()
# [...]
Minimal example: repl.it/#Rabbid76/PyGame-MinimalApplicationLoop
I need to use the turtle function to create a shape that moves and that can be paused. I figured out how to do that but now I need to make it run for 10 seconds then end. It also needs to print the seconds as the countdown runs and the timer needs to pause when the app is paused.
This is what I have so far.
import turtle
import time
wn = turtle.Screen()
wn.bgcolor('blue')
player = turtle.Turtle()
player.color('yellow')
player.shape('triangle')
player.penup()
speed=1
def PlayerPause():
global speed
speed = 0
def PlayerPlay():
global speed
speed = 1
while True:
player.forward(speed)
player.left(speed)
def Timer():
seconds = 11
for i in range(1,11):
print(str(seconds - i)+ ' Seconds remain')
time.sleep(1)
print('GAME OVER')
turtle.listen()
turtle.onkey(PlayerPause, 'p')
turtle.onkey(PlayerPlay, 'r')
turtle.onkey(Timer, 'e')
wn.mainloop()
I suggest you practice "incremental development." That means instead writing a whole bunch of code and then trying to make it work, you make just one relatively small thing work, then gradually add more functions, one small step at a time.
I'll sketch how you could do this for this question.
Get something to happen once a second. Just make some kind of visible change once a second. It could be making some object alternately appear and disappear. It can be anything that is easy, visible, and doesn't break what you already have. The Screen class has an ontimer method you can use for this.
Only after the first step is working, start counting seconds and displaying the counter. Don't worry about pausing or terminating. Just make a counter that shows increasing numbers as long as the script runs.
Change it to shut everything down when the counter gets to ten.
Change it to count down from ten to zero instead of up from zero to ten.
Change the timer function to check whether the action is paused. If so, it should not change the seconds counter.
If you get stuck on any step, you can post a more specific question.
I am trying to implement an alarm trigger functionality for an IoT device using Python thread, but have a problem understanding the logic for it.
My scenario:
I have a sensor that can send me triggers for motion and tamper. So if there is any motion or tamper detected by the sensor, it should trigger the siren.
The Siren is on a GPIO port that I have configured in a separate class. There is only one siren.
Now my code:
def siren(self):
print("Turning on the siren")
setGPIOvalue(<port>, <value>)
def triggeralarms(self,):
siren_trigger = threading.Thread(target=self.siren)
if (alarmed == True):
# Check for all the sensors if there is any alarms to be triggered
for i in range(len(a.senList)):
# Motion alarm
if (motion == True):
print("-----------------> Setting the motion alarm")
if not siren_trigger.is_alive():
siren_trigger.start()
motion == False
# Tamper alarm
if (tamper == True):
print("-----------------> Setting the tamper alarm")
if not siren_trigger.is_alive():
siren_trigger.start()
tamper == False
In the siren, there is a delay of 10 sec.
The triggeralarms() function keeps on checking the status in loop.
Issue:
Now the problem is that the code triggers the GPIO for both motion and tamper sometimes. So both motion and tamper create a thread to trigger the siren.
What I am looking is for to somehow to check if the siren thread is already running, then it should now be started again.
For example, if the motion sensor triggers the siren, and I also receive the trigger for tamper, then if the siren thread is already running, tamper should not start the siren thread again.
I tried to by checking siren_trigger.is_alive() but it seems to be not working.
I am missing the logic here.
The LEDs dont blink and i get this error every time i run my python program.
blink.py:4: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
GPIO.setup(16,GPIO.OUT)
blink.py:5: RuntimeWarning: This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.
GPIO.setup(18,GPIO.OUT)
I've done some research into the problem but none of the solutions work
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(16,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
while True:
GPIO.output(16, GPIO.HIGH)
GPIO.output(18, GPIO.LOW)
time.sleep(1)
GPIO.output(16, GPIO.LOW)
GPIO.output(18, GPIO.HIGH)
time.sleep(1)
Does anyone have a solution?
Have you tried using try/except/finally blocks in your while-loop for handling errors? (Let me know if try/except/finally is unfamiliar to you).
Here's an example you can take a look at
http://raspi.tv/2013/rpi-gpio-basics-3-how-to-exit-gpio-programs-cleanly-avoid-warnings-and-protect-your-pi
Good luck!
This is because the GPIO pins are already in use. Were they set up in another script before this? You should perform GPIO cleanup after every use. As #Tommi mentioned in their answer, a try/except/finally block is useful for triggering cleanup afterwards. Here is an example demonstrating this, adapted from this site.
import RPi.GPIO as GPIO
import time
# Consider calling GPIO.cleanup() first
GPIO.setmode(GPIO.BCM)
GPIO.setup(16,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
try:
# Your code here
while True:
GPIO.output(16, GPIO.HIGH)
GPIO.output(18, GPIO.LOW)
time.sleep(1)
GPIO.output(16, GPIO.LOW)
GPIO.output(18, GPIO.HIGH)
time.sleep(1) # This line should be here so it is part of the while loop
except KeyboardInterrupt:
# Here you put any code you want to run before the program
# exits when you press CTRL+C
print("Keyboard interrupt")
except:
# This catches ALL other exceptions including errors.
# You won't get any error messages for debugging
# so only use it once your code is working
print("Other error or exception occurred!")
finally:
GPIO.cleanup() # This ensures a clean exit
I found out that the raspberry pi 3B GPIO pins are not in order, the place i was using them said it was in order but it was not. So after fixing one light blinks and one light continuously stays on but i need both to blink i shall look further.
I'm trying to utilize threading and queueing (based on a recommendation) to pause the main process.
My program basically iterates through images, opening and closing them utilizing a 3-second time-loop for each iteration.
I'm trying to use threading to interject a time.sleep(20) if a certain condition is met (x == True). The condition is being met (evident by the output of the print statement), but time.sleep(20) is not affecting the main process.
I plan to subsitute time.sleep(20) with a more complex process but for simpliclity I've used it here.
import time
import subprocess
import pickle
import keyboard
import threading
from threading import Thread
import multiprocessing
import queue
import time
with open('C:\\Users\Moondra\\Bioteck.pickle', 'rb') as file:
bio = pickle.load(file)
q = queue.LifoQueue(0)
def keyboard_press(): # This is just receiving boolean values based on key presses
while True:
q.put(keyboard.is_pressed('down'))
x = q.get()
print(x)
if x == True:
time.sleep(20)
t = Thread(target = keyboard_press, args= ())
t.start()
if __name__ == "__main__":
for i in bio[:5]:
p = subprocess.Popen(["C:\Program Files\IrfanView\i_view64.exe",'C:\\Users\Moondra\\Bioteck_charts\{}.png'.format(i)])
time.sleep(3)
p.kill()
So why isn't my thread affecting my main process?
Thank you.
Update:
So It seems I have to use flags and use flag as a global variable within my function. I would like to avoid using global but it's not working without globalizing flag within my function.
Second, I don't know how to restart the thread.
Once the thread returns the flag as false, the thread sort of just stalls.
I tried starting the thread again, with t.start, but I received the error:
RuntimeError: threads can only be started once
Here is updated code:
def keyboard_press():
while True:
global flag
q.put(keyboard.is_pressed('down'))
x = q.get()
print(x)
if x == True:
flag = False
#print('keyboard_flag is',flag)
return flag
if __name__ == "__main__":
flag = True
q = queue.LifoQueue(0)
t = Thread(target = keyboard_press, args= ())
t.start()
for i in bio[:5]:
p = subprocess.Popen(["C:\Program Files\IrfanView\i_view64.exe",'C:\\Users\Moondra\\Bioteck_charts\{}.png'.format(i)])
time.sleep(3)
print ('flag is',flag)
if flag == True:
p.kill()
else:
time.sleep(20)
p.kill()
flag = True
#t.start() #doesn't seem to work.
why isn't my thread affecting my main process?
Because you have not written any code to be executed by the keyboard_press() thread that would affect the main process.
It looks like you're trying to create a slide show that shows one image every three seconds, and you want it to pause for an extra twenty seconds when somebody presses a key. Is that right?
So, you've got one thread (the main thread) that runs the slide show, and you've got another that polls the keyboard, but your two threads don't communicate with one another.
You put a time.sleep(20) call in your keyboard thread. But that only pauses the keyboard thread. It doesn't do anything at all to the main thread.
What you need, is for the keyboard thread to set a variable that the main thread looks at after it wakes up from its three second sleep. The main thread can look at the variable, and see if a longer sleep has been requested, and if so, sleep for twenty more seconds.
Of course, after the longer sleep, you will want the main thread to re-set the variable so that it won't always sleep for twenty seconds after the first time the keyboard is touched.
P.S.: I am not a Python expert. I know that in other programming environments (e.g., Java), you also have to worry about "memory visibility." That is, when a variable is changed by one thread, there is no guarantee of when (if ever) some other thread will see the change...
...Unless, the threads use some kind of synchronization when they access the variable.
Based on what I have read (It's on the Internet! It must be true!), Python either does not have that problem now, or it did not have that problem in the recent past. I'm not sure which.
If memory consistency actually is an issue, then you will either have to use a mutex when you access the shared variable, or else you will have to make the threads communicate through some kind of a synchronized object such as a queue.