From fa30822a7d27f50bcc12bd3a73048708771b510a Mon Sep 17 00:00:00 2001 From: jens Date: Mon, 29 Nov 2021 19:22:17 +0000 Subject: [PATCH] Replace labrobot.py --- gui/labrobot.py | 440 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 348 insertions(+), 92 deletions(-) diff --git a/gui/labrobot.py b/gui/labrobot.py index d9e8769..6b4b9dd 100644 --- a/gui/labrobot.py +++ b/gui/labrobot.py @@ -1,108 +1,364 @@ +import tkinter as tk +from tkinter.constants import W, X +import serial.tools.list_ports +import functools +import tkinter.ttk as ttk +from configparser import ConfigParser +import os +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 = 115200 + serialObj.open() + + +root = tk.Tk() +#configue root +root.title("Jfs Labrobot") +root.geometry('800x500+300+300') +root.columnconfigure(0,weight=1) +root.rowconfigure(0,weight=1) +#root.config(bg='#b7f731') + +notebook = ttk.Notebook(root) +notebook.grid(sticky='news',padx=5,pady=5) +notebook.enable_traversalrightmainframe = ttk.Frame(notebook) + +mainframe = ttk.Frame(notebook) +#mainframe.rowconfigure(0,weight=1) +mainframe.columnconfigure(0,weight=1) + +notebook.add(mainframe,text='main',underline=0) + +leftframe = ttk.Frame(mainframe) + +leftframe.columnconfigure(0,weight=1) +leftframe.rowconfigure(1,weight=1) +leftframe.grid(column=0,row=0,sticky='news') + +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) + +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') + +b1 = ttk.Button(uprightframe,text='Home All',width=12) +b1.grid(row=0,column=0,sticky='nw') +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") + +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') -class LabPis: - """ Point in Lab Space | e.g. Point of a pipette tip""" - default_x = 0 - default_y = 0 - default_z = 0 - default_e = 0 # e.g piston position - default_id = 0 +###################### Parts +## init Labrobot - def __init__(self, x=default_x,y=default_y,z=default_z,id=default_id,e=default_e): - self.x = x - self.y = y - self.z = z - self.e = e - self.id = id - def __str__(self) -> str: - return(f'') +xoffset = tk.DoubleVar() +yoffset = tk.DoubleVar() +rows = tk.IntVar() +cols = tk.IntVar() +xspace = tk.DoubleVar() +yspace = tk.DoubleVar() +tipvol = tk.IntVar() +zlevel = tk.DoubleVar() +tipup = tk.DoubleVar() +tiphub = tk.DoubleVar() +tipspeed = tk.IntVar() +akttip = tk.IntVar() -class LabPip(LabPis): - default_vol = 1000 # pipette volume - default_top = 20 # piston top position - default_hub = 10 # piston max hub - default_fe = 2000 # speed piston +chemX = tk.DoubleVar() +chemY = tk.DoubleVar() +chemVol = tk.DoubleVar() +chemZ = tk.DoubleVar() +deltaz = tk.DoubleVar() +tauch = tk.DoubleVar() - 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 +def conf_read(): + config = ConfigParser() + config.read(os.path.join(os.path.dirname(__file__), "config.ini"),) + xoffset.set(float(config.get('tipblock','xoffset',fallback=0))) + yoffset.set(float(config.get('tipblock','yoffset',fallback=0))) + rows.set(int(config.get('tipblock','rows',fallback=0))) + cols.set(int(config.get('tipblock','cols',fallback=0))) + xspace.set(float(config.get('tipblock','xspace',fallback=0))) + yspace.set(float(config.get('tipblock','yspace',fallback=0))) + tipvol.set(int(config.get('tipblock','tipvol',fallback=0))) + zlevel.set(float(config.get('tipblock','zlevel',fallback=0))) + tipup.set(float(config.get('tipblock','tipup',fallback=0))) + tiphub.set(float(config.get('tipblock','tiphub',fallback=0))) + tipspeed.set(int(config.get('tipblock','tipspeed',fallback=0))) + chemX.set(float(config.get('chemblock','chemx',fallback=0))) + chemY.set(float(config.get('chemblock','chemy',fallback=0))) + chemVol.set(float(config.get('chemblock','chemvol',fallback=0))) + chemZ.set(float(config.get('chemblock','chemz',fallback=0))) + deltaz.set(float(config.get('chemblock','deltaz',fallback=0))) + tauch.set(float(config.get('chemblock','tauch',fallback=0))) + +def conf_write(): + config = ConfigParser() + config.read(os.path.join(os.path.dirname(__file__), "config.ini"),) + config.set('tipblock','xoffset',str(xoffset.get())) + config.set('tipblock','yoffset',str(yoffset.get())) + config.set('tipblock','rows',str(rows.get())) + config.set('tipblock','cols',str(cols.get())) + config.set('tipblock','xspace',str(xspace.get())) + config.set('tipblock','yspace',str(yspace.get())) + config.set('tipblock','tipvol',str(tipvol.get())) + config.set('tipblock','zlevel',str(zlevel.get())) + config.set('tipblock','tipup',str(tipup.get())) + config.set('tipblock','tiphub',str(tiphub.get())) + config.set('tipblock','tipspeed',str(tipspeed.get())) + config.set('chemblock','chemx',str(chemX.get())) + config.set('chemblock','chemy',str(chemY.get())) + config.set('chemblock','chemvol',str(chemVol.get())) + config.set('chemblock','chemz',str(chemZ.get())) + config.set('chemblock','deltaz',str(deltaz.get())) + config.set('chemblock','tauch',str(tauch.get())) + with open(os.path.join(os.path.dirname(__file__), "config.ini"),'w') as f: + config.write(f) +conf_read() + +lpb = lrb.LabPipBlock(xoffset.get(),yoffset.get(),zlevel.get(),rows.get(),cols.get(),xspace.get(),yspace.get()) +pip = lrb.LabPip(vol=tipvol.get(),top=tipup.get(),hub=tiphub.get(),fe=tipspeed.get()) +chem = lrb.ChemLoc(chemX.get(),chemY.get(),chemZ.get(),chemVol.get(),deltaz.get(),tauch.get()) + +partframe = ttk.Frame(notebook) +#partframe.rowconfigure(0,weight=1) +partframe.columnconfigure(0,weight=1) +notebook.add(partframe,text='parts',underline=0) + +pipblockframe =ttk.LabelFrame(partframe,text='Tip Block') +pipblockframe.grid(column=0,row=0,sticky='wns',padx=5,pady=5) +pl1 = ttk.Label(pipblockframe,text='X offset').grid(column=0,row=0,padx=5) +pe1 = ttk.Entry(pipblockframe,textvariable=xoffset) +pe1.grid(column=1,row=0,sticky='e') +pl2 = ttk.Label(pipblockframe,text='rows').grid(column=0,row=2,padx=5) +pe2 = ttk.Entry(pipblockframe,textvariable=rows) +pe2.grid(column=1,row=2,sticky='e') +pl3 = ttk.Label(pipblockframe,text='columns').grid(column=0,row=3,padx=5) +pe3 = ttk.Entry(pipblockframe,textvariable=cols) +pe3.grid(column=1,row=3,sticky='e') +pl4 = ttk.Label(pipblockframe,text='x space').grid(column=0,row=4,padx=5) +pe4 = ttk.Entry(pipblockframe,textvariable=xspace) +pe4.grid(column=1,row=4,sticky='e') +pl5 = ttk.Label(pipblockframe,text='y space').grid(column=0,row=5,padx=5) +pe5 = ttk.Entry(pipblockframe,textvariable=yspace) +pe5.grid(column=1,row=5,sticky='e') +pl6 = ttk.Label(pipblockframe,text='Y offset').grid(column=0,row=1,padx=5) +pe6 = ttk.Entry(pipblockframe,textvariable=yoffset) +pe6.grid(column=1,row=1,sticky='e') +pl8 = ttk.Label(pipblockframe,text='Z uptake').grid(column=0,row=6,padx=5) +pe8 = ttk.Entry(pipblockframe,textvariable=zlevel) +pe8.grid(column=1,row=6,sticky='e') +ttk.Separator(pipblockframe, orient=tk.HORIZONTAL).grid(row=7,sticky='ew') +pl7 = ttk.Label(pipblockframe,text='Tip Volume').grid(column=0,row=8,padx=5) +pe7 = ttk.Entry(pipblockframe,textvariable=tipvol) +pe7.grid(column=1,row=8,sticky='e') +pl9 = ttk.Label(pipblockframe,text='Tip Top').grid(column=0,row=9,padx=5) +pe9 = ttk.Entry(pipblockframe,textvariable=tipup) +pe9.grid(column=1,row=9,sticky='e') +pl10 = ttk.Label(pipblockframe,text='Tip Hub').grid(column=0,row=10,padx=5) +pe10 = ttk.Entry(pipblockframe,textvariable=tiphub) +pe10.grid(column=1,row=10,sticky='e') +pl11 = ttk.Label(pipblockframe,text='Tip Speed').grid(column=0,row=11,padx=5) +pe11 = ttk.Entry(pipblockframe,textvariable=tipspeed) +pe11.grid(column=1,row=11,sticky='e') +ttk.Separator(pipblockframe, orient=tk.HORIZONTAL).grid(row=80,sticky='ew') +pl12 = ttk.Label(pipblockframe,text='Akt Tip').grid(column=0,row=81,padx=5) +pe12 = ttk.Entry(pipblockframe,textvariable=akttip) +pe12.grid(column=1,row=81,sticky='e') +ttk.Separator(pipblockframe, orient=tk.HORIZONTAL).grid(row=98,sticky='ew') +pb1 = ttk.Button(pipblockframe,text='Set') +pb1.grid(column=0,row=99,sticky='e') +pb2 = ttk.Button(pipblockframe,text='Save') +pb2.grid(column=1,row=99,sticky='w') + +chemframe =ttk.LabelFrame(partframe,text='Chemicals') +chemframe.grid(column=1,row=0,sticky='wns',padx=5,pady=5) +cl1 = ttk.Label(chemframe,text='X pos').grid(column=0,row=0,padx=5) +ce1 = ttk.Entry(chemframe,textvariable=chemX) +ce1.grid(column=1,row=0,sticky='e') +cl2 = ttk.Label(chemframe,text='Y pos').grid(column=0,row=1,padx=5) +ce2 = ttk.Entry(chemframe,textvariable=chemY) +ce2.grid(column=1,row=1,sticky='e') +cl3 = ttk.Label(chemframe,text='Z Surface').grid(column=0,row=2,padx=5) +ce3 = ttk.Entry(chemframe,textvariable=chemZ) +ce3.grid(column=1,row=2,sticky='e') +cl4 = ttk.Label(chemframe,text='Volume').grid(column=0,row=3,padx=5) +ce4 = ttk.Entry(chemframe,textvariable=chemVol) +ce4.grid(column=1,row=3,sticky='e') +cl5 = ttk.Label(chemframe,text='DeltaZ/ml').grid(column=0,row=4,padx=5) +ce5 = ttk.Entry(chemframe,textvariable=deltaz) +ce5.grid(column=1,row=4,sticky='e') +### commands and bindings + +pb2.config(command=conf_write) + + + +def set_tipblock(): + global lpb + lpb.xoffset = float(xoffset.get()) + lpb.yoffset = float(yoffset.get()) + lpb.rows = int(rows.get()) + lpb.columns = int(cols.get()) + lpb.deltax = float(xspace.get()) + lpb.deltay = float(yspace.get()) + lpb.z = float(zlevel.get()) + lpb.akt = int(akttip.get()) + global pip + pip.vol = int(tipvol.get()) + pip.hub = float(tiphub.get()) + pip.fe = int(tipspeed.get()) + pip.top = float(tipup.get()) + global chem + chem.xloc = float(chemX.get()) + chem.yloc = float(chemY.get()) + chem.vol = float(chemVol.get()) + chem.zloc = float(chemZ.get()) + chem.deltaz = float(deltaz.get()) + chem.tauch = float(tauch.get()) + +pb1.config(command=set_tipblock) - def __str__(self) -> str: - return super().__str__()[:-1]+f'|top={self.top}|hub={self.hub}|vol={self.vol}|fe={self.fe}>' +def homeAll(): + serialObj.write(b'\n') +b1.configure(command=homeAll) - def sendE(self): - return f'\n' +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(): + serialObj.write(pip.up().encode('utf-8')) +b9.configure(command=upTip) + +def downTip(): + serialObj.write(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() - def sendXY(self): - print(f'\n') - return f'\n' +b8.configure(command=nextTip) - def go_top(self): - self.e=self.top - return self.sendE() +def load(): + serialObj.write(pip.go_top().encode('utf-8')) + serialObj.write(pip.go_down().encode('utf-8')) + serialObj.write(pip.go_top().encode('utf-8')) +b13.config(command=load) - def get_tip(self,l): - self.up() - self.x = l[0] - self.y = l[1] - self.z = l[2] - return self.sendXY() +def dispense(): + serialObj.write(pip.go_down().encode('utf-8')) +b12.config(command=dispense) - def up(self): - print(f'\n') - return f'\n' - - def down(self): - return f'\n' - - - -class LabPipBlock(): - """ Pipettenblock description - x_offset, y_offset of first tip, - z for take a tip, - number of rows and columns, - deltax,deltay space between first and last tips - """ - - def __init__(self,xoffset,yoffset,z,anz,rows,deltax,deltay): - self.xoffset = xoffset - self.yoffset = yoffset - self.anz = anz - self.rows = rows - self.columns = anz / rows - self.deltax = deltax - self.deltay = deltay - self.z = z - self.akt = 0 - - def next(self): - if self.akt == self.anz: - return f'No more tips !!' - else : - r = self.anz / self.rows - m = self.akt % r # column - c = self.akt // r # row - self.akt += 1 - x = self.xoffset + (m * self.deltax/(self.columns-1)) - y = self.yoffset + (c * self.deltay/(self.rows)) - return x,y,self.z +def top(): + serialObj.write(pip.go_top().encode('utf-8')) +b11.config(command=top) +def takeChem(): + print(chem.getXY()) + pip.setXY(chem.getXY()) + serialObj.write(pip.sendXY().encode('utf-8')) + pip.setZ(chem.load(1)) + serialObj.write(pip.down().encode('utf-8')) + serialObj.write(pip.go_top().encode('utf-8')) + upTip() -#Job 100myl of A in Vial 1 -#v1 = LabPis(200,200,100,21) -#a1 = LabPis(100,100,100,1) -#p1 = LabPis() -if __name__ == '__main__': - lpb = LabPipBlock(16,1,78,20,5,108,86) - pip = LabPip(vol=500) - pip.fe =5000 - for i in range(20): - print(pip.get_tip(lpb.next())) + +b14.config(command=takeChem) +def checkSerialPort(): + if serialObj.isOpen() and serialObj.in_waiting: + recentPacket = serialObj.readline() + recentPacketString = recentPacket.decode('utf') + txt.insert('0.1',recentPacketString,'small') + + + +while True: + root.update() + checkSerialPort() + +