#!/usr/bin/env python3 import sys import getopt import glob import serial import struct import tkinter from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk) # Implement the default Matplotlib key bindings. from matplotlib.backend_bases import key_press_handler from matplotlib.figure import Figure import numpy as np tempe = 0 tSetGlobal = 0.0 controllerDebugWindowOpen = 0 tick = 0 tickArray = [] tActArray = [] tSetArray = [] tickDebug = 0 tickDebugArray = [] tActDebugArray = [] tSetDebugArray = [] errDebugArray = [] errSumDebugArray = [] outOrigDebugArray = [] outDebugArray = [] outAvgDebugArray = [] sleepCounterDebugArray = [] rxInputBuffer = bytearray() rxStatemachine = 0 def serial_ports(): """ Lists serial port names :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = serial.Serial(port) s.close() result.append(port) except (OSError, serial.SerialException): pass return result #print(serial_ports()) availableSerialPorts = serial_ports() print('choose a port:') counter = 0 for port in availableSerialPorts: print(' [' + str(counter) + '] ' + port) counter += 1 choosenPort = input('(type a number (0)) ') if choosenPort == '': choosenPortNumber = 0 else: choosenPortNumber = int(choosenPort) counter = 0 #serialPort = '/dev/pts/19' serialPort = '/dev/ttyACM0' serialPort = availableSerialPorts[choosenPortNumber] try: ser = serial.Serial(serialPort, 19200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, timeout=0, writeTimeout=0) except: serialPort = '/dev/ttyACM1' ser = serial.Serial(serialPort, 19200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, timeout=0, writeTimeout=0) def readSerial(): while True: c = ser.read() # attempt to read a character from Serial #was anything read? if len(c) == 0: break else: #print('DATA') #log.insert(END, ':' + c.hex()) global rxInputBuffer global rxStatemachine rxInputBuffer.append(c[0]) if rxStatemachine == 0: if rxInputBuffer[0] == 0xff: rxStatemachine = 1 rxInputBuffer = rxInputBuffer[1:] elif rxStatemachine == 1: if rxInputBuffer[0] == 0xf1: rxStatemachine = 2 else: rxStatemachine = 0 rxInputBuffer = rxInputBuffer[1:] elif rxStatemachine == 2: if len(rxInputBuffer) >= rxInputBuffer[0] + 1: processData(rxInputBuffer[1:rxInputBuffer[0] + 1]) rxInputBuffer = bytearray() rxStatemachine = 0 else: if len(rxInputBuffer) > 256: print('rxInputBuffer reset!') rxInputBuffer = bytearray() rxStatemachine = 0 root.after(10, readSerial) # check serial again soon def processData(input): global tSetGlobal print([ "0x%02x" % b for b in input ]) # ~ print(str([hex(x) for x in input])) # ~ if input[0] == 0x11: # ~ if input[1] == 100: # ~ temperatureString.set(str(round(((input[2] * 256) + input[3]) * 0.4833149757 + 35.1689715661)) + "degC") # ~ processControllerDebugData(((input[2] * 256) + input[3]) * 0.4833149757 + 35.1689715661, 20, 10, 0, -10, -20) if input[0] == 0x33: print("debugDataEnabled") tickDebugArray.clear() tActDebugArray.clear() tSetDebugArray.clear() errDebugArray.clear() errSumDebugArray.clear() outOrigDebugArray.clear() outDebugArray.clear() outAvgDebugArray.clear() sleepCounterDebugArray.clear() elif input[0] == 0x34: print("debugDataDisabled") elif input[0] == 0x8d: cartridge_temperature_adc_raw = ((input[1] * 256) + input[2]) tAct = struct.unpack('>f', input[3:7])[0] tSet = struct.unpack('>f', input[7:11])[0] err = struct.unpack('>f', input[11:15])[0] errSum = struct.unpack('>f', input[15:19])[0] outOrig = struct.unpack('>f', input[19:23])[0] out = input[23] * 256 + input[24] outAvg = input[25] * 256 + input[26] sleepCounter = input[27] * 256 + input[28] if out > 32767: out -= 65536 tActString.set(str(round(tAct)) + "degC") tSetString.set("(" + str(round(tSet)) + "degC)") tSetGlobal = tSet processTemperatureData(tAct, tSet) processControllerDebugData(tAct, tSet, err, errSum, outOrig, out, outAvg, sleepCounter) elif input[0] == 0x8c: tAct = struct.unpack('>f', input[1:5])[0] tSet = struct.unpack('>f', input[5:9])[0] tActString.set(str(round(tAct)) + "degC") tSetString.set("(" + str(round(tSet)) + "degC)") tSetGlobal = tSet processTemperatureData(tAct, tSetGlobal) # ~ elif input[0] == 0x91: # ~ tSet = struct.unpack('>f', input[1:5])[0] # ~ tSetString.set("(" + str(round(tSet)) + "degC)") # ~ elif input[0] == 0x92: # ~ controllerValueKpString.set("Kp: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x93: # ~ controllerValueKpString.set("Kp: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x94: # ~ controllerValueKiString.set("Ki: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x95: # ~ controllerValueKiString.set("Ki: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x96: # ~ controllerValueKdString.set("Kd: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x97: # ~ controllerValueKdString.set("Kd: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x98: # ~ controllerValueKitString.set("Kit: " + str(struct.unpack('>f', input[1:5])[0])) # ~ elif input[0] == 0x99: # ~ controllerValueKitString.set("Kit: " + str(struct.unpack('>f', input[1:5])[0])) elif input[0] == 0xa0: controllerValueKpString.set("Kp: " + str(struct.unpack('>f', input[1:5])[0])) elif input[0] == 0xa1: controllerValueKiString.set("Ki: " + str(struct.unpack('>f', input[1:5])[0])) elif input[0] == 0xa2: controllerValueKdString.set("Kd: " + str(struct.unpack('>f', input[1:5])[0])) elif input[0] == 0xa3: controllerValueKitString.set("Kit: " + str(struct.unpack('>f', input[1:5])[0])) elif input[0] == 0xf0: tSet = struct.unpack('>f', input[1:5])[0] controllerKp = struct.unpack('>f', input[5:9])[0] controllerKi = struct.unpack('>f', input[9:13])[0] controllerKd = struct.unpack('>f', input[13:17])[0] controllerKit = struct.unpack('>f', input[17:21])[0] tSetString.set("(" + str(round(tSet)) + "degC)") tSetGlobal = tSet controllerValueKpString.set("Kp: " + str(controllerKp)) controllerValueKiString.set("Ki: " + str(controllerKi)) controllerValueKdString.set("Kd: " + str(controllerKd)) controllerValueKitString.set("Kit: " + str(controllerKit)) def sendSerial(payloadType, payload): # ~ print('send ' + str(len(input)) + ' byte(s): ' + str([hex(x) for x in input])) data = bytearray([0xff, 0xf1]) data.append(1 + len(payload)) data.append(payloadType) data.extend(bytearray(payload)) print("send " + str([ "0x%02x" % b for b in data ])) ser.write(data) def createNewWindow(): global controllerDebugWindowOpen newWindow = tkinter.Toplevel(root) newWindow.protocol("WM_DELETE_WINDOW", lambda: closeWindow(newWindow)) # ~ labelExample = tkinter.Label(master=newWindow, text="new window") # ~ labelExample.pack() canvas2 = FigureCanvasTkAgg(controllerDebugFigure, master=newWindow) # A tk.DrawingArea. canvas2.draw() canvas2.get_tk_widget().pack() controllerDebugWindowOpen = 1 def closeWindow(myVar): print("closeWindow " + str(myVar)) controllerDebugWindowOpen = 0 myVar.destroy() def increaseTemperature(): global tempe, temperatureString tempe = tempe + 10 temperatureString.set(str(tempe) + "degC") def processTemperatureData(tAct, tSet): global tick, tickArray, tActArray, tSetArray tickArray.append(tick) tickArray = tickArray[-30:] tick = tick + 1 tActArray.append(tAct) tActArray = tActArray[-30:] tSetArray.append(tSet) tSetArray = tSetArray[-30:] yMin = tSet - 10 yMax = tSet + 10 if min(tActArray) < yMin: yMin = min(tActArray) - 2 if max(tActArray) > yMax: yMax = max(tActArray) + 2 temperatureFigureAxis1.clear() temperatureFigureAxis1.plot(tickArray, tActArray, linewidth=1, color="black") temperatureFigureAxis1.plot(tickArray, tSetArray, linewidth=1, color="green") temperatureFigureAxis1.set_ylim(yMin, yMax) # ~ temperatureFigure.tight_layout() temperatureFigure.canvas.draw() def processControllerDebugData(tAct, tSet, err, errSum, outOrig, out, outAvg, sleepCounter): # ~ print("processControllerDebugData") global tickDebug, tickDebugArray, tActDebugArray, tSetDebugArray, errDebugArray, errSumDebugArray, outOrigDebugArray, outDebugArray, outAvgDebugArray, sleepCounterDebugArray global controllerDebugWindowOpen tickDebugArray.append(tickDebug) tickDebugArray = tickDebugArray[-1000:] tickDebug = tickDebug + 1 tActDebugArray.append(tAct) tActDebugArray = tActDebugArray[-1000:] tSetDebugArray.append(tSet) tSetDebugArray = tSetDebugArray[-1000:] errDebugArray.append(err) errDebugArray = errDebugArray[-1000:] errSumDebugArray.append(errSum) errSumDebugArray = errSumDebugArray[-1000:] outOrigDebugArray.append(outOrig) outOrigDebugArray = outOrigDebugArray[-1000:] outDebugArray.append(out) outDebugArray = outDebugArray[-1000:] outAvgDebugArray.append(outAvg) outAvgDebugArray = outAvgDebugArray[-1000:] sleepCounterDebugArray.append(sleepCounter) sleepCounterDebugArray = sleepCounterDebugArray[-1000:] if controllerDebugWindowOpen == 1: # ~ ax1.clear() # ~ ax1.plot(tickArray, tActArray, linewidth=2, color='black') # ~ fig.canvas.draw() controllerDebugFigureAxis1.clear() controllerDebugFigureAxis1.plot(tickDebugArray, tActDebugArray, linewidth=1, color="black", label="tAct") controllerDebugFigureAxis1.plot(tickDebugArray, tSetDebugArray, linewidth=1, color="green", label="tSet") controllerDebugFigureAxis1.plot(tickDebugArray, errDebugArray, linewidth=1, color="red", label="err") controllerDebugFigureAxis1.plot(tickDebugArray, errSumDebugArray, linewidth=1, color="orange", label="errSum") controllerDebugFigureAxis1.plot(tickDebugArray, outOrigDebugArray, linewidth=1, color="royalblue", label="outOrig") controllerDebugFigureAxis1.plot(tickDebugArray, outDebugArray, linewidth=1, color="blueviolet", label="out") controllerDebugFigureAxis1.plot(tickDebugArray, outAvgDebugArray, linewidth=1, color="blue", label="outAvg") controllerDebugFigureAxis1.plot(tickDebugArray, sleepCounterDebugArray, linewidth=1, color="grey", label="sleepCounter") controllerDebugFigureAxis1.legend(loc="lower left") controllerDebugFigureAxis1.set_ylim(-100, 1000) # ~ controllerDebugFigure.tight_layout() controllerDebugFigure.canvas.draw() root = tkinter.Tk() root.wm_title("Embedding in Tk") root.geometry("320x850") # ~ root.protocol("WM_DELETE_WINDOW", lambda: closeWindow(root)) # ~ fig = Figure(figsize=(5, 4), dpi=100) # ~ fig2 = Figure(figsize=(5, 4), dpi=100) # ~ t = np.arange(0, 3, .01) # ~ fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t)) # ~ fig2.add_subplot(111).plot(t, 2 * np.cos(2 * np.pi * t)) temperatureFigure = Figure(figsize=(3, 2)) temperatureFigureAxis1 = temperatureFigure.add_subplot(1, 1, 1) temperatureFigureAxis1.yaxis.set_label_position("right") temperatureFigureAxis1.yaxis.tick_right() temperatureFigure.tight_layout() controllerDebugFigure = Figure(figsize=(15, 9)) controllerDebugFigureAxis1 = controllerDebugFigure.add_subplot(1, 1, 1) controllerDebugFigureAxis1.yaxis.set_label_position("right") controllerDebugFigureAxis1.yaxis.tick_right() controllerDebugFigureAxis1.set_ylim(-200, 500) controllerDebugFigure.tight_layout() # ~ canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea. # ~ canvas.draw() # pack_toolbar=False will make it easier to use a layout manager later on. # ~ toolbar = NavigationToolbar2Tk(canvas, root, pack_toolbar=False) # ~ toolbar.update() # ~ canvas.mpl_connect("key_press_event", lambda event: print(f"you pressed {event.key}")) # ~ canvas.mpl_connect("key_press_event", key_press_handler) # ~ btn = tk.Button(root, text="Press", command=lambda: myFunction("See this worked!")) # ~ button = tkinter.Button(master=root, text="Quit", command=root.quit) buttonNewWindow = tkinter.Button(master=root, text="open controller debug window", command=createNewWindow) # Packing order is important. Widgets are processed sequentially and if there # is no space left, because the window is too small, they are not displayed. # The canvas is rather flexible in its size, so we pack it last which makes # sure the UI controls are displayed as long as possible. # ~ button.pack(side=tkinter.BOTTOM) buttonNewWindow.pack(side=tkinter.BOTTOM) # ~ toolbar.pack(side=tkinter.BOTTOM, fill=tkinter.X) # ~ canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1) tkinter.Button(master=root, text="set 330degC", command=lambda: sendSerial(0x91, [0x01, 0x4a])).pack() tkinter.Button(master=root, text="set 200degC", command=lambda: sendSerial(0x91, [0x00, 0xc8])).pack() tkinter.Button(master=root, text="set 0degC", command=lambda: sendSerial(0x91, [0x00, 0x00])).pack() tActString = tkinter.StringVar() tActString.set("0degC") tSetString = tkinter.StringVar() tSetString.set("(0degC)") controllerValueKpString = tkinter.StringVar() controllerValueKpString.set("Kp: 0") controllerValueKiString = tkinter.StringVar() controllerValueKiString.set("Ki: 0") controllerValueKdString = tkinter.StringVar() controllerValueKdString.set("Kd: 0") controllerValueKitString = tkinter.StringVar() controllerValueKitString.set("Kit: 0") tkinter.Label(master=root, textvariable=tActString, font=("Free Mono", 40)).pack() tkinter.Label(master=root, textvariable=tSetString, font=("Free Mono", 20)).pack() canvas = FigureCanvasTkAgg(temperatureFigure, master=root) # A tk.DrawingArea. canvas.draw() canvas.get_tk_widget().pack() # ~ tkinter.Button(master=root, text="Kp +1", command=lambda: sendSerial(0x92, [])).pack() tkinter.Label(master=root, textvariable=controllerValueKpString, font=("Free Mono", 20)).pack() textValueKp = tkinter.Text(master=root, height=1, width=20) textValueKp.pack() tkinter.Button(master=root, text="set Kp", command=lambda: sendSerial(0xa0, convertStringToFloatBytearray(textValueKp.get("1.0", "end-1c")))).pack() # ~ tkinter.Button(master=root, text="Kp -1", command=lambda: sendSerial(0x93, [])).pack() # ~ tkinter.Button(master=root, text="Ki +1", command=lambda: sendSerial(0x94, [])).pack() tkinter.Label(master=root, textvariable=controllerValueKiString, font=("Free Mono", 20)).pack() textValueKi = tkinter.Text(master=root, height=1, width=20) textValueKi.pack() tkinter.Button(master=root, text="set Ki", command=lambda: sendSerial(0xa1, convertStringToFloatBytearray(textValueKi.get("1.0", "end-1c")))).pack() # ~ tkinter.Button(master=root, text="Ki -1", command=lambda: sendSerial(0x95, [])).pack() # ~ tkinter.Button(master=root, text="Kd +1", command=lambda: sendSerial(0x96, [])).pack() tkinter.Label(master=root, textvariable=controllerValueKdString, font=("Free Mono", 20)).pack() textValueKd = tkinter.Text(master=root, height=1, width=20) textValueKd.pack() tkinter.Button(master=root, text="set Kd", command=lambda: sendSerial(0xa2, convertStringToFloatBytearray(textValueKd.get("1.0", "end-1c")))).pack() # ~ tkinter.Button(master=root, text="Kd -1", command=lambda: sendSerial(0x97, [])).pack() # ~ tkinter.Button(master=root, text="Kit +1", command=lambda: sendSerial(0x98, [])).pack() tkinter.Label(master=root, textvariable=controllerValueKitString, font=("Free Mono", 20)).pack() textValueKit = tkinter.Text(master=root, height=1, width=20) textValueKit.pack() tkinter.Button(master=root, text="set Kit", command=lambda: sendSerial(0xa3, convertStringToFloatBytearray(textValueKit.get("1.0", "end-1c")))).pack() # ~ tkinter.Button(master=root, text="Kit -1", command=lambda: sendSerial(0x99, [])).pack() tkinter.Button(master=root, text="enable debug data", command=lambda: sendSerial(0x33, [])).pack() tkinter.Button(master=root, text="disable debug data", command=lambda: sendSerial(0x34, [])).pack() # ~ tkinter.Button(master=root, text="init", command=lambda: sendSerial(0xf0, [])).pack() def convertStringToFloatBytearray(inputString): try: floatValue = float(inputString) byteArrayValue = bytearray(struct.pack('>f', floatValue)) # ~ print(str(floatValue)) # ~ print([ "0x%02x" % b for b in byteArrayValue ]) return byteArrayValue except: print("can not convert [" + inputString + "] to float!") return [] root.after(100, readSerial) sendSerial(0xf0, []) tkinter.mainloop()