Page 1 of 1

Help with single button to multiple GPIO

Posted: Mon Apr 13, 2015 9:28 pm
by Davies
Hi all im new to programming and have read many tutorials to get thus far but im having some issues in how to get my single button to execute multiple of outputs based from other inputs, currently this kind of works but the button gets stuck and the label doesn't appear until all the script has run.

Code: Select all

from Tkinter import *
import RPi.GPIO as GPIO
import time
import Tkinter as tk

GPIO.setmode(GPIO.BCM)

GPIO.setup(27, GPIO.OUT, initial=0)
GPIO.setup(22, GPIO.OUT, initial=0)
GPIO.setup(18, GPIO.OUT, initial=0)
GPIO.setup(23, GPIO.OUT, initial=0)
GPIO.setup(24, GPIO.OUT, initial=0)
GPIO.setup(21, GPIO.OUT, initial=0)
GPIO.setup(17, GPIO.IN, GPIO.PUD_DOWN)
GPIO.setup(25, GPIO.IN, GPIO.PUD_DOWN)


root = tk.Tk()
root.title("Tester")


def toggle_text():
    if button["text"] == "Begin Test":
        button["text"] = "Stop Test"
        label["text"] = "Test Began"
        label.config(bg='green', fg='black')
        time.sleep(0.5)
        GPIO.output(21, 1)
        time.sleep(0.5)
    else:
        button["text"] = "Begin Test"
        label["text"] = "Test Ended"
        label.config(bg='dark red', fg='white')
        GPIO.output(21, 0)
        GPIO.output(27, 0)
        GPIO.output(22, 0)
        GPIO.output(18, 0)
        GPIO.output(23, 0)
        GPIO.output(24, 0)
        time.sleep(0.5)
    if GPIO.input(25) == TRUE:
        print GPIO.input(25)
        label["text"] = "Relay 1"
        label.config(bg='blue', fg='yellow')
        time.sleep(2)
        GPIO.output(27, 1)
        time.sleep(2)
    else:
        print "Relay 1 failed"
        time.sleep(0.5)
    if GPIO.input(25) == TRUE:
        print GPIO.input(25)
        label["text"] = "Relay 2"
        label.config(bg='black', fg='white')
        time.sleep(2)
        GPIO.output(22, 1)
        time.sleep(2)
    else:
        print ["Relay 2 failed"]
        time.sleep(0.5)
    if GPIO.input(25) == TRUE:
        print GPIO.input(25)
        label["text"] = "Relay 3"
        label.config(bg='pink', fg='green')
        time.sleep(2)
        GPIO.output(18, 1)
        time.sleep(2)
    else:
        print ["Relay 3 failed"]
        time.sleep(0.5)
    if GPIO.input(25) == TRUE:
        print GPIO.input(25)
        label["text"] = "Relay 4"
        label.config(bg='yellow', fg='black')
        time.sleep(2)
        GPIO.output(23, 1)
        time.sleep(2)
    else:
        print ["Relay 4 failed"]
        time.sleep(0.5)
    if GPIO.input(25) == TRUE:
        print GPIO.input(25)
        label["text"] = "Relay 5"
        label.config(bg='orange', fg='black')
        time.sleep(2)
        GPIO.output(24, 1)
        time.sleep(2)
    else:
        print ["Relay 5 failed"]
        time.sleep(0.5)
    if GPIO.input(17) == TRUE:
        print GPIO.input(17)
        label["text"] = "Cancelled"
        label.config(bg='red', fg='white')
        time.sleep(2)
        GPIO.output(21, 0)
        time.sleep(2)
        GPIO.output(27, 0)
        time.sleep(2)
        GPIO.output(22, 0)
        time.sleep(2)
        GPIO.output(18, 0)
        time.sleep(2)
        GPIO.output(23, 0)
        time.sleep(2)
        GPIO.output(24, 0)
        time.sleep(2)
    else:
        print ["input 2 failed try press a button"]
        time.sleep(0.5)


button = tk.Button(text="Begin Test", width=12, command=toggle_text)
button.pack(padx=100, pady=10)
button2 = tk.Button(text="Quit", command=exit)
button2.pack(padx=50, pady=10)
label = tk.Label(text=" ", width=24, font='bold')
label.pack(padx=200, pady=10)

