moved axis mapping to config file

This commit is contained in:
x12sa
2026-01-16 13:38:45 +01:00
parent 32d76b0941
commit 3e278a68a2
2 changed files with 256 additions and 193 deletions

View File

@@ -1,60 +1,112 @@
import builtins
import time
#from pathlib import Path
from bec_lib import bec_logger
# Logger initialization
logger = bec_logger.logger
if builtins.__dict__.get("bec") is not None:
bec = builtins.__dict__.get("bec")
dev = builtins.__dict__.get("dev")
umv = builtins.__dict__.get("umv")
umvr = builtins.__dict__.get("umvr")
# Pull BEC globals if present
bec = builtins.__dict__.get("bec")
dev = builtins.__dict__.get("dev")
umv = builtins.__dict__.get("umv")
umvr = builtins.__dict__.get("umvr")
class cSAXSInitSmaractStagesError(Exception):
pass
class cSAXSInitSmaractStages:
# Class-level mappings for axes and devices
AXIS_MAP = {c: i for i, c in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ")}
devices = {
"xbpm3x": "A",
"xbpm3y": "B",
"sl3trxi": "C",
"sl3trxo": "D",
"sl3trxb": "E",
"sl3trxt": "F",
"fast_shutter_n1_x": "H",
"fast_shutter_o1_x": "G",
"fast_shutter_o2_x": "F",
"filter_array_1_x": "B",
"filter_array_2_x": "C",
"filter_array_3_x": "D",
"filter_array_4_x": "E",
"sl4trxi": "G",
"sl4trxo": "H",
"sl4trxb": "I",
"sl4trxt": "A",
"sl5trxi": "C",
"sl5trxo": "D",
"sl5trxb": "E",
"sl5trxt": "F",
"xbimtrx": "A",
"xbimtry": "B",
}
"""
Runtime SmarAct utilities for referencing and moving to initial positions.
This class no longer relies on static mappings. Instead, it:
- discovers available devices from `list(dev.keys())`
- reads the numeric channel/axis from each device's `user_parameter['bl_smar_stage']`
- reads `init_position` from `user_parameter['init_position']`
"""
def __init__(self, client) -> None:
self.client = client
def smaract_reference_stages(self, force=False, devices_to_reference=None):
# ------------------------------
# Internal helpers (runtime-based)
# ------------------------------
def _yesno(self, question: str, default: str = "y") -> bool:
"""
Reference SmarAct stages.
Use OMNYTools.yesno if available; otherwise default to 'yes' (or fallback to input()).
"""
try:
if hasattr(self, "OMNYTools") and hasattr(self.OMNYTools, "yesno"):
return self.OMNYTools.yesno(question, default)
except Exception:
pass
# Fallback: default answer without interaction
# (Safe default: 'y' proceeds; adjust if you want interactive input)
logger.info(f"[cSAXS] (yesno fallback) {question} -> default '{default}'")
return (default or "y").lower().startswith("y")
def _get_user_param_safe(self, device_name: str, key: str):
"""
Safe access to device user parameters from current BEC session.
"""
try:
return dev[device_name].user_parameter.get(key)
except Exception:
return None
def _iter_session_devices(self):
"""
Yield device names available in current BEC session.
"""
if dev is None:
return
for name in list(dev.keys()):
yield name
def _build_session_axis_map(self, selection: set | None = None) -> dict:
"""
Build runtime axis map {device_name: channel} for devices that define 'bl_smar_stage'.
If 'selection' is provided, restrict to names in selection.
"""
axis_map = {}
missing = []
for name in self._iter_session_devices() or []:
if selection is not None and name not in selection:
continue
ch = self._get_user_param_safe(name, "bl_smar_stage")
if ch is None:
missing.append(name)
continue
try:
axis_map[name] = int(ch)
except Exception:
missing.append(name)
if missing and selection is None:
logger.info(
"[cSAXS] Devices without 'bl_smar_stage' (ignored): " + ", ".join(sorted(missing))
)
return axis_map
def _get_device_object(self, device_name: str):
"""
Return the live device object from BEC 'dev'.
"""
try:
return getattr(dev, device_name)
except Exception:
return None
# ------------------------------
# Public API
# ------------------------------
def smaract_reference_stages(self, force: bool = False, devices_to_reference=None):
"""
Reference SmarAct stages using runtime discovery.
Parameters
----------
@@ -62,22 +114,21 @@ class cSAXSInitSmaractStages:
If True, re-reference ALL selected stages.
If False (default), only reference stages that are currently NOT referenced.
devices_to_reference : iterable of str, optional
devices_to_reference : iterable of str or str, optional
If provided, only these devices will be considered for referencing.
If None (default), all stages in `self.devices` are candidates.
If None, all devices in the current session that define 'bl_smar_stage' are considered.
Behavior
--------
- Runtime-based: reads axis channel from user_parameter['bl_smar_stage'].
- If devices_to_reference is given → restrict referencing to those.
- If force=False → skip devices already referenced.
- If force=True → re-reference selected devices always.
- Only newly referenced devices are passed to
smaract_components_to_initial_position() afterwards.
smaract_components_to_initial_position(devices_to_move=[...]) afterwards.
Examples
--------
Reference only stages that are NOT referenced yet (default)
csaxs.smaract_reference_stages()
@@ -107,39 +158,32 @@ class cSAXSInitSmaractStages:
Check referencing status of all stages
csaxs.smaract_check_all_referenced()
"""
# Normalize selection
if isinstance(devices_to_reference, str):
devices_to_reference = [devices_to_reference]
selection = set(devices_to_reference) if devices_to_reference else None
selection = (
set(devices_to_reference)
if devices_to_reference is not None
else set(self.devices.keys())
)
# Build axis map for selected devices (or all devices present)
axis_map = self._build_session_axis_map(selection=selection)
if selection:
unknown = sorted(list(selection - set(axis_map.keys())))
if unknown:
print(f"Unknown devices requested or missing 'bl_smar_stage' (ignored): {unknown}")
unknown = selection - set(self.devices.keys())
if unknown:
print(f"Unknown devices requested and ignored: {sorted(unknown)}")
selection = selection.intersection(self.devices.keys())
newly_referenced = []
already_referenced = []
failed = []
to_verify = [] # devices that need a final verification
print("\nStarting SmarAct referencing...\n")
for dev_name in sorted(selection):
axis_letter = self.devices[dev_name]
ch = self.AXIS_MAP[axis_letter]
for dev_name in sorted(axis_map.keys()):
ch = axis_map[dev_name]
d = self._get_device_object(dev_name)
try:
d = getattr(dev, dev_name)
except AttributeError:
if d is None:
print(f"{dev_name}: device not accessible, skipping.")
failed.append(dev_name)
continue
@@ -153,22 +197,33 @@ class cSAXSInitSmaractStages:
already_referenced.append(dev_name)
continue
# Perform referencing
print(f"{dev_name}: referencing axis {ch}...")
# Start referencing
print(f"{dev_name}: referencing axis...")
d.controller.set_closed_loop_move_speed(ch, 1)
d.controller.find_reference_mark(ch, 0, 1000, 1)
time.sleep(0.1)
# Verify
# Add to list for final verification
to_verify.append((dev_name, ch, d))
except Exception as e:
print(f"Error referencing {dev_name} (axis {ch}): {e}")
failed.append(dev_name)
time.sleep(1.0)
print("\nVerifying referencing state...\n")
for dev_name, ch, d in to_verify:
try:
if d.controller.axis_is_referenced(ch):
print(f"{dev_name}: successfully referenced.")
newly_referenced.append(dev_name)
else:
print(f"{dev_name}: referencing FAILED.")
failed.append(dev_name)
except Exception as e:
print(f"Error referencing {dev_name} (axis {ch}): {e}")
print(f"{dev_name}: verification error: {e}")
failed.append(dev_name)
# --- Summary ---
@@ -181,47 +236,42 @@ class cSAXSInitSmaractStages:
# --- Move newly referenced only ---
if newly_referenced:
print("Moving newly referenced stages to initial positions...")
self.smaract_components_to_initial_position(
devices_to_move=newly_referenced
)
self.smaract_components_to_initial_position(devices_to_move=newly_referenced)
else:
print("No newly referenced stages.")
def smaract_check_all_referenced(self):
"""
Check if all SmarAct axes are referenced.
Check reference state for all SmarAct devices that define 'bl_smar_stage'.
"""
for dev_name, axis_letter in self.devices.items():
ch = self.AXIS_MAP[axis_letter]
axis_map = self._build_session_axis_map(selection=None)
for dev_name in sorted(axis_map.keys()):
ch = axis_map[dev_name]
d = self._get_device_object(dev_name)
if d is None:
print(f"{dev_name}: device not accessible or unsupported.")
continue
try:
d = getattr(dev, dev_name)
if d.controller.axis_is_referenced(ch):
print(f"{dev_name} (axis {ch}) is referenced.")
else:
print(f"{dev_name} (axis {ch}) is NOT referenced.")
except AttributeError:
print(f"{dev_name}: device not accessible or unsupported.")
except Exception as e:
print(f"Error checking {dev_name} (axis {ch}): {e}")
def smaract_components_to_initial_position(
self,
devices_to_move=None,
):
def smaract_components_to_initial_position(self, devices_to_move=None):
"""
Move selected (or all) SmarAct-based components to their configured init_position.
Parameters
----------
devices_to_move : iterable of str, optional
devices_to_move : iterable of str or str, optional
Specific device names to move (e.g. ["xbpm3x", "sl3trxi"]).
If None, all known SmarAct devices defined in `self.devices` are considered.
If None, all devices in the current session that define 'bl_smar_stage' are considered.
Behavior
--------
- Runtime-based: uses user_parameter['bl_smar_stage'] (numeric channel) and 'init_position'.
- Only axes that are referenced will be moved.
- Unreferenced axes are skipped with a WARNING; the operation continues.
- Devices missing `init_position` are skipped and listed.
@@ -232,108 +282,75 @@ class cSAXSInitSmaractStages:
devices_to_move = [devices_to_move]
selection = set(devices_to_move) if devices_to_move else None
planned_moves = []
not_referenced = []
missing_params = []
inaccessible_devices = []
# Resolve axis map based on selection
axis_map = self._build_session_axis_map(selection=selection)
unknown_requested = []
# If a selection is provided, pre-check for unknown device names
if selection is not None:
known = set(self.devices.keys())
unknown_requested = sorted(list(selection - known))
if selection:
unknown_requested = sorted(list(selection - set(axis_map.keys())))
if unknown_requested:
bec_logger.logger.warning(
"[cSAXS] The following requested devices are unknown and will be ignored: "
logger.warning(
"[cSAXS] Requested devices unknown or missing 'bl_smar_stage': "
+ ", ".join(unknown_requested)
)
# First confirmation: intent
scope_desc = (
"all SmarAct-based components"
if selection is None
else "the selected SmarAct-based components"
)
if not self.OMNYTools.yesno(
scope_desc = "all SmarAct-based components" if selection is None else "the selected SmarAct-based components"
if not self._yesno(
f"Do you want to move {scope_desc} to the init position as defined in the config file?",
"y",
):
return
# --- Pre-check phase ---
for dev_name, axis_letter in self.devices.items():
# If a selection is provided, only consider those in the selection
if selection is not None and dev_name not in selection:
continue
planned_moves = []
not_referenced = []
missing_params = []
inaccessible_devices = []
try:
d = getattr(dev, dev_name)
except AttributeError:
bec_logger.logger.warning(
f"[cSAXS] Device {dev_name} not accessible, skipping."
)
# --- Pre-check phase ---
for dev_name in sorted(axis_map.keys()):
d = self._get_device_object(dev_name)
if d is None:
logger.warning(f"[cSAXS] Device {dev_name} not accessible, skipping.")
inaccessible_devices.append(dev_name)
continue
# Resolve channel
ch = self.AXIS_MAP.get(axis_letter, None)
if ch is None:
bec_logger.logger.warning(
f"[cSAXS] Axis map has no entry for letter '{axis_letter}' "
f"(device {dev_name}); skipping."
)
continue
ch = axis_map[dev_name]
try:
# Reference check
if not d.controller.axis_is_referenced(ch):
not_referenced.append(dev_name)
continue
# Fetch init_position
init_pos = self.OMNYTools._get_user_param_safe(
dev_name,
"init_position",
)
# Fetch init_position (from user parameters)
init_pos = self._get_user_param_safe(dev_name, "init_position")
if init_pos is None:
missing_params.append(dev_name)
continue
planned_moves.append((dev_name, init_pos))
planned_moves.append((dev_name, float(init_pos)))
except Exception as exc:
bec_logger.logger.error(
f"[cSAXS] Error during pre-check for {dev_name}: {exc}"
)
logger.error(f"[cSAXS] Error during pre-check for {dev_name}: {exc}")
if not planned_moves:
# Nothing to move—still summarize why.
header = "\nNo motions planned. Summary of issues:"
lines = []
if not_referenced:
lines.append(
" - Not referenced: " + ", ".join(sorted(not_referenced))
)
lines.append(" - Not referenced: " + ", ".join(sorted(not_referenced)))
if missing_params:
lines.append(
" - Missing init_position: " + ", ".join(sorted(missing_params))
)
lines.append(" - Missing init_position: " + ", ".join(sorted(missing_params)))
if inaccessible_devices:
lines.append(
" - Not accessible: " + ", ".join(sorted(inaccessible_devices))
)
lines.append(" - Not accessible: " + ", ".join(sorted(inaccessible_devices)))
if unknown_requested:
lines.append(
" - Unknown requested: " + ", ".join(sorted(unknown_requested))
)
lines.append(" - Unknown requested: " + ", ".join(sorted(unknown_requested)))
if not lines:
lines.append(" - (No eligible devices or nothing to do.)")
print(header)
for line in lines:
print(line)
bec_logger.logger.warning("[cSAXS] Nothing to do.")
logger.warning("[cSAXS] Nothing to do.")
return
# --- Summary table ---
@@ -342,7 +359,7 @@ class cSAXSInitSmaractStages:
print(f"{'Device':<35} {'Init position':>20}")
print("-" * 60)
for dev_name, init_pos in planned_moves:
print(f"{dev_name:<35} {init_pos:>20}")
print(f"{dev_name:<35} {init_pos:>20.6g}")
print("-" * 60)
# Notes / diagnostics
@@ -353,79 +370,78 @@ class cSAXSInitSmaractStages:
print("\nNote: The following requested devices are unknown and were ignored:")
print(", ".join(unknown_requested))
if not_referenced:
print(
"\nNote: The following devices are NOT referenced and will be skipped:"
)
print("\nNote: The following devices are NOT referenced and will be skipped:")
print(", ".join(sorted(not_referenced)))
if missing_params:
print(
"\nNote: The following devices have no init_position defined and will be skipped:"
)
print("\nNote: The following devices have no init_position defined and will be skipped:")
print(", ".join(sorted(missing_params)))
if inaccessible_devices:
print(
"\nNote: The following devices were not accessible and will be skipped:"
)
print("\nNote: The following devices were not accessible and will be skipped:")
print(", ".join(sorted(inaccessible_devices)))
# Second confirmation: execution
if not self.OMNYTools.yesno(
"Proceed with the motions listed above?",
"y",
):
bec_logger.logger.info(
"[cSAXS] Motion to initial position aborted by user."
)
if not self._yesno("Proceed with the motions listed above?", "y"):
logger.info("[cSAXS] Motion to initial position aborted by user.")
return
# --- Execution phase (SIMULTANEOUS MOTION) ---
if umv is None:
logger.error("[cSAXS] 'umv' is not available in this session.")
return
# Build a flat argument list: [dev1, pos1, dev2, pos2, ...]
move_args = []
for dev_name, init_pos in planned_moves:
try:
d = getattr(dev, dev_name)
move_args.append(d)
move_args.append(init_pos)
bec_logger.logger.info(
f"[cSAXS] Preparing move: {dev_name} -> {init_pos}"
)
except Exception as exc:
bec_logger.logger.error(
f"[cSAXS] Could not access {dev_name}: {exc}"
)
d = self._get_device_object(dev_name)
if d is None:
logger.error(f"[cSAXS] Could not access {dev_name}, skipping.")
continue
move_args.append(d)
move_args.append(init_pos)
logger.info(f"[cSAXS] Preparing move: {dev_name} -> {init_pos}")
if not move_args:
bec_logger.logger.warning(
"[cSAXS] No valid devices left for simultaneous motion."
)
logger.warning("[cSAXS] No valid devices left for simultaneous motion.")
return
# Now trigger simultaneous move
# Trigger simultaneous move
try:
bec_logger.logger.info(
f"[cSAXS] Starting simultaneous motion of {len(planned_moves)} devices."
)
umv(*move_args) # <-- simultaneous move
logger.info(f"[cSAXS] Starting simultaneous motion of {len(planned_moves)} devices.")
umv(*move_args) # simultaneous move
except Exception as exc:
bec_logger.logger.error(
f"[cSAXS] Simultaneous motion failed: {exc}"
)
logger.error(f"[cSAXS] Simultaneous motion failed: {exc}")
return
bec_logger.logger.info(
"[cSAXS] Simultaneous SmarAct motion to initial positions completed."
)
logger.info("[cSAXS] Simultaneous SmarAct motion to initial positions completed.")
# Final warning summary about unreferenced devices
if not_referenced:
logger.warning(
"[cSAXS] Some stages were NOT moved because they are not referenced:\n"
+ ", ".join(sorted(not_referenced))
+ "\nPlease reference these axes and re-run if needed."
)
class cSAXSSmaract:
def __init__(self, client) -> None:
self.client = client
def fshn1in(self):
# Fetch in position
in_pos = self.OMNYTools._get_user_param_safe("fast_shutter_n1_x","in")
umv(dev.fast_shutter_n1_x,in_pos)
def _get_user_param_safe(self, device_name: str, key: str):
try:
return dev[device_name].user_parameter.get(key)
except Exception:
return None
def fshn1in(self):
"""
Move fast shutter n1 to its 'in' position defined in user parameters.
"""
in_pos = self._get_user_param_safe("fast_shutter_n1_x", "in")
if in_pos is None:
logger.error("[cSAXS] No 'in' position defined for fast_shutter_n1_x.")
return
if umv is None:
logger.error("[cSAXS] 'umv' is not available in this session.")
return
umv(dev.fast_shutter_n1_x, in_pos)

View File

@@ -1,3 +1,4 @@
################## XBOX 1 ES #####################
xbpm3x:
description: X-ray beam position x monitor 1 in ESbox1
@@ -18,6 +19,8 @@ xbpm3x:
readoutPriority: baseline
userParameter:
init_position: -22.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 0
xbpm3y:
description: X-ray beam position y monitor 1 in ESbox1
@@ -38,6 +41,8 @@ xbpm3y:
readoutPriority: baseline
userParameter:
init_position: -2
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 1
sl3trxi:
description: ESbox1 slit 3 inner blade movement
@@ -58,6 +63,8 @@ sl3trxi:
readoutPriority: baseline
userParameter:
init_position: -5.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 2
sl3trxo:
description: ESbox1 slit 3 outer blade movement
@@ -78,6 +85,8 @@ sl3trxo:
readoutPriority: baseline
userParameter:
init_position: 6
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 3
sl3trxb:
description: ESbox1 slit 3 bottom blade movement
@@ -98,6 +107,8 @@ sl3trxb:
readoutPriority: baseline
userParameter:
init_position: -5.8
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 4
sl3trxt:
description: ESbox1 slit 3 top blade movement
@@ -118,6 +129,8 @@ sl3trxt:
readoutPriority: baseline
userParameter:
init_position: 5.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 5
fast_shutter_n1_x:
description: ESbox1 New fast shutter 1 x movment
@@ -139,6 +152,8 @@ fast_shutter_n1_x:
userParameter:
init_position: -7
in: 0
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 7
fast_shutter_o1_x:
description: ESbox1 Old fast shutter 1 x movment
@@ -159,6 +174,8 @@ fast_shutter_o1_x:
readoutPriority: baseline
userParameter:
init_position: -15.8
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 6
fast_shutter_o2_x:
description: ESbox1 Old fast shutter 2 x movment
@@ -179,6 +196,8 @@ fast_shutter_o2_x:
readoutPriority: baseline
userParameter:
init_position: -15.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 5
filter_array_1_x:
description: ESbox1 Filter Array 1 x movment
@@ -199,6 +218,8 @@ filter_array_1_x:
readoutPriority: baseline
userParameter:
init_position: 25
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 1
filter_array_2_x:
description: ESbox1 Filter Array 2 x movment
@@ -219,6 +240,8 @@ filter_array_2_x:
readoutPriority: baseline
userParameter:
init_position: 25.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 2
filter_array_3_x:
description: ESbox1 Filter Array 3 x movment
@@ -239,6 +262,8 @@ filter_array_3_x:
readoutPriority: baseline
userParameter:
init_position: 25.8
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 3
filter_array_4_x:
description: ESbox1 Filter Array 4 x movment
@@ -259,6 +284,8 @@ filter_array_4_x:
readoutPriority: baseline
userParameter:
init_position: 25
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 4
sl4trxi:
description: ESbox1 slit 4 inner blade movement
@@ -279,6 +306,8 @@ sl4trxi:
readoutPriority: baseline
userParameter:
init_position: -5.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 6
sl4trxo:
description: ESbox1 slit 4 outer blade movement
@@ -299,6 +328,8 @@ sl4trxo:
readoutPriority: baseline
userParameter:
init_position: 6
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 7
sl4trxb:
description: ESbox1 slit 4 bottom blade movement
@@ -319,6 +350,8 @@ sl4trxb:
readoutPriority: baseline
userParameter:
init_position: -5.8
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 8
sl4trxt:
description: ESbox1 slit 4 top blade movement
@@ -339,6 +372,8 @@ sl4trxt:
readoutPriority: baseline
userParameter:
init_position: 5.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 0
################## XBOX 2 ES #####################
@@ -361,6 +396,8 @@ sl5trxi:
readoutPriority: baseline
userParameter:
init_position: -6
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 2
sl5trxo:
description: ESbox2 slit 5 outer blade movement
@@ -381,6 +418,8 @@ sl5trxo:
readoutPriority: baseline
userParameter:
init_position: 5.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 3
sl5trxb:
description: ESbox2 slit 5 bottom blade movement
@@ -401,6 +440,8 @@ sl5trxb:
readoutPriority: baseline
userParameter:
init_position: -5.5
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 4
sl5trxt:
description: ESbox1 slit 5 top blade movement
@@ -421,6 +462,8 @@ sl5trxt:
readoutPriority: baseline
userParameter:
init_position: 6
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 5
xbimtrx:
description: ESbox2 beam intensity monitor x movement
@@ -441,6 +484,8 @@ xbimtrx:
readoutPriority: baseline
userParameter:
init_position: -14.7
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 0
xbimtry:
description: ESbox2 beam intensity monitor y movement
@@ -461,3 +506,5 @@ xbimtry:
readoutPriority: baseline
userParameter:
init_position: 0
# bl_smar_stage to use csaxs reference method. assign number according to axis channel
bl_smar_stage: 1