Python GUI – Production Line example

Using Python, Tkinter, canvas ,and photoimage function with some threading

My webhost not allowing some file extension so need to put image as individually (sorry)

The images are for operator sequence , I tried to put them all in a zip but not allowed.

Code (will also need the image files)

# -*- coding: utf-8 -*-
"""
Created on Thu Mar 30 08:29:16 2023

@author: aleja
"""

from tkinter import *
import math
import time
import os    #for path filename join
import threading

Stop_Belt=1
UUT_is_on_belt=0
UUT_Pushed=0
Num_of_pass=0
Num_of_fail=0
Num_of_miss=0
Num_of_total_UUT=0

#GUI setup below
myWindow=Tk()
myWindow.title("myWindow")
myWindow.minsize(660,350)
myWindow.maxsize(660,350) #if you want to move the operator table to see rest of belt comment out


# do this or frame (last frame row number, in window will not follow window (expanding)
myWindow.grid_rowconfigure(1,weight=1)  #Important This was the reason for  on frame being stuck at bottom was row 0 but 3frames
myWindow.grid_columnconfigure(0,weight=1)
myWindow.configure(background='gray')

#frame1 
# adjust r,c,sticky, row and column config as need
frame1=Frame(myWindow,width=200,height=200,bg='lightblue')
frame1.grid(row=0, column=0, sticky='NEWS', padx=10, pady=10, columnspan=2)
frame1.rowconfigure(0,weight=1)
frame1.columnconfigure(0,weight=1) #the lastcol goes along with rigth side expanding


#frame1 
# adjust r,c,sticky, row and column config as need
frame2=Frame(myWindow,width=200,height=200,bg='lightblue')
frame2.grid(row=1, column=0, sticky='NEWS', padx=10, pady=10, columnspan=1)
frame2.rowconfigure(0,weight=1)
frame2.columnconfigure(3,weight=1) #the lastcol goes along with rigth side expanding



#Frame1 objects
#Conveyor belt
canv1=Canvas(frame1,width=190, height=190, bg='blue', bd=0, highlightthickness=0)
canv1.grid(row=0, column=0, columnspan=1,sticky="NEWS")
canv1.columnconfigure(0,weight=1)


#operator table
canv2=Canvas(frame1,width=250, height=250, bg='green', bd=0, highlightthickness=0)
canv2.grid(row=0, column=1, columnspan=2,sticky="NEWS")
canv2.columnconfigure(0,weight=1)

#LED1=canv1.create_oval(LTRX,LTRY,LTRX+dia,LTRY+dia,fill='orange')
location_down=20
Belt=canv1.create_rectangle(50,10+location_down,500,150+location_down,fill='orange')

#Solenoid to push UUT to pass bin
location_down_sp=15
sp_x1=220
sp_y1=10
sp_width=50
sp_height=20
Solenoid_Pass_Push=canv1.create_rectangle(sp_x1,sp_y1+location_down_sp,sp_x1+sp_width,sp_y1+sp_height+location_down_sp,fill='green')

#Solenoid to push UUT to fail bin
location_down_sf=15
sf_x1=110
sf_y1=10
sf_width=50
sf_height=20
Solenoid_Fail_Push=canv1.create_rectangle(sf_x1,sf_y1+location_down_sf,sf_x1+sp_width,sf_y1+sf_height+location_down_sf,fill='red')





#UUT is hiding under table ready for move
UUT_x1=460
UUT_y1=80
UUT_x2=490
UUT_y2=130
UUT_on_belt=canv1.create_rectangle(UUT_x1,UUT_y1,UUT_x2,UUT_y2,fill='lightgreen')
UUT_On_Belt=0

#after UUT so its top layer
#location of pass bin to collect UUT
pbinx1=sp_x1-30
pbiny1=200
pbin_width=50+50
pbin_height=70
Pass_Bin=canv1.create_rectangle(pbinx1,pbiny1,pbinx1+pbin_width,pbiny1+pbin_height,fill='green')
Pass_Bin_Label=canv1.create_text(pbinx1+50,pbiny1+20,fill="white",text="Pass Bin")
Pass_Bin_count=canv1.create_text(pbinx1+50,pbiny1+40,fill="white",text="0")
#canv1.itemconfig(Pass_Bin_count,text="1") #this is how to change text after create