root.mainloop()

GPIO.cleanup()

Re: Help with single button to multiple GPIO

Posted: Mon Apr 13, 2015 9:51 pm
by Can-Toi
@Davis: Without proper indentation, your Python code is hard to read. Could you edit your post and use the "code" tag to correctly display the indentation in your script? You'll probably have to copy+paste your code again.

Re: Help with single button to multiple GPIO

Posted: Tue Apr 14, 2015 8:35 am
by scotty101
You have a slight problem with the way your are expecting python and Tkinter to behave

When you press the button, toggle_text() will run once and once only. It won't run again until you press the button again.
Since you haven't given a description of what your program should do I am guessing but I suspect you need the button press to start off a state machine to run through a series of steps.

Have a look at this topic where I have given an example of a state machine using python and tkinter to drive a set of traffic lights. It uses the .after method to schedule the next task to happen after a delay period.
Hope that helps

Re: Help with single button to multiple GPIO

Posted: Tue Apr 14, 2015 8:42 am
by scotty101
Another thing that will be causing you problems, particularly related to the Label not appearing is that you do not specify that the root application is the master for each of the widgets. Change your code to look like the following snippet of your original code.

Code: Select all

from Tkinter import *
import RPi.GPIO as GPIO
import time
## NO!!!! Convention is to just have the from Tkinter import 
## import Tkinter as tk
......................
root = Tk()
root.title("Tester")
.....................................
button = Button(root,text="Begin Test", width=12, command=toggle_text)
button.pack(padx=100, pady=10)
button2 = Button(root,text="Quit", command=exit)
button2.pack(padx=50, pady=10)
label = Label(root,text=" ", width=24, font='bold')
label.pack(root,padx=200, pady=10)

root.mainloop()
................

Re: Help with single button to multiple GPIO

Posted: Tue Apr 14, 2015 9:53 pm
by Davies
Thank you for your help, what im trying to do in the bigger picture is to build some software that will control a robot. the robot will move forward and back at specific intervals, and certain switches will stop the robot moving either forward or back or both completely until its reset, but the raspberry is operating the switch and checking the motor has stopped driving forward via a relay connected to the motor wires.
im also wanting a widget to run with the current process on a computer screen connected to the Pi
so my python code will end up basically saying
if button in the window is pressed, output1 drive forwards #clicked button robot drives forward
if input1 is high, label says driving forward #input1 connected to forward motor wiring
if input1 driving forward, wait 2 sec output3 stop forward drive
if input1 is low, label says stopped driving forward
if input1 forward drive has stopped, output2 to drive backwards
if input2 is high, label says driving back #input 2 connected to reverse motor wiring
it input2 driving backwards, output4 to stop backwards
if input2 is low, label says backwards drive has stopped
if input2 is low, output1 drive forwards
# then it will go on to disconnect another switch and ensure both forwards and backwards movement has stopped
# then bring a pop up saying completed and finish leaving the widget open

I have an idea of how to write the majority of that but at the moment im just trying to get my code to work a bunch of LEDs so I can get the layout and gui working before writing hundreds of lines of code

currently the gui crashes until all the code has ran and then the button changes text and becomes clickable, and the label appears

Re: Help with single button to multiple GPIO

Posted: Wed Apr 15, 2015 8:21 am
by scotty101
Well, I can't help you write all of it but I have made a suggestion about how to fix the crashing issue.

Re: Help with single button to multiple GPIO

Posted: Wed Apr 15, 2015 9:06 am
by Davies
Thanks scotty101 I've implemented the code changes you advised but it still behaves exactly the same

Re: Help with single button to multiple GPIO

