feat: add first draft for mo1bragg ophyd positioner
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
from ophyd import Device, PositionerBase, EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV, Kind, Signal, DeviceStatus
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd.utils import LimitError
|
||||
from typing import Literal
|
||||
import enum
|
||||
|
||||
class Mo1BraggError(Exception):
|
||||
"""Mo1Bragg specific exception"""
|
||||
|
||||
class MoveType(str, enum.Enum):
|
||||
ENERGY = 'energy'
|
||||
ANGLE = 'angle'
|
||||
|
||||
class MoveTypeSignal(Signal):
|
||||
""" Custom Signal to set the move type of the Bragg positioner"""
|
||||
|
||||
def set(self, value:str | MoveType) -> None:
|
||||
""" Returns currently active move method
|
||||
|
||||
Args:
|
||||
value (str | MoveType) : Can be either 'energy' or 'angle'
|
||||
"""
|
||||
if value not in ['energy', 'angle']:
|
||||
raise ValueError(f"Invalid input for MoveTypeSignal {value}, can be either 'energy' or 'angle'")
|
||||
self._readback = value
|
||||
|
||||
class Mo1Bragg(Device, PositionerBase):
|
||||
|
||||
USER_ACCESS = ["set_xtal"]
|
||||
|
||||
offset_si111 = Cpt(EpicsSignalWithRBV, suffix='offset_si111', kind=Kind.config, auto_monitor=True)
|
||||
offset_si311 = Cpt(EpicsSignalWithRBV, suffix='offset_si311', kind=Kind.config, auto_monitor=True)
|
||||
# For the moment commented until the PV suffix in EPICS changes (RBV was on xtal_RBV_ENUM -> xtal_ENUM_RBV)
|
||||
xtal_enum = Cpt(EpicsSignal, suffix='xtal_ENUM', kind=Kind.config, auto_monitor=True)
|
||||
d_spacing_si111 = Cpt(EpicsSignalWithRBV, suffix='d_spacing_si111', kind=Kind.config, auto_monitor=True)
|
||||
d_spacing_si311 = Cpt(EpicsSignalWithRBV, suffix='d_spacing_si311', kind=Kind.config, auto_monitor=True)
|
||||
set_offset = Cpt(EpicsSignal, suffix ='set_offset', kind=Kind.config)
|
||||
current_xtal = Cpt(EpicsSignalRO, suffix='current_xtal_RBV_ENUM', kind=Kind.normal, auto_monitor=True)
|
||||
move_type = Cpt(MoveTypeSignal, value='energy', kind=Kind.normal)
|
||||
|
||||
feedback_pos_energy = Cpt(EpicsSignalRO, suffix="feedback_pos_energy_RBV", kind=Kind.hinted, auto_monitor=True)
|
||||
feedback_pos_angle = Cpt(EpicsSignalRO, suffix="feedback_pos_angle_RBV", kind=Kind.hinted, auto_monitor=True)
|
||||
low_limit_angle = Cpt(EpicsSignalRO, suffix="lo_lim_pos_RBV", kind=Kind.config, auto_monitor=True)
|
||||
high_limit_angle = Cpt(EpicsSignalRO, suffix="hi_lim_pos_RBV", kind=Kind.config, auto_monitor=True)
|
||||
|
||||
move_velocity = Cpt(EpicsSignalWithRBV, suffix="move_velocity", kind=Kind.config, auto_monitor=True)
|
||||
setpoint_abs_angle = Cpt(EpicsSignalWithRBV, suffix="set_abs_pos_angle", kind=Kind.normal, auto_monitor=True)
|
||||
setpoint_abs_energy = Cpt(EpicsSignalWithRBV, suffix="set_abs_pos_energy", kind=Kind.normal, auto_monitor=True)
|
||||
setpoint_rel_angle = Cpt(EpicsSignalWithRBV, suffix="set_rel_pos_angle", kind=Kind.normal, auto_monitor=True)
|
||||
setpoint_rel_energy = Cpt(EpicsSignalWithRBV, suffix="set_rel_pos_energy", kind=Kind.normal, auto_monitor=True)
|
||||
|
||||
move_abs = Cpt(EpicsSignal, suffix="move_abs", kind=Kind.config)
|
||||
move_abs_done = Cpt(EpicsSignalRO, suffix="move_abs_done_RBV", kind=Kind.normal, auto_monitor=True)
|
||||
|
||||
SUB_READBACK = "readback"
|
||||
_default_sub = SUB_READBACK
|
||||
|
||||
@property
|
||||
def limits(self) -> tuple:
|
||||
"""Return limits of the Bragg positioner"""
|
||||
if self.move_type.get() == 'energy':
|
||||
raise NotImplementedError("PVs need to still be exposed to the softIOC")
|
||||
# return ()
|
||||
return (self.low_limit_angle.get(), self.high_limit_angle.get())
|
||||
|
||||
@property
|
||||
def low_limit(self) -> float:
|
||||
""" Return low limit of axis"""
|
||||
return self.limits[0]
|
||||
|
||||
@property
|
||||
def high_limit(self) -> float:
|
||||
""" Return high limit of axis"""
|
||||
return self.limits[1]
|
||||
|
||||
#pylint: disable:arguments-differ
|
||||
def check_value(self, value:float) -> None:
|
||||
""" Check if value is within limits
|
||||
|
||||
Args:
|
||||
value (float) : value to move axis to.
|
||||
"""
|
||||
low_limit, high_limit = self.limits
|
||||
|
||||
if low_limit < high_limit and not low_limit <= value <= high_limit:
|
||||
raise LimitError(f"position={value} not within limits {self.limits}")
|
||||
|
||||
|
||||
# def move(self, value:float, move_type:str='angle', **kwargs) -> DeviceStatus:
|
||||
# self._stopped = False
|
||||
# status = super().move(value)
|
||||
# # Start motion
|
||||
|
||||
# def thread_function(status):
|
||||
# while self.move_abs_done == 0
|
||||
# self._run_subs(sub_type=self.SUB_READBACK, value = self.feedback_pos_angle.get())
|
||||
|
||||
# if self._stopped ==True:
|
||||
# status.set_exception()
|
||||
# return
|
||||
|
||||
# status.set_finished()
|
||||
|
||||
# def stop()->None:
|
||||
# self._stopped=True
|
||||
|
||||
|
||||
|
||||
|
||||
# def _move_and_finished(self, start_pos, stop_pos, st):
|
||||
|
||||
# success = True
|
||||
|
||||
|
||||
|
||||
|
||||
def set_xtal(self,
|
||||
xtal_enum:Literal['111', '311'],
|
||||
offset_si111:float=None,
|
||||
offset_si311:float=None,
|
||||
d_spacing_si111:float=None,
|
||||
d_spacing_si311:float=None,
|
||||
)->None:
|
||||
""" Method to set the crystal
|
||||
|
||||
Args:
|
||||
"""
|
||||
if offset_si111 is not None:
|
||||
self.offset_si111.set(offset_si111)
|
||||
if offset_si311 is not None:
|
||||
self.offset_si311.set(offset_si311)
|
||||
if d_spacing_si111 is not None:
|
||||
self.d_spacing_si111.set(d_spacing_si111)
|
||||
if d_spacing_si311 is not None:
|
||||
self.d_spacing_si311.set(d_spacing_si311)
|
||||
if xtal_enum == '111':
|
||||
crystal_set = 0
|
||||
elif xtal_enum == '311':
|
||||
crystal_set = 1
|
||||
else:
|
||||
raise ValueError(f"Invalid argument for xtal_enum : {xtal_enum}, choose from '111' or '311'")
|
||||
self.xtal_enum.set(crystal_set)
|
||||
self.set_offset.set(1)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
#bragg = Mo1Bragg(name='bragg', prefix="X01DA-OP-MO1:BRAGG:")
|
||||
pass
|
||||
Reference in New Issue
Block a user