enhance syncronization -> parameters in setup_sync

-> sp.setup_sync(verbose=args.verbose&0x40,timeOfs=0.03,timeCor=0.0005)
- cleanup code
- add motion markers
- add debug data
- rework triggerSync
- BUT nothing should change in Sync
This commit is contained in:
2022-10-04 16:39:13 +02:00
parent 7a968aac96
commit 20c6d690e8
6 changed files with 438 additions and 202 deletions

190
Readme.md
View File

@@ -1274,4 +1274,194 @@ Make z to move over the grid.
?? what are the PV for the camera, zoom etc ???
```
30.9.22 Debug Synchronization
=============================
https://docs.google.com/document/d/1soSuCZYyfGf_ntcgG_Y1_WeGuo_687OuFn0s4sMj1uY/edit
remote ssh tunnel + start gather_server
---------------------------------------
```
PPMAC=SAR-CPPM-EXPMX1
rsync -va ~/Documents/prj/SwissFEL/PBTools/pbtools/gather/gather_server root@$PPMAC:/tmp/
lsof -i -n | grep '127.0.0.1:1000'
ssh -L 10001:localhost:22 root@$PPMAC 'uname -a'
ssh -L 10002:localhost:2332 root@$PPMAC 'uname -a'
ssh root@$PPMAC
LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/gather_server
```
cleanup /tmp/
-------------
```
PPMAC=SAR-CPPM-EXPMX1
ssh root@$PPMAC rm /tmp/gather_server /tmp/triggerSync
ssh root@$PPMAC ls -l /tmp
```
start debug tools
-----------------
```
PPMAC=SAR-CPPM-EXPMX1
PBInspect --host=$PPMAC&
gpasciiCommander --host $PPMAC -i
ssh root@$PPMAC
ssh root@$PPMAC rm /tmp/gather_server /tmp/triggerSync
ssh root@$PPMAC ls -l /tmp
```
restart IOC
-----------
```
ssh saresc-cons-03
PPMAC=SAR-CPPM-EXPMX1
telnet $PPMAC 50001
Ctrl-X
dbgf SAR-CPPM-EXPMX1:MOD_VER
caget SAR-CPPM-EXPMX1:MOD_VER
```
checking versions
-----------------
```
git: 7a968aac967
asyn 427.0.2
motorBase alpha_220518
asynMotor alpha_220518
powerPmac alpha_220518
PB_COMMON 2.0.1
gpasciiCommander 0.9.0
ESB_MX 0.0.2
```
zamofing_t@ganymede:~/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX$
git loggraph -10
* 7a968aa 2022-09-20 (HEAD -> master, tag: latest, tag: 0.0.2, psigithub/master) change speeds and directions [Thierry Zamofing]
* 00588f8 2022-09-16 minor changes [Thierry Zamofing]
* d52a6ce 2022-08-30 minor changes [Thierry Zamofing]
* f47e111 2022-05-20 (tag: 0.0.1) add DET_Z motor [Thierry Zamofing]
* 8e5b15e 2022-05-20 wip [Thierry Zamofing]
* 399282c 2019-03-20 enhance triggering [Thierry Zamofing]
* eda8caf 2019-03-19 wip [Thierry Zamofing]
* 0c45705 2019-03-08 optimize [Thierry Zamofing]
* c962ebd 2019-03-06 documentation [Thierry Zamofing]
git reset --hard 7a968aa
rmake -e LIBVERSION=42.42.42 uninstall install
-> restart IOC
ssh root@$PPMAC rm /tmp/triggerSync
cd python
git dt latest -- shapepath.py
./shapepath.py --host=localhost:10001:10002
removing test verion
ssh sf-lc7 ls -l /ioc/modules/ESB_MX/
ssh sf-lc7 rm -rf /ioc/modules/ESB_MX/42.42.42
IOC locations
-------------
```
~/Documents/prj/SwissFEL/epics_ioc_boot_sf/ESC_all/ESB_MX_PowerBrick
They are just using the new alphy driver. That should have no impact on the motion config.
```
Current (old) Synchronization
-----------------------------
```
default:
/ESB_MX/src/triggerSync/triggerSync.c -> read usage
simulate start trigger -> pshm->Coord[1].Q[10]=1 to simulate a Jungfrau aquire start\n\
simulate frame trigger -> pshm->Coord[1].Q[11]
Coord[1].Q[0] is incremented at each trigger
Coord[1].DesTimeBase is adjusted at each frame trigger
Coord[1].pDesTimeBase=Coord[1].DesTimeBase.a
gpascii: set Gather.Enable=1
PMAC: LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/triggerSync 10 0 11 -> wait for start trigger
gpascii: set Start trigger: pshm->Coord[1].Q[10]=1 or set EVR that generates the trigger
PMAC: start Gather (Gather.Enable=2)
count and sync frames:
Coord[1].Q[0] = frame counter
gpascii: stop Gather -> Gather.Enable=0
PMAC: triggerSync stops when Gather.Enable=0
```
Enhanced Synchronization
------------------------
```
(to be tested)
Coord[1].pDesTimeBase=Coord[1].DesTimeBase.a
For “external time base”, in which the coordinate systems time base value is proportional to the
frequency of an incoming encoder signal or pulse train, Coord[x].pDesTimeBase should be set
to EncTable[i].DeltaPos.a
Setup EncTable:
EncTable[n].type = (3)Software 1/T encoder extension (5)Four-byte read 32 bit int (11) Float 32f or 64f
The ERV are mapped to
//Power PMAC Software Reference Manual.pdf Gate3[i].Chan[j].Status -> page 919 UserFlag
(gate3_1->Chan[0].Status&0x800) = Gate3[1].Chan[0].UserFlag Trigger start
(gate3_1->Chan[1].Status&0x800) = Gate3[1].Chan[1].UserFlag Trigger frame
Use EncTable 20 as Frame counter
Gate3[1].Chan[1].EncCtrl = $encctrl
EncTable[20].type = 3
EncTable[20].pEnc = Gate3[1].Chan[1].UserFlag.a (is same as Gate3[1].Chan[1].Status) thus it will not work
EncTable[20].pEnc1 = Gate3[1].Chan[0].TimerA.a
EncTable[20].index1 = 0
EncTable[20].index2 = 0
EncTable[20].index3 = 0
EncTable[20].index4 = 0
EncTable[20].index5 = 0
EncTable[20].ScaleFactor = 1/256
-> THIS DOES NOT WORK WITH CURRENT CONNECTIONS !
-> ONE PHYSICAL ENCODER WOULD NEED PULSE AND DIRECTION INPUT AND SET Gate3[1].Chan[1].EncCtrl TO 'pulse and direction' mode
> Sys.Ddata[0]=Sys.Ddata[0]+10
Use EncTable 20 as Frame counter
Gate3[1].Chan[1].EncCtrl = $encctrl
EncTable[20].type = 11 //loating point read
EncTable[20].pEnc = Sys.Ddata[0].a
EncTable[20].pEnc1 = Gate3[1].Chan[0].TimerA.a
EncTable[20].index1 = 0
EncTable[20].index2 = 0
EncTable[20].index3 = 0
EncTable[20].index4 = 0
EncTable[20].index5 = 99 //multiply with 100
EncTable[20].index5 = 1 //float64
EncTable[20].ScaleFactor = 1/256
EncTable[20].ScaleFactor=1E-3
Use EncTable 20 as Frame counter
EncTable[20].type = 1 //32 Bit uint
EncTable[20].pEnc = Sys.Udata[0].a
EncTable[20].index1 = 0
EncTable[20].index2 = 0
EncTable[20].index3 = 0
EncTable[20].index4 = 0
EncTable[20].index5 = 0
EncTable[20].index5 = 0
EncTable[20].ScaleFactor=1E-3
2.1 trigger zu spät
1.9 trigger zu früh

