144 lines
5.5 KiB
Python
Executable File
144 lines
5.5 KiB
Python
Executable File
""" Diffractometer
|
|
|
|
motorized axis:
|
|
|
|
SARES30-CPCL-ECMC02:ROT2THETA
|
|
SARES30-CPCL-ECMC02:ROTTHETA
|
|
SARES30-CPCL-ECMC02:TRXBASE
|
|
SARES30-CPCL-ECMC02:TRYBASE
|
|
|
|
"""
|
|
|
|
import time
|
|
|
|
from slic.core.adjustable import PVAdjustable, Linked, Adjustable, Collection
|
|
from slic.core.device import Device
|
|
from slic.devices.general.motor import Motor
|
|
|
|
class MotorECMC(Motor):
|
|
'''Regular motor class with extras for ECMC servo motors (tolerance deadbands, PIDs ...)'''
|
|
def __init__(self, ID, **kwargs):
|
|
super().__init__(ID, **kwargs)
|
|
self.deadband_epics = PVAdjustable(self.name+'-SetAtTrgtDB',units='mm',name='Tolerance deadband for EPICS target reached flag.')
|
|
self.deadband_ecmc = PVAdjustable(self.name+'-SetCtrlDB',units='mm', name='Tolerance deadband for ECMC servo motor control')
|
|
self.deadbands = Collection(self.name+'motion deadbands',[self.deadband_epics,self.deadband_ecmc])
|
|
|
|
self.p = PVAdjustable(self.name+'-Ctrl-Kp',name='P parameter')
|
|
self.i = PVAdjustable(self.name+'-Ctrl-Ki',name='I parameter')
|
|
self.d = PVAdjustable(self.name+'-Ctrl-Kd',name='D parameter')
|
|
self.pids = Collection(self.name+'PID values',[self.p,self.i,self.d])
|
|
self.enabled = PVAdjustable(self.name+'-EnaCmd',name='Axis enabled')
|
|
|
|
class Diffractometer(Device):
|
|
def __init__(self, ID, **kwargs):
|
|
super().__init__(ID, **kwargs)
|
|
|
|
self.twotheta = MotorECMC(ID + ":ROT2THETA") # , ID=None, name=None, units=None, internal=False):
|
|
self.theta = MotorECMC(ID + ":ROTTHETA") # , ID=None, name=None, units=None, internal=False):
|
|
|
|
self.trx_base = MotorECMC(ID + ":TRXBASE") # , ID=None, name=None, units=None, internal=False):
|
|
self.try_base = MotorECMC(ID + ":TRYBASE") # , ID=None, name=None, units=None, internal=False):
|
|
|
|
self.tr_x = MotorECMC(ID + ":TRX")
|
|
self.tr_y = MotorECMC(ID + ":TRY")
|
|
self.tr_z = MotorECMC(ID + ":TRZ")
|
|
|
|
self.td = MotorECMC(ID + ":TD")
|
|
self.td_y = Motor("SARES30-MOBI2:MOT_Z") # Extra Huber stage for the diffractometer motor
|
|
|
|
if ID == "SARES32-GPS":
|
|
self.name = "DM2: Cristallina pulsed magnet diffractometer"
|
|
# This diffractometer also has extra swivel stages
|
|
self.rot_x = MotorECMC(ID + ":ROTX")
|
|
self.rot_z = MotorECMC(ID + ":ROTZ")
|
|
self.axes = Collection(self.name+'movable axes',[self.twotheta,self.theta,self.tr_x,self.tr_y,self.tr_z,self.td,self.trx_base,self.try_base,
|
|
self.rot_x,self.rot_z])
|
|
if ID == "SARES31-GPS":
|
|
self.name = "DM1: Cristallina dilution fridge diffractometer"
|
|
self.axes = Collection(self.name+'movable axes',[self.twotheta,self.theta,self.tr_x,self.tr_y,self.tr_z,self.td,self.trx_base,self.try_base])
|
|
|
|
|
|
def enable_all_axes(self):
|
|
for axis in self.axes.adjs:
|
|
axis.enabled.set_target_value(True).wait()
|
|
|
|
def disable_all_axes(self):
|
|
for axis in self.axes.adjs:
|
|
axis.enabled.set_target_value(False).wait()
|
|
|
|
|
|
# class Diffractometer(Device):
|
|
# def __init__(self, ID, motor_naming="MOTOR", **kwargs):
|
|
# super().__init__(ID, **kwargs)
|
|
|
|
# self.twotheta = Motor("SARES30-CPCL-ECMC02:ROT2THETA") # , ID=None, name=None, units=None, internal=False):
|
|
# self.theta = Motor("SARES30-CPCL-ECMC02:ROTTHETA") # , ID=None, name=None, units=None, internal=False):
|
|
|
|
# self.trx_base = Motor("SARES30-CPCL-ECMC02:TRXBASE") # , ID=None, name=None, units=None, internal=False):
|
|
# self.try_base = Motor("SARES30-CPCL-ECMC02:TRYBASE") # , ID=None, name=None, units=None, internal=False):
|
|
|
|
# self.tr_x = Motor("SARES30-CPCL-ECMC02:TRX")
|
|
# self.tr_y = Motor("SARES30-CPCL-ECMC02:TRY")
|
|
# self.tr_z = Motor("SARES30-CPCL-ECMC02:TRZ")
|
|
|
|
# self.td = Motor("SARES30-CPCL-ECMC02:TD")
|
|
|
|
|
|
# Set speed:
|
|
# diffractometer.theta._motor.VELO = 0.25
|
|
|
|
class ThetasCombined(Linked):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(self, *args, **kwargs)
|
|
|
|
def connect_axis(self):
|
|
"""
|
|
calculate offset to match scale factor
|
|
"""
|
|
|
|
offset = self.secondary.get_current_value() - self.primary.get_current_value() * self.scale_factor
|
|
self.offset = offset
|
|
|
|
|
|
class DelayAxis(MotorECMC):
|
|
def __init__(self, axis, delay_after_move=1):
|
|
#super().__init__(self, *args, **kwargs)#
|
|
delay_time = delay_after_move
|
|
self.axis = axis
|
|
|
|
def set_target_value(self, value):
|
|
start_time = time.time()
|
|
|
|
self.axis.set_target_value(value)
|
|
while self.axis.is_moving():
|
|
time.sleep(0.1)
|
|
|
|
elapsed = time.time() - start_time
|
|
wait_time = max(0, self.delay_time - elapsed)
|
|
time.sleep(wait_time)
|
|
|
|
|
|
class Delayed(Adjustable):
|
|
def __init__(self, ID, adj, delay_after_move=0, **kwargs):
|
|
super().__init__(ID, **kwargs)
|
|
self.adj = adj
|
|
self.delay_after_move = delay_after_move
|
|
|
|
def get_current_value(self):
|
|
value = self.adj.get_current_value()
|
|
return value
|
|
|
|
def set_target_value(self, value):
|
|
start_time = time.time()
|
|
|
|
self.adj.set_target_value(value).wait()
|
|
|
|
while self.adj.is_moving():
|
|
time.sleep(0.02)
|
|
|
|
elapsed = time.time() - start_time
|
|
wait_time = max(0, self.delay_time - elapsed)
|
|
time.sleep(wait_time)
|
|
|
|
def is_moving(self):
|
|
return self.adj.is_moving() |