#after UUT so its top layer
#location of pass bin to collect UUT
fbinx1=sf_x1-30
fbiny1=200
fbin_width=50+50
fbin_height=70
Fail_Bin=canv1.create_rectangle(fbinx1,fbiny1,fbinx1+fbin_width,fbiny1+fbin_height,fill='red')
Fail_Bin_Label=canv1.create_text(fbinx1+50,fbiny1+20,fill="darkblue",text="Fail Bin")
Fail_Bin_count=canv1.create_text(fbinx1+50,fbiny1+40,fill="darkblue",text="0")

Missed_Bin_Label=canv1.create_text(fbinx1-40,fbiny1+20,fill="white",text="Missed Bin")
Missed_Bin_count=canv1.create_text(fbinx1-40,fbiny1+40,fill="white",text="0")

#------------starting  image------------------------------

#if you get pyimageN you may need to close the ipython console an try again
folder_for_image='C:/python/Python Move Object/images_ProductionLine/' #where you put your images for this project
imagepath=os.path.join(folder_for_image,"PersonTopViewProductionLine_NorthUUT.png")
print(imagepath)
img_Operator1=PhotoImage(file=(imagepath))

#image of operator
Operator1=canv2.create_image(130,160,image=img_Operator1)
Operator_label=canv2.create_text(fbinx1+50,fbiny1+20,fill="white",text="Operator Count")
Operator_count=canv2.create_text(fbinx1+50,fbiny1+40,fill="white",text="0")

#------------------------------------------------------

def Operator_Put_UUT_On_Belt():
    global Stop_Belt
    global UUT_is_on_belt
    global Num_of_total_UUT
    START_Operator['state']="disabled"
    Start_Belt['state']="disabled"
    
    Put_UUT_On_Belt_File_List=["PersonTopViewProductionLine_NorthUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_10West.png",\
                              "PersonTopViewProductionLine_NorthUUT_20West.png",\
                              "PersonTopViewProductionLine_NorthUUT_30West.png",\
                              "PersonTopViewProductionLine_NorthUUT_40West.png",\
                              "PersonTopViewProductionLine_NorthUUT_50West.png",\
                              "PersonTopViewProductionLine_NorthUUT_60West.png",\
                              "PersonTopViewProductionLine_NorthUUT_70West.png",\
                              "PersonTopViewProductionLine_NorthUUT_90West.png"] #yes i forget a 80 image

    Back_For_Next_UUT_List=["PersonTopViewProductionLine_NorthUUT_90West.png",\
                              "PersonTopViewProductionLine_NorthUUT_90West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_80West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_70West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_60West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_50West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_40West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_30West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_20West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_10West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT_0West_NoUUT.png",\
                              "PersonTopViewProductionLine_NorthUUT.png"] #yes i forget a 80 image                             

   
    for imageFile in Put_UUT_On_Belt_File_List:                          
        img_Operator1.config(file=os.path.join(folder_for_image,imageFile)) #do NOT make another PhotoImage
        myWindow.update()
        time.sleep(.2)
        print("Operator moving to Belt with UUT") #temp slow down

    print("UUT drop to conveyor belt")
    canv1.coords(UUT_on_belt,UUT_x1,UUT_y1,UUT_x2,UUT_y2)
    UUT_is_on_belt=1
    Num_of_total_UUT=Num_of_total_UUT+1
    print("Operator reported total UUT:",Num_of_total_UUT)
    canv2.itemconfig(Operator_count,text=str(Num_of_total_UUT))
        
    for imageFile in Back_For_Next_UUT_List:                          
        img_Operator1.config(file=os.path.join(folder_for_image,imageFile)) #do NOT make another PhotoImage
        myWindow.update()
        time.sleep(.2)
        print("Operator moving back for next UUT") #temp slow down
    #start with button enabled=normal
    
    START_Operator['state']="disabled"
    Start_Belt['state']="normal"
    Stop_Belt=0 #enable belt ok to move
    print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
    return     
    
