From 308b4edacd03976c921ca54495028bc6ed5f652e Mon Sep 17 00:00:00 2001 From: x01dc Date: Tue, 18 Aug 2026 15:19:17 +0200 Subject: [PATCH 1/2] fix(flomni): abort sample transfer when stage-out is declined ftransfer_gripper_move() silently returned on "No" to the stage-out confirmation, but its return was indistinguishable from success to its callers (ftransfer_get_sample/ftransfer_put_sample), which then proceeded to command the physical get/mount sequence on the controller -- moving the gripper without the stage ever having moved out or the gripper being positioned at the transfer coordinates. Now raises FlomniError instead, which propagates out of both callers and stops the transfer before any controller command is sent. Co-Authored-By: Claude Sonnet 5 --- .../bec_ipython_client/plugins/flomni/flomni.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py index 86c2499c..2465eb80 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py @@ -1090,17 +1090,18 @@ class FlomniSampleTransferMixin: if position == 0 and fsamx_pos > -160: print("Use GUI interface.") - if self.ftransfer_confirm_dialog("May the flomni stage be moved out for the sample change? Feedback will be disabled and alignment will be lost!", "y"): - - # if self.OMNYTools.yesno( - # "May the flomni stage be moved out for the sample change? Feedback will be disabled and alignment will be lost!", - # "y", - # ): + if self.ftransfer_confirm_dialog( + "May the flomni stage be moved out for the sample change? " + "Feedback will be disabled and alignment will be lost!", + "y", + ): print("OK. continue.") self.ftransfer_flomni_stage_out() else: - print("Stopping.") - return + raise FlomniError( + "Stage-out declined by user. Aborting sample transfer before any " + "gripper motion." + ) self.ensure_gripper_up() self.check_tray_in() -- 2.54.0 From 8936071766bb427f2a1e1e57833613e5572a7bcb Mon Sep 17 00:00:00 2001 From: x01dc Date: Wed, 19 Aug 2026 10:15:52 +0200 Subject: [PATCH 2/2] fix(flomni): stop OSA collision at fosa_in(), correct stale foptz init position fosa_in() moved fosax/fosay/fosaz straight to their configured "in" positions with no collision check. ffzp_info() already computed OSA-to-pin clearance but never gated the move on it. Add a shared _osa_remaining_space() helper (also used to deduplicate ffzp_info()'s own calculation) and raise FlomniOpticsError in fosa_in() when the computed clearance at the target position is <= 0. Root cause of the specific collision seen: stage init's _align_setup() hardcoded foptz to 23 instead of its calibrated "in" value of 17 (ptycho_flomni.yaml), 6 mm off from what fosaz's own "in" calibration assumes. Hardcode foptz to 17 instead, and lock foptz.limits to +-0.1 mm around it in both set_limits() and _align_setup() so any future move away from 17 requires deliberately widening the limits first. Also corrects the stale "in: 23" in ptycho_flomni.yaml's foptz userParameter to 17. Co-Authored-By: Claude Sonnet 5 --- .../plugins/flomni/flomni.py | 5 ++-- .../plugins/flomni/flomni_optics_mixin.py | 25 ++++++++++++++++--- csaxs_bec/device_configs/ptycho_flomni.yaml | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py index 2465eb80..3c1fe4dc 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py @@ -305,7 +305,7 @@ class FlomniInitStagesMixin: dev.ftransx.limits = [0, 50] dev.ftray.limits = [-200, 0] dev.fsamy.limits = [2, 3.5] - dev.foptz.limits = [22.5, 28] + dev.foptz.limits = [17 - 0.1, 17 + 0.1] dev.foptx.limits = [-17, -12] dev.fheater.limits = [-15, 0] dev.feyex.limits = [-18, -1] @@ -333,7 +333,8 @@ class FlomniInitStagesMixin: # the fopty 3.87 should put us in place for a lower FZP on the lower FZP chip - umv(dev.foptz, 23) + umv(dev.foptz, 17) + dev.foptz.limits = [17 - 0.1, 17 + 0.1] flomni_samx_in = dev.fsamx.user_parameter.get("in") if flomni_samx_in is None: diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py index bd309f4b..20004b63 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_optics_mixin.py @@ -5,6 +5,10 @@ from rich.console import Console from rich.table import Table +class FlomniOpticsError(Exception): + pass + + class FlomniOpticsMixin: @staticmethod def _get_user_param_safe(device, var): @@ -13,6 +17,12 @@ class FlomniOpticsMixin: raise ValueError(f"Device {device} has no user parameter definition for {var}.") return param.get(var) + def _osa_remaining_space(self, fosaz_target: float) -> float: + """Clearance (mm) between the OSA and a normal OMNY pin if fosaz were + at `fosaz_target`, at the *current* foptz reading. <=0 means collision.""" + foptz_val = dev.foptz.readback.get() + return -fosaz_target + (33 - foptz_val) + def feye_out(self): dev.fsh.fshclose() self.foptics_in() @@ -188,6 +198,16 @@ class FlomniOpticsMixin: ) if need_move_osa: + remaining = self._osa_remaining_space(fosaz_in) + if remaining <= 0: + foptz_val = dev.foptz.readback.get() + raise FlomniOpticsError( + f"Refusing to move OSA to its IN position: at the current foptz " + f"({foptz_val:.2f}), fosaz IN ({fosaz_in:.4f}) would leave " + f"{remaining:.2f} mm of clearance to a normal OMNY pin -- a " + "collision. Check/recalibrate the fosaz 'in' user parameter for " + "the current foptz before proceeding (see ffzp_info())." + ) umv(dev.fosax, fosax_in, dev.fosay, fosay_in) umv(dev.fosaz, fosaz_in) else: @@ -311,13 +331,12 @@ class FlomniOpticsMixin: console.print(table) fosaz_val = dev.fosaz.readback.get() - foptz_val = dev.foptz.readback.get() fosaz_in = self._get_user_param_safe("fosaz", "in") tol_osa = 0.010 # mm, 10 microns - remaining_current = -fosaz_val + (33 - foptz_val) - remaining_at_in = -fosaz_in + (33 - foptz_val) + remaining_current = self._osa_remaining_space(fosaz_val) + remaining_at_in = self._osa_remaining_space(fosaz_in) print("\nOSA Information:") print(f" Current fosaz {fosaz_val:.1f}") diff --git a/csaxs_bec/device_configs/ptycho_flomni.yaml b/csaxs_bec/device_configs/ptycho_flomni.yaml index e0c9e663..e6b0b8e4 100644 --- a/csaxs_bec/device_configs/ptycho_flomni.yaml +++ b/csaxs_bec/device_configs/ptycho_flomni.yaml @@ -144,7 +144,7 @@ foptz: readoutPriority: baseline connectionTimeout: 20 userParameter: - in: 23 + in: 17 deviceTags: - ptycho_flomni -- 2.54.0