I'm using Python on Raspbian (a type of linux) on the Raspberry Pi (an embedded processor board) to monitor GPIO inputs.
See simplified version of my code below. I have an infinite loop in the python script waiting for something to happen on a GPIO i/p. Is this the correct way to do it? I.e. does this mean that the CPU is running at full whack just going round this loop, leaving no CPU cycles for other stuff? Especially as I need to be running other things in parallel (e.g. the browser).
Also what happens if the CPU is busy doing something else and a GPIO i/p changes? Does the GPIO event get stored somewhere so it is eventually serviced, or does it just get lost?
Is there a better way of doing this?
(For your answers, please note that I'm new to linux, and v. new to python and real-time programming)
#!/usr/bin/python
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def ButtonHandler(channel):
print "Button pressed " + str(channel)
# do stuff here
GPIO.add_event_detect(16, GPIO.FALLING, callback=ButtonHandler, bouncetime=200)
while True:
pass
Yes, doing while True: pass will burn 100% of your CPU (or as close to it as possible) doing nothing.
From what I understand (hopefully this is documented somewhere), the RPi.GPIO module spawns a background thread that waits on the GPIO and calls your callback function for each event. So your main thread really has nothing to do. If you want this to run as a service, make it sleep for long periods of time. If you want to run it interactively (in which case you probably want it easier to cancel), sleep for shorter periods of time, maybe 0.5 seconds, and add some way to exit the loop.
It would be even nicer if you could do the GPIO select in the main thread, or get a handle to the GPIO background thread that you can just join, either of which would burn no CPU at all. However, the module doesn't seem to be designed in a way to make that easy.
However, looking at the source, there is a wait_for_edge method. Presumably you could loop around GPIO.wait_for_edge instead of setting a callback. But without the documentation, and without a device to test for myself, I'm not sure I'd want to recommend this to a novice.
Meanwhile:
Also what happens if the CPU is busy doing something else and a GPIO i/p changes? Does the GPIO event get stored somewhere so it is eventually serviced, or does it just get lost?
Well, while your thread isn't doing anything, the GPIO background thread seems to be waiting on select, and select won't let it miss events. (Based on the name, that wait_for_edge function sounds like it might be edge-triggered rather than level-triggered, however, which is part of the reason I'm wary of recommending it.)
Related
the question started of with an anki addon that is being written in python, and in the middle of tuning my function (i thought the functionality was flawed due to things not registering, so i added timeouts but it turns out to be other stuff). i noticed that everything from the keyboard library seems to ignore the time.sleep(), wait the total time, then burst out everything at once.
def someFunction(self):
keyboard.send("ctrl+a")
time.sleep(1)
keyboard.send("ctrl+c")
time.sleep(3)
rawText = pyperclip.paste()
newText = string_manipulation(rawText)
keyboard.write(newText)
this is the code from my project. which is equivalent to below:
time.sleep(4) #1+3=4
keyboard.send("ctrl+a")
keyboard.send("ctrl+c")
keyboard.write(newtext)
I thought it might be because i bundled the library myself. so i went to use notepad++, plain editor with cmd to recreate the problem. and to make it easier to observe, i made the time difference very obvious in between the sleep.
def example():
time.sleep(3)
keyboard.send("a")
time.sleep(1)
keyboard.send("b")
time.sleep(10)
keyboard.send("c")
so when running the script in cmd, and staying in the cmd, it waits for 11 seconds then have an outburst of "abc".
but quickly switch to a text editor after executing the script in cmd, then in the text editor it treats the time.sleep() normally.
system: windows
python version: 3.6.4
keyboard library version: 0.13.4 (latest install, on 10.06.2019)
so my question follows:
what is the cause python to treat time.sleep() in a chunky fashion.
if it is the keyboard library itself, then is there ways around it?
(in the documentation it mentioned sometimes the library can plain out not work at all in other applications)
if there is no other way around it, is there other alternative libraries?
(option that isnt pyautogui, because i've tried so hard to bundle it into my project, but the imports of this library loops back on itself all the time. causing everything to break.)
p.s. for the python experts and pyqt addon experts out there, I know this is far from optimal to achieve this goal, i am still learning on my own, and very new to programming, so if there are any advises on other means of accomplishing it. I would love to hear your ideas on it! :)
I'm new to Python myself so I can't give you a pythonic answer, but in C/C++ and other languages I've used, what Sleep() does is tell the system, "Hand off the rest of my processing time slice with the CPU back to the system for another thread/process to use, and don't give me any time for however many seconds I specified."
So:
time.sleep(3)
keyboard.send("a")
time.sleep(1)
keyboard.send("b")
time.sleep(10)
keyboard.send("c")
This code first relinquishes processing to immediately and for about three seconds, and then it's going to come back to your thread eventually and keyboard.send("a") is going to be called. It probably ends up tossing the "a" on a queue of characters to be sent to the keyboard, but then you immediately tell your process to time.sleep(1) which interrupts the flow of your code and gives up approximately one second of time to the other threads/processes, then you send "b" to the queue and relinquish about 10 more seconds to the other threads/processes.
When you finally come back to the keyboard.send("c") it's likely that you have "a" and "b" still in the queue because you never gave the under-the-hood processing a chance to do anything. If this is the main thread, you could be stopping all kinds of messages from being processed through the internal message queue, and now since you're not calling sleep anymore, you get "a", "b" and "c" sent to the keyboard out of the queue, seemingly all at once.
That's my best guess based on my old knowledge of other languages and how operating systems treat events being "sent" and message queues and those sorts of things.
Good luck! I could be completely wrong as to how the Python engine works, but ultimately this has to get down to the system level stuff and in Windows, there is a message queue that posts events like this into the queue to be processed.
Perhaps you can spin off another thread where the send and sleep's happen, so that in the main thread, where the system message processing usually exists, that can keep ticking along and getting your characters to the keyboard. This way you're not putting the main thread that has lots of work to do to give up it's CPU time.
I'm writing a program to control GPIO's on my raspberry pi. I would like my program to ask me how long I would like to keep a GPIO on before it turns off.
Is it possible to have it stay on for 1 hour and then turn off. The problem I'm having is that when its on for an hour I cant issue any other commands to turn on other GPIO's because sleep.time is still being processed. I'd like to set multiple GPIO's for different times at the same time.
There are many ways to solve the problem. Conceptually, instead of sleeping 30 seconds and then doing something, you can sleep one second, do a bunch of stuff, check the time, lather, rinse, repeat. And by "sleep one second" it could just as easily be a tenth of a second or five seconds or whatever seems reasonable to me.
Another solution is to create a second thread (or process) for this sleep command so that your main thread (or process) runs unabated.
The choice depends on what all you need to do, how accurate you need the delay to be, what other things are running on the system, and so on.
Your current script only have one thread running, the sleep() will put the current running thread into sleep mode which blocks further commands.
time.sleep(secs) Python Doc
time.sleep(secs)
Suspend execution of the current thread for the given number of seconds.
You will need one more thread on the background which keeps the timer for you. In the mean time, the thread on the foreground can still takes other commands.
I recommend you read this page
threading – Manage concurrent threads
I have a python function that turns on some LEDs, then pauses (time.sleep), and then turns off the LEDs via the Raspberry Pi. It's a bit more complicated than that - it's actually a bunch of LEDs in various patterns so several hundred lines of code. This function does everything in an infinite loop. Originally, I called the function in a thread because I have some other code that runs continuously as well.
Now, I need to be able to terminate the function. This could be required after 10 seconds or 100 seconds. Each time will just depend. In looking through the site and researching threading, it doesn't sound wise to just terminate the thread and I can't really use a flag because there are so many lines of code in the function.
Is there an alternative to using threads?
If you don't need much explicit data sharing between threads, you could use multiprocessing, which is very similar to the threading module, but uses processes (which can be terminated safely).
I have a python program I want to run in the background (on a Raspberry Pi) that waits for GPIO input then performs an action and continues waiting for input until the process is killed.
What is the most efficient way to achieve this. My understanding is that using while true is not so efficient. Ideally it would use interrupts - and I could use GPIO.wait_for_edge - but that would need to be in some loop or way of continuing operation upon completion of the handler.
Thanks
According to this: http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio GPIO.wait_for_edge(23, GPIO.FALLING) will wait for a transition on pin 23 using interrupts instead of polling. It'll only continue when triggered. You can enclose it in a try: / except KeyboardInterrupt to catch ctrl-c.
If you want to continue processing then you should register a call back function for your interrupt. See: http://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/
def callback(channel):
do something here
GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback)
continue your program here, likely in some sort of state machine
I understand that when you say "using while true" you mean polling,
which is checking the gpio state at some time interval to detect
changes, in the expense of some processing time.
One alternative to avoid polling (from the docs) is wait_for_edge():
The wait_for_edge() function is designed to block execution of your program
until an edge is detected.
Which seems to be what you are looking for; the program would suspend
execution using epool() IIUC.
Now assuming you meant that you don't want to use GPIO.wait_for_edge()
because you don't want to loose GPIO state changes while handling
events, you'll need to use threading. One possible solution is putting
events in a Queue, and setup:
One thread to do the while True: queue.put(GPIO.wait_for_edge(...)).
Another thread to perform the Queue.get().
I am using Python with the Rasbian OS (based on Linux) on the Raspberry Pi board. My Python script uses GPIOs (hardware inputs). I have noticed when a GPIO activates, its callback will interrupt the current thread.
This has forced me to use locks to prevent issues when the threads access common resources. However it is getting a bit complicated. It struck me that if the GPIO was 'queued up' until the main thread went to sleep (e.g. hits a time.sleep) it would simplify things considerably (i.e. like the way that javascript deals with things).
Is there a way to implement this in Python?
Are you using RPi.GPIO library? Or you call your Python code from C when a callback fires?
In case of RPi.GPIO, it runs a valid Python thread, and you do not need extra synchronization if you organize the threads interaction properly.
The most common pattern is to put your event in a queue (in case of Python 3 this library will do the job, Python 2 has this one). Then, when your main thread is ready to process the event, process all the events in your queue. The only problem is how you find a moment for processing them. The simplest solution is to implement a function that does that and call it from time to time. If you use a long sleep call, you may have to split it into many smaller sleeps to make sure the external events are processed often enough. You may even implement your own wrapper for sleep that splits one large delay into several smaller ones and processes the queue between them. The other solution is to use Queue.get with timeout parameter instead of sleep (it returns immediately after an event arrives into the queue), however, if you need to sleep exactly for a period you specified, you may have to do some extra magic such as measuring the time yourself and calling get again if you need to wait more after processing the events.
Use a Queue from the multithreading module to store the tasks you want to execute. The main loop periodically checks for entries in the queue and executes them one by one when it finds something.
You GPIO monitoring threads put their tasks into the queue (only one is required to collect from many threads).
You can model your tasks as callable objects or function objects.