diff --git a/gui/besta.py b/gui/besta.py new file mode 100644 index 0000000..5ac7b2c --- /dev/null +++ b/gui/besta.py @@ -0,0 +1,114 @@ +import tkinter as tk +import tkinter.ttk as ttk +import serial.tools.list_ports + +command = [] + +ports = serial.tools.list_ports.comports() +serialObj = serial.Serial() + +def serial_ports(): + return serial.tools.list_ports.comports() + +def on_select(event=None): + serialObj.port = cb.get().split(' ')[0] + serialObj.baudrate = 9600 + serialObj.open() + +root = tk.Tk() +#configue root +root.title("Jfs Besta") +root.geometry('800x500+300+300') +root.columnconfigure(0,weight=1) +root.rowconfigure(1,weight=1) +port = tk.IntVar() + +cb =ttk.Combobox(root,values=serial_ports()) +cb.grid(row=0,column=0,stick="nwe") +cb.bind('<>',on_select) + +scb =tk.Scrollbar(root) +scb.grid(row=1,column=1,sticky='ns') +txt = tk.Text(root) +txt.grid(row=1,column=0,sticky='ewns') +scb.config(command=txt.yview) +txt.config(yscrollcommand=scb.set) +txt.tag_configure('small',font=('Verdana',8),foreground='black') + +portlbl = ttk.Label(root,textvariable=port,background='grey',font='none 24 bold') +portlbl.config(anchor=tk.CENTER) +portlbl.grid(row=0,column=2,sticky='nsew') + +left = ttk.LabelFrame(root,text='Commands') +left.grid(row=1,column=2,sticky='ne') + +class Callback: + def __init__(self,func,*args,**kwargs): + self.func=func + self.args=args + self.kwargs=kwargs + def __call__(self): + self.func(*self.args,**self.kwargs) + +def default_callback(i): + cmd = [0x2A,0x01,0x01,0x00,0x02] + cmd[2] = i + cmd[4] = i+1 + command.append(cmd) + command.append( [0x2A,0x01,90,0x00,91]) #get position + +for i in range(1,7): + btn = ttk.Button(left,text = f'Goto {i}',command=Callback(default_callback,i)) + btn.grid(row=i-1,column=2) + +ttk.Button(left,text='up',command=Callback(default_callback,70)).grid(row=8,column=2) +ttk.Button(left,text='down',command=Callback(default_callback,71)).grid(row=9,column=2) +ttk.Button(left,text='Position',command=Callback(default_callback,90)).grid(row=10,column=2) +ttk.Button(left,text='Aus',command=Callback(default_callback,76)).grid(row=11,column=2) + +def checkcommand(x): + i = x[2] + if i<=6: + return f'Goto Port {i} ->' + if i==70: + return 'up ->' + if i==71: + return 'down ->' + if i==90: + return 'Position :' + if i==76: + return 'Ausschalten ' + +def checkdone(x): + i = x[2] + if i == 255: + return "." + if i == 250: + return "Falscher Befehl\n" + if i == 245: + return "Gerät in Störung\n" + if i <= 6: + port.set(i) + return f' {i} \n' + +weiter = True +def checkSerialPort(): + global weiter + if serialObj.isOpen() and serialObj.in_waiting: + inp = serialObj.read(size=4) + txt.insert(tk.END,checkdone(inp)) + weiter = True + if (len(command) > 0) & (weiter==True) : + if serialObj.isOpen() : + x = command.pop(0) + txt.insert(tk.END,checkcommand(x),'small') + serialObj.write(bytes(x)) + weiter=False + else : + txt.insert('0.1','Kein Port geöffnet !!!\n') + x = command.clear() + +while True: + root.update() + checkSerialPort() + \ No newline at end of file diff --git a/gui/labrobot.py b/gui/labrobot.py index 1b5c8e4..efcc74e 100644 --- a/gui/labrobot.py +++ b/gui/labrobot.py @@ -31,10 +31,10 @@ class LabPip(LabPis): def __init__(self, x=LabPis.default_x, y=LabPis.default_y, z=LabPis.default_z, id=LabPis.default_id, e=LabPis.default_e, vol=default_vol,hub=default_hub,fe=default_fe,top=default_top): super().__init__(x=x, y=y, z=z, id=id, e=e) - self.vol = vol - self.fe = fe - self.hub = hub - self.top = top + self.vol = float(vol) + self.fe = float(fe) + self.hub = float(hub) + self.top = float(top) self.aktvol = 0 #def __str__(self) -> str: @@ -118,14 +118,14 @@ class LabPipBlock(): """ def __init__(self,xoffset,yoffset,z,rows,cols,deltax,deltay): - self.xoffset = xoffset - self.yoffset = yoffset - self.rows = rows - self.columns = cols + self.xoffset = float(xoffset) + self.yoffset = float(yoffset) + self.rows = int(rows) + self.columns = int(cols) self.anz = self.rows * self.columns - self.deltax = deltax - self.deltay = deltay - self.z = z + self.deltax = float(deltax) + self.deltay = float(deltay) + self.z = float(z) self.akt = 0 @@ -152,12 +152,12 @@ class LabPipBlock(): return x,y,self.z def say_ok(self): - print('ok') + print(self.anz) class LabReactBlock(LabPipBlock): def __init__(self, xoffset, yoffset, z, rows, cols, deltax, deltay): - super().__init__(xoffset, yoffset, z, rows, cols, deltax, deltay) + super().__init__(float(xoffset), float(yoffset),float(z), int(rows), int(cols), float(deltax), float(deltay)) class ChemLoc(): diff --git a/gui/main.ini b/gui/main.ini new file mode 100644 index 0000000..60dc8c7 --- /dev/null +++ b/gui/main.ini @@ -0,0 +1,2 @@ +[global] +home = diff --git a/gui/pipettes.ini b/gui/pipettes.ini new file mode 100644 index 0000000..1a87d7e --- /dev/null +++ b/gui/pipettes.ini @@ -0,0 +1,13 @@ +[1000] +xoffset = 14.5 +yoffset = 6.0 +rows = 5 +cols = 10 +xspace = 12.0 +yspace = 17.0 +tipvol = 1000 +zlevel = 74.0 +tipup = 22.0 +tipdown = 30.0 +tipspeed = 2000 +tiphub = 16.5 \ No newline at end of file diff --git a/gui/testtk.py b/gui/testtk.py index 2ce2ce8..9558664 100644 --- a/gui/testtk.py +++ b/gui/testtk.py @@ -2,6 +2,26 @@ import tkinter as tk import tkinter.ttk as ttk import os from configparser import ConfigParser +import serial.tools.list_ports +from idlelib.tooltip import * +import labrobot as lrb +# serial ports +ports = serial.tools.list_ports.comports() +serialObj = serial.Serial() + +def serial_ports(): + return serial.tools.list_ports.comports() + +def on_select(event=None): + serialObj.port = cb.get().split(' ')[0] + serialObj.baudrate = 115000 + serialObj.open() + +# commands +command = [] + +## main,' +orders =['Home','HomeX','HomeY'] ## chemicals substances = ['Water','Propanol','Aceton'] @@ -26,7 +46,7 @@ def init_chem(): frame = ttk.LabelFrame(chemframe,text=p) frame.grid(column=c,row=r) c +=1 - if c > 3: + if c > 4: c=0 r +=1 for i in range(len(clabels)): @@ -37,38 +57,352 @@ def init_chem(): entry.grid(row=i,column=1,sticky='w') centrys.append([p,clabels[i],entry]) +## vessels +vessels = ['1ml','HPLC','Kuvette'] +vlabels = ['rxoffset','ryoffset','rrows','rcols','rxspace','ryspace','rzlevel'] +ventrys = [] +vess_config = ConfigParser() +def load_vess_config(): + vess_config.read(os.path.join(os.path.dirname(__file__), "vessels.ini"),) +def conf_vess_write(): + for p in vessels: + vess_config[p] = {} + for x in ventrys: + if x[0] == p: + vess_config[p][x[1]] = x[2].get() + with open(os.path.join(os.path.dirname(__file__), "vessels.ini"),'w') as f: + vess_config.write(f) +def init_vess(): + c =0 + r = 0 + for p in vessels: + frame = ttk.LabelFrame(vessframe,text=p) + frame.grid(column=c,row=r) + c +=1 + if c > 4: + c=0 + r +=1 + for i in range(len(vlabels)): + tk.Label(frame,text=vlabels[i]).grid(row=i,column=0) + var = tk.StringVar() + entry = tk.Entry(frame,width=10,textvariable=var) + var.set(vess_config[p][vlabels[i]]) + entry.grid(row=i,column=1,sticky='w') + ventrys.append([p,vlabels[i],entry]) + +##pipettes + +pipettes = ['1000','200','100'] +plabels = ['xoffset','yoffset','rows','cols','xspace','yspace','tipvol','zlevel','tipup','tipdown','tipspeed','tiphub'] +pentrys = [] +pipet_config = ConfigParser() +def load_pipet_config(): + pipet_config.read(os.path.join(os.path.dirname(__file__), "pipettes.ini"),) +def pipet_vess_write(): + for p in pipettes: + pipet_config[p] = {} + for x in pentrys: + if x[0] == p: + pipet_config[p][x[1]] = x[2].get() + with open(os.path.join(os.path.dirname(__file__), "pipettes.ini"),'w') as f: + pipet_config.write(f) +def init_pipet(): + c =0 + r = 0 + for p in pipettes: + frame = ttk.LabelFrame(pipetframe,text=p) + frame.grid(column=c,row=r) + c +=1 + if c > 4: + c=0 + r +=1 + for i in range(len(plabels)): + tk.Label(frame,text=plabels[i]).grid(row=i,column=0) + var = tk.StringVar() + entry = tk.Entry(frame,width=10,textvariable=var) + var.set(pipet_config[p][plabels[i]]) + entry.grid(row=i,column=1,sticky='w') + pentrys.append([p,plabels[i],entry]) root = tk.Tk() - +akttip = tk.IntVar() +lbp = lrb.LabPipBlock +pip = lrb.LabPip ##init load_chem_config() substances = chem_config.sections() +load_vess_config() +vessels = vess_config.sections() +load_pipet_config() +pipettes= pipet_config.sections() +print(pipettes) #configue root root.title("Jfs Labrobot") root.geometry('800x500+300+300') notebook = ttk.Notebook(root) -notebook.grid(sticky='news',padx=5,pady=5) +#notebook.grid(sticky='news',padx=5,pady=5) +notebook.pack(fill='both',expand=1) notebook.enable_traversalrightmainframe = ttk.Frame(notebook) -## mainframe +## mainframe left mainframe = ttk.Frame(notebook) mainframe.columnconfigure(0,weight=1) notebook.add(mainframe,text='main',underline=0) -fra1 = ttk.LabelFrame(mainframe,text=' Test') +leftframe = ttk.LabelFrame(mainframe,text='Serial Connection') +leftframe.columnconfigure(0,weight=1) +leftframe.rowconfigure(1,weight=1) +leftframe.grid(column=0,row=0,sticky='news') +cb =ttk.Combobox(leftframe,values=serial_ports()) +cb.grid(row=0,column=0,stick="nwe") +cb.bind('<>',on_select) +scb =tk.Scrollbar(leftframe) +scb.grid(row=1,column=1,sticky='ns') +#txt = tk.Text(leftframe,height=30,width=50) +txt = tk.Text(leftframe) +txt.grid(row=1,column=0,sticky='ewns') +scb.config(command=txt.yview) +txt.config(yscrollcommand=scb.set) +txt.tag_configure('small',font=('Verdana',8),foreground='black') +#mainframe right +rightframe = ttk.Frame(mainframe) +rightframe.columnconfigure(0,weight=1) +rightframe.rowconfigure(0,weight=1) +rightframe.grid(column=1,row=0,sticky='new') + +uprightframe =ttk.LabelFrame(rightframe,text='Basic') +uprightframe.grid(column=0,row=0,sticky='ns') + +downrightframe =ttk.LabelFrame(rightframe,text='More to select') +downrightframe.grid(column=0,row=1,sticky='new',pady=5) + +b1 = ttk.Button(uprightframe,text='Home All',width=12) +b1.grid(row=0,column=0,sticky='nw') +b1t = Hovertip(b1,'All Axis to Home\nZ-axis first') +b2 = ttk.Button(uprightframe,text='Home X',width=12) +b2.grid(row=0,column=1,sticky='ne') +b3 = ttk.Button(uprightframe,text='Home Y',width=12) +b3.grid(row=1,column=0,sticky='nw') +b4 = ttk.Button(uprightframe,text='Home Z',width=12) +b4.grid(row=1,column=1,sticky='ne') +b6 = ttk.Button(uprightframe,text='Home P',width=12) +b6.grid(row=2,column=0,sticky='nw') +b7 = ttk.Button(uprightframe,text='Get Position',width=12) +b7.grid(row=2,column=1,sticky='ne') +l1 = ttk.Label(uprightframe,text="Enter G-Code").grid(row=3,column=0) +e1 = ttk.Entry(uprightframe) +e1.grid(row=3,column=1) +b5 = ttk.Button(uprightframe,text='Send Code') +b5.grid(row=4,column=1,sticky="ne") +b5t = Hovertip(b5,'Send Gcode\ndon\'t forget < >') + +b8 = ttk.Button(downrightframe,text='Next Tip') +b8.grid(row=0,column=0,sticky='ne') +b9 = ttk.Button(downrightframe,text='Up') +b9.grid(row=0,column=1,sticky='ne') +b10 = ttk.Button(downrightframe,text='Down') +b10.grid(row=0,column=2,sticky='ne') +b11 = ttk.Button(downrightframe,text='Top') +b11.grid(row=1,column=0,sticky='ne') +b13 = ttk.Button(downrightframe,text='Load') +b13.grid(row=1,column=1,sticky='ne') +b12 = ttk.Button(downrightframe,text='Dispense') +b12.grid(row=1,column=2,sticky='ne') +b14 = ttk.Button(downrightframe,text='Take Chem') +b14.grid(row=2,column=0,sticky='ne') +b15 = ttk.Button(downrightframe,text='Next Vessel') +b15.grid(row=2,column=1,sticky='ne') +b16 = ttk.Button(downrightframe,text='Load Next') +b16.grid(row=2,column=2,sticky='ne') +ttk.Label(downrightframe,text='Start Vessel').grid(row=3,column=0,sticky='e') +e2 =ttk.Entry(downrightframe,width=5) +e2.grid(row=3,column=1,sticky='w') +ttk.Label(downrightframe,text='Last Vessel').grid(row=4,column=0,sticky='e') +e3 =ttk.Entry(downrightframe,width=5) +e3.grid(row=4,column=1,sticky='w') +b17 = ttk.Button(downrightframe,text='Load All') +b17.grid(row=4,column=2,sticky='e') +b18 = ttk.Button(downrightframe,text='Clear Tip') +b18.grid(row=3,column=2,sticky='e') +## Info Panel +downrightframe1 =ttk.LabelFrame(rightframe,text='Info') +downrightframe1.grid(column=0,row=2,sticky='new',pady=5) +i1l = ttk.Label(downrightframe1,text='Tip Nr') +i1l.grid(row=0,column=0) +i2l =ttk.Label(downrightframe1,textvariable=akttip) +i2l.grid(row=0,column=1) + + + +## Test Zugriff +downrightframe2 =ttk.LabelFrame(rightframe,text='Tests') +downrightframe2.grid(column=0,row=3,sticky='new',pady=5) +fra1 = ttk.LabelFrame(downrightframe2,text=' Chemicals') fra1.grid(row=0,column=0,sticky='nw') chemsub = tk.StringVar() chemlab = tk.StringVar() chemit = tk.StringVar() - def doit(*args): chemit.set(str(chem_config[chemsub.get()][chemlab.get()])) - chemopt = ttk.OptionMenu(fra1,chemsub,substances[0],*substances,command=doit) -chemopt.grid(row=0,column=0,sticky='e') +chemopt.grid(row=1,column=0,sticky='e') chemopt1 = ttk.OptionMenu(fra1,chemlab,clabels[0],*clabels,command=doit) -chemopt1.grid(row=0,column=1,sticky='e') +chemopt1.grid(row=1,column=1,sticky='e') chemerg = ttk.Label(fra1,textvariable=chemit) -chemerg.grid(row=0,column=2,sticky='ne') +chemerg.grid(row=1,column=2,sticky='ne') + +fra2 = ttk.LabelFrame(downrightframe2,text=' Pipettes') +fra2.grid(row=1,column=0,sticky='nw') +pips = tk.StringVar() +def do_pipettes(*args): + global lpb + lpb = lrb.LabPipBlock(pipet_config[pips.get()]['xoffset'], + pipet_config[pips.get()]['yoffset'], + pipet_config[pips.get()]['zlevel'], + pipet_config[pips.get()]['rows'], + pipet_config[pips.get()]['cols'], + pipet_config[pips.get()]['xspace'], + pipet_config[pips.get()]['yspace']) + global pip + pip = lrb.LabPip(pipet_config[pips.get()]['tipvol'], + pipet_config[pips.get()]['tipup'], + pipet_config[pips.get()]['tiphub'], + pipet_config[pips.get()]['tipspeed']) + +pipopt = ttk.OptionMenu(fra2,pips,pipettes[0],*pipettes,command=do_pipettes) +pipopt.grid(row=0,column=0,sticky='ew') +fra3 = ttk.LabelFrame(downrightframe2,text=' Vessels') +fra3.grid(row=2,column=0,sticky='nw') + +## main serial command +def homeAll(): + serialObj.write(b'\n') + #print(lpb.say_ok(), pip.getVol()) +b1.configure(command=homeAll) + +def homeX(): + serialObj.write(b'\n') +b2.configure(command=homeX) + +def homeY(): + serialObj.write(b'\n') +b3.configure(command=homeY) + +def homeZ(): + serialObj.write(b'\n') +b4.configure(command=homeZ) + +def homeP(): + serialObj.write(b'\n') +b6.configure(command=homeP) + +def getPos(): + serialObj.write(b'\n') +b7.configure(command=getPos) + +def do_gcode(): + s = e1.get() + s = s + '\n' + print(s) + serialObj.write(s.encode('utf-8')) +b5.configure(command=do_gcode) + +def upTip(): + command.append(pip.up().encode('utf-8')) +b9.configure(command=upTip) + +def downTip(): + command.append(pip.down().encode('utf-8')) +b10.configure(command=downTip) + +def nextTip(): + upTip() + serialObj.write(pip.get_tip(lpb.next()).encode('utf-8')) + akttip.set(lpb.akt) + downTip() +b8.configure(command=nextTip) + +def load(): + if pip.amIdown() == False: + command.append(pip.go_top().encode('utf-8')) + command.append(pip.go_down().encode('utf-8')) + else: + command.append(pip.go_top().encode('utf-8')) + pip.setVolMax() + aktvol.set(pip.getVol()) +b13.config(command=load) + +def dispense(): + v = reaPart.get() + if pip.dispenseVol(v): + command.append(pip.sendE().encode('utf-8')) + else : + takeChem() + upTip() + command.append(pip.get_tip(react.same()).encode('utf-8')) + downTip() + if pip.dispenseVol(v): + command.append(pip.sendE().encode('utf-8')) + else: + print('Error') + aktvol.set(pip.getVol()) + print(pip.getVol()) + +b12.config(command=dispense) + +def top(): + command.append(pip.go_top().encode('utf-8')) +b11.config(command=top) + +def takeChem(): + upTip() + pip.setXY(chem.getXY()) + command.append(pip.sendXY().encode('utf-8')) + pip.setZ(chem.load(pip.vol/1000)) #load 1ml + command.append(pip.down().encode('utf-8')) + load() + command.append(pip.up().encode('utf-8')) + chemVol.set(chem.vol) +b14.config(command=takeChem) + +def nextVessel(): + upTip() + command.append(pip.get_tip(react.next()).encode('utf-8')) + rakt.set(react.akt) + downTip() +b15.config(command=nextVessel) + +def loadNext(): + upTip() + takeChem() + nextVessel() + dispense() + upTip() +b16.config(command=loadNext) + +def loadSerie(): + takeChem() + p = startVessel.get() + q = lastVessel.get() + 1 + for i in range(p,q): + print(i) + react.akt = i + rakt.set(react.akt) + upTip() + command.append(pip.get_tip(react.same()).encode('utf-8')) + downTip() + dispense() + upTip() +b17.config(command=loadSerie) + +def clearTip(): + upTip() + pip.setXY(chem.getXY()) + command.append(pip.sendXY().encode('utf-8')) + pip.clearVol() + command.append(pip.sendE().encode('utf-8')) + +b18.config(command=clearTip) + ##chemicals chemframe = ttk.Frame(notebook) @@ -76,6 +410,32 @@ notebook.add(chemframe,text='chemicals',underline=0) init_chem() tk.Button(chemframe,text='Load',command = load_chem_config).grid(row=100,column=0,sticky='ew') tk.Button(chemframe,text='Save',command = conf_chem_write).grid(row=100,column=1,sticky='ew') +##vessels +vessframe = ttk.Frame(notebook) +notebook.add(vessframe,text='vessel',underline=0) +init_vess() +##pipettes +pipetframe = ttk.Frame(notebook) +notebook.add(pipetframe,text='pipettes',underline=0) +init_pipet() + +## looping and working +weiter = True +def checkSerialPort(): + global weiter + if serialObj.isOpen() and serialObj.in_waiting: + recentPacket = serialObj.readline() + recentPacketString = recentPacket.decode('utf') + txt.insert('0.1',recentPacketString,'small') + weiter = True + if (len(command) > 0) & (weiter==True) : + x = command.pop(0) + txt.insert('0.1',x,'small') + serialObj.write(x) + weiter=False + -root.mainloop() \ No newline at end of file +while True: + root.update() + checkSerialPort() \ No newline at end of file diff --git a/gui/vessels.ini b/gui/vessels.ini new file mode 100644 index 0000000..9e771de --- /dev/null +++ b/gui/vessels.ini @@ -0,0 +1,8 @@ +[1ml] +rxoffset = 225.0 +ryoffset = 150.0 +rrows = 4 +rcols = 6 +rxspace = 20.0 +ryspace = 19.0 +rzlevel = 70.0