From 53d4a148458bccdde0390a61821840930d2ec78a Mon Sep 17 00:00:00 2001 From: vshekar1 Date: Wed, 11 Dec 2024 16:07:55 -0500 Subject: [PATCH 1/4] Changed cryostream PV --- config_params.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_params.py b/config_params.py index 4eec0140..d6509d76 100644 --- a/config_params.py +++ b/config_params.py @@ -91,7 +91,7 @@ class OnMountAvailOptions(Enum): DEWAR_SECTORS = {'amx':8, 'fmx':8, 'nyx':8} PUCKS_PER_DEWAR_SECTOR = {'amx':3, 'fmx':3, 'nyx':3} -cryostreamTempPV = {"amx": "XF:17IDB-ES:AMX{CS:1}SAMPLE_TEMP_RBV", "fmx": "FMX:cs700:gasT-I", "nyx":"XF:19ID2:CS700:TEMP"} +cryostreamTempPV = {"amx": "XF:17ID1:CS700:TEMP", "fmx": "FMX:cs700:gasT-I", "nyx":"XF:19ID2:CS700:TEMP"} VALID_EXP_TIMES = { "amx": {"min": 0.005, "max": 1, "digits": 3}, From ddb64c57af701e1fd676833e130adc41e9661090 Mon Sep 17 00:00:00 2001 From: vshekar1 Date: Mon, 4 Nov 2024 17:44:30 -0500 Subject: [PATCH 2/4] Added cs700 PVPositioner Added cs700 PVPositioner for both AMX and FMX --- mxbluesky/devices/base_devices.py | 297 ++++++++++++++++++++++++++++++ mxbluesky/devices/generic.py | 20 +- start_bs.py | 5 +- 3 files changed, 319 insertions(+), 3 deletions(-) create mode 100644 mxbluesky/devices/base_devices.py diff --git a/mxbluesky/devices/base_devices.py b/mxbluesky/devices/base_devices.py new file mode 100644 index 00000000..6f839330 --- /dev/null +++ b/mxbluesky/devices/base_devices.py @@ -0,0 +1,297 @@ +from ophyd.pv_positioner import PVPositioner +from ophyd import Component as Cpt +from ophyd.signal import Signal +from ophyd.utils import ReadOnlyError +import numpy as np +from typing import Optional + +# Note: These signals and devices are available in the latest versions of ophyd +# The reason its copied here is because LSDC GUI uses python 3.6 and ophyd needs +# python >= 3.8. Can safely be deleted once LSDC python is upgraded + + +class InternalSignalMixin: + """ + Mix-in class for adding the `InternalSignal` behavior to any signal class. + + A signal class with this mixin will reject all sets and puts unless + internal=True is passed as an argument. + + The intended use for this is to signify that a signal is for internal use + by the class only. That is, it would be a mistake to try to cause puts to + this signal by code external to the Device class. + + Some more concrete use-cases would be things like soft "status" type + signals that should be read-only except that the class needs to edit it, + or EPICS signals that should be written to by the class but are likely to + cause issues for external writes due to behavior complexity. + """ + + def put(self, *args, internal: bool = False, **kwargs): + """ + Write protection for an internal signal. + + This method is not intended to be used from outside of the device + that defined this signal. All writes must be done with internal=True. + """ + if not internal: + raise InternalSignalError() + return super().put(*args, **kwargs) + + def set(self, *args, internal: bool = False, **kwargs): + """ + Write protection for an internal signal. + + This method is not intended to be used from outside of the device + that defined this signal. All writes must be done with internal=True. + """ + if not internal: + raise InternalSignalError() + return super().set(*args, internal=internal, **kwargs) + + +class InternalSignal(InternalSignalMixin, Signal): + """ + A soft Signal that stores data but should only be updated by the Device. + + Unlike SignalRO, which will unilaterally block all writes, this will + allow writes with internal=True. + + The intended use for this is to signify that a signal is for internal use + by the class only. That is, it would be a mistake to try to cause puts to + this signal by code external to the Device class. + + Some more concrete use-cases would be things like soft "status" type + signals that should be read-only except that the class needs to edit it, + or calculated "done" signals for positioner classes. + """ + + +class InternalSignalError(ReadOnlyError): + """ + A read-only error sourced from trying to write to an internal signal. + """ + + def __init__(self, message=None): + if message is None: + message = ( + "This signal is for internal use only. " + "You should not be writing to it from outside " + "the parent class. If you do need to write to " + "this signal, you can use signal.put(value, internal=True)." + ) + super().__init__(message) + + +class PVPositionerComparator(PVPositioner): + """ + PV Positioner with a software done signal. + + The done state is set by a comparison function defined in the class body. + The comparison function takes two arguments, readback and setpoint, + returning True if we are considered done or False if we are not. + + This class is intended to support `PVPositionerIsClose`, but exists to + allow some flexibility if we want to use other metrics for deciding if + the PVPositioner is done. + + Internally, this will subscribe to both the ``setpoint`` and ``readback`` + signals, updating ``done`` as appropriate. + + Parameters + ---------- + prefix : str, optional + The device prefix used for all sub-positioners. This is optional as it + may be desirable to specify full PV names for PVPositioners. + limits : 2-element sequence, optional + (low_limit, high_limit) + name : str + The device name + egu : str, optional + The engineering units (EGU) for the position + settle_time : float, optional + The amount of time to wait after moves to report status completion + timeout : float, optional + The default timeout to use for motion requests, in seconds. + + Attributes + ---------- + setpoint : Signal + The setpoint (request) signal + readback : Signal or None + The readback PV (e.g., encoder position PV) + actuate : Signal or None + The actuation PV to set when movement is requested + actuate_value : any, optional + The actuation value, sent to the actuate signal when motion is + requested + stop_signal : Signal or None + The stop PV to set when motion should be stopped + stop_value : any, optional + The value sent to stop_signal when a stop is requested + put_complete : bool, optional + If set, the specified PV should allow for asynchronous put completion + to indicate motion has finished. If ``actuate`` is specified, it will be + used for put completion. Otherwise, the ``setpoint`` will be used. See + the `-c` option from ``caput`` for more information. + """ + + done = Cpt(InternalSignal, value=0) + done_value = 1 + + def __init__(self, prefix: str, *, name: str, **kwargs): + self._last_readback = None + self._last_setpoint = None + super().__init__(prefix, name=name, **kwargs) + if None in (self.setpoint, self.readback): + raise NotImplementedError( + "PVPositionerComparator requires both " + "a setpoint and a readback signal to " + "compare!" + ) + + def __init_subclass__(cls, **kwargs): + """Set up callbacks in subclass.""" + super().__init_subclass__(**kwargs) + if None not in (cls.setpoint, cls.readback): + cls.setpoint.sub_value(cls._update_setpoint) + cls.readback.sub_value(cls._update_readback) + + def done_comparator(self, readback: Any, setpoint: Any) -> bool: + """ + Override done_comparator in your subclass. + + This method should return True if we are done moving + and False otherwise. + """ + raise NotImplementedError("Must implement a done comparator!") + + def _update_setpoint(self, *args, value: Any, **kwargs) -> None: + """Callback to cache the setpoint and update done state.""" + self._last_setpoint = value + # Always set done to False when a move is requested + # This means we always get a rising edge when finished moving + # Even if the move distance is under our done moving tolerance + self.done.put(0, internal=True) + self._update_done() + + def _update_readback(self, *args, value: Any, **kwargs) -> None: + """Callback to cache the readback and update done state.""" + self._last_readback = value + self._update_done() + + def _update_done(self) -> None: + """Update our status to done if we pass the comparator.""" + if None not in (self._last_readback, self._last_setpoint): + is_done = self.done_comparator(self._last_readback, self._last_setpoint) + done_value = int(is_done) + if done_value != self.done.get(): + self.done.put(done_value, internal=True) + + +class PVPositionerIsClose(PVPositionerComparator): + """ + PV Positioner that updates done state based on np.isclose. + + Effectively, this will treat our move as complete if the readback is + sufficiently close to the setpoint. This is generically helpful for + PV positioners that don't have a ``done`` signal built into the hardware. + + The arguments atol and rtol can be set as class attributes or passed as + initialization arguments. + + atol is a measure of absolute tolerance. If atol is 0.1, then you'd be + able to be up to 0.1 units away and still count as done. This is + typically the most useful parameter for calibrating done tolerance. + + rtol is a measure of relative tolerance. If rtol is 0.1, then you'd be + able to deviate from the goal position by up to 10% of its value. This + is useful for small quantities. For example, defining an atol for a + positioner that ranges from 1e-8 to 2e-8 could be somewhat awkward. + + Parameters + ---------- + prefix : str, optional + The device prefix used for all sub-positioners. This is optional as it + may be desirable to specify full PV names for PVPositioners. + limits : 2-element sequence, optional + (low_limit, high_limit) + name : str + The device name + egu : str, optional + The engineering units (EGU) for the position + settle_time : float, optional + The amount of time to wait after moves to report status completion + timeout : float, optional + The default timeout to use for motion requests, in seconds. + atol : float, optional + A measure of absolute tolerance. If atol is 0.1, then you'd be + able to be up to 0.1 units away and still count as done. + rtol : float, optional + A measure of relative tolerance. If rtol is 0.1, then you'd be + able to deviate from the goal position by up to 10% of its value + + Attributes + ---------- + setpoint : Signal + The setpoint (request) signal + readback : Signal or None + The readback PV (e.g., encoder position PV) + actuate : Signal or None + The actuation PV to set when movement is requested + actuate_value : any, optional + The actuation value, sent to the actuate signal when motion is + requested + stop_signal : Signal or None + The stop PV to set when motion should be stopped + stop_value : any, optional + The value sent to stop_signal when a stop is requested + put_complete : bool, optional + If set, the specified PV should allow for asynchronous put completion + to indicate motion has finished. If ``actuate`` is specified, it will be + used for put completion. Otherwise, the ``setpoint`` will be used. See + the `-c` option from ``caput`` for more information. + atol : float, optional + A measure of absolute tolerance. If atol is 0.1, then you'd be + able to be up to 0.1 units away and still count as done. + rtol : float, optional + A measure of relative tolerance. If rtol is 0.1, then you'd be + able to deviate from the goal position by up to 10% of its value + """ + + atol: Optional[float] = None + rtol: Optional[float] = None + + def __init__( + self, + prefix: str, + *, + name: str, + atol: Optional[float] = None, + rtol: Optional[float] = None, + **kwargs, + ): + if atol is not None: + self.atol = atol + if rtol is not None: + self.rtol = rtol + super().__init__(prefix, name=name, **kwargs) + + def done_comparator(self, readback: float, setpoint: float) -> bool: + """ + Check if the readback is close to the setpoint value. + + Uses numpy.isclose to make the comparison. Tolerance values + atol and rtol for numpy.isclose are taken from the attributes + self.atol and self.rtol, which can be defined as class attributes + or passed in as init parameters. + + If atol or rtol are omitted, the default values from numpy are + used instead. + """ + kwargs = {} + if self.atol is not None: + kwargs["atol"] = self.atol + if self.rtol is not None: + kwargs["rtol"] = self.rtol + return np.isclose(readback, setpoint, **kwargs) diff --git a/mxbluesky/devices/generic.py b/mxbluesky/devices/generic.py index e9c9cbdd..98595e5c 100644 --- a/mxbluesky/devices/generic.py +++ b/mxbluesky/devices/generic.py @@ -1,6 +1,8 @@ from ophyd import Component as Cpt -from ophyd import Device, EpicsMotor, EpicsSignal +from ophyd import Device, EpicsMotor, EpicsSignal, EpicsSignalRO from mxbluesky.devices import standardize_readback +from mxbluesky.devices.base_devices import PVPositionerIsClose +from enum import IntEnum, unique class WorkPositions(Device): gx = Cpt(EpicsSignal, "{Gov:Robot-Dev:gx}Pos:Work-Pos") @@ -33,4 +35,18 @@ def __init__(self, *args, **kwargs): self.cy = self.py self.z = self.pz self.cz = self.pz - self.omega = self.o \ No newline at end of file + +@unique +class CryoStreamCmd(IntEnum): + START_RAMP = 1 + STOP_RAMP = 0 + + +class CryoStream(PVPositionerIsClose): + readback = Cpt(EpicsSignalRO, 'TEMP') + setpoint = Cpt(EpicsSignal, 'RTEMP') + actuate = Cpt(EpicsSignal, "RAMP.PROC") + actuate_value = CryoStreamCmd.START_RAMP + stop_signal = Cpt(EpicsSignal, "RAMP.PROC") + stop_value = CryoStreamCmd.STOP_RAMP + diff --git a/start_bs.py b/start_bs.py index 44064966..770f3d2a 100755 --- a/start_bs.py +++ b/start_bs.py @@ -114,6 +114,7 @@ class SampleXYZ(Device): if (beamline=="amx"): from mxbluesky.devices import (WorkPositions, TwoClickLowMag, LoopDetector, MountPositions, TopAlignerFast, TopAlignerSlow, GoniometerStack) + from mxbluesky.devices.generic import CryoStream mercury = ABBIXMercury('XF:17IDB-ES:AMX{Det:Mer}', name='mercury') mercury.read_attrs = ['mca.spectrum', 'mca.preset_live_time', 'mca.rois.roi0.count', 'mca.rois.roi1.count', 'mca.rois.roi2.count', 'mca.rois.roi3.count'] @@ -144,11 +145,12 @@ class SampleXYZ(Device): loop_detector = LoopDetector(name="loop_detector") top_aligner_fast = TopAlignerFast(name="top_aligner_fast", gov_robot=gov_robot) top_aligner_slow = TopAlignerSlow(name="top_aligner_slow") - + cs700 = CryoStream("XF:17ID1:CS700:", name="cs700", atol=0.1) elif beamline == "fmx": from mxbluesky.devices import (WorkPositions, TwoClickLowMag, LoopDetector, MountPositions, TopAlignerFast, TopAlignerSlow, GoniometerStack) + from mxbluesky.devices.generic import CryoStream mercury = ABBIXMercury('XF:17IDC-ES:FMX{Det:Mer}', name='mercury') mercury.read_attrs = ['mca.spectrum', 'mca.preset_live_time', 'mca.rois.roi0.count', 'mca.rois.roi1.count', 'mca.rois.roi2.count', 'mca.rois.roi3.count'] @@ -181,6 +183,7 @@ class SampleXYZ(Device): top_aligner_slow = TopAlignerSlow(name="top_aligner_slow") import setenergy_lsdc + cs700 = CryoStream("XF:17ID2:CS700:", name="cs700", atol=0.1) elif beamline=="nyx": from mxbluesky.devices.md2 import LightDevice, BeamstopDevice, MD2SimpleHVDevice, MD2Device, ShutterDevice From d7b6ca44f82684447792a7164ba611f00cec390b Mon Sep 17 00:00:00 2001 From: vshekar1 Date: Tue, 17 Dec 2024 02:57:47 -0500 Subject: [PATCH 3/4] Removed generic devices since server runs python 3.8 --- mxbluesky/devices/base_devices.py | 297 ------------------------------ mxbluesky/devices/generic.py | 3 +- 2 files changed, 1 insertion(+), 299 deletions(-) delete mode 100644 mxbluesky/devices/base_devices.py diff --git a/mxbluesky/devices/base_devices.py b/mxbluesky/devices/base_devices.py deleted file mode 100644 index 6f839330..00000000 --- a/mxbluesky/devices/base_devices.py +++ /dev/null @@ -1,297 +0,0 @@ -from ophyd.pv_positioner import PVPositioner -from ophyd import Component as Cpt -from ophyd.signal import Signal -from ophyd.utils import ReadOnlyError -import numpy as np -from typing import Optional - -# Note: These signals and devices are available in the latest versions of ophyd -# The reason its copied here is because LSDC GUI uses python 3.6 and ophyd needs -# python >= 3.8. Can safely be deleted once LSDC python is upgraded - - -class InternalSignalMixin: - """ - Mix-in class for adding the `InternalSignal` behavior to any signal class. - - A signal class with this mixin will reject all sets and puts unless - internal=True is passed as an argument. - - The intended use for this is to signify that a signal is for internal use - by the class only. That is, it would be a mistake to try to cause puts to - this signal by code external to the Device class. - - Some more concrete use-cases would be things like soft "status" type - signals that should be read-only except that the class needs to edit it, - or EPICS signals that should be written to by the class but are likely to - cause issues for external writes due to behavior complexity. - """ - - def put(self, *args, internal: bool = False, **kwargs): - """ - Write protection for an internal signal. - - This method is not intended to be used from outside of the device - that defined this signal. All writes must be done with internal=True. - """ - if not internal: - raise InternalSignalError() - return super().put(*args, **kwargs) - - def set(self, *args, internal: bool = False, **kwargs): - """ - Write protection for an internal signal. - - This method is not intended to be used from outside of the device - that defined this signal. All writes must be done with internal=True. - """ - if not internal: - raise InternalSignalError() - return super().set(*args, internal=internal, **kwargs) - - -class InternalSignal(InternalSignalMixin, Signal): - """ - A soft Signal that stores data but should only be updated by the Device. - - Unlike SignalRO, which will unilaterally block all writes, this will - allow writes with internal=True. - - The intended use for this is to signify that a signal is for internal use - by the class only. That is, it would be a mistake to try to cause puts to - this signal by code external to the Device class. - - Some more concrete use-cases would be things like soft "status" type - signals that should be read-only except that the class needs to edit it, - or calculated "done" signals for positioner classes. - """ - - -class InternalSignalError(ReadOnlyError): - """ - A read-only error sourced from trying to write to an internal signal. - """ - - def __init__(self, message=None): - if message is None: - message = ( - "This signal is for internal use only. " - "You should not be writing to it from outside " - "the parent class. If you do need to write to " - "this signal, you can use signal.put(value, internal=True)." - ) - super().__init__(message) - - -class PVPositionerComparator(PVPositioner): - """ - PV Positioner with a software done signal. - - The done state is set by a comparison function defined in the class body. - The comparison function takes two arguments, readback and setpoint, - returning True if we are considered done or False if we are not. - - This class is intended to support `PVPositionerIsClose`, but exists to - allow some flexibility if we want to use other metrics for deciding if - the PVPositioner is done. - - Internally, this will subscribe to both the ``setpoint`` and ``readback`` - signals, updating ``done`` as appropriate. - - Parameters - ---------- - prefix : str, optional - The device prefix used for all sub-positioners. This is optional as it - may be desirable to specify full PV names for PVPositioners. - limits : 2-element sequence, optional - (low_limit, high_limit) - name : str - The device name - egu : str, optional - The engineering units (EGU) for the position - settle_time : float, optional - The amount of time to wait after moves to report status completion - timeout : float, optional - The default timeout to use for motion requests, in seconds. - - Attributes - ---------- - setpoint : Signal - The setpoint (request) signal - readback : Signal or None - The readback PV (e.g., encoder position PV) - actuate : Signal or None - The actuation PV to set when movement is requested - actuate_value : any, optional - The actuation value, sent to the actuate signal when motion is - requested - stop_signal : Signal or None - The stop PV to set when motion should be stopped - stop_value : any, optional - The value sent to stop_signal when a stop is requested - put_complete : bool, optional - If set, the specified PV should allow for asynchronous put completion - to indicate motion has finished. If ``actuate`` is specified, it will be - used for put completion. Otherwise, the ``setpoint`` will be used. See - the `-c` option from ``caput`` for more information. - """ - - done = Cpt(InternalSignal, value=0) - done_value = 1 - - def __init__(self, prefix: str, *, name: str, **kwargs): - self._last_readback = None - self._last_setpoint = None - super().__init__(prefix, name=name, **kwargs) - if None in (self.setpoint, self.readback): - raise NotImplementedError( - "PVPositionerComparator requires both " - "a setpoint and a readback signal to " - "compare!" - ) - - def __init_subclass__(cls, **kwargs): - """Set up callbacks in subclass.""" - super().__init_subclass__(**kwargs) - if None not in (cls.setpoint, cls.readback): - cls.setpoint.sub_value(cls._update_setpoint) - cls.readback.sub_value(cls._update_readback) - - def done_comparator(self, readback: Any, setpoint: Any) -> bool: - """ - Override done_comparator in your subclass. - - This method should return True if we are done moving - and False otherwise. - """ - raise NotImplementedError("Must implement a done comparator!") - - def _update_setpoint(self, *args, value: Any, **kwargs) -> None: - """Callback to cache the setpoint and update done state.""" - self._last_setpoint = value - # Always set done to False when a move is requested - # This means we always get a rising edge when finished moving - # Even if the move distance is under our done moving tolerance - self.done.put(0, internal=True) - self._update_done() - - def _update_readback(self, *args, value: Any, **kwargs) -> None: - """Callback to cache the readback and update done state.""" - self._last_readback = value - self._update_done() - - def _update_done(self) -> None: - """Update our status to done if we pass the comparator.""" - if None not in (self._last_readback, self._last_setpoint): - is_done = self.done_comparator(self._last_readback, self._last_setpoint) - done_value = int(is_done) - if done_value != self.done.get(): - self.done.put(done_value, internal=True) - - -class PVPositionerIsClose(PVPositionerComparator): - """ - PV Positioner that updates done state based on np.isclose. - - Effectively, this will treat our move as complete if the readback is - sufficiently close to the setpoint. This is generically helpful for - PV positioners that don't have a ``done`` signal built into the hardware. - - The arguments atol and rtol can be set as class attributes or passed as - initialization arguments. - - atol is a measure of absolute tolerance. If atol is 0.1, then you'd be - able to be up to 0.1 units away and still count as done. This is - typically the most useful parameter for calibrating done tolerance. - - rtol is a measure of relative tolerance. If rtol is 0.1, then you'd be - able to deviate from the goal position by up to 10% of its value. This - is useful for small quantities. For example, defining an atol for a - positioner that ranges from 1e-8 to 2e-8 could be somewhat awkward. - - Parameters - ---------- - prefix : str, optional - The device prefix used for all sub-positioners. This is optional as it - may be desirable to specify full PV names for PVPositioners. - limits : 2-element sequence, optional - (low_limit, high_limit) - name : str - The device name - egu : str, optional - The engineering units (EGU) for the position - settle_time : float, optional - The amount of time to wait after moves to report status completion - timeout : float, optional - The default timeout to use for motion requests, in seconds. - atol : float, optional - A measure of absolute tolerance. If atol is 0.1, then you'd be - able to be up to 0.1 units away and still count as done. - rtol : float, optional - A measure of relative tolerance. If rtol is 0.1, then you'd be - able to deviate from the goal position by up to 10% of its value - - Attributes - ---------- - setpoint : Signal - The setpoint (request) signal - readback : Signal or None - The readback PV (e.g., encoder position PV) - actuate : Signal or None - The actuation PV to set when movement is requested - actuate_value : any, optional - The actuation value, sent to the actuate signal when motion is - requested - stop_signal : Signal or None - The stop PV to set when motion should be stopped - stop_value : any, optional - The value sent to stop_signal when a stop is requested - put_complete : bool, optional - If set, the specified PV should allow for asynchronous put completion - to indicate motion has finished. If ``actuate`` is specified, it will be - used for put completion. Otherwise, the ``setpoint`` will be used. See - the `-c` option from ``caput`` for more information. - atol : float, optional - A measure of absolute tolerance. If atol is 0.1, then you'd be - able to be up to 0.1 units away and still count as done. - rtol : float, optional - A measure of relative tolerance. If rtol is 0.1, then you'd be - able to deviate from the goal position by up to 10% of its value - """ - - atol: Optional[float] = None - rtol: Optional[float] = None - - def __init__( - self, - prefix: str, - *, - name: str, - atol: Optional[float] = None, - rtol: Optional[float] = None, - **kwargs, - ): - if atol is not None: - self.atol = atol - if rtol is not None: - self.rtol = rtol - super().__init__(prefix, name=name, **kwargs) - - def done_comparator(self, readback: float, setpoint: float) -> bool: - """ - Check if the readback is close to the setpoint value. - - Uses numpy.isclose to make the comparison. Tolerance values - atol and rtol for numpy.isclose are taken from the attributes - self.atol and self.rtol, which can be defined as class attributes - or passed in as init parameters. - - If atol or rtol are omitted, the default values from numpy are - used instead. - """ - kwargs = {} - if self.atol is not None: - kwargs["atol"] = self.atol - if self.rtol is not None: - kwargs["rtol"] = self.rtol - return np.isclose(readback, setpoint, **kwargs) diff --git a/mxbluesky/devices/generic.py b/mxbluesky/devices/generic.py index 98595e5c..6a5a7f19 100644 --- a/mxbluesky/devices/generic.py +++ b/mxbluesky/devices/generic.py @@ -1,7 +1,6 @@ from ophyd import Component as Cpt -from ophyd import Device, EpicsMotor, EpicsSignal, EpicsSignalRO +from ophyd import Device, EpicsMotor, EpicsSignal, EpicsSignalRO, PVPositionerIsClose from mxbluesky.devices import standardize_readback -from mxbluesky.devices.base_devices import PVPositionerIsClose from enum import IntEnum, unique class WorkPositions(Device): From d2eddf703f54d02f61fad6b6d64febbb8a9add0b Mon Sep 17 00:00:00 2001 From: vshekar1 Date: Tue, 17 Dec 2024 21:13:36 -0500 Subject: [PATCH 4/4] Fixed config param for FMX and fixed goniometer --- config_params.py | 2 +- mxbluesky/devices/generic.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config_params.py b/config_params.py index d6509d76..a56c7f93 100644 --- a/config_params.py +++ b/config_params.py @@ -91,7 +91,7 @@ class OnMountAvailOptions(Enum): DEWAR_SECTORS = {'amx':8, 'fmx':8, 'nyx':8} PUCKS_PER_DEWAR_SECTOR = {'amx':3, 'fmx':3, 'nyx':3} -cryostreamTempPV = {"amx": "XF:17ID1:CS700:TEMP", "fmx": "FMX:cs700:gasT-I", "nyx":"XF:19ID2:CS700:TEMP"} +cryostreamTempPV = {"amx": "XF:17ID1:CS700:TEMP", "fmx": "XF:17ID2:CS700:TEMP", "nyx":"XF:19ID2:CS700:TEMP"} VALID_EXP_TIMES = { "amx": {"min": 0.005, "max": 1, "digits": 3}, diff --git a/mxbluesky/devices/generic.py b/mxbluesky/devices/generic.py index 6a5a7f19..0317560a 100644 --- a/mxbluesky/devices/generic.py +++ b/mxbluesky/devices/generic.py @@ -34,6 +34,7 @@ def __init__(self, *args, **kwargs): self.cy = self.py self.z = self.pz self.cz = self.pz + self.omega = self.o @unique class CryoStreamCmd(IntEnum):