feat: trigger iterates steps in bg thread
CI for mx_bec / test (push) Successful in 27s

This commit is contained in:
2026-08-19 11:28:57 +02:00
parent 35454fb2c9
commit be5bb1da7f
+49 -5
View File
@@ -2,14 +2,14 @@
from __future__ import annotations from __future__ import annotations
import threading
from typing import Literal, cast from typing import Literal, cast
from bec_lib.logger import bec_logger from bec_lib.logger import bec_logger
from ophyd import Component as Cpt from ophyd import Component as Cpt
from ophyd import Kind, Signal from ophyd import DeviceStatus, Kind, Signal
from ophyd_devices import EpicsMotorEC from ophyd_devices import EpicsMotorEC
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
from ophyd_devices.utils.psi_device_base_utils import Status
from mx_bec.devices.beam_profile import BeamProfile from mx_bec.devices.beam_profile import BeamProfile
@@ -20,6 +20,21 @@ class BeamSteerer(PSIDeviceBase):
"""Based on the beam profile, step towards the centre by moving the focussing mirrors. """Based on the beam profile, step towards the centre by moving the focussing mirrors.
Assumes everything is done at max zoom.""" Assumes everything is done at max zoom."""
def __init__(
self,
*,
name: str,
prefix: str = "",
scan_info: ScanInfo | None = None,
device_manager: DeviceManagerBase | None = None,
**kwargs,
):
super().__init__(
name=name, prefix=prefix, scan_info=scan_info, device_manager=device_manager, **kwargs
)
self._busy = threading.Lock()
self._abort = threading.Event()
# Config # Config
hfm_step_per_x_px = Cpt(Signal, name="hfm_step_per_x_px", kind=Kind.config) hfm_step_per_x_px = Cpt(Signal, name="hfm_step_per_x_px", kind=Kind.config)
vfm_step_per_y_px = Cpt(Signal, name="hfm_step_per_y_px", kind=Kind.config) vfm_step_per_y_px = Cpt(Signal, name="hfm_step_per_y_px", kind=Kind.config)
@@ -93,8 +108,37 @@ class BeamSteerer(PSIDeviceBase):
return x_status return x_status
if y_status is not None: if y_status is not None:
return y_status return y_status
return Status(done=True) return None
def _iterate_steps(self, status):
logger.info("Running beam steering...")
step_count = 1
try:
while (_step_status := self.step_towards_centre()) is not None:
logger.info(f"Beam steering iteration: {step_count}")
step_count += 1
if self._abort.is_set():
raise RuntimeError(f"{self.name}: aborted")
_step_status.wait()
except Exception as exc:
status.set_exception(exc)
else:
status.set_finished()
finally:
self._busy.release()
def trigger(self): def trigger(self):
"""External interface for 'step_towards_centre'""" """External interface for to iterate stepping towards the centre until finished"""
return self.step_towards_centre()
if not self._busy.acquire(blocking=False):
raise RuntimeError(f"{self.name} is still busy")
self._abort.clear()
status = DeviceStatus(self, timeout=60, settle_time=0.0)
threading.Thread(
target=self._routine, args=(status,), daemon=True, name=f"{self.name}_trigger"
).start()
return status
def stop(self, *, success=False):
self._abort.set()
super().stop(success=success)