Posted: Wed Apr 15, 2015 10:06 am
by scotty101
I've had to comment out a lot of it since I don't have a Pi handy, but this code works (I've also fixed the quit button so that it calls the correct function to destroy the Tkinter window and kill the mainloop)

Code: Select all

from Tkinter import *
##import RPi.GPIO as GPIO
import time

##GPIO.setmode(GPIO.BCM)
##
##GPIO.setup(27, GPIO.OUT, initial=0)
##GPIO.setup(22, GPIO.OUT, initial=0)
##GPIO.setup(18, GPIO.OUT, initial=0)
##GPIO.setup(23, GPIO.OUT, initial=0)
##GPIO.setup(24, GPIO.OUT, initial=0)
##GPIO.setup(21, GPIO.OUT, initial=0)
##GPIO.setup(17, GPIO.IN, GPIO.PUD_DOWN)
##GPIO.setup(25, GPIO.IN, GPIO.PUD_DOWN)


root = Tk()
root.title("Tester")

def btnQuitPressed():
    root.destroy()

def btnStartPressed():
    if button["text"] == "Begin Test":
        button["text"] = "Stop Test"
        label["text"] = "Test Began"
        label.config(bg='green', fg='black')
##        time.sleep(0.5)
##        GPIO.output(21, 1)
##        time.sleep(0.5)
##    else:
##        button["text"] = "Begin Test"
##        label["text"] = "Test Ended"
##        label.config(bg='dark red', fg='white')
##        GPIO.output(21, 0)
##        GPIO.output(27, 0)
##        GPIO.output(22, 0)
##        GPIO.output(18, 0)
##        GPIO.output(23, 0)
##        GPIO.output(24, 0)
##        time.sleep(0.5)
##    if GPIO.input(25) == TRUE:
##        print GPIO.input(25)
##        label["text"] = "Relay 1"
##        label.config(bg='blue', fg='yellow')
##        time.sleep(2)
##        GPIO.output(27, 1)
##        time.sleep(2)
##    else:
##        print "Relay 1 failed"
##        time.sleep(0.5)
##    if GPIO.input(25) == TRUE:
##        print GPIO.input(25)
##        label["text"] = "Relay 2"
##        label.config(bg='black', fg='white')
##        time.sleep(2)
##        GPIO.output(22, 1)
##        time.sleep(2)
##    else:
##        print ["Relay 2 failed"]
##        time.sleep(0.5)
##    if GPIO.input(25) == TRUE:
##        print GPIO.input(25)
##        label["text"] = "Relay 3"
##        label.config(bg='pink', fg='green')
##        time.sleep(2)
##        GPIO.output(18, 1)
##        time.sleep(2)
##    else:
##        print ["Relay 3 failed"]
##        time.sleep(0.5)
##    if GPIO.input(25) == TRUE:
##        print GPIO.input(25)
##        label["text"] = "Relay 4"
##        label.config(bg='yellow', fg='black')
##        time.sleep(2)
##        GPIO.output(23, 1)
##        time.sleep(2)
##    else:
##        print ["Relay 4 failed"]
##        time.sleep(0.5)
##    if GPIO.input(25) == TRUE:
##        print GPIO.input(25)
##        label["text"] = "Relay 5"
##        label.config(bg='orange', fg='black')
##        time.sleep(2)
##        GPIO.output(24, 1)
##        time.sleep(2)
##    else:
##        print ["Relay 5 failed"]
##        time.sleep(0.5)
##    if GPIO.input(17) == TRUE:
##        print GPIO.input(17)
##        label["text"] = "Cancelled"
##        label.config(bg='red', fg='white')
##        time.sleep(2)
##        GPIO.output(21, 0)
##        time.sleep(2)
##        GPIO.output(27, 0)
##        time.sleep(2)
##        GPIO.output(22, 0)
##        time.sleep(2)
##        GPIO.output(18, 0)
##        time.sleep(2)
##        GPIO.output(23, 0)
##        time.sleep(2)
##        GPIO.output(24, 0)
##        time.sleep(2)
##    else:
##        print ["input 2 failed try press a button"]
##        time.sleep(0.5)


button = Button(root,text="Begin Test", width=12, command=btnStartPressed)
button.pack(padx=100, pady=10)
button2 = Button(root,text="Quit", command=btnQuitPressed)
button2.pack(padx=50, pady=10)
label = Label(root,text="Inactive", width=24, font='bold')
label.pack(padx=200, pady=10)

root.mainloop()

##GPIO.cleanup()
As I said before in my previous post which you clearly didn't read, you need to use the Tkinter .after command to schedule events. The reason the GUI "crashes" is that you are using time.sleep which hogs the process giving no time for the GUI to do what it needs to do. Look at the traffic light example I posted above and create a similar state machine with .after commands implementing the delay.