Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
implementation of a button
#1
Hi guys!

I bought a Raspberry Pi some time ago, and now I started a little project. First, I programmed a traffic light, which switches from green to yellow and then red, then it goes back to green and so on. It keeps going on forever. Now I want to add a light for pedestrian, which flashes when the traffic light is red and only if I pressed a button before. I read something about 2 threads which run at the same time, so one thread is always checking if the button was pressed or not. The code looks like this:

import RPi.GPIO as GPIO import time import _thread GPIO.setmode(GPIO.BCM) rot = 0; gelb = 1; gruen = 2; blau = 3; taster = 4 Ampel=[4,18,23,24,25] GPIO.setup(Ampel[rot], GPIO.OUT, initial = False) GPIO.setup(Ampel[gelb], GPIO.OUT, initial = False) GPIO.setup(Ampel[gruen], GPIO.OUT, initial = True) GPIO.setup(Ampel[blau], GPIO.OUT, initial = False) GPIO.setup(25, GPIO.IN) print("Taster drücken für Fussgängerblinklicht, Ctrl+C beendet das Programm") fussg = False def taste(): GPIO.setmode(GPIO.BCM) GPIO.setup(25, GPIO.IN) while True: if GPIO.input(25) == 1: fussg = True try: while True: if fussg == True: GPIO.output(Ampel[gruen], False) GPIO.output(Ampel[gelb], True) time.sleep(1) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[rot], True) time.sleep(0.6) for i in range(10): GPIO.output(Ampel[blau], True); time.sleep(0.05) GPIO.output(Ampel[blau], False); time.sleep(0.05) time.sleep(0.6) GPIO.output(Ampel[rot], False) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[gruen], True) time.sleep(3) fussg = False else: time.sleep(3) GPIO.output(Ampel[gruen], False) GPIO.output(Ampel[gelb], True) time.sleep(1) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[rot], True) time.sleep(2) GPIO.output(Ampel[gelb], True) time.sleep(0.6) GPIO.output(Ampel[rot], False) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[gruen], True) except KeyboardInterrupt: GPIO.cleanup() _thread.start_new_thread(taste, ())
I don't get an error message, but the program do not work. It has no effect if I press the button or not, the blue (pedestrian) light do not flash.
Can someone help me? Thanks a lot!

EDIT: Sry, I actually get an error message:
Exception in thread Thread-1: Traceback (most recent call last): File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner self.run() File "/usr/lib/python3.5/threading.py", line 862, in run self._target(*self._args, **self._kwargs) File "/home/pi/Desktop/ampel02.py", line 34, in schleife if fussg == True: UnboundLocalError: local variable 'fussg' referenced before assignment
Reply
#2
You should consider starting the thread right before your main while loop. Currently your program will iterate through your loop without starting the thread. Also you already set the GPIO mode and declared PIN 25 as input, you do not need to do it in the thread again. Your thread shares all global variables with the rest of your application. So your code shall look like this
import RPi.GPIO as GPIO import time import _thread GPIO.setmode(GPIO.BCM) rot = 0; gelb = 1; gruen = 2; blau = 3; taster = 4 Ampel=[4,18,23,24,25] GPIO.setup(Ampel[rot], GPIO.OUT, initial = False) GPIO.setup(Ampel[gelb], GPIO.OUT, initial = False) GPIO.setup(Ampel[gruen], GPIO.OUT, initial = True) GPIO.setup(Ampel[blau], GPIO.OUT, initial = False) GPIO.setup(25, GPIO.IN) print("Taster drücken für Fussgängerblinklicht, Ctrl+C beendet das Programm") fussg = False def taste(): while True: if GPIO.input(25) == 1: fussg = True _thread.start_new_thread(taste, ()) try: while True: if fussg == True: GPIO.output(Ampel[gruen], False) GPIO.output(Ampel[gelb], True) time.sleep(1) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[rot], True) time.sleep(0.6) for i in range(10): GPIO.output(Ampel[blau], True); time.sleep(0.05) GPIO.output(Ampel[blau], False); time.sleep(0.05) time.sleep(0.6) GPIO.output(Ampel[rot], False) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[gruen], True) time.sleep(3) fussg = False else: time.sleep(3) GPIO.output(Ampel[gruen], False) GPIO.output(Ampel[gelb], True) time.sleep(1) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[rot], True) time.sleep(2) GPIO.output(Ampel[gelb], True) time.sleep(0.6) GPIO.output(Ampel[rot], False) GPIO.output(Ampel[gelb], False) GPIO.output(Ampel[gruen], True) except KeyboardInterrupt: GPIO.cleanup()
Furthermore, I am not sure how the setup function is defined, so if you get True when the button is pressed or if you get False if you press the button. If you have tried this configuration before it is fine, if not try to use
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
instead of
GPIO.setup(25, GPIO.IN)
I have not tested the program, but I hope it works now Smile
Reply
#3
Thank you very much! unfortunately it is still not working ^^ I now get a error message like this once i stop the script:

