Skip to content

Commit

Permalink
rng for tip shaping
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ceds92 committed Apr 27, 2023
1 parent 17bee6d commit f1a3e1d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 16 deletions.
47 changes: 35 additions & 12 deletions scanbot/scanbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -1385,18 +1405,16 @@ 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

if(not filePath): break # If the scan was stopped before finishing, stop program

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
Expand All @@ -1415,19 +1433,25 @@ 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):
if(size < sizeTarget and size > 0):
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
Expand All @@ -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
Expand Down
44 changes: 40 additions & 4 deletions scanbot/scanbot_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -895,6 +896,7 @@ def _quit(self,arg_dict):
###############################################################################
handler_class = scanbot_interface

finish = False
if('-z' in sys.argv):
rcfile = ''
try:
Expand All @@ -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')
Expand All @@ -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
Expand Down

0 comments on commit f1a3e1d

Please sign in to comment.