Workaround on motor schema expected by BEC to move
This commit is contained in:
@@ -11,7 +11,7 @@ Created on Wed Jan 29 2025
|
||||
@author: mohacsi_i
|
||||
"""
|
||||
import numpy as np
|
||||
from ophyd import Device, Component, EpicsSignal, Kind, Staged
|
||||
from ophyd import Device, Component, EpicsSignal, EpicsSignalWithRBV, Kind, Staged
|
||||
from ophyd.areadetector import NDDerivedSignal
|
||||
|
||||
|
||||
@@ -20,24 +20,13 @@ from bec_lib import bec_logger
|
||||
logger = bec_logger.logger
|
||||
|
||||
class SilentNDDerivedSignal(NDDerivedSignal):
|
||||
def inverse(self, value):
|
||||
"""Shape the flat array to send as a result of ``.get``"""
|
||||
array_shape = self.derived_shape[: self.derived_ndims]
|
||||
if not any(array_shape):
|
||||
raise RuntimeWarning(f"Invalid array size {self.derived_shape}")
|
||||
return self._readback
|
||||
|
||||
array_len = np.prod(array_shape)
|
||||
if len(value) < array_len:
|
||||
raise RuntimeWarning(
|
||||
f"cannot reshape array of size {len(value)} "
|
||||
f"into shape {tuple(array_shape)}. Check IOC configuration."
|
||||
)
|
||||
return self._readback
|
||||
|
||||
return np.asarray(value[:array_len]).reshape(array_shape)
|
||||
|
||||
|
||||
"""Silent version of NDDerivedSignal, it does not spam the terminal on
|
||||
every defective frame (shit happens, ok?)."""
|
||||
def _array_shape_callback(self, **kwargs):
|
||||
try:
|
||||
super()._array_shape_callback(**kwargs)
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
|
||||
class NDArrayPreview(Device):
|
||||
@@ -56,13 +45,15 @@ class NDArrayPreview(Device):
|
||||
_default_sub = SUB_MONITOR
|
||||
|
||||
# Status attributes
|
||||
min_callback_time = Component(
|
||||
EpicsSignalWithRBV, "MinCallbackTime", kind=Kind.config, put_complete=True)
|
||||
array_size_x = Component(EpicsSignal, "ArraySize0_RBV", kind=Kind.config)
|
||||
array_size_y = Component(EpicsSignal, "ArraySize1_RBV", kind=Kind.config)
|
||||
array_size_z = Component(EpicsSignal, "ArraySize2_RBV", kind=Kind.config)
|
||||
ndimensions = Component(EpicsSignal, "NDimensions_RBV", kind=Kind.config)
|
||||
array_data = Component(EpicsSignal, "ArrayData", kind=Kind.omitted)
|
||||
shaped_image = Component(
|
||||
NDDerivedSignal,
|
||||
SilentNDDerivedSignal,
|
||||
derived_from="array_data",
|
||||
shape=("array_size_z", "array_size_y", "array_size_x"),
|
||||
num_dimensions="ndimensions",
|
||||
|
||||
@@ -10,6 +10,7 @@ import time
|
||||
import threading
|
||||
from threading import Thread, Lock
|
||||
import requests
|
||||
from collections import OrderedDict
|
||||
from requests.adapters import HTTPAdapter, Retry
|
||||
from ophyd import Component, Kind, Signal, PVPositioner
|
||||
from ophyd.status import SubscriptionStatus
|
||||
@@ -57,10 +58,11 @@ class LimitedSmarGonSignal(Signal):
|
||||
if value > hil:
|
||||
raise ValueError(f"Target {value} outside of limits {self.limits}")
|
||||
|
||||
def put(self, value, *, timestamp=None, **kwargs):
|
||||
def put(self, value, *, timestamp=None, force=False, metadata=None, **kwargs,):
|
||||
"""Overriden put to add communication with smargopolo"""
|
||||
# Validate new value and get timestamp
|
||||
self.check_value(value)
|
||||
if not force:
|
||||
self.check_value(value)
|
||||
if timestamp is None:
|
||||
timestamp = time.time()
|
||||
|
||||
@@ -86,7 +88,7 @@ class SmarGonAxis(PVPositioner):
|
||||
This class controls the SmarGon goniometer via the REST interface. All
|
||||
SmarGon axes share a common mutex to manage actual HW access.
|
||||
"""
|
||||
USER_ACCESS = ["omove"]
|
||||
USER_ACCESS = ["omove", "oldmove"]
|
||||
|
||||
# Status attributes
|
||||
sg_url = Component(Signal, kind=Kind.config, metadata={"write_access": False})
|
||||
@@ -133,7 +135,7 @@ class SmarGonAxis(PVPositioner):
|
||||
)
|
||||
|
||||
def on_target():
|
||||
"""NOTE: This assumes that both readback and setpoint is always up to date"""
|
||||
"""Monitors the setpoint and readback and calculates the on_target flag"""
|
||||
time.sleep(2)
|
||||
while True:
|
||||
# Read back target and setpoint values
|
||||
@@ -154,11 +156,12 @@ class SmarGonAxis(PVPositioner):
|
||||
self._mon = threading.Thread(target=on_target, daemon=True)
|
||||
self._mon.start()
|
||||
|
||||
def move(self, position, wait=True, timeout=None, moved_cb=None):
|
||||
def omove(self, position, wait=True, timeout=None, moved_cb=None):
|
||||
"""Move command that's masked by BEC"""
|
||||
return self.omove(position, wait, timeout, moved_cb)
|
||||
self.done.put(0, force=True)
|
||||
return self.move(position, wait, timeout, moved_cb)
|
||||
|
||||
def omove(self, position, wait=True, timeout=2.0, moved_cb=None):
|
||||
def oldmove(self, position, wait=True, timeout=2.0, moved_cb=None):
|
||||
"""Original move command without the BEC wrappers"""
|
||||
status = self.setpoint.set(position, settle_time=0.1).wait()
|
||||
if not wait:
|
||||
@@ -172,7 +175,21 @@ class SmarGonAxis(PVPositioner):
|
||||
status = SubscriptionStatus(self.readback, on_target, timeout=timeout, settle_time=0.1)
|
||||
return status
|
||||
|
||||
def describe(self):
|
||||
"""Workaround to schema expected by the BEC"""
|
||||
d = super().describe()
|
||||
d[str(self.name)] = d[f"{self.name}_readback"]
|
||||
return d
|
||||
|
||||
|
||||
def read(self) -> OrderedDict[str, dict]:
|
||||
"""Workaround to schema expected by the BEC"""
|
||||
d = super().read()
|
||||
d[str(self.name)] = d[f"{self.name}_readback"]
|
||||
return d
|
||||
|
||||
def _pos_changed(self, timestamp=None, value=None, **kwargs):
|
||||
"""Remove EPICS dependency"""
|
||||
pass
|
||||
|
||||
def _go_n_get(self, address, **kwargs):
|
||||
|
||||
@@ -6,7 +6,7 @@ Ophyd devices for the PX III beamline, including the MX specific Aerotech A3200
|
||||
"""
|
||||
from .A3200 import AerotechAbrStage
|
||||
from .A3200utils import A3200Axis
|
||||
from .SmarGon import SmarGonAxis
|
||||
from .SmarGon2 import SmarGonAxis
|
||||
from .StdDaqPreview import StdDaqPreviewDetector
|
||||
from .NDArrayPreview import NDArrayPreview
|
||||
from .SamCamDetector import SamCamDetector
|
||||
|
||||
Reference in New Issue
Block a user