SFELPHOTON-1957:stop-go-and-return motion(1)

for now: mode 7 is a 1:1 copy of mode 6
This commit is contained in:
2026-05-08 13:31:54 +02:00
parent 6e391c1f81
commit d74a087430
5 changed files with 460 additions and 172 deletions
+144 -9
View File
@@ -738,7 +738,7 @@ class ShapePath(MotionBase):
tmove: (m) time to move in ms (move start on FEL-trigger
twait: (m) time to wait in ms
(tmove+twait will be rounded to a multiple of fel_per)
mode:6 pvt motion 'hit and return using grid parameters. continous motion on 2n ells to pump then same 2n wells to probe, then go 2 rows down
mode:6 pvt motion 'hit and return using grid parameters. continous motion on 2n wells to pump then same 2n wells to probe, then go 2 rows down
common kwargs plus:
trf : (o) transformation that will be done on 'grid points'
grid : (m) grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0}
@@ -746,8 +746,20 @@ class ShapePath(MotionBase):
smv : (o) time(in num of shots) to move to next section (horiz/vert)
default is (ssz[0]-1,ssz[1])
sdelay: (o) shots count of delay. Default is ssz[0]*ssz[1]
mode:7 pvt motion 'stop-go-hit-and-return using grid parameters. stop go motion on 2n wells to pump then same 2n wells to probe, then go 2 rows down
common kwargs plus:
trf : (o) transformation that will be done on 'grid points'
grid : (m) grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0}
ssz : (m) section size (in wells)
smv : (o) time(in num of shots) to move to next section (horiz/vert)
default is (ssz[0]-1,ssz[1])
sdelay: (o) section shots count delay. Default is ssz[0]*ssz[1]. A the point will be reached after sdelay shots in the next loop
tmove: (m) time(in num of shots) to move to the next well
twait: (m) time(in num of shots) to wait at the well
if twait=0, the motion will will not stop but continue motion (as mode 4 or 6)
seccnt: (o) number of timmes a section motion is done (default=2)
'''
if mode not in (1,3,4,5,6): #### pvt motion
if mode not in (1,3,4,5,6,7): #### pvt motion
raise ValueError(f'unsupported mode:{mode}')
try:
self.sync_prg
@@ -838,14 +850,14 @@ class ShapePath(MotionBase):
ox, oy=g['pos']
px, py=g['pitch']
#self.mot_pts=pt
self.mot_pts=pt*np.array(g['pitch'], np.float)+np.array(g['pos'], np.float)
self.mot_pts=pt*np.array(g['pitch'], np.float64)+np.array(g['pos'], np.float64)
else:
ox, oy=(0,0)
px, py=(1,1)
self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf
#prg+=f' linear abs\n X{ox:g} Y{oy:g}\n'
prg+=f' linear abs\n X{ox-px:g} Y{oy-py:g}\n' # start one position out of grid
else: #mode==6: #### pvt motion, hit and return using grid parameters
else: #mode in (6,7): #### pvt motion, hit and return using grid parameters
g=kwargs['grid']
nx,ny=g['count'] #total count of wells
#TODO: rework pt calculation
@@ -857,7 +869,7 @@ class ShapePath(MotionBase):
except KeyError as e:
ox, oy=g['pos']
px, py=g['pitch']
self.mot_pts=pt*np.array(g['pitch'], np.float)+np.array(g['pos'], np.float)
self.mot_pts=pt*np.array(g['pitch'], np.float64)+np.array(g['pos'], np.float64)
else:
ox, oy=(0,0)
px, py=(1,1)
@@ -1165,6 +1177,126 @@ enable plc 2
}}
}}
'''
elif mode==7:
if scan==0:
raise Exception('scan=0 not supported')
pass
else: # scan=1
vsx=px/(pt2pt_time)*scale*CoordFeedTime # scaling for Deltatau
vsy=py/(pt2pt_time)*scale*CoordFeedTime # scaling for Deltatau
#g=kwargs['grid']
#ox,oy=g['pos'] #origin position in um (or counts if scaled)
#px,py=g['pitch'] #pitch to next position in um (or 1 if scaled)
#nx,ny=g['count'] #total count of wells
#sx,sy=kwargs['ssz'] #section size (in wells)
#tsx, tsy, tsd #time scale to pvt move to (next horiz|next vert| after position #6)
tx,ty=nx//sx,ny//sy #total sections
#variables
cx,cy,dx,dy,n,k,t,vx,vy,x,x0,y,y0=map(lambda x: f'L{x}',range(13))
# replace in python code of hit_and_return.py setup_motion:
# (cx|cy|dx|dy|n|k|sx|sy|tsd|tsx|tsy|tx|ty|vsx|vsy|vx|vy|x|x0|y|y0) -> {\1}
# if ([^:]*): -> if \(\1\){{
# else: -> }}else{{
# elif ([^:]*): -> }}else if \(\1\){{
prg+=f'''\
//mode 7: stop-go-and-return pvt motion
{t}=1 // motion pvt tome scaling
{k}=-1 // key position
{cx}=0;{cy}=0 // section counter
{x0}=0;{y0}=0;{n}=0 // counter well in region
{dx}=0;{dy}=1 // motion pitch
{vx}=0;{vy}={vsy} // scaled velocity
pvt{pt2pt_time} abs
while(1){{
if ({cy}%2==0){{ // even rows
{x}={sx}*{cx}+{x0};{y}={sy}*{cy}+{y0}
}}else{{ // odd rows
{x}=({tx}-{cx})*{sx}-{x0}-1;{y}={sy}*{cy}+{y0}
{vx}=-{vx}
}}
{x0}+={dx};{y0}+={dy}
//send 1"A:move(%d) X%g:%g Y%g:%g",{k},{ox}+{x}*{px},{vx},{oy}+{y}*{py},{vy}
X({ox}+{x}*{px}):({vx}) Y({oy}+{y}*{py}):({vy})
if ({t}!=1){{
pvt{pt2pt_time} abs;{t}=1
}}
if ({k}>=0){{ //if keypoint not directly followed by an other keypoint, define future velocity
if ({k}==0 || {k}==4){{
{vx}=0;{vy}={vsy}
}}else if ({k}==2){{
{vx}=0;{vy}=-{vsy}
}}else if ({k}==5){{
{vx}=-{vsx};{vy}=0
}}else if ({k}==6){{
{n}+=1
if ({tsd}!=1) {{
pvt{pt2pt_time*tsd} abs;{t}={tsd}
}}
}}else if ({k}==7){{
//send 1"next h section"
{cx}+=1
{x0}=0;{y0}=0;{n}=0;{dx}=0;{dy}=0
if ({tsx}!=1) {{
pvt{pt2pt_time*tsx} abs;{t}={tsx}
}}
}}else if ({k}==8){{
//send 1"next v section"
{cx}=0;{cy}+=1
{x0}=0;{y0}=0;{n}=0;{dx}=0;{dy}=0
if ({cy}>={ty}){{
//send 1"finished whole grid"
break
}}
if ({tsy}!=1) {{
pvt{pt2pt_time*tsy} abs;{t}={tsy}
}}
}}
//send 1"after keypoint %d: %g|%g",{k},{vx},{vy}
{k}=-1
}}
if ({y0}=={sy}-1){{
if ({dy}==1){{ //(1)
{dx}=1;{dy}=0
{vx}={vsx}/2;{vy}={vsy}/2
}}else{{
{k}=2;{dx}=0;{dy}=-1 //(2)
{vx}={vsx}/2;{vy}=-{vsy}/2
}}
}}else if ({y0}==1 && {x0}>0 && {x0}<{sx}-1){{
if ({dy}==-1){{ //(3)
{dx}=1;{dy}=0
{vx}={vsx}/2;{vy}=-{vsy}/2
}}else{{
{k}=4;{dx}=0;{dy}=1 //(4)
{vx}={vsx}/2;{vy}={vsy}/2
}}
}}else if ({y0}==0){{
if ({n}==1 && {x0}==1){{ //(7 or 8)
if ({cx}<{tx}-1){{
{k}=7;{dx}=-1;{dy}=0
{vx}=0;{vy}=0
}}else{{ //(8)
{k}=8;{dx}={sx}-1;{dy}={sy}
{vx}=0;{vy}=0
}}
}}else if ({x0}==1){{ //(6)
{k}=6;{dx}=-1;{dy}=0
{vx}=-{vsx};{vy}=0
}}else if ({x0}==0){{ //(0)
{k}=0;{dx}=0;{dy}=1
{vx}=0;{vy}={vsy}
}}else if ({x0}=={sx}-1){{ //(5)
{k}=5;{dx}=-1;{dy}=0
{vx}=-{vsx}/2;{vy}=-{vsy}/2
}}
}}
}}
'''
#common code to repeat the motion multiple times
if cnt>1:
@@ -1360,7 +1492,7 @@ if __name__=='__main__':
sp.setup_motion(fnPrg=fn+'.prg',scale=1.,cnt=1,dwell=100,mode=4,grid=grid)
elif mode==5:
sp.setup_motion(fnPrg=fn+'.prg',scale=1.,cnt=1,dwell=100,mode=5,grid=grid,tmove=tmove,twait=twait)
elif mode==6:
elif mode==60:
grid={'pos':(-1000, -1200), 'pitch':(120, 120), 'count':(16, 20)}
ssz=(6, 10) # section size (in wells)
smv=(ssz[0]-1+4,ssz[1]+1+8) # time(in num of shots) to move to next section (horiz/vert)
@@ -1374,14 +1506,17 @@ if __name__=='__main__':
grid={'pos':(-1000, -1200), 'pitch':(120, 120), 'count':(30, 20)}
ssz=(2, 10) # section size (in wells)
sp.setup_motion(fnPrg=fn+'.prg',scale=1.,cnt=1,dwell=100,mode=6,grid=grid,ssz=ssz)
elif mode==70: # mode 7 testcase 0
grid={'pos':(-1000, -1200), 'pitch':(120, 120), 'count':(16, 20)}
ssz=(6, 10) # section size (in wells)
smv=(ssz[0]-1+4,ssz[1]+1+8) # time(in num of shots) to move to next section (horiz/vert)
sdelay=ssz[0]*ssz[1]+5 # wait after <swait> section for motion trigger. swait=0:never wait
sp.setup_motion(fnPrg=fn+'.prg',scale=1.,cnt=1,dwell=100,mode=7,grid=grid,ssz=ssz,smv=smv,sdelay=sdelay)
else:
raise(ValueError(f'unsupported mode:{mode}'))
if sp.comm:
sp.setup_gather()
sp.homing() #homing if needed
sp.run() #start motion program
_log.info('wait_armed')