0

So I'm trying to make this GUI for a small project I'm doing on a raspberry pi. Basically, a state machine which changes states based on button presses (imagine it's like a little quiz). For some reason, when I run the module, I get an error that says:

Exception in Tkinter callback
Traceback (most recent call last): 
File:"/usr/lib/python2.7/lib-tk/Tkinter.py", line 1535, in __call__
     return self.func(*args)
File:"/usr/lib/python2.7/lib-tk/Tkinter.py", line 586, in callit
     func(*args)
File "/home/pi/Desktop/SafetyDoorknob.py", line 79, in safety_loop
NameError: global name 'currentState' is not defined

I've been searching around the internet a lot based on this error code, but I haven't found anything that has helped. I'm new to Python and Tkinter (within the last week) and I just wanted to see if anyone here could help. Here is a copy of my code, below. Thank you in advance for any help and please bear with me as I'm still learning this sort of stuff

import Tkinter as tk
from PIL import Image, ImageTk
import requests
import time
import RPi.GPIO as GPIO
import random
import os
import sys

Button_A = 29 # The GPIO pin the button is attached to
Button_B = 31 # The GPIO pin the button is attached to
Button_C = 33 # The GPIO pin the button is attached to
Button_D = 35 # The GPIO pin the button is attached to
Button_Confirm = 37 # The GPIO pin the button is attached to

Relay_Contact = 38

#//////Setting up the pinmodes///////
GPIO.setmode(GPIO.BCM) #Defines what the numbering scheme is for the pins
GPIO.setup(Button_A, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Setting the button as an input and turning on some Pull-up resistors
GPIO.setup(Button_B, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(Button_C, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(Button_D, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(Button_Confirm, GPIO.IN,pull_up_down=GPIO.PUD_UP)

GPIO.setup(Relay_Contact, GPIO.OUT) #Making the Relay contact an output.

global usableQuestions
global currentState
global stateStartTime
global picPath
global correctAnswer
global allAnswers

mainFolderPath = "/home/pi/SafetyDoorknob/AllQuestions" #All Level Folders will be in SafetyDoorknob
answersPath = "/home/pi/SafetyDoorknob/DoorknobAnswers.txt"
picPath = "/home/pi/SafetyDoorknob/HomeScreen.jpg"
answers_file = open(answersPath,'r')
allAnswers = answers_file.readline().split(",") #Load all answers into String Array
usableQuestions = os.listdir(mainFolderPath)


root = tk.Tk()
root.geometry("800x480")
root.configure(background = 'black')
root.wm_attributes('-type','splash')

def buttonPressToAnswer():
    currentAnswer = ""

    if GPIO.input(Button_A) == 0:
        time.sleep(0.02)
        currentAnswer = "A"
    elif GPIO.input(Button_B) == 0:
        time.sleep(0.02)
        currentAnswer = "B"
    elif GPIO.input(Button_C) == 0:
        time.sleep(0.02)
        currentAnswer = "C"
    elif GPIO.input(Button_D) == 0:
        time.sleep(0.02)
        currentAnswer = "D"

    return currentAnswer


def get_State_Time():

    stateTime = time.time() - stateStartTime
    return int(round(stateTime))

def setState(newState):
    currentState = newState
    stateStartTime = time.time()

def safety_loop():

    if currentState == 0: #Startup State
        picPath = "/home/pi/SafetyDoorknob/HomeScreen.jpg"

        if GPIO.input(Button_Confirm) == 0:
            time.sleep(0.02)
            while GPIO.input(Button_Confirm) == 0:
                pass
            setState(1)
            picPath = pick_rand_img()
        root.after(10,safety_loop)

    elif currentState == 1: #Question 1 State
        while get_State_Time() <= 120:
            if buttonPressToAnswer() == correctAnswer:
                break
            else:
                pass
        if get_State_Time() <=120:
            setState(2)
            picPath = pick_rand_img()
        else:
            setState(0)

        root.after(10,safety_loop)

    elif currentState == 2: #Question 2 State
        while get_State_Time() <= 120:
            if buttonPressToAnswer() == correctAnswer:
                break
            else:
                pass
        if get_State_Time() <=120:
            setState(3)
            picPath = pick_rand_img()
        else:
            setState(0)

        root.after(10,safety_loop)

    elif currentState == 3: #Question 3 State
        while get_State_Time() <= 120:
            if buttonPressToAnswer() == correctAnswer:
                break
            else:
                pass
        if get_State_Time() <=120:
            setState(4)
            picPath = pick_rand_img()
        else:
            setState(0)

        root.after(10,safety_loop)

    elif currentState == 4: #Door Open State

        GPIO.output(Relay_Contact,1)
        time.sleep(60)
        GPIO.output(Relay_Contact,0)


def pick_rand_img():

    if len(usableQuestions) == 0:

        usableQuestions = os.listdir(mainFolderPath)


    randomIndex = random.randint(0,len(usableQuestions) - 1)
    randQuestion = usableQuestions[randomIndex] #Picks random question
    correctAnswer = allAnswers[randomIndex]


    newQuestionPath = mainFolderPath + randQuestion
    usableQuestions.pop(randomIndex)
    allAnswers.pop(randomIndex)

    return newQuestionPath

img = ImageTk.PhotoImage(Image.open(picPath))
panel = tk.Label(root,image = img)

panel.pack(side = "bottom",fill = "both",expand = "yes")
setState(0)
root.after(10,safety_loop)
root.mainloop()
1
  • I think that the currentState variable in the function setState is considered as local by python, so you need to add global currentState inside the function.
    – j_4321
    Commented May 16, 2017 at 14:14

1 Answer 1

1

You should make currentState in setState function a global variable.

def setState(newState):
    currentState = newState

created a local variable in setState, which isn't available to other functions. Your setState funnction should be:

def setState(newState):
    ## make currentStage and stateStartTime global
    global currentState, stateStartTime 
    currentState = newState
    stateStartTime = time.time()

You should also use the global keyword -as shown above- in other functions that change global variables (I couldn't test your code fully since I do not have some of the modules)

2
  • So I tried doing that, and it solved the first error. I also changed the code such at other functions that change global variables have the global keyword. However, now my gui just displays a black screen, instead of an image. Not sure where to go from here since I'm not getting any error code pop up Commented May 16, 2017 at 14:27
  • I tested just the gui and image part on windows and it works fine with the exception of root.wm_attributes('-type','splash'), which I had to comment out because it was giving an error (haven't had the chance to test on a Pi yet). You can try the same to see if it works: take out all the code, leaving the gui and image part so you can test it.
    – Khristos
    Commented May 16, 2017 at 15:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.