View File

@@ -7,6 +7,8 @@
# *-----------------------------------------------------------------------*
'''
Coord[1].Q[0] : sync points when using setup_sync(mode=2)
-3: when armed (at start position)
-2: triggerSync waiting for start trigger
0: after setup_sync(mode=2) call
idx: index of position during run
-1: pvt motion is finished
@@ -44,7 +46,7 @@ class MotionBase:
self.meta={'srv_per':ServoPeriod,'pt2pt_time':40,'sync_flag':0,'sync_mode':2}
self.meta.update(kwargs)
def setup_sync(self, crdId=1, prgId=2,verbose=False, timeOfs=0.):
def setup_sync(self, crdId=1, prgId=2,verbose=False, timeOfs=0.,timeCor=0.):
'''setup the timing synchronization for the motion program
kwargs:
sync_mode : default=2
@@ -88,41 +90,43 @@ class MotionBase:
flag0='Coord[{crdId}].Q[10]'.format(crdId=crdId) if sync_flag&1 else 'Gate3[1].Chan[0].UserFlag'
flag1='Coord[{crdId}].Q[11]'.format(crdId=crdId) if sync_flag&2 else 'Gate3[1].Chan[1].UserFlag'
if sync_mode==1:
prg = '''
Coord[{crdId}].Q[0]=-2
Coord[{crdId}].TimeBaseSlew=1 //1E-4 is default
Coord[{crdId}].DesTimeBase=0
while({flag0}==0){{}}
Coord[{crdId}].Q[0]=-1
Gather.Enable=2
while({flag1}==0){{}}
Coord[1].DesTimeBase=Sys.ServoPeriod
'''.format(crdId=crdId, flag0=flag0, flag1=flag1)
prg = f'\n{flag0}=0\n' if sync_flag&1 else ''
prg += f'''
Coord[{crdId}].Q[0]=-2 motion program started and armed
Coord[{crdId}].TimeBaseSlew=1 //1E-4 is default
Coord[{crdId}].DesTimeBase=0
while({flag0}==0){{}}
Coord[{crdId}].Q[0]=-1
Gather.Enable=2
while({flag1}==0){{}}
Coord[1].DesTimeBase=Sys.ServoPeriod
'''
else:
prg = '''
//Gather.Enable=2 is done in the sync program
Coord[1].TimeBaseSlew=1 //1E-4 is default
Coord[1].DesTimeBase=0
//Coord[1].Q[0]=-1 is done in the sync program
'''.format(crdId=crdId, flag0=flag0, flag1=flag1)
prg = f'''
//Gather.Enable=2 is done in the triggerSync program
Coord[1].TimeBaseSlew=1 //1E-4 is default
Coord[1].DesTimeBase=0
Coord[1].Q[0]=-3 //motion program started and waits. Arm(-2) is done in triggerSync program
'''
self.sync_prg = prg
#download and start triggerSync code
comm=self.comm
if comm is None: return
arg=0 #argument to pass to triggerSync program
if sync_mode==2:arg+=1 #synchronize
arg+=sync_flag*2 #simulated or real triggers
if verbose: arg+=8
if sync_mode==2 or arg&4:
mode=0 #mode to pass to triggerSync program
if sync_mode==2:mode+=1 #synchronize
mode+=sync_flag*2 #simulated or real triggers
if verbose: mode+=8
if sync_mode==2 or mode&4:
sftp = comm.sftp
dst = '/tmp/triggerSync'
src = os.path.abspath(os.path.join(os.path.dirname(__file__), 'triggerSync'))
sftp.put(src, dst)
sftp.chmod(dst, 0o755)
cmd = 'LD_LIBRARY_PATH=/opt/ppmac/libppmac/ ' + dst
cmd+=' %g %g %d'%(pt2pt_time,timeOfs,arg)
#cmd+=' %d %g %g %g'%(mode,pt2pt_time,timeOfs,timeCor)
cmd+=' %d %g %g'%(mode,pt2pt_time+timeCor,timeOfs)
self.cmdSync = cmd
print ('starting '+cmd)
self.syncShell=comm.shell_channel(cmd)