def Move_UUT_On_Belt():
    global Stop_Belt
    global UUT_Pushed
    global UUT_is_on_belt
    global Num_of_miss
    START_Operator['state']="disabled"
    Start_Belt['state']="disabled"
    for UUT_Location in range(UUT_x1-40):
         if(Stop_Belt==0):
             if(UUT_is_on_belt==0): break
             canv1.coords(UUT_on_belt,UUT_x1-UUT_Location,UUT_y1,UUT_x2-UUT_Location,UUT_y2)
             myWindow.update()
             print("Belt is Moving  ",UUT_Location)
             time.sleep(.01)
             
    if(UUT_is_on_belt==1): 
     canv1.coords(UUT_on_belt,UUT_x1,UUT_y1,UUT_x2,UUT_y2)
    myWindow.update()
    START_Operator['state']="normal"
    Start_Belt['state']="disabled"

    if (UUT_Location==(UUT_x1-40-1) and UUT_is_on_belt==1 and UUT_Pushed==0):
        Num_of_miss=Num_of_miss+1
        print("miss bin total: ",Num_of_miss)
        canv1.itemconfig(Missed_Bin_count,text=str(Num_of_miss))
    UUT_is_on_belt=0
    print("Belt Stop")
    print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
    return

def Move_PassPush():
    UUT_coords=[]
    Start_PassPush['state']="disabled"
    global Stop_Belt
    global UUT_is_on_belt
    global location_down_sp
    global Num_of_pass
    global UUT_Pushed
    Stop_Belt=1  #stop belt on any push attempt
    for PassPushy in range(35):
         canv1.coords(Solenoid_Pass_Push,sp_x1,sp_y1+location_down_sp+PassPushy,sp_x1+sp_width,sp_y1+sp_height+location_down_sp+PassPushy)
         myWindow.update()
         print("Pass Push  ",PassPushy)
         time.sleep(0.001)
    location_down_sp=location_down_sp+40
    
    print("get UUT position")
    print(canv1.coords(UUT_on_belt))
    UUT_coords=canv1.coords(UUT_on_belt)
    # using thread so same time as push UUT_Move_to_bin(UUT_coords)
    if  (sp_x1<=UUT_coords[2] and UUT_coords[0]<=sp_x1+sp_width and UUT_is_on_belt==1):  #check uut in pass push width
       threading.Thread(target=UUT_Move_to_bin,args=(UUT_coords,)).start()#create and start same line 
       Stop_Belt=1
       UUT_Pushed=1
       Num_of_pass=Num_of_pass+1
       print("Number of Pass UUT: ", Num_of_pass)
       canv1.itemconfig(Pass_Bin_count,text=str(Num_of_pass))
       
    else:
       Stop_Belt=0
       
    for PassPushy in range(35):
         canv1.coords(Solenoid_Pass_Push,sp_x1,sp_y1+location_down_sp-PassPushy,sp_x1+sp_width,sp_y1+sp_height+location_down_sp-PassPushy)
         myWindow.update()
         print("Pass Push  ",PassPushy)
         time.sleep(0.001)     
    location_down_sp=location_down_sp-40
    canv1.coords(Solenoid_Pass_Push,sp_x1,sp_y1+location_down_sp,sp_x1+sp_width,sp_y1+sp_height+location_down_sp)
    myWindow.update()
    if(UUT_Pushed==1):
      Stop_Belt=1
    else:
      Stop_Belt=0#continue moving UUT left    
    Start_PassPush['state']="normal"
    UUT_Pushed=0
    print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)
    return

