Week 12 - Programming Input / Output Devices

This week our goal is to program / modify a program to interface with our input board

I decided after a bit of exploring to learn about Tkinter by modifying the hello.light.45.py program.

I began by changing colors and fonts and then added an arrow that points to the current value on the bar graph.

This got me to thinking, this reminded me of the Sickbay monitors on the original Star Trek. I decided to try to remake the program to resemble those monitors. First, I had to change the x and y coordinates to make the bar graph up and down instead of left and right. Next, I had to reverse the direction, as I wanted the full bar to be on the top of the graph. I used Tkinter to add an appropriate scale, and labels to match the theme. I left the changing numbers at the top, but they can be removed to create a more accurate depection of the TV monitors. The entire project is graphically scaleable, except for the textual elements.

Overall not bad, I not only learned a lot about Tkinter, but also I now understand most of the original program.

Download the program: hello.light.45.trek.py


# hello.light.45.trek.py
#
# receive and display light level
# hello.light.45.trek.py serial_port
# heavily based on hello.light.45.py with the following authorship
## Neil Gershenfeld
## CBA MIT 10/24/09
##
## (c) Massachusetts Institute of Technology 2009
## Permission granted for experimental and personal use;
## license for commercial sale available from MIT
##
# Modified 4/13 by Chris Wiemer to resemble Star Trek TOS Sickbay/Medical Tricorder Monitors

from Tkinter import *
import serial

WINDOW = 600 # window size
eps = 0.5 # filter time constant
filter = 0.0 # filtered value

def idle(parent,canvas):
   global filter, eps # global variables
   #
   # idle routine
   #
   byte2 = 0
   byte3 = 0
   byte4 = 0
   ser.flush()
   while 1:
      #
      # find framing 
      #
      byte1 = byte2
      byte2 = byte3
      byte3 = byte4
      byte4 = ord(ser.read())
      if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)):
         break
   low = ord(ser.read())
   high = ord(ser.read())
   value = 256*high + low
   filter = (1-eps)*filter + eps*value
   x = int(.1*WINDOW + (.9-.1)*WINDOW*filter/1024.0)
   canvas.itemconfigure("text",text="%.1f"%filter)
#
# moves arrow polygon to match input
#
   canvas.coords('marker',.31*WINDOW,x,.42*WINDOW,x+.03*WINDOW,.42*WINDOW,x+.05*WINDOW,.45*WINDOW,x+.05*WINDOW,.45*WINDOW,x+.03*WINDOW,.46*WINDOW,x+.01*WINDOW,.46*WINDOW,x-.01*WINDOW,.45*WINDOW,x-.03*WINDOW,.45*WINDOW,x-.05*WINDOW,.42*WINDOW,x-.05*WINDOW,.42*WINDOW,x-.03*WINDOW)
   canvas.update()
   parent.after_idle(idle,parent,canvas)

#
#  check command line arguments
#
if (len(sys.argv) != 2):
   print "command line: hello.light.45.py serial_port"
   sys.exit()
