#!/usr/bin/env python # *-----------------------------------------------------------------------* # | | # | Copyright (c) 2014 by Paul Scherrer Institute (http://www.psi.ch) | # | | # | Author Thierry Zamofing (thierry.zamofing@psi.ch) | # *-----------------------------------------------------------------------* """ motion procedures for PSSS: mode: 0: homing 1: calc energy and SPECTRUM_X out of camera arm angle move CamPosX out of CristBendRot """ from __future__ import print_function from errno import ENETRESET import logging, sys, os, json import CaChannel, time import numpy as np class PSSS: def __init__(self, args): # import pdb; pdb.set_trace() # sys.exit() # {'mode': 0, 'stdout': True, 'var': []} # {'mode': 5, 'stdout': True, 'var': ['SARFE10-PSSS059']} self.args = args prefix = self.args.var[0] prefix = prefix[0 : prefix.find("-") + 1] self.prefix = prefix # print('Prefix='+prefix) self.pv = dict() def getPv(self, name): try: pv = self.pv[name] except KeyError: prefix = self.prefix pv = CaChannel.CaChannel(prefix + name) pv.searchw() self.pv[name] = pv return pv def moveLimit(self, m, val): self.moveAbs(m, val) def waitMotionDone(self, m): s = m + ".DMOV" pv = self.getPv(s) sys.stdout.write("wait motion " + s + " ") sys.stdout.flush() while pv.getw() == 0: sys.stdout.write(".") sys.stdout.flush() time.sleep(0.1) print("done") def setPos(self, m, ofs): pvSET = self.getPv(m + ".SET") pvVAL = self.getPv(m + ".VAL") pvSET.putw(1) # Set print("set ofset to %f" % ofs) pvVAL.putw(ofs) # set value (without move) time.sleep(0.1) # wait for safety pvSET.putw(0) # Use time.sleep(0.1) # wait for safety def moveAbs(self, m, val): pvVAL = self.getPv(m + ".VAL") pvVAL.putw(val) # set position and move def homing(self): pvNameLst = ( "PSSS055:MOTOR_ROT_X1", "PSSS055:MOTOR_X1", "PSSS055:MOTOR_Y1", "PSSS055:MOTOR_PROBE", "PSSS059:MOTOR_X5", "PSSS059:MOTOR_Y5", "PSSS059:MOTOR_Z5", "PSSS059:MOTOR_X3", "PSSS059:MOTOR_Y3", ) pvHOME = self.getPv("PSSS059:HOMING.VAL") if pvHOME.getw(1) == 1: print("homing still in progress. abort new procedure") # return pvHOME.putw(1) # homing in progress try: pvHomr = self.getPv(pvNameLst[0] + ".HOMR") pvHomr.putw(1) # homing MOTOR_ROT_X1 self.waitMotionDone(pvNameLst[0]) homing = ( (1, 200, 10, 0), # PSSS055:MOTOR_X1 Home on +limit switch to +10mm (2, 10, 4.475, 2.22), # PSSS055:MOTOR_Y1 Home on +limit switch to +4.475mm (3, 50, 0, -9), # PSSS055:MOTOR_PROBE Home on +limit switch to +0mm (4, 80, 35, 0), # PSSS059:MOTOR_X5 Home on +limit switch to +35mm (5, 30, 10, 0), # PSSS059:MOTOR_Y5 Home on +limit switch to +10mm # (6,20,8.9,0), # PSSS059:MOTOR_Z5 Home on +limit switch to +8.9mm Set HLM to 10, LLM to -2mm (7, 30, 1, 0), # PSSS059:MOTOR_X3 Home on +limit switch to +10mm (8, 30, 1, -1.4), # PSSS059:MOTOR_Y3 Home on +limit switch to +10mm ) for idx, mvLim, setPos, mvPos in homing: pvName = pvNameLst[idx] print("homing %s %f %f %f" % (pvName, mvLim, setPos, mvPos)) self.moveLimit(pvName, mvLim) for idx, mvLim, setPos, mvPos in homing: pvName = pvNameLst[idx] self.waitMotionDone(pvName) self.setPos(pvName, setPos) time.sleep(2) print("sleep 2 sec.") for idx, mvLim, setPos, mvPos in homing: pvName = pvNameLst[idx] self.moveAbs(pvName, mvPos) for idx, mvLim, setPos, mvPos in homing: pvName = pvNameLst[idx] self.waitMotionDone(pvName) except AssertionError as e: # BaseException as e: print(e) pvHOME.putw(3) # homing failed else: pvHOME.putw(2) # homing done def set_energy_motor(self, energy2motor, scan=False, rotWait=False): crystalType = self.getPv("PSSS059:CRYSTAL_SP").getw() # crystalType=2 # print(crystalType) # print(type(crystalType)) if crystalType == 0: return # 0 None # 1 Si(111)R155 # 2 Si(220)R75 # 3 Si(220)R145 # 4 Si(220)R200 # 5 Si(333)R155 # load lut fnXtlLst = (None, "Si111R155", "Si220R75", "Si220R145", "Si220R200", "Si333R155") # print(__file__) base = os.path.dirname(__file__) fn = os.path.join(base, "lut" + fnXtlLst[crystalType] + ".txt") lut = np.genfromtxt(fn, delimiter="\t", names=True) # lut # lut.dtype # lut[1]['Energy'] # lut['Energy'] # lut=np.genfromtxt(fn, delimiter='\t',skip_header=1) if energy2motor: energy = self.getPv("PSSS059:ENERGY").getw() # energy =6000 gratingType = self.getPv("PSSS055:GRATING_SP").getw() # gratingType=3 camPosX = "CamPosX" if gratingType in (1, 2): camPosX += "_100nm" elif gratingType == 3: camPosX += "_150nm" elif gratingType == 4: camPosX += "_200nm" camArmRot = np.interp(energy, lut["Energy"], lut["CamArmRot"]) cristBendRot = np.interp(energy, lut["Energy"], lut["CristBendRot"]) camPosX = np.interp(energy, lut["Energy"], lut[camPosX]) evPerPix = np.interp(energy, lut["Energy"], lut["EvPerPix"]) else: camArmRot = self.getPv("PSSS059:MOTOR_ROT_X4").getw() idx = ~np.isnan(lut["CamArmRot"]) lutCamArmRot = lut["CamArmRot"][idx] energy = np.interp(camArmRot, lutCamArmRot[::-1], lut["Energy"][idx][::-1]) evPerPix = np.interp(camArmRot, lutCamArmRot[::-1], lut["EvPerPix"][idx][::-1]) # camera: 2560 x 2160 n = 2560 i = np.arange(n) - n / 2 spctr_x = energy + i * evPerPix pv = self.getPv("PSSS059:SPECTRUM_X") pv.putw(spctr_x) pv = self.getPv("PSSS059:SPECTRUM_Y") mu = 2560.0 / 2 sigma = 100.0 x = np.arange(2560.0) spctr_y = 1000.0 * np.exp(-((x - mu) ** 2 / (2.0 * sigma**2))) pv.putw(spctr_y) if energy2motor: print( "energy2motor: camArmRot: %g cristBendRot: %g camPosX:%g evPerPix:%g" % (camArmRot, cristBendRot, camPosX, evPerPix) ) pv = self.getPv("PSSS059:MOTOR_ROT_X4") pv.putw(camArmRot) pv = self.getPv("PSSS059:MOTOR_ROT_X3") pv.putw(cristBendRot) if rotWait == True: self.waitMotionDone("PSSS059:MOTOR_ROT_X3") if scan == False: # if True the camera X position will not be changed pv = self.getPv("PSSS059:MOTOR_X5") pv.putw(camPosX) else: print("motor2energy: energy: %g evPerPix:%g" % (energy, evPerPix)) pv = self.getPv("PSSS059:ENERGY") pv.putw(energy) def grating2motor(self): energy = self.getPv("PSSS059:ENERGY").getw() gratingType = self.getPv("PSSS055:GRATING_SP").getw() if gratingType == 0: print("no grating") girderX = 0.0 else: base = os.path.dirname(__file__) fn = fn = os.path.join(base, "lutGirderXTrans.txt") lut = np.genfromtxt(fn, delimiter="\t", names=True) d = {1: "100nm", 2: "100nm", 3: "150nm", 4: "200nm"} print(gratingType) grtStr = d[gratingType] girderX = np.interp(energy, lut["Energy"], lut[grtStr]) print("girderX:%g" % (girderX)) pv = self.getPv("PSSS059:MOTOR_X2") pv.putw(girderX) if __name__ == "__main__": 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" (h, t) = os.path.split(sys.argv[0]) cmd = "\n " + (t if len(h) > 3 else sys.argv[0]) + " " exampleCmd = ("MYPREFIX",) epilog = ( __doc__ + """ Examples:""" + "".join(map(lambda s: cmd + s, exampleCmd)) + "\n " ) fmt = MyFormatter() parser = OptionParser(epilog=epilog, formatter=fmt) parser.add_option("-m", "--mode", type="int", help="move instead of homing", default=0) parser.add_option("-s", "--stdout", action="store_true", help="log to stdout instead of file") (args, other) = parser.parse_args() # print(args,other) args.var = other # args.var=('SARFE10-',) fn = ( "/afs/psi.ch/intranet/Controls/scratch/" + os.path.basename(__file__) + "_" + os.environ.get("USER") + ".log" ) if not args.stdout: print("output redirected to file:\n" + fn) stdoutBak = sys.stdout sys.stdout = open(fn, "a+") print("*" * 30 + "\n" + time.ctime() + ": run on host:" + os.environ.get("HOSTNAME")) print("Args:" + str(args) + " " + str(args.var)) sys.stdout.flush() psss = PSSS(args) if args.mode == 0: psss.homing() elif args.mode == 1: psss.set_energy_motor(energy2motor=True) elif args.mode == 2: psss.set_energy_motor(energy2motor=False) elif args.mode == 3: psss.grating2motor() elif args.mode == 4: psss.set_energy_motor(energy2motor=True, scan=True) elif args.mode == 5: psss.set_energy_motor(energy2motor=True, scan=True, rotWait=True) print("PSSS_motion done.") return # os.environ['EPICS_CA_ADDR_LIST']='localhost' # os.environ['EPICS_CA_ADDR_LIST']='172.26.0.255 172.26.2.255 172.26.8.255 172.26.16.255 172.26.24.255 172.26.32.255 172.26.40.255 172.26.110.255 172.26.111.255 172.26.120.255 129.129.242.255 129.129.243.255' parse_args()