#next put all changes dont on passpush into failPush
def Move_FailPush():    
    UUT_coords=[]
    global Stop_Belt
    global UUT_is_on_belt
    global location_down_sf
    global Num_of_fail
    global UUT_Pushed
    Start_FailPush['state']="disabled"
    Stop_Belt=1
    for FailPushy in range(35):
         canv1.coords(Solenoid_Fail_Push,sf_x1,sf_y1+location_down_sf+FailPushy,sf_x1+sf_width,sf_y1+sf_height+location_down_sf+FailPushy)
         myWindow.update()
         print("Fail Push  ",FailPushy)
         time.sleep(0.001)
    location_down_sf=location_down_sf+40
    #Move UUT down
    print("get UUT position")
    print(canv1.coords(UUT_on_belt))
    UUT_coords=canv1.coords(UUT_on_belt)
    # using thread so same time as push UUT_Move_to_bin(UUT_coords)
    if  (sf_x1<=UUT_coords[2] and UUT_coords[0]<=sf_x1+sf_width and UUT_is_on_belt==1):  #check uut in pass push width
       threading.Thread(target=UUT_Move_to_bin,args=(UUT_coords,)).start()#create and start same line 
       Stop_Belt=1  
       UUT_Pushed=1
       Num_of_fail=Num_of_fail+1
       print("Number of Fail UUT: ", Num_of_fail)
       canv1.itemconfig(Fail_Bin_count,text=str(Num_of_fail))    
       
    else:
       Stop_Belt=0   #continue belt
    #Return Fail Push back
    for FailPushy in range(35):
         canv1.coords(Solenoid_Fail_Push,sf_x1,sf_y1+location_down_sf-FailPushy,sf_x1+sf_width,sf_y1+sf_height+location_down_sf-FailPushy)
         myWindow.update()
         print("Fail Push  ",FailPushy)
         time.sleep(0.001)
    location_down_sf=location_down_sf-40
    canv1.coords(Solenoid_Fail_Push,sf_x1,sf_y1+location_down_sf,sf_x1+sf_width,sf_y1+sf_height+location_down_sf)
    myWindow.update()
    if(UUT_Pushed==1):
      Stop_Belt=1
    else:
      Stop_Belt=0#continue moving UUT left        
    Start_FailPush['state']="normal"
    UUT_Pushed=0
    print("UUT_is_on_belt",UUT_is_on_belt, "UUT pushed",UUT_Pushed)    
    return
    

def UUT_Move_to_bin(UUT_coords):
    global UUT_is_on_belt
    UUT_is_on_belt=0
    for UUT_down_y in range(100):
        canv1.coords(UUT_on_belt,UUT_coords[0],UUT_coords[1]+UUT_down_y,UUT_coords[2],UUT_coords[3]+UUT_down_y)
        time.sleep(0.001)
        myWindow.update()
    UUT_is_on_belt=0
    print("UUT is off Belt")
    return   

Start_Belt=Button(frame2, text='START_Belt',width=15, command=lambda:Move_UUT_On_Belt())
Start_Belt.grid(row=1, column=0,padx=10,pady=10,sticky='')  

Start_FailPush=Button(frame2, text='START_Fail_Push',width=15, command=lambda:Move_FailPush())
Start_FailPush.grid(row=1, column=1,padx=10,pady=10,sticky='')   
 

Start_PassPush=Button(frame2, text='START_Pass_Push',width=15, command=lambda:Move_PassPush())
Start_PassPush.grid(row=1, column=2,padx=10,pady=10,sticky='')   

START_Operator=Button(frame2, text='START_Operator',width=15, command=lambda:Operator_Put_UUT_On_Belt())
START_Operator.grid(row=1, column=3,padx=10,pady=10,sticky='E')  


#start with button enabled=normal
START_Operator['state']="normal"
Start_Belt['state']="disabled"

#last Line
myWindow.mainloop()

download for python code incase select all text not available.

Download for operator images

Unzip the images of the operator to a folder and make sure to update the folder path in the python code.

I used spyder python ide if you forget to make the folder correct you may have to close the ipython console , fix the path and try again. Something in the PhotoImage in tkinter does not clean up correct when there is a python error. So i have to close the console part in the ide fix and rerun.

Notes

  • Presentation: example GUI Production Line with Operator, Conveyor belt and Pass Fail plunger and counts
  • Programming Language used: Python 3.7 in Spyder
  • Presentation app: Microsoft’s PowerPoint,Paint,3D Paint for transparent images
  • Python and Tkinter are product of respective company
  • Presentation shown to spark ideas of use.
  • This presentation is not connected to or endorsed by any company.
  • Use at your own risk.
  • Tags: Python, Python3.7, Tkinter , Canvas ,GUI, Sequence of Image, PhotoImage, Thread, Threading

About LV_TS_Test_Engineer_3000_VI

Automated Test Equipment Software
This entry was posted in Test Sector and tagged , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s