port = sys.argv[1]
#
# open serial port
#
ser = serial.Serial(port,9600)
ser.setDTR()
#
# set up GUI
#
root = Tk()
#
# sets the text that appears in the title bar
#
root.title('Light Level -- hello.light.45.py (q to exit)')
#
# sets the letter q on the keyboard to trigger exiting the script
#
root.bind('q','exit')
#
# creates the blank window
#
canvas = Canvas(root, width=.5*WINDOW, height=WINDOW, background='black') 
#
# sets the font and size of the type used for the number readings and label
# the next text line can be commented out for a more accurate appearance
#
canvas.create_text(.15*WINDOW,.075*WINDOW,text=".33",font=("Helvetica", 20),tags="text",fill="yellow") 
canvas.create_text(.15*WINDOW,.95*WINDOW,text="LIGHT",font=("Helvetica", 20),tags="label",fill="yellow") 
#
# creates scale
#
canvas.create_rectangle(.15*WINDOW,.1*WINDOW,.16*WINDOW,.26*WINDOW, tags="scale1", fill='red')
canvas.create_line(.12*WINDOW,.1*WINDOW,.19*WINDOW,.1*WINDOW,fill='red')
canvas.create_text(.10*WINDOW,.1*WINDOW,text="0",font=("Helvetica", 10),fill="red")
canvas.create_line(.14*WINDOW,.18*WINDOW,.17*WINDOW,.18*WINDOW,fill='red')
canvas.create_line(.12*WINDOW,.26*WINDOW,.19*WINDOW,.26*WINDOW,fill='red')
canvas.create_text(.10*WINDOW,.26*WINDOW,text="200",font=("Helvetica", 10),fill="red")
canvas.create_line(.14*WINDOW,.33*WINDOW,.17*WINDOW,.33*WINDOW,fill='yellow')
canvas.create_line(.12*WINDOW,.41*WINDOW,.19*WINDOW,.41*WINDOW,fill='yellow')
canvas.create_text(.10*WINDOW,.41*WINDOW,text="400",font=("Helvetica", 10),fill="yellow")
canvas.create_rectangle(.15*WINDOW,.26*WINDOW,.16*WINDOW,.49*WINDOW, tags="scale2", fill='yellow')
canvas.create_line(.14*WINDOW,.49*WINDOW,.17*WINDOW,.49*WINDOW,fill='green')
canvas.create_line(.12*WINDOW,.57*WINDOW,.19*WINDOW,.57*WINDOW,fill='green')
canvas.create_text(.10*WINDOW,.57*WINDOW,text="600",font=("Helvetica", 10),fill="green")
canvas.create_rectangle(.15*WINDOW,.49*WINDOW,.16*WINDOW,.73*WINDOW, tags="scale3", fill='green')
canvas.create_line(.14*WINDOW,.65*WINDOW,.17*WINDOW,.65*WINDOW,fill='green')
canvas.create_line(.12*WINDOW,.73*WINDOW,.19*WINDOW,.73*WINDOW,fill='green')
canvas.create_text(.10*WINDOW,.73*WINDOW,text="800",font=("Helvetica", 10),fill="green")
canvas.create_line(.14*WINDOW,.80*WINDOW,.17*WINDOW,.80*WINDOW,fill='yellow')
canvas.create_rectangle(.15*WINDOW,.73*WINDOW,.16*WINDOW,.80*WINDOW, tags="scale4", fill='yellow')
canvas.create_rectangle(.15*WINDOW,.80*WINDOW,.16*WINDOW,.9*WINDOW, tags="scale5", fill='red')
canvas.create_line(.12*WINDOW,.88*WINDOW,.19*WINDOW,.88*WINDOW,fill='red')
canvas.create_text(.10*WINDOW,.88*WINDOW,text="1000",font=("Helvetica", 10),fill="red")
canvas.create_polygon(.05*WINDOW,.49*WINDOW,.07*WINDOW,.49*WINDOW,.07*WINDOW,.73*WINDOW,.05*WINDOW,.73*WINDOW,.05*WINDOW,.725*WINDOW,.06*WINDOW,.725*WINDOW,.06*WINDOW,.495*WINDOW,.05*WINDOW,.495*WINDOW, tags="scaleside", fill='green')
#
# create the triangle that shows current levels
#
canvas.create_polygon(.31*WINDOW,.3*WINDOW,.42*WINDOW,.33*WINDOW,.42*WINDOW,.35*WINDOW,.45*WINDOW,.35*WINDOW,.45*WINDOW,.35*WINDOW,.46*WINDOW,.36*WINDOW,.46*WINDOW,.29*WINDOW,.45*WINDOW,.27*WINDOW,.45*WINDOW,.25*WINDOW,.42*WINDOW,.25*WINDOW,.42*WINDOW,.27*WINDOW, tags='marker',fill='white')
canvas.pack()
#
# start idle loop
#
root.after(100,idle,root,canvas)
root.mainloop()
back to index