View File

@@ -17,63 +17,36 @@ verbose bits:
0x20 plot pvt trajectory (before motion)
0x40 print sync details
Gather motor order
idx 0 1 2 3 4 5 6
OLD Motor[3].ActPos Motor[2].ActPos Motor[1].ActPos Motor[3].DesPos Motor[2].DesPos Motor[1].DesPos Gate3[1].Chan[1].UserFlag
if mode&1:
self.plot_trajectory()
if mode&2:
self.plot_pos_error()
if mode&4:
self.plot_bode(xy=(3,1),mode=31,db=True) # FX
self.plot_bode(xy=(2,0),mode=31,db=True) # FY
if mode&8:
self.plot_trigger_jitter()
Gather motor order
idx 0 1 2 3 4
NEW Motor[1].ActPos Motor[2].ActPos Motor[1].DesPos Motor[2].DesPos Gate3[1].Chan[1].UserFlag
NEW y.ActPos x.ActPos y.DesPos x.DesPos Gate3[1].Chan[1].UserFlag
OLD->NEW
0->none
1->1
2->0
3->none
4->3
5->2
Mot 1: Stage Y Parker MX80L D11 25mm one pole cycle = 13mm = 2048 phase_step
Mot 2: Stage X Parker MX80L D11 25mm one pole cycle = 13mm = 2048 phase_step
Mot 3: Rotation stage LS Mecapion MDM-DC06DNC0H 32 poles = 1 rev = 16*2048=32768 phase_step
Mot 4: Stage X Stada Stepper 670mA 200 poles 1 rev = 100*2048 phase_step (2 stepper motor)
Mot 5: Stage Z Stada Stepper 670mA 200 poles 1 rev = 100*2048 phase_step (2 stepper motor)
Enc 6: Interferometer Y
Enc 7: Interferometer X
tunnel PowerBrick port locally
------------------------------
Port 22 on PowerBrick is the ssh server port
Port 2332 on PowerBrick is the gather port of gather_server
PPMAC=SAR-CPPM-EXPMX1
rsync -vai ~/Documents/prj/SwissFEL/PBTools/pbtools/gather/gather_server root@$PPMAC:/tmp/
ssh root@$PPMAC
LD_LIBRARY_PATH=/opt/ppmac/libppmac/ /tmp/gather_server
rsync -vai ~/Documents/prj/SwissFEL/PBTools/pbtools/gather/gather_server root@$PPMAC:/tmp
ssh -L 10001:localhost:22 root@$PPMAC 'uname -a'
ssh -L 10002:localhost:2332 root@$PPMAC 'uname -a'
-> this tunnels port 22 and 2332 of $PPMAC to 10001 and 10002 of localhost
('uname -a' is just to execute a command and return, because the port remains open)
Tests:
nc localhost 10001
nc localhost 10002
list close ssh tunnel
---------------------
lsof -i -n | egrep 'ssh'
lsof -i -n | grep '127.0.0.1:1000'
s.a. https://docs.google.com/document/d/1soSuCZYyfGf_ntcgG_Y1_WeGuo_687OuFn0s4sMj1uY/
'''
from __future__ import print_function
#from __future__ import absolute_import,division,generators,nested_scopes,print_function,unicode_literals,with_statement
try: raw_input;input=raw_input
except NameError: pass
@@ -305,7 +278,7 @@ class DebugPlot:
hl = ax.plot(pts[:, 0], pts[:, 1], 'r.', label='points')
hl += ax.plot(pts[:, 0], pts[:, 1], 'y--', label='direct')
hl += ax.plot(rec[:, 3], rec[:, 2], 'b-', label='DesPos') # desired path
hl += ax.plot(rec[:, 1], rec[:, 0], 'g-', label='ActPos') # actual path
hl += ax.plot(rec[:, 1], rec[:, 0], 'g.', label='ActPos') # actual path
try:
pvt = self.pvt
except AttributeError:
@@ -333,6 +306,23 @@ class DebugPlot:
ax2.legend(loc='best')
plt.show(block=False)
def plot_dbg(self):
rec = self.rec # yA,xA,yD,xD,trig
ts=self.meta['srv_per']*self.meta['acq_per']
fig = plt.figure('debug plot')
ax = fig.add_subplot(1, 1, 1)
t=np.arange(rec.shape[0],dtype=np.uint32)
#address=("Motor[1].ActPos", "Motor[2].ActPos", "Motor[1].DesPos", "Motor[2].DesPos", "Gate3[1].Chan[1].UserFlag","EncTable[20].DeltaPos")
hl = []
rec[0, 5]=rec[0, 6]=0
hl += ax.plot(t, rec[:, 6], 'rx', label='EncTable[20].DeltaPos')
hl += ax.plot(t, rec[:, 5], 'b-', label='Coord[1].TimeBase')
hl += ax.plot(t, rec[:, 4], 'g.', label='Gate3[1].Chan[1].UserFlag')
ax.xaxis.set_label_text('ms (timebase: %g ms per data point)' % ts)
ax.legend(loc='best')
plt.show(block=False)
def plot_gather(self,mode=255):
try:
meta=self.meta
@@ -355,6 +345,10 @@ class DebugPlot:
if mode&8:
self.plot_trigger_jitter()
#self.plot_dbg()
plt.show(block=False)
def plot_bode(self,xy=(0,1),mode=25,db=True):
@@ -445,8 +439,8 @@ class DebugPlot:
plt.show(block=False)
def load_npz(self,fn='/tmp/shapepath.npz'):
fh=np.load(fn)
for k,v in fh.iteritems():
fh=np.load(fn,allow_pickle=True)
for k,v in fh.items():
setattr(self,k,v)
self.meta=self.meta.item()
@@ -571,15 +565,6 @@ class ShapePath(MotionBase):
for x in np.arange(mult)*shift:
stack.append(pts+(x,y))
pts=np.vstack(stack)
#xx,yy=np.meshgrid(range(w), range(h))
#pts=np.array([xx.reshape(-1),yy.reshape(-1)],dtype=np.float).transpose()*pitch
#if xy:
#else:
# smlpitch
#pts+=ofs
self.points=pts
@@ -654,36 +639,26 @@ class ShapePath(MotionBase):
comm=self.comm
gt=self.gather
gt.set_phasemode(False)
if self.meta['sync_flag']&2:
meta=self.meta
if meta['sync_flag']&2:
address=("Motor[1].ActPos","Motor[2].ActPos","Motor[1].DesPos","Motor[2].DesPos","Coord[1].Q[11]")
else:
address=("Motor[1].ActPos","Motor[2].ActPos","Motor[1].DesPos","Motor[2].DesPos","Gate3[1].Chan[1].UserFlag")
#address=("Motor[1].ActPos","Motor[2].ActPos","Motor[1].DesPos","Motor[2].DesPos","Gate3[1].Chan[1].UserFlag","EncTable[20].PrevEnc")
#address=("Motor[1].ActPos", "Motor[2].ActPos", "Motor[1].DesPos", "Motor[2].DesPos", "Gate3[1].Chan[1].UserFlag","Coord[1].TimeBase","EncTable[20].DeltaPos")
gtMaxLn=gt.set_address(*address)
if acq_per is None:
ovhdTime=100
acq_per=int(np.ceil((self.meta['pt2pt_time']*self.points.shape[0]+ovhdTime)/(gtMaxLn*self.meta['srv_per'])))
acq_per=int(np.ceil((meta['pt2pt_time']*self.points.shape[0]+ovhdTime)/(gtMaxLn*meta['srv_per'])))
gt.set_property(MaxSamples=1000000, Period=acq_per)
#gt.set_property(Period=acq_per)
self.meta.update({'acq_per':acq_per,'address':address})
meta.update({'acq_per':acq_per,'address':address})
def setup_coord_trf(self,fx='X',fy='Y',cz='0'):
# FY:1, FX:2, ROT_Y:3, CX:4, CZ:5,
if self.comm is None: return
comm = self.comm
gpascii = comm.gpascii
prg = '''&1a
#1-> Y
#2-> X
#3-> A
&0#4->0
&0#5->0
&0#6->0
&0#7->0
#1..3j/
//#8->0
//#1..8j/
'''
prg=f'''&1a
&1#3->0
&1#4->0
@@ -699,7 +674,6 @@ class ShapePath(MotionBase):
#5->{cz}
#1,2,5j/
'''
gpascii.send_block(prg)
def setup_motion(self,prgId=2,fnPrg=None,mode=0,**kwargs):
@@ -719,6 +693,22 @@ class ShapePath(MotionBase):
numPad : number of padding points to reduce aliasing (default=16)
'''
prg=['close all buffers','open prog %d'%(prgId)]
#Use EncTable 20 as Frame counter
#dont use Coord[1].DesTimeBase as the time base but use the virtual encoder:
# Coord[1].pDesTimeBase=Coord[1].DesTimeBase.a #(default)
prg.append('''\
EncTable[20].type = 1 //32 Bit uint
EncTable[20].pEnc = Sys.Udata[0].a
EncTable[20].index1 = 0
EncTable[20].index2 = 0
EncTable[20].index3 = 0
EncTable[20].index4 = 0
EncTable[20].index5 = 0
EncTable[20].index5 = 0
EncTable[20].ScaleFactor=1E-3
//Coord[1].pDesTimeBase=EncTable[20].DeltaPos.a
''')
verb=self.verbose
comm=self.comm
if comm is not None:
@@ -768,7 +758,8 @@ class ShapePath(MotionBase):
plt.show(block=False)
pv[1:-1, (2, 3)]*=CoordFeedTime #scaling for Deltatau
prg.append(' linear abs')
prg.append('linear abs')
#prg.append('X%g Y%g' % tuple(pv[0, (0,1)]-(120,120)))
prg.append('X%g Y%g' % tuple(pv[0, (0,1)]))
prg.append('dwell 10')
try: prg.extend(self.sync_prg.split('\n'))
@@ -781,6 +772,10 @@ class ShapePath(MotionBase):
prg.append(' pvt%g abs'%pt2pt_time) #100ms to next position
for idx in range(1,pv.shape[0]):
prg.append('X%g:%g Y%g:%g'%tuple(pv[idx,(0,2,1,3)]))
#if idx%78==10: #sync data all 256 points
# prg.append('Coord[1].Q[12]=Sys.ServoCount')
# #prg.append(f'Coord[1].Q[13]={idx}')
# prg.append(f'Coord[1].Q[13]=Motor[1].DesPos')
prg.append('X%g Y%g' % tuple(pv[-1, (0,1)]))
if cnt>1:
prg.append('dwell 10')
@@ -813,6 +808,7 @@ class ShapePath(MotionBase):
def gather_upload(self,fnRec=None):
gt=self.gather
comm=self.comm
gt.wait_stopped(verbose=True)
self.rec=rec=gt.upload()
@@ -824,23 +820,24 @@ class ShapePath(MotionBase):
del self.syncShell
pts=self.points
ofsy=-rec[0,2]+pts[0,1]
ofsx=-rec[0,3]+pts[0,0]
rec[:,(1,3)]+=ofsx
rec[:,(0,2)]+=ofsy
ofsy=comm.gpascii.get_variable("Motor[1].HomePos", type_=float)
ofsx=comm.gpascii.get_variable("Motor[2].HomePos", type_=float)
rec[:,(0,2)]-=ofsy
rec[:,(1,3)]-=ofsx
if fnRec:
np.savez_compressed(fnRec, rec=rec, pts=pts, meta=self.meta)
if __name__=='__main__':
#import logging
#logger = logging.getLogger(__name__)
#logger = logging.getLogger('pbtools.misc.pp_comm')
#logger.setLevel(logging.DEBUG)
#logging.basicConfig(format=('%(asctime)s %(name)-12s '
# '%(levelname)-8s %(message)s'),
# datefmt='%m-%d %H:%M',
# )
import logging
_log=logging.getLogger(__name__)
logging.getLogger('pbtools.misc.pp_comm').setLevel(logging.INFO)
logging.getLogger('paramiko').setLevel(logging.WARNING)
logging.getLogger('matplotlib').setLevel(logging.INFO)
#https://docs.python.org/3/library/logging.html#logging.Formatter add %(name)s to identify the logger
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
import argparse
def unique_filename(fnBase):
i = 0;
@@ -854,20 +851,6 @@ if __name__=='__main__':
def run_test(args):
#dp=DebugPlot();dp.plot_gather();return
#import socket
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # create an INET, STREAMing socket
#s.settimeout(.1)
#try:
# port=22 #ssh port
# s.connect((args.host, port)) # try to connect to port
# s.close()
#except (socket.error, socket.gaierror) as e:
# comm=gather=None
#else:
# comm = PPComm(host=args.host)
# gather = Gather(comm)
hpp=args.host.split(':')
param={'host':hpp[0]}
if len(hpp)>1:
@@ -885,7 +868,7 @@ if __name__=='__main__':
#sp = ShapePath(comm, gather, args.verbose,sync_mode=0,pt2pt_time=10)
#simulated start and frame trigger no sync
sp = ShapePath(comm, gather, args.verbose,sync_mode=1,sync_flag=3)
#sp = ShapePath(comm, gather, args.verbose,sync_mode=1,sync_flag=3)
#simulated start and frame trigger with sync
#sp = ShapePath(comm, gather, args.verbose,sync_mode=2,sync_flag=3)
@@ -894,7 +877,7 @@ if __name__=='__main__':
#sp = ShapePath(comm, gather, args.verbose,sync_mode=1,sync_flag=1)
#simulated start real frame trigger with sync
#sp = ShapePath(comm, gather, args.verbose,sync_mode=2,sync_flag=1)
sp = ShapePath(comm, gather, args.verbose,sync_mode=2,sync_flag=1)
fn='/tmp/shapepath'
#fn =unique_filename('ShapePathAnalyser/records/19_01_24/spiral')
@@ -927,18 +910,36 @@ if __name__=='__main__':
#sp.gen_spiral_points(rStart=100,rInc=130,numSeg=4,numCir=2, ofs=(0, 0))
#sp.gen_grid_points(w=20,h=20,pitch=100,rnd=0,ofs=(0,+2000));sp.sort_points(False);
#sp.gen_grid_points(w=5,h=10,pitch=100,rnd=0,ofs=(0,+2000));sp.sort_points(False,10);
sp.gen_grid_points(w=125,h=125,pitch=3,rnd=0,ofs=(0,+2000));sp.sort_points(False,125); sp.meta['pt2pt_time']=5
#sp.gen_grid_points(w=50,h=50,pitch=120,rnd=0,ofs=(0,+2000));sp.sort_points(False,50); sp.meta['pt2pt_time']=10
#sp.gen_grid_points(w=16,h=16,pitch=120,rnd=0,ofs=(0,+2000));sp.sort_points(False,16); sp.meta['pt2pt_time']=10
#12.5x12.5
sp.gen_grid_points(w=78,h=78,pitch=120,rnd=0,ofs=(-10000,-12000));sp.sort_points(False,78); sp.meta['pt2pt_time']=10
#23.0x23.0 -> only 3 data points from shot to shot: 6,9,12,14,17,20...
#sp.gen_grid_points(w=162,h=162,pitch=120,rnd=0,ofs=(-10000,-12000));sp.sort_points(False,162); sp.meta['pt2pt_time']=10
#sp.gen_grid_points(w=1,h=10,pitch=100,rnd=0,ofs=(0,0))
#sp.gen_spiral_points(rStart=100,rInc=20,numSeg=8,numCir=32, ofs=(0, 0))
#sp.gen_spiral_points(rStart=100,rInc=10,numSeg=2,numCir=32, phase=45, ofs=(0, 0))
#sp.gen_spiral_points(rStart=100,rInc=10,numSeg=4,numCir=32, ofs=(0, 0))
#sp.gen_closed_shifted()
gtMaxLn=116508;ovhdTime=100
gtMaxLn=int(sp.comm.gpascii.get_variable('Gather.MaxLines')) # 116508
if gtMaxLn==0:
sp.setup_gather(acq_per=1)
gtMaxLn=int(sp.comm.gpascii.get_variable('Gather.MaxLines')) # 116508
ovhdTime=100
acq_per=int(np.ceil((sp.meta['pt2pt_time']*sp.points.shape[0]+ovhdTime)/(gtMaxLn*sp.meta['srv_per'])))
if args.verbose&0x01:
print(f'''\
Gather.MaxLines:{gtMaxLn}
Gather.Period: {acq_per}
meta: {sp.meta}
Filename: {fn}.[prg|npz]
''')
sp.setup_gather(acq_per=acq_per)
sp.setup_sync(verbose=args.verbose&32,timeOfs=0.05)
sp.setup_sync(verbose=args.verbose&0x40,timeOfs=0.03,timeCor=0.0005)
sp.setup_coord_trf() # reset to shape path system
#sp.meta['pt2pt_time']=10 #put between setup_sync and setup_motion to have more motion points than FEL syncs
sp.setup_motion(fnPrg=fn+'.prg', mode=3, scale=1.,dwell=10)
@@ -946,8 +947,11 @@ if __name__=='__main__':
#sp.setup_motion(fnPrg=fn + '.prg', mode=1, scale=0,dwell=10)
sp.homing() #homing if needed
sp.run() #start motion program
print('wait_armed')
sp.wait_armed() # wait until motors are at first position
print('trigger')
sp.trigger(0.5) #send a start trigger (if needed) ater given time
print('progress..')
if not comm is None:
while True:
p=sp.progress()
@@ -955,55 +959,31 @@ if __name__=='__main__':
print('progress %d/%d'%(p,sp.points.shape[0]));time.sleep(.1)
sp.gather_upload(fnRec=fn+'.npz')
dp=DebugPlot(sp);dp.plot_gather(mode=11)
print('done')
plt.show(block=False)
input('press return')
#sp.plot_points(sp.points);plt.show()
#>>>run gather and plot trajectory<<<
#return
from optparse import OptionParser, IndentedHelpFormatter
class MyFormatter(IndentedHelpFormatter):
'helper class for formating the OptionParser'
def __init__(self):
IndentedHelpFormatter.__init__(self)
def format_epilog(self, epilog):
if epilog:
return epilog
else:
return ""
def parse_args():
'main command line interpreter function'
#usage: gpasciiCommunicator.py --host=PPMACZT84 myPowerBRICK.cfg
(h, t)=os.path.split(sys.argv[0]);cmd='\n '+(t if len(h)>3 else sys.argv[0])+' '
exampleCmd=('-v15',
'--host=localhost:10001:10002'
)
epilog=__doc__+'''
Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n '
fmt=MyFormatter()
parser=OptionParser(epilog=epilog, formatter=fmt)
parser.add_option('-v', '--verbose', type="int", dest='verbose', help='verbosity bits (see below)', default=0)
parser.add_option('--host', help='hostname', default='SAR-CPPM-EXPMX1')
'--host=localhost:10001:10002 -v 0x5d',
'--host=localhost:10001:10002 -v 0x59'
)
epilog=__doc__+'\nExamples:'+''.join(map(lambda s:cmd+s, exampleCmd))+'\n '
parser=argparse.ArgumentParser(epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-m", "--mode", type=lambda x:int(x, 0), help="mode (see bitmasks) default=0x%(default)x", default=0xff)
parser.add_argument('-v', '--verbose', type=lambda x:int(x, 0), dest='verbose', help='verbosity bits (see below) default=0x%(default)x', default=0x00)
parser.add_argument('--host', help='hostname', default='SAR-CPPM-EXPMX1')
#parser.add_option('--host', help='hostname', default='localhost:10001:10002')
#parser.add_option('--host', help='hostname')
(args, other)=parser.parse_args()
args.other=other
args=parser.parse_args()
_log.info('Arguments:{}'.format(args.__dict__))
run_test(args)
#------------------ Main Code ----------------------------------
#dp=DebugPlot('/tmp/shapepath.npz');dp.plot_gather(mode=11);plt.show()
#exit(0)
#ssh_test()
ret=parse_args()
exit(ret)

View File

@@ -1,12 +1,13 @@
#HOST=MOTTEST-CPPM-CRM0573
HOST=SAR-CPPM-EXPMX1
XENOMAI_INC_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include
XENOMAI_LIB_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib
#XENOMAI_INC_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include
#XENOMAI_LIB_DIR=/opt/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib
XENOMAI_INC_DIR=/tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/include
XENOMAI_LIB_DIR=/tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/lib
INC=-I/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/libppmac -I/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/rtpmac -I$(XENOMAI_INC_DIR)
LIB=-L/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/opt/ppmac/libppmac -lppmac -L/opt/eldk-4.2/PPMAC_rootfs-7-wheezy/usr/local/xenomai-2.6.2.1/lib -lnative -lxenomai -lpthread_rt -lpthread -lrt -ldl
CC=/opt/eldk-4.2/usr/bin/ppc_4xxFP-g++
@@ -14,8 +15,15 @@ LD=$(CC)
all: triggerSync
triggerSync.o: $(XENOMAI_INC_DIR)
$(XENOMAI_INC_DIR):
mkdir -p /tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/
rsync -vai root@$(HOST):/usr/local/xenomai-2.6.2.1/ /tmp/powerpc-465-rootfs/usr/local/xenomai-2.6.2.1/
%.o: %.c
$(CC) -g $(INC) -c $^ -o $@
$(CC) -g $(INC) -c $< -o $@
triggerSync: triggerSync.o
$(LD) -g $(LIB) $^ -o $@

Binary file not shown.

View File

@@ -33,11 +33,23 @@
extern struct SHM *pshm;
static char mode=0;
static float mtPt2Pt=40.f; //motion point to point time
static float timeOfs=0.f; //time ofset
static float timeOfs=0.f; //time ofset (start time adjustment)
static float timeCor=0.f; //time correction (frame to frame time adjustment)
#define CLOCK_RES 1e-9 //Clock resolution is 1 ns by default
#define SIMFLAG0 (pshm->Coord[1].Q[10])
#define SIMFLAG1 (pshm->Coord[1].Q[11])
//EncTable[20].pEnc= Coord[1].Q[12].a does not work
//EncTable[20].pEnc= Sys.Udata[0].a works uint32
//EncTable[20].pEnc= Sys.Idata[0].a works int32
//EncTable[20].pEnc= Sys.Fdata[0].a works float32
//EncTable[20].pEnc= Sys.Ddata[0].a works float64
//#define ENCVAL (*((double *)pushm+0))
#define ENCVAL (*((unsigned int *)pushm+0))
//#define SIMFLAG0 (pshm->P[10])
//#define SIMFLAG1 (pshm->P[11])
//Power PMAC Software Reference Manual.pdf Gate3[i].Chan[j].Status -> page 919 UserFlag
@@ -76,6 +88,14 @@ void trigsync_func(void *arg)
printf("ending trigsync_func because Gather.Enable==0\n");
return;
}
//unsigned int lastQ12=0; //Q12 value for further sync
double mxActPos,mxDesPos,mxHomePos=pshm->Motor[2].HomePos;
double myActPos,myDesPos,myHomePos=pshm->Motor[1].HomePos;
printf("Wait motion program arrived at start position...\n");
while(pshm->Coord[1].Q[0]!=-3)
rt_task_wait_period(NULL);
pshm->Coord[1].Q[0]=-2;
srvPer=pshm->ServoPeriod;
@@ -93,29 +113,30 @@ void trigsync_func(void *arg)
}
printf("Flag 0: %.5f ms\n", (rt_timer_read() - rtStart)/1E6);
pshm->Gather.Enable=2; //start gathering data
pshm->Coord[1].Q[0]=-1;
if(mode&4)
{
while(SIMFLAG1)
rt_task_wait_period(NULL);
while(!SIMFLAG1)
rt_task_wait_period(NULL);
}
else
{
while(FLAG1)
rt_task_wait_period(NULL);
while(!FLAG1)
rt_task_wait_period(NULL);
}
//puts("waitFlag1");
//gate3_1->Chan[1].Status f057f77f
//gate3_1->Chan[1].Status f057ff7f
//printf("gate3_1->Chan[1].Status %x\n",gate3_1->Chan[1].Status);
//FEL shot arrived FLAG1 0->1: first frame trigger before first cristall
pshm->Gather.Enable=2; //start gathering data
pshm->Coord[1].Q[0]=-1;
ENCVAL=0;
printf("Flag 1: %.5f ms\n", (rt_timer_read() - rtStart)/1E6);
rtStart=rtLast=rt_timer_read();
scStart=scLast=pshm->ServoCount;
mtAct=0.f;
pshm->Coord[1].Q[0]=0;
srvPer=0.2f;
//pshm->Coord[1].DesTimeBase=srvPer; //start motion at default speed
pshm->Coord[1].DesTimeBase=srvPer*(mtPt2Pt+timeOfs)/mtPt2Pt; //start motion at default speed
if(mode&8)
@@ -134,24 +155,53 @@ void trigsync_func(void *arg)
else
{
while(FLAG1)
{
rt_task_wait_period(NULL);
ENCVAL=( (i-1)*mtPt2Pt + (pshm->ServoCount-scLast)*srvPer )*1000;
}
while(!FLAG1)
{
rt_task_wait_period(NULL);
ENCVAL=( (i-1)*mtPt2Pt + (pshm->ServoCount-scLast)*srvPer )*1000;
}
}
//FEL shot arrived
//FEL shot arrived FLAG1 0->1
//ENCVAL+=mtPt2Pt*1000; //ENCVAL in us
ENCVAL=i*mtPt2Pt*1000; //ENCVAL in us
rtCur = rt_timer_read();
scCur=pshm->ServoCount;
//if (lastQ12!=(unsigned int)pshm->Coord[1].Q[12])
//{
// //'Coord[1].Q[12]=Sys.ServoCount'
// //'Coord[1].Q[13]={idxOfPoint}'
// //type of pshm->Coord[1].Q[12] is double
// lastQ12=(unsigned int)pshm->Coord[1].Q[12]; //saved ServoCount in program code
// //mxActPos=pshm->Motor[2].ActPos;mxDesPos=pshm->Motor[2].DesPos;
// //myActPos=pshm->Motor[1].ActPos;myDesPos=pshm->Motor[1].DesPos;
// //printf("*** SYNC *** Trigger count:%d, ProgIdx:%d, ServoCount diff:%d-%d=%d", i, (unsigned int)pshm->Coord[1].Q[13], lastQ12,scCur, lastQ12-scCur);
// printf("*** SYNC *** Trigger count:%d, myDesPos:%.2f, ServoCount diff:%d-%d=%d\n", i, pshm->Coord[1].Q[13]-myHomePos, lastQ12,scCur, lastQ12-scCur);
// //printf(" X,Y ActPos:(%.5g %.5g) DesPos:(%.5g %.5g)\n", mxActPos-mxHomePos, myActPos-myHomePos, mxDesPos-mxHomePos, myDesPos-myHomePos);
//}
rtDiff=rtCur-rtLast;
scDiff=scCur-scLast;
mtAct+=scDiff*srvPer;
mtAct+=scDiff*srvPer+timeCor;
mtDes=i*mtPt2Pt+timeOfs;
srvPer=(mtPt2Pt+mtDes-mtAct)/scDiff;
//srvPer=pshm->ServoPeriod; //default speed
pshm->Coord[1].DesTimeBase=srvPer;
pshm->Coord[1].Q[0]++;
if(mode&8)
printf("Trigger count:%d, rtDiff:%.3fms scDiff:%d mtAct:%.3f mtDes:%.3f srvPer:%.6f\n", i, rtDiff/1E6,scDiff, mtAct,mtDes,srvPer);
{
mxActPos=pshm->Motor[2].ActPos;mxDesPos=pshm->Motor[2].DesPos;
myActPos=pshm->Motor[1].ActPos;myDesPos=pshm->Motor[1].DesPos;
printf(" X,Y ActPos:(%.5g %.5g) DesPos:(%.5g %.5g) ", mxActPos-mxHomePos, myActPos-myHomePos, mxDesPos-mxHomePos, myDesPos-myHomePos);
printf("Trigger count:%d, rtDiff:%.3fms scDiff:%d mtAct:%.3f mtDes:%.3f srvPer:%.6f ENCVAL:%u \n", i, rtDiff/1E6,scDiff, mtAct,mtDes,srvPer,ENCVAL);
}
rtLast=rtCur;
scLast=scCur;
}
@@ -163,12 +213,13 @@ void trigsim_func(void *arg)
RT_TASK *curtask;
RT_TASK_INFO curtaskinfo;
int iret = 0;
int loopPeriod=1e7;//Expressed in ticks (this is the default task period)
curtask = rt_task_self();
rt_task_inquire(curtask, &curtaskinfo);
//Print the info
//printf("Starting task %s with period of %f ms ....\n", curtaskinfo.name,10*1E6/1E6);
printf("Starting task %s with period of %f ms ....\n", curtaskinfo.name,loopPeriod/1E6);
//Make the task periodic with a specified loop period
//rt_task_set_periodic(NULL, TM_NOW, 10*1E6);
//rt_task_set_periodic(NULL, TM_NOW, loopPeriod); //not critical here because not polling but rt_task_sleep_until ...
printf("Starting task %s \n", curtaskinfo.name);
int i,j=0;
@@ -180,9 +231,8 @@ void trigsim_func(void *arg)
for(i=0,rtSlice=rtStart;;i++)
{
rtSlice=rtStart+i*40*1E6; // a slice is 40 ms
//rtSlice=rtStart+i*40.2*1E6; // a slice is 40 ms
//rtSlice+=(rand()%(int)(1*1E6)); //0.1ms jitter
rtSlice=rtStart+i*mtPt2Pt*1E6; // a slice is mtPt2Pt ms
//rtSlice+=(rand()%(int)(1*1E6)); //0.1ms jitter to test sync
rt_task_sleep_until(rtSlice); //in ns
if(mode&4)
{
@@ -275,6 +325,11 @@ mode:\n\
bit2:4: simulate frame trigger\n\
bit3:8: verbose\n\
\n\
pt2ptTime: point to point time in ms (default=10, float value)\n\
timeOfs: once added time offset in ms (default=0, float value)\n\
scl: scale factor (so far unused, default=1, float value)\n\
\n\
\n\
simulate start trigger:\n\
set pshm->Coord[1].Q[10]=1 to simulate a Jungfrau aquire start\n\
\n\
@@ -297,7 +352,7 @@ Coord[1].Q[0]= 0 : got frame trigger 0\n\
Coord[1].Q[0] is incremented at each trigger\n\
sync task ends when Gather.Enable==0\n\
";
printf("usage:\n%s pt2ptTime timeOfs mode\n",cmd);
printf("usage:\n%s mode pt2ptTime timeOfs(default=0) scl(default=1)\n",cmd);
puts(s);
return -1;
}
@@ -308,22 +363,21 @@ int main(int argc, char *argv[])
int initialized=0;
int i;
char *s;
if(argc!=4)
return usage(argv[0]);
mtPt2Pt=strtof(argv[1], &s);
if (argv[1]==s)
return usage(argv[0]);
timeOfs=strtof(argv[2], &s);
if (argv[2]==s)
return usage(argv[0]);
mode=(int)strtol(argv[3], &s, 10);
if (argv[3]==s)
if(argc<2)
return usage(argv[0]);
mode=(int)strtol(argv[1], &s, 10);
if (argc>2)
mtPt2Pt=strtof(argv[2], &s);
if (argc>3)
timeOfs=strtof(argv[3], &s);
if (argc>4)
timeCor=strtof(argv[4], &s);
puts(argv[0]);
puts(argv[1]);
puts(argv[2]);
puts(argv[3]);
printf("mtPt2Pt:%g timeOfs:%g mode:%d\n",mtPt2Pt,timeOfs,mode);
//puts(argv[2]);
//puts(argv[3]);
//puts(argv[4]);
printf("mode:%d mtPt2Pt:%3.8gms timeOfs:%3.8gms timeCor:%3.8gms\n",mode,mtPt2Pt,timeOfs,timeCor);
if ((err = InitLibrary()) != 0) {
abort();
}