From f1a3e1d9fbdc88fdd94af350df7eecb13a0a695c Mon Sep 17 00:00:00 2001 From: ceds92 Date: Fri, 28 Apr 2023 09:14:53 +1000 Subject: [PATCH] rng for tip shaping Autotip shaping now uses an rng to determine tip lift between 1 nm and -ztip. Turn off message reactions if we're not using zulip --- scanbot/scanbot.py | 47 +++++++++++++++++++++++++++--------- scanbot/scanbot_interface.py | 44 ++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/scanbot/scanbot.py b/scanbot/scanbot.py index a8479cc..5c2a2b0 100644 --- a/scanbot/scanbot.py +++ b/scanbot/scanbot.py @@ -1315,7 +1315,7 @@ def moveTipToTarget(self,lightOnOff, cameraPort, xStep, zStep, xV, zV, xF, zF, a self.survey2(user_args=[],_help=False,surveyParams=self.survey2Params) return - def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,message="",iamauto=False): + def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,rng,sleepTime,tipShape_hk,message="",iamauto=False): NTCP,connection_error = self.connect() # Connect to nanonis via TCP if(connection_error): global_.running.clear() # Free up the running flag @@ -1339,9 +1339,12 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m self.interface.sendReply("Tip lifts -zQA and -ztip must be < 0") return + if(rng == 1): rng = np.random.default_rng() + else: rng = 0 + tipShapeProps[10] = 1 # Make sure feedback on after tip shape tipShapeProps[3] = ztip # Amount to dip the tip into the surface - tipShapeProps[7] = -3*ztip # Amount to withdraw the tip from the surface + tipShapeProps[7] = -3*ztip # Amount to withdraw the tip from the surface tipCheckerProps = tipShaper.PropsGet() # These will be the tip shaper properties used to perform a light tip-shaping action which is scanned over to assess tip quality tipCheckerProps[1] = 1 # Turn on the change bias checkbox @@ -1363,9 +1366,26 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m attempt = 0 # Keep track of number of attempts to tip shape tipQA = False # Temp flag - xy = np.array([0,0]) - while(attempt < n or n==-1): - scanModule.FrameSet(*xy, w=wh, h=wh) + + piezo = Piezo(NTCP) + range_x,range_y,_ = piezo.RangeGet() + dx = 3*wh + x = np.linspace(-1, 1,n) * (n-1)*dx/2 + y = x + + snakedGrid = [] + for j in y: + for i in x: + snakedGrid.append(np.array([i, j, wh, wh])) + if(i>range_x/2 or j>range_y/2): + self.interface.sendReply("Error: Grid size exceeds scan area. Reduce -n",message=message) + self.disconnect(NTCP) # Close the TCP connection + global_.running.clear() # Free up the running flag + return + x = np.array(list(reversed(x))) # Snake the grid - better for drift + + for frame in snakedGrid: + scanModule.FrameSet(*frame) scanModule.Action(scan_action="start",scan_direction="up") # Start an upward scan for numSeconds in range(sleepTime): # Sleep at one second intervals so we can still stop the routine without lag if we need to @@ -1385,7 +1405,6 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m cleanImage = np.flipud(cleanImage) # Flip because the scan direction is up if(not isClean): scanModule.Action(scan_action='stop') - xy = xy + np.array([2*wh,0]) # Move the scan frame self.interface.sendReply("Bad area, moving scan frame") continue # Don't count the attempt if the area sucks @@ -1393,10 +1412,9 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m tipCheckPos = utilities.getCleanCoordinate(cleanImage, lxy=wh) # Do some processing to find a clean location to assess tip quality if(not len(tipCheckPos)): # If no coordinate is returned because the area is bad... - xy = xy + np.array([2*wh,0]) # Move the scan frame continue # Don't count the attempt if the area sucks - tipCheckPos += xy # Convert frame-relative coordinate to absolute coordinate + tipCheckPos += frame[0:2] # Convert frame-relative coordinate to absolute coordinate folme.XYPosSet(*tipCheckPos,Wait_end_of_move=True) # Move the tip to a clean place self.tipShapeProps(*tipCheckerProps) # Set the tip shaping properties up for the very light action @@ -1415,9 +1433,9 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m # Probably do something here to periodically check scan area (as # above) in case the tip blew up and left the area a mess. - tipCheckPos -= xy # Convert absolute coodinate to frame-relative coordinate + tipCheckPos -= frame[0:2] # Convert absolute coodinate to frame-relative coordinate symmetry,size = utilities.assessTip(tipImprint,wh,tipCheckPos) # Assess the quality of the tip based on the imprint it leaves on the surface - + self.interface.sendReply("Imprint size: " + str(size) + "\nImprint symm: " + str(symmetry)) # if(size < 0): contour not found, do something about that. if(symmetry > symTarget): @@ -1425,9 +1443,15 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m tipQA = True # Tip quality is good if it meets the target scores break # Stop the routine if a good tip has been achieved - edgeOfFrame = xy - np.array([wh,0])/2 + edgeOfFrame = frame[0:2] - np.array([wh,0])/2 folme.XYPosSet(*edgeOfFrame,Wait_end_of_move=True) # Move the tip to the left edge of the scan frame + if(rng): + r = rng.integers(low=1000, high=-ztip*1000e9, size=1)[0] + r /= -1000e9 + tipShapeProps[3] = r # Amount to dip the tip into the surface + tipShapeProps[7] = -3*r # Amount to withdraw the tip from the surface + if(tipShape_hk): try: import hk_tipShape @@ -1447,7 +1471,6 @@ def autoTipShape(self,n,wh,symTarget,sizeTarget,zQA,ztip,sleepTime,tipShape_hk,m time.sleep(1) if(self.checkEventFlags()): break # Check event flags - xy = xy + np.array([2*wh,0]) # Move the scan frame attempt += 1 scanModule.PropsSet(series_name=basename) # Put back the original basename diff --git a/scanbot/scanbot_interface.py b/scanbot/scanbot_interface.py index 9cef9c0..5ff60bc 100644 --- a/scanbot/scanbot_interface.py +++ b/scanbot/scanbot_interface.py @@ -508,6 +508,7 @@ def autoTipShape(self,user_args,_help=False): '-size' : ['1.2', lambda x: float(x), "(float) Max size of the desired tip imprint in units of nm2"], '-zQA' : ['-0.9e-9', lambda x: float(x), "(float) z-lift when performing a light tip shape to asses quality of tip (m)"], '-ztip' : ['-1.5e-9', lambda x: float(x), "(float) z-lift when performing a tip shape to alter the tip (m)"], + '-rng' : ['1', lambda x: int(x), "(int) Flag to randomise -ztip from 1 nm to -ztip value. 1=Yes, 0=No"], '-st' : ['10', lambda x: int(x), "(int) Drift compensation time (s)"], '-hk_tipShape' : ['0', lambda x: int(x), "(int) Flag to call the hook hk_tipShape. Use this hook to adjust the tip shaping parameters based on size/symmetry scores, or based on the image of the tip imprint itself. 0=Don't call, 1=Call"],} @@ -739,7 +740,7 @@ def reactToMessage(self,reaction,message=""): """ if(not self.bot_handler): # If we're not using zulip - print("Scanbot reaction: " + reaction) # Send reaction to console + # print("Scanbot reaction: " + reaction) # Send reaction to console return reactTo = message # If we're reacting to a specific zulip message @@ -787,7 +788,7 @@ def sendPNG(self,pngFilename,notify=True,message=""): ############################################################################### # Misc ############################################################################### - def stop(self,user_args,_help=False): + def stop(self,user_args=[],_help=False): arg_dict = {'-s' : ['1', lambda x: int(x), "(int) Stop scan in progress. 1=Yes"]} if(_help): return arg_dict @@ -808,7 +809,7 @@ def stop(self,user_args,_help=False): if(args[0] == 1): self.scanbot.stop() def threadTask(self,func,override=False): - if(override): self.stop(args=[]) + if(override): self.stop() if global_.running.is_set(): return "Error: something already running" global_.running.set() t = threading.Thread(target=func) @@ -895,6 +896,7 @@ def _quit(self,arg_dict): ############################################################################### handler_class = scanbot_interface +finish = False if('-z' in sys.argv): rcfile = '' try: @@ -915,8 +917,9 @@ def _quit(self,arg_dict): sys.exit() os.system("zulip-run-bot scanbot_interface.py --config=" + rcfile) + finish = True -if('-c' in sys.argv): +if('-c' in sys.argv and not finish): print("Console mode: type 'exit' to end scanbot") go = True handler_class = scanbot_interface(run_mode='c') @@ -928,6 +931,39 @@ def _quit(self,arg_dict): finish = True +# if('-g' in sys.argv and not finish): +# import customtkinter as ctk +# from MainPanel import MainPanel as mp +# import ctypes + +# class App(ctk.CTk): +# WIDTH = 512 +# HEIGHT = 512 +# def __init__(self): +# super().__init__() +# self.title("EPWE") +# self.protocol("WM_DELETE_WINDOW", self.on_closing) + +# dpi = self.winfo_fpixels('1i') +# try: +# scaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)/100 # Account for windows scale factor in display settings +# except: +# scaleFactor = 1 # Might not work on mac - haven't tested + +# handler_class = scanbot_interface(run_mode='g') +# self.mainPanel = mp(self, handler_class, width=self.WIDTH, height=self.HEIGHT, dpi=dpi, scaleFactor=scaleFactor) +# self.geometry("%dx%d" % (self.WIDTH, 850)) + +# def on_closing(self, event=0): +# self.mainPanel.quit() + +# if('-g' in sys.argv and not finish): +# ctk.set_appearance_mode("Dark") # Modes: system (default), light, dark +# ctk.set_default_color_theme("blue") # Themes: blue (default), dark-blue, green + +# app = App() +# app.mainloop() + # if('-g' in sys.argv and not finish): # print("Booting in GUI mode...") # import tkinter as tk