fix: address v4 scan migration review findings for flomni/lamni/omny
- restore omny_fermat_scan scan_name (was broken by _v4 rename) - restore missing settling delay after LamNI feedback_disable - make LamNI drift-correction moves consistently concurrent - use self.actions.set for flomni rtx/rtz moves - cap flomni corridor_size (explicit and auto-estimated) at 3um Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit was merged in pull request #212.
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b813b05bb1
commit
53f246a8d3
@@ -20,6 +20,8 @@ import time
|
||||
from typing import Annotated
|
||||
|
||||
import numpy as np
|
||||
from scipy.spatial import cKDTree
|
||||
|
||||
from bec_lib import messages
|
||||
from bec_lib.alarm_handler import Alarms
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
@@ -62,6 +64,7 @@ class FlomniFermatScan(ScanBase):
|
||||
}
|
||||
|
||||
MIN_POSITIONS = 20 # Minimum number of positions required for a valid scan
|
||||
MAX_CORRIDOR_SIZE = 3 # Corridor size is capped at this value (in um) for stability
|
||||
|
||||
def __init__(
|
||||
# fmt: off
|
||||
@@ -122,6 +125,13 @@ class FlomniFermatScan(ScanBase):
|
||||
logger.warning("The zshift is smaller than -100 um. It will be limited to -100 um.")
|
||||
self.zshift = -100
|
||||
|
||||
if self.corridor_size is not None and self.corridor_size > self.MAX_CORRIDOR_SIZE:
|
||||
logger.warning(
|
||||
f"The corridor_size is larger than {self.MAX_CORRIDOR_SIZE} um. It will be"
|
||||
f" limited to {self.MAX_CORRIDOR_SIZE} um."
|
||||
)
|
||||
self.corridor_size = self.MAX_CORRIDOR_SIZE
|
||||
|
||||
self.update_scan_info(
|
||||
exp_time=exp_time,
|
||||
frames_per_trigger=frames_per_trigger,
|
||||
@@ -154,8 +164,12 @@ class FlomniFermatScan(ScanBase):
|
||||
f"The number positions must exceed {self.MIN_POSITIONS}. Currently: {len(positions)}."
|
||||
)
|
||||
|
||||
corridor_size = self.corridor_size
|
||||
if corridor_size is None:
|
||||
corridor_size = min(self._estimate_corridor_size(positions), self.MAX_CORRIDOR_SIZE)
|
||||
|
||||
self.positions = self.components.optimize_trajectory(
|
||||
positions, optimization_type="corridor", corridor_size=self.corridor_size
|
||||
positions, optimization_type="corridor", corridor_size=corridor_size
|
||||
)
|
||||
flip_axes = self.reverse_trajectory()
|
||||
if flip_axes:
|
||||
@@ -318,8 +332,8 @@ class FlomniFermatScan(ScanBase):
|
||||
if self.flomni_rotation_status:
|
||||
self.flomni_rotation_status.wait()
|
||||
|
||||
rtx_status = dev.rtx.set(self.cenx)
|
||||
rtz_status = dev.rtz.set(self.positions[0][2])
|
||||
rtx_status = self.actions.set(dev.rtx, self.cenx, wait=False)
|
||||
rtz_status = self.actions.set(dev.rtz, self.positions[0][2], wait=False)
|
||||
|
||||
dev.rtx.controller.laser_tracker_on()
|
||||
|
||||
@@ -370,6 +384,24 @@ class FlomniFermatScan(ScanBase):
|
||||
)
|
||||
self.flomni_rotation_status = self.actions.set(self.dev.fsamroy, angle, wait=False)
|
||||
|
||||
@staticmethod
|
||||
def _estimate_corridor_size(positions: np.ndarray, factor: float = 1.5) -> float:
|
||||
"""
|
||||
Estimate the corridor size based on the median nearest-neighbor distance
|
||||
of the positions, matching the estimation used by the corridor path
|
||||
optimizer if no corridor_size is provided.
|
||||
|
||||
Args:
|
||||
positions (np.ndarray): Array of positions
|
||||
factor (float): Scaling factor for the median distance
|
||||
|
||||
Returns:
|
||||
float: Estimated corridor size
|
||||
"""
|
||||
tree = cKDTree(positions[:, :2])
|
||||
dists, _ = tree.query(positions[:, :2], k=2) # k=1 is itself
|
||||
return factor * np.median(dists[:, 1])
|
||||
|
||||
@staticmethod
|
||||
def get_flomni_fermat_spiral_pos(
|
||||
m1_start: float,
|
||||
|
||||
@@ -69,6 +69,7 @@ class LamNIComponents(ScanComponents):
|
||||
|
||||
# disable the feedback
|
||||
self._dev.rtx.controller.feedback_disable()
|
||||
time.sleep(0.05)
|
||||
|
||||
rtx_current = self._dev.rtx.readback.get()
|
||||
rty_current = self._dev.rty.readback.get()
|
||||
@@ -109,8 +110,11 @@ class LamNIComponents(ScanComponents):
|
||||
logger.info(
|
||||
f"Compensating {[val/1000 for val in self.lamni_to_stage_coordinates(x_drift,y_drift)]}"
|
||||
)
|
||||
self._dev.lsamx.set(move_x).wait()
|
||||
self._dev.lsamy.set(move_y).wait()
|
||||
lsamx_set = self._dev.lsamx.set(move_x)
|
||||
lsamy_set = self._dev.lsamy.set(move_y)
|
||||
|
||||
lsamx_set.wait()
|
||||
lsamy_set.wait()
|
||||
|
||||
time.sleep(0.01)
|
||||
rtx_current = self._dev.rtx.readback.get()
|
||||
|
||||
@@ -42,7 +42,7 @@ class OmnyFermatScan(ScanBase):
|
||||
# Scan name: This is the name of the scan, e.g. "line_scan". This is used for display purposes and to identify the scan type in user interfaces.
|
||||
# Choose a descriptive name that does not conflict with existing scan names.
|
||||
# It must be a valid Python identifier, that is, it can only contain letters, numbers, and underscores, and must not start with a number.
|
||||
scan_name = "omny_fermat_scan_v4"
|
||||
scan_name = "omny_fermat_scan"
|
||||
|
||||
gui_config = {
|
||||
"Scan Parameters": [
|
||||
|
||||
Reference in New Issue
Block a user