Unhandled exception in thread started by <function taste at 0x767ad5d0> Traceback (most recent call last): File "/home/pi/Desktop/ampel02.py", line 22, in taste if GPIO.input(25) == 1: RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)
It think that's why I declared the GPIO Input twice. I feel like the thread don't change 'fussg' from False to True, so the if condition is never true and the light never flashes.
Reply
#4
Ok, then it really was needed in the thread :D just use the taste function as you defined it previously :) hope it works :)
Reply
#5
I tested it on my Pi and it works now. The first problem was, that the thread was started after the infite while loop, as I mentioned already. The second problem is, that eventhough threads share the same memory, variables are not shared that way. The variables have to be given as an parameter to the function (for lists it works just fine) or (in this case) they have to be declared as global. The thread creates every time the button is pressed a new variable named fussg, but that does not influence the globally declared variable fussg. The trick is to declare the variable as global so that the thread knows where to look for it. The working code is here, I modified it a bit though, first of all buttons are kind of tricky and this was the configuration in which the button recognized that it was pressed.
import RPi.GPIO as GPIO import time import _thread GPIO.setmode(GPIO.BCM) # wie oft blau geblinkt werden soll NUMBER_OF_FLASHES = 10 rot, gelb, gruen, blau, taster = 0,1,2,3,4 col_dic = {0:"rot", 1:"gelb", 2:"grün", 3:"blau", 4:"taste"} Ampel=[4, 18, 23, 24, 25] for i, pin in enumerate(Ampel):	init = False	if i == gruen:	init = True	if i == taster:	print("Initialisierung Taste")	GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)	else:	print("Initialisierung Licht %s"%col_dic[i])	GPIO.setup(pin, GPIO.OUT, initial=init) print("Taster drücken für Fussgängerblinklicht") fussg = False def taste():	global fussg	while True:	if not GPIO.input(Ampel[taster]):	fussg = True _thread.start_new_thread(taste, ()) try:	while True:	GPIO.output(Ampel[gruen], False)	GPIO.output(Ampel[gelb], True)	time.sleep(1)	GPIO.output(Ampel[gelb], False)	GPIO.output(Ampel[rot], True)	if fussg:	time.sleep(0.6)	for i in range(NUMBER_OF_FLASHES):	GPIO.output(Ampel[blau], True)	time.sleep(0.05)	GPIO.output(Ampel[blau], False)	time.sleep(0.05)	fussg = False	else:	time.sleep(2)	GPIO.output(Ampel[gelb], True)	time.sleep(0.6)	GPIO.output(Ampel[gelb], False)	GPIO.output(Ampel[rot], False)	GPIO.output(Ampel[gruen], True)	time.sleep(3) except KeyboardInterrupt:	GPIO.cleanup()
I don't know why you got the exception saying that the mode has to be set, but for me this worked just perfectly.
Have fun
cheers python
Reply
#6
I‘m currently not at home bu I‘ll try it tomorrow morning. Thank you very much!!, I nearly lost my motivation xd
Reply
#7
Well it works a lot better than before, but it's not exactly what I wanted ^^. Now the blue light flashes everytime the traffic light is red. But it should only flash if I press the button before. Furthermore the light switches from red directly to green and not first yellow anymore. Do you know what I mean?

Probably the error is in line 31 where you wrote:
if not GPIO.input(Ampel[taster]):
I think there is still a problem in the code of the button, because it changes fussg everytime to True, so the light flashes everytime.
Reply
#8
IIITT WOOORKEEED! :DD I finally realised a big problem was the button itself. Sometimes the GPIO input was detected as true altough I didn't even press the button. Furthermore I changed the if condition in the taste function to GPIO.event_detected.

Thank you so much for your help!
Reply
#9
I didn't copy you code, I typed it while looking at your code. It could be that I missed switching a light so that it went from red to green :D The button worked for me, but buttons are often a bit tricky, so as I mentioned the code worked on my Pi with this configuration of the button :D
I'm glad I could help you :)
Reply


User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020
This forum uses Lukasz Tkacz MyBB addons.
Forum use Krzysztof "Supryk" Supryczynski addons.