From 4fc31e5f5d5abe91bfaf321dbc9a3a730caf8aa7 Mon Sep 17 00:00:00 2001 From: gac-x06da Date: Mon, 27 Jan 2025 17:37:53 +0100 Subject: [PATCH] Samcam image preview and smargon waiting --- .../device_configs/x06da_device_config.yaml | 22 +---- pxiii_bec/devices/A3200.py | 2 +- pxiii_bec/devices/A3200utils.py | 6 +- pxiii_bec/devices/NDArrayPreview.py | 14 +++- pxiii_bec/devices/SmarGon.py | 50 ++++++++--- pxiii_bec/devices/StdDaqPreview.py | 82 ++++++++++--------- pxiii_bec/devices/__init__.py | 2 +- 7 files changed, 101 insertions(+), 77 deletions(-) diff --git a/pxiii_bec/device_configs/x06da_device_config.yaml b/pxiii_bec/device_configs/x06da_device_config.yaml index c1ef2df..a49287a 100644 --- a/pxiii_bec/device_configs/x06da_device_config.yaml +++ b/pxiii_bec/device_configs/x06da_device_config.yaml @@ -448,7 +448,7 @@ samimg: prefix: 'X06DA-SAMCAM:image1:' deviceTags: - detector - enabled: true + enabled: false readoutPriority: async readOnly: false softwareTrigger: false @@ -599,7 +599,7 @@ abr: shx: description: SmarGon X axis deviceClass: pxiii_bec.devices.SmarGonAxis - deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'} + deviceConfig: {prefix: 'SCS', low_limit: -2, high_limit: 2, sg_url: 'http://x06da-smargopolo.psi.ch:3000'} onFailure: buffer enabled: true readoutPriority: monitored @@ -608,7 +608,7 @@ shx: shy: description: SmarGon Y axis deviceClass: pxiii_bec.devices.SmarGonAxis - deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'} + deviceConfig: {prefix: 'SCS', low_limit: -2, high_limit: 2, sg_url: 'http://x06da-smargopolo.psi.ch:3000'} onFailure: buffer enabled: true readoutPriority: monitored @@ -626,7 +626,7 @@ shz: chi: description: SmarGon CHI axis deviceClass: pxiii_bec.devices.SmarGonAxis - deviceConfig: {prefix: 'SCS', sg_url: 'http://x06da-smargopolo.psi.ch:3000'} + deviceConfig: {prefix: 'SCS', low_limit: 0, high_limit: 40, sg_url: 'http://x06da-smargopolo.psi.ch:3000'} onFailure: buffer enabled: true readoutPriority: monitored @@ -641,17 +641,3 @@ phi: readoutPriority: monitored readOnly: false softwareTrigger: false - - - - -# samimgs: -# description: Sample camera image -# deviceClass: ophyd_devices.devices.areadetector.plugins.ImagePlugin_V35 -# deviceConfig: {prefix: 'X06DA-SAMCAM:image1:', foo: 'bar'} -# onFailure: buffer -# enabled: false -# readoutPriority: monitored -# readOnly: true -# softwareTrigger: false - diff --git a/pxiii_bec/devices/A3200.py b/pxiii_bec/devices/A3200.py index ea67224..63cd4e9 100644 --- a/pxiii_bec/devices/A3200.py +++ b/pxiii_bec/devices/A3200.py @@ -140,7 +140,7 @@ class AerotechAbrMixin(CustomDeviceMixin): scan_range_y = scanargs["range"] scan_steps_y = scanargs["steps"] d["scan_command"] = AbrCmd.VERTICAL_LINE_SCAN - d["var_1"] = scan_range_y / scan_steps_y + d["var_1"] = scan_range_y / scan_steps_y d["var_2"] = scan_steps_y d["var_3"] = scan_exp_time d["var_4"] = 0 diff --git a/pxiii_bec/devices/A3200utils.py b/pxiii_bec/devices/A3200utils.py index 60a4cee..5d4cdd5 100644 --- a/pxiii_bec/devices/A3200utils.py +++ b/pxiii_bec/devices/A3200utils.py @@ -8,10 +8,10 @@ import types from ophyd import Component, PVPositioner, Signal, EpicsSignal, EpicsSignalRO, Kind, PositionerBase from ophyd.status import Status, MoveStatus -from .A3200enums import AbrMode - from bec_lib import bec_logger +from .A3200enums import AbrMode + logger = bec_logger.logger @@ -115,7 +115,7 @@ class A3200Axis(PVPositioner): # Patching the parent's PVs into the axis class to check for direct/locked mode if parent is None: - def maybe_add_prefix(self, instance, kw, suffix): + def maybe_add_prefix(self, _, kw, suffix): # Patched not to enforce parent prefix when no parent if kw in self.add_prefix: return suffix diff --git a/pxiii_bec/devices/NDArrayPreview.py b/pxiii_bec/devices/NDArrayPreview.py index 343e50c..1deb236 100644 --- a/pxiii_bec/devices/NDArrayPreview.py +++ b/pxiii_bec/devices/NDArrayPreview.py @@ -20,9 +20,11 @@ class NDArrayPreview(Device): This is a monolithic class to display images from AreaDetector's ImagePlugin without the use of DynamicDeviceComponent or multiple interitance (that doesn't work with BEC). + + NOTE: As an explicit request, it doesnt record the data, unless """ # Subscriptions for plotting image - USER_ACCESS = ["image"] + USER_ACCESS = ["image", "savemode"] SUB_MONITOR = "device_monitor_2d" _default_sub = SUB_MONITOR @@ -37,7 +39,7 @@ class NDArrayPreview(Device): derived_from="array_data", shape=("array_size_z", "array_size_y", "array_size_x"), num_dimensions="ndimensions", - kind=Kind.normal, + kind=Kind.omitted, ) def read(self): @@ -47,6 +49,14 @@ class NDArrayPreview(Device): self._run_subs(sub_type=self.SUB_MONITOR, value=image) return super().read() + def savemode(self, save=False): + """ Toggle save mode for the shaped image""" + #pylint: disable=protected-access + if save: + self.shaped_image._kind = Kind.normal + else: + self.shaped_image._kind = Kind.omitted + def image(self): """ Fallback method in case image streaming fills up the BEC""" array_size = (self.array_size_z.get(), self.array_size_y.get(), self.array_size_x.get()) diff --git a/pxiii_bec/devices/SmarGon.py b/pxiii_bec/devices/SmarGon.py index 87f9562..1ddad0f 100644 --- a/pxiii_bec/devices/SmarGon.py +++ b/pxiii_bec/devices/SmarGon.py @@ -1,6 +1,8 @@ import time import requests -from ophyd import Component, Device, Kind, Signal, SignalRO +from threading import Thread +from ophyd import Component, Device, Kind, Signal, SignalRO, PVPositioner +from ophyd.status import SubscriptionStatus try: from bec_lib import bec_logger @@ -36,7 +38,7 @@ class SmarGonSignal(Signal): timestamp = time.time() # Perform the actual write to SmargoPolo - r = self.parent._go_n_put(f"{self.write_addr}?{self.addr.upper()}={value}", **kwargs) + r = self.parent._go_n_put(f"{self.write_addr}?{self.addr.upper()}={value}") old_value = self._readback self._timestamp = timestamp @@ -79,23 +81,32 @@ class SmarGonSignalRO(Signal): TODO: Add monitoring """ - def __init__(self, *args, read_addr="readbackSCS", **kwargs): + def __init__(self, *args, read_addr="readbackSCS", auto_monitor=False, **kwargs): super().__init__(*args, **kwargs) self._metadata["write_access"] = False self.read_addr = read_addr self.addr = self.parent.name + if auto_monitor: + self._mon = Thread(target=self.poll, daemon=True) + self._mon.start() + def get(self, *args, **kwargs): r = self.parent._go_n_get(self.read_addr) - # print(r) + if isinstance(r, dict): self.put(r[self.addr.upper()], force=True) else: self.put(r, force=True) - return super().get(*args, **kwargs) + return self._readback + def poll(self, *args, **kwargs): + """ Fooo""" + while True: + time.sleep(0.2) + self.get() -class SmarGonAxis(Device): +class SmarGonAxis(PVPositioner): """SmarGon client deice This class controls the SmarGon goniometer via the REST interface. @@ -107,11 +118,12 @@ class SmarGonAxis(Device): mode = Component(SmarGonSignalRO, read_addr="mode", kind=Kind.config) # Axis parameters - readback = Component(SmarGonSignalRO, kind=Kind.hinted) + readback = Component(SmarGonSignalRO, kind=Kind.hinted, auto_monitor=True) setpoint = Component(SmarGonSignal, kind=Kind.normal) done = Component(SignalRO, value=1, kind=Kind.normal) # moving = Component(SmarGonMovingSignalRO, kind=Kind.config) moving = 1 + _tol = 0.001 def __init__( self, @@ -122,7 +134,6 @@ class SmarGonAxis(Device): read_attrs=None, configuration_attrs=None, parent=None, - device_manager=None, sg_url: str = "http://x06da-smargopolo.psi.ch:3000", low_limit=None, high_limit=None, @@ -132,7 +143,7 @@ class SmarGonAxis(Device): self.__class__.__dict__["setpoint"].kwargs["write_addr"] = f"target{prefix}" self.__class__.__dict__["setpoint"].kwargs["low_limit"] = low_limit self.__class__.__dict__["setpoint"].kwargs["high_limit"] = high_limit - + self.__class__.__dict__["sg_url"].kwargs["value"] = sg_url super().__init__( prefix=prefix, name=name, @@ -140,11 +151,8 @@ class SmarGonAxis(Device): read_attrs=read_attrs, configuration_attrs=configuration_attrs, parent=parent, - # device_manager=device_manager, **kwargs, ) - self.sg_url._metadata["write_access"] = False - self.sg_url.set(sg_url, force=True).wait() def initialize(self): """Helper function for initial readings""" @@ -153,6 +161,24 @@ class SmarGonAxis(Device): r = self._go_n_get("corr_type") print(r) + def move(self, position, wait=True, timeout=None, moved_cb=None): + + status = self.setpoint.set(position, settle_time=0.1) + + if not wait: + return status + else: + status.wait() + + def on_target(*, value, **_): + distance = abs(value-position) + print(distance) + return bool(distance