I'm trying to demonstrate how using a state machine can clarify the logic of most Raspberry Pi projects. All of the code is available as a gist, but the problem portion is around line 34:
while True:
onoff.read(GPIO.input(button_no))
time.sleep(.001)
The state machine is designed to use a button (momentary latch) to toggle an LED on and off in a reasonable fashion (push-release, light turns on; push-release, light turns off).
The code works as listed in the gist, but as soon as you comment out the sleep
call the behavior changes to (push, light turns on; release, light turns off).
Given the real-time nature of the Pi, I believe this pause impacts it in a way that would not apply to a simulated environment. I'm pretty sure it's a Pi-specific issue.
What could be going on, here?
-
Perhaps it has something to do with this quote from the project page of RPi.GPIO: "Note that this module is unsuitable for real-time or timing critical applications. This is because you can not predict when Python will be busy garbage collecting. It also runs under the Linux kernel which is not suitable for real time applications - it is multitasking O/S and another process may be given priority over the CPU, causing jitter in your program." I haven't the expertise to say if this is the source of the issue, but it deserves an explanationSean Allred– Sean Allred2014年01月12日 05:27:14 +00:00Commented Jan 12, 2014 at 5:27
-
1Just as a side-note. Why check so often? People can only notice a delay if its more that 100ms. So checking every 100ms or 0.1 seconds is more than adequate. Checking less often will lessen the CPU load.Gerben– Gerben2014年01月12日 13:27:58 +00:00Commented Jan 12, 2014 at 13:27
-
Busy looping (i.e., without a delay) is generally an atrocious way to code.goldilocks– goldilocks2014年01月12日 18:58:05 +00:00Commented Jan 12, 2014 at 18:58
-
1@goldilocks It generally is, but I take (my only) solace in that this meant to be a single-purpose device. @ Gerben, I will be inserting a one second delay in the final code, but I I was still curious about why this problem happened in the first place.Sean Allred– Sean Allred2014年01月12日 19:40:21 +00:00Commented Jan 12, 2014 at 19:40
2 Answers 2
The reason is contact bounce - any mechanical switch will have contact bounce.
See the link for possible solutions https://raspberrypi.stackexchange.com/a/10338/8697
The code fragment you posted is very poor code. The Pi will devote most of its resources to a tight loop. You should explore interrupts or callbacks.
-
1Thanks! I can only reproduce and iterate on what I have seen done; I don't yet have a whole lot of experience in embedded systems. Are there any projects you can point to as examples of good practice (e.g. with interrupts/callbacks/...)?Sean Allred– Sean Allred2014年01月12日 19:42:13 +00:00Commented Jan 12, 2014 at 19:42
-
The description at ryniker.ods.org/raspberrypi/MagPi/GPIO_interrupts and examples ryniker.ods.org/raspberrypi/MagPi may help. (Originally from MagPi Iss 7)Milliways– Milliways2014年01月16日 01:34:07 +00:00Commented Jan 16, 2014 at 1:34
Because without the sleep call, you're in a tight loop and there's no chance for other threads to run. If you really need to poll like this (without callbacks) then you must wait a little bit (maybe 0.1 seconds makes more sense) to give the poor Pi chance to do what you're waiting for.
Imagine your boss wants you to finish some work, and he asks you every 0.001 seconds whether you've done it yet or not. Would you be able to get the work done? ;)
-
Having been in a similar but not so drastic situation, I can understand that. It's still odd that the behavior changes, but I can jokingly chalk that up to 'the laws of physics begin to break down'.Sean Allred– Sean Allred2014年01月13日 17:11:24 +00:00Commented Jan 13, 2014 at 17:11