Compare commits
11 Commits
test_gitea
...
fix/async_
| Author | SHA1 | Date | |
|---|---|---|---|
| 7233fb8d35 | |||
| 32d3232008 | |||
|
|
725eed17ed | ||
|
|
1d9fb39c0e | ||
|
|
f1dd299fad | ||
| 1fcb213336 | |||
|
|
b08c7bf44b | ||
|
|
d16f6b703c | ||
|
|
f526d5cc05 | ||
|
|
8f7914b978 | ||
|
|
6c65d5546c |
@@ -47,25 +47,13 @@ jobs:
|
||||
python-version: "${{ inputs.PYTHON_VERSION || '3.11' }}"
|
||||
|
||||
- name: Checkout BEC Core
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: bec/bec
|
||||
ref: "${{ inputs.BEC_CORE_BRANCH || 'main' }}"
|
||||
path: ./bec
|
||||
run: git clone --depth 1 --branch "${{ inputs.BEC_CORE_BRANCH || 'main' }}" https://github.com/bec-project/bec.git ./bec
|
||||
|
||||
- name: Checkout Ophyd Devices
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: bec/ophyd_devices
|
||||
ref: "${{ inputs.OPHYD_DEVICES_BRANCH || 'main' }}"
|
||||
path: ./ophyd_devices
|
||||
run: git clone --depth 1 --branch "${{ inputs.OPHYD_DEVICES_BRANCH || 'main' }}" https://github.com/bec-project/ophyd_devices.git ./ophyd_devices
|
||||
|
||||
- name: Checkout BEC Widgets
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: bec/bec_widgets
|
||||
ref: "${{ inputs.BEC_WIDGETS_BRANCH || 'main' }}"
|
||||
path: ./bec_widgets
|
||||
run: git clone --depth 1 --branch "${{ inputs.BEC_WIDGETS_BRANCH || 'main' }}" https://github.com/bec-project/bec_widgets.git ./bec_widgets
|
||||
|
||||
- name: Checkout BEC Plugin Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -14,6 +14,8 @@ from typeguard import typechecked
|
||||
from csaxs_bec.bec_ipython_client.plugins.cSAXS import cSAXSBeamlineChecks
|
||||
from csaxs_bec.bec_ipython_client.plugins.flomni.flomni_optics_mixin import FlomniOpticsMixin
|
||||
from csaxs_bec.bec_ipython_client.plugins.flomni.x_ray_eye_align import XrayEyeAlign
|
||||
from csaxs_bec.bec_ipython_client.plugins.flomni.gui_tools import flomniGuiTools
|
||||
from csaxs_bec.bec_ipython_client.plugins.omny.omny_general_tools import OMNYTools
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
@@ -24,27 +26,57 @@ if builtins.__dict__.get("bec") is not None:
|
||||
umvr = builtins.__dict__.get("umvr")
|
||||
|
||||
|
||||
class FlomniToolsError(Exception):
|
||||
pass
|
||||
|
||||
class FlomniInitError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class FlomniError(Exception):
|
||||
pass
|
||||
|
||||
class FlomniTools:
|
||||
def yesno(self, message: str, default="none", autoconfirm=0) -> bool:
|
||||
if autoconfirm and default == "y":
|
||||
self.printgreen(message + " Automatically confirming default: yes")
|
||||
return True
|
||||
elif autoconfirm and default == "n":
|
||||
self.printgreen(message + " Automatically confirming default: no")
|
||||
return False
|
||||
if default == "y":
|
||||
message_ending = " [Y]/n? "
|
||||
elif default == "n":
|
||||
message_ending = " y/[N]? "
|
||||
else:
|
||||
message_ending = " y/n? "
|
||||
while True:
|
||||
user_input = input(self.OKBLUE + message + message_ending + self.ENDC)
|
||||
if (
|
||||
user_input == "Y" or user_input == "y" or user_input == "yes" or user_input == "Yes"
|
||||
) or (default == "y" and user_input == ""):
|
||||
return True
|
||||
if (
|
||||
user_input == "N" or user_input == "n" or user_input == "no" or user_input == "No"
|
||||
) or (default == "n" and user_input == ""):
|
||||
return False
|
||||
else:
|
||||
print("Please expicitely confirm y or n.")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class FlomniInitStagesMixin:
|
||||
|
||||
def flomni_init_stages(self):
|
||||
|
||||
user_input = input("Starting initialization of flOMNI stages. OK? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Starting initialization of flOMNI stages. OK?"):
|
||||
print("staring...")
|
||||
else:
|
||||
return
|
||||
|
||||
if self.check_all_axes_of_fomni_referenced():
|
||||
user_input = input("Continue anyways? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("All axes are referenced. Continue anyways?"):
|
||||
print("ok then...")
|
||||
else:
|
||||
return
|
||||
@@ -74,10 +106,8 @@ class FlomniInitStagesMixin:
|
||||
dev.feyex.limits = [-30, -1]
|
||||
print("done")
|
||||
|
||||
user_input = input(
|
||||
"Init of foptz. Can the stage move to the upstream limit without collision? [y/n]"
|
||||
)
|
||||
if user_input == "y":
|
||||
|
||||
if self.OMNYTools.yesno("Init of foptz. Can the stage move to the upstream limit without collision?"):
|
||||
print("good then")
|
||||
else:
|
||||
return
|
||||
@@ -131,10 +161,7 @@ class FlomniInitStagesMixin:
|
||||
dev.fsamy.limits = [2, 3.1]
|
||||
print("done")
|
||||
|
||||
user_input = input(
|
||||
"Init of tracking stages. Did you remove the outer laser flight tubes? [y/n]"
|
||||
)
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Init of tracking stages. Did you remove the outer laser flight tubes?"):
|
||||
print("good then")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -150,8 +177,7 @@ class FlomniInitStagesMixin:
|
||||
dev.ftrackz.limits = [4.5, 5.5]
|
||||
print("done")
|
||||
|
||||
user_input = input("Init of sample stage. Is the piezo at about 0 deg? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Init of sample stage. Is the piezo at about 0 deg?"):
|
||||
print("good then")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -168,11 +194,7 @@ class FlomniInitStagesMixin:
|
||||
print("done")
|
||||
|
||||
print("Initializing UPR stage.")
|
||||
user_input = input(
|
||||
"To ensure that the end switches work, please check that they are currently not pushed."
|
||||
" Is everything okay? [y/n]"
|
||||
)
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("To ensure that the end switches work, please check that they are currently not pushed. Is everything okay?"):
|
||||
print("good then")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -193,8 +215,7 @@ class FlomniInitStagesMixin:
|
||||
time.sleep(1)
|
||||
continue
|
||||
break
|
||||
user_input = input("Shall I start the index search? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Shall I start the index search?"):
|
||||
print("good then. Starting index search.")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -213,11 +234,7 @@ class FlomniInitStagesMixin:
|
||||
dev.fsamroy.limits = [-5, 365]
|
||||
print("done")
|
||||
|
||||
user_input = input(
|
||||
"Init of foptx. Can the stage move to the positive limit without collision? Attention:"
|
||||
" tracker flight tube! [y/n]"
|
||||
)
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Init of foptx. Can the stage move to the positive limit without collision? Attention: tracker flight tube!"):
|
||||
print("good then")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -241,8 +258,7 @@ class FlomniInitStagesMixin:
|
||||
continue
|
||||
break
|
||||
|
||||
user_input = input("Start limit switch search of fopty? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Start limit switch search of fopty?"):
|
||||
print("good then")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -275,8 +291,7 @@ class FlomniInitStagesMixin:
|
||||
return False
|
||||
|
||||
def set_limits(self):
|
||||
user_input = input("Set default limits for flOMNI? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Set default limits for flOMNI?"):
|
||||
print("setting limits...")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -303,8 +318,7 @@ class FlomniInitStagesMixin:
|
||||
dev.ftrackz.limits = [4.5, 5.5]
|
||||
|
||||
def _align_setup(self):
|
||||
user_input = input("Start moving stages to default initial positions? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("Start moving stages to default initial positions?", "y"):
|
||||
print("Start moving stages...")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -397,7 +411,8 @@ class FlomniSampleTransferMixin:
|
||||
raise FlomniError("Ftray is not at the 'IN' position. Aborting.")
|
||||
|
||||
def ftransfer_flomni_stage_in(self):
|
||||
sample_in_position = bool(float(dev.flomni_samples.sample_placed.sample0.get()))
|
||||
sample_in_position = dev.flomni_samples.is_sample_slot_used(0)
|
||||
#bool(float(dev.flomni_samples.sample_placed.sample0.get()))
|
||||
if not sample_in_position:
|
||||
raise FlomniError("There is no sample in the sample stage. Aborting.")
|
||||
self.reset_correction()
|
||||
@@ -410,6 +425,8 @@ class FlomniSampleTransferMixin:
|
||||
umv(dev.fsamx, fsamx_in)
|
||||
dev.fsamx.limits = [fsamx_in - 0.4, fsamx_in + 0.4]
|
||||
|
||||
self.flomnigui_idle()
|
||||
|
||||
def laser_tracker_show_all(self):
|
||||
dev.rtx.controller.laser_tracker_show_all()
|
||||
|
||||
@@ -449,6 +466,10 @@ class FlomniSampleTransferMixin:
|
||||
self.device_manager.devices.fsamx.controller.lights_on()
|
||||
|
||||
def ftransfer_flomni_stage_out(self):
|
||||
|
||||
self.flomnigui_show_cameras()
|
||||
|
||||
|
||||
target_pos = -162
|
||||
if np.isclose(dev.fsamx.readback.get(), target_pos, 0.01):
|
||||
return
|
||||
@@ -496,22 +517,20 @@ class FlomniSampleTransferMixin:
|
||||
self.check_tray_in()
|
||||
self.check_sensor_connected()
|
||||
|
||||
sample_in_gripper = bool(float(dev.flomni_samples.sample_in_gripper.get()))
|
||||
sample_in_gripper = dev.flomni_samples.is_sample_in_gripper()
|
||||
if sample_in_gripper:
|
||||
raise FlomniError(
|
||||
"The gripper does carry a sample. Cannot proceed getting another sample."
|
||||
)
|
||||
|
||||
sample_signal = getattr(dev.flomni_samples.sample_placed, f"sample{position}")
|
||||
sample_in_position = bool(float(sample_signal.get()))
|
||||
sample_in_position = dev.flomni_samples.is_sample_slot_used(position)
|
||||
if not sample_in_position:
|
||||
raise FlomniError(f"The planned pick position [{position}] does not have a sample.")
|
||||
|
||||
user_input = input(
|
||||
"Please confirm that there is currently no sample in the gripper. It would be dropped!"
|
||||
" [y/n]"
|
||||
)
|
||||
if user_input == "y":
|
||||
self.flomnigui_show_cameras()
|
||||
|
||||
|
||||
if self.OMNYTools.yesno("Please confirm that there is currently no sample in the gripper. It would be dropped!", "y"):
|
||||
print("good then")
|
||||
else:
|
||||
print("Stopping.")
|
||||
@@ -555,12 +574,12 @@ class FlomniSampleTransferMixin:
|
||||
self.check_tray_in()
|
||||
self.check_sensor_connected()
|
||||
|
||||
sample_in_gripper = bool(float(dev.flomni_samples.sample_in_gripper.get()))
|
||||
sample_in_gripper = dev.flomni_samples.is_sample_in_gripper()
|
||||
#bool(float(dev.flomni_samples.sample_in_gripper.get()))
|
||||
if not sample_in_gripper:
|
||||
raise FlomniError("The gripper does not carry a sample.")
|
||||
|
||||
sample_signal = getattr(dev.flomni_samples.sample_placed, f"sample{position}")
|
||||
sample_in_position = bool(float(sample_signal.get()))
|
||||
sample_in_position = dev.flomni_samples.is_sample_slot_used(position)
|
||||
if sample_in_position:
|
||||
raise FlomniError(f"The planned put position [{position}] already has a sample.")
|
||||
|
||||
@@ -593,8 +612,9 @@ class FlomniSampleTransferMixin:
|
||||
self.flomni_modify_storage_non_interactive(100, 0, "-")
|
||||
self.flomni_modify_storage_non_interactive(position, 1, sample_name)
|
||||
|
||||
# TODO: flomni_stage_in if position == 0
|
||||
# bec.queue.next_dataset_number += 1
|
||||
if position == 0:
|
||||
self.ftransfer_flomni_stage_in()
|
||||
bec.queue.next_dataset_number += 1
|
||||
|
||||
def sample_get_name(self, position: int = 0) -> str:
|
||||
"""
|
||||
@@ -605,36 +625,51 @@ class FlomniSampleTransferMixin:
|
||||
|
||||
def ftransfer_sample_change(self, new_sample_position: int):
|
||||
self.check_tray_in()
|
||||
sample_in_gripper = dev.flomni_samples.sample_in_gripper.get()
|
||||
# sample_in_gripper = dev.flomni_samples.sample_in_gripper.get()
|
||||
sample_in_gripper = dev.flomni_samples.is_sample_in_gripper()
|
||||
if sample_in_gripper:
|
||||
raise FlomniError("There is already a sample in the gripper. Aborting.")
|
||||
|
||||
self.check_position_is_valid(new_sample_position)
|
||||
|
||||
sample_placed = getattr(
|
||||
dev.flomni_samples.sample_placed, f"sample{new_sample_position}"
|
||||
).get()
|
||||
if new_sample_position == 0:
|
||||
raise FlomniError("The new sample to place cannot be the sample in the sample stage. Aborting.")
|
||||
|
||||
# sample_placed = getattr(
|
||||
# dev.flomni_samples.sample_placed, f"sample{new_sample_position}"
|
||||
# ).get()
|
||||
sample_placed = dev.flomni_samples.is_sample_slot_used(new_sample_position)
|
||||
if not sample_placed:
|
||||
raise FlomniError(
|
||||
f"There is currently no sample in position [{new_sample_position}]. Aborting."
|
||||
)
|
||||
|
||||
sample_in_sample_stage = dev.flomni_samples.sample_placed.sample0.get()
|
||||
# sample_in_sample_stage = dev.flomni_samples.sample_placed.sample0.get()
|
||||
sample_in_sample_stage = dev.flomni_samples.is_sample_slot_used(0)
|
||||
if sample_in_sample_stage:
|
||||
# find a new home for the sample...
|
||||
empty_slots = []
|
||||
for name, val in dev.flomni_samples.read().items():
|
||||
if "flomni_samples_sample_placed_sample" not in name:
|
||||
continue
|
||||
if val.get("value") == 0:
|
||||
empty_slots.append(int(name.split("flomni_samples_sample_placed_sample")[1]))
|
||||
# for name, val in dev.flomni_samples.read().items():
|
||||
# if "flomni_samples_sample_placed_sample" not in name:
|
||||
# continue
|
||||
# if val.get("value") == 0:
|
||||
# empty_slots.append(int(name.split("flomni_samples_sample_placed_sample")[1]))
|
||||
for j in range(1,20):
|
||||
if not dev.flomni_samples.is_sample_slot_used(j):
|
||||
empty_slots.append(j)
|
||||
if not empty_slots:
|
||||
raise FlomniError("There are no empty slots available. Aborting.")
|
||||
|
||||
print(f"The following slots are empty: {empty_slots}.")
|
||||
|
||||
while True:
|
||||
user_input = input(f"Where shall I put the sample? Default: [{empty_slots[0]}]")
|
||||
user_input = input(f"Where shall I put the sample? Default: [{empty_slots[0]}] ")
|
||||
|
||||
if user_input.strip() == "":
|
||||
# No entry: use default
|
||||
user_input = empty_slots[0]
|
||||
break
|
||||
|
||||
try:
|
||||
user_input = int(user_input)
|
||||
if user_input not in empty_slots:
|
||||
@@ -700,20 +735,20 @@ class FlomniSampleTransferMixin:
|
||||
if confirm != -1:
|
||||
return
|
||||
|
||||
user_input = input("All OK? Continue? [y/n]")
|
||||
if user_input == "y":
|
||||
if self.OMNYTools.yesno("All OK? Continue?", "y"):
|
||||
print("good then")
|
||||
dev.ftransy.controller.socket_put_confirmed("confirm=1")
|
||||
else:
|
||||
print("Stopping.")
|
||||
return
|
||||
exit
|
||||
|
||||
def ftransfer_gripper_is_open(self) -> bool:
|
||||
status = bool(float(dev.ftransy.controller.socket_put_and_receive("MG @OUT[9]").strip()))
|
||||
return status
|
||||
|
||||
def ftransfer_gripper_open(self):
|
||||
sample_in_gripper = dev.flomni_samples.sample_in_gripper.get()
|
||||
sample_in_gripper = dev.flomni_samples.is_sample_in_gripper()
|
||||
#dev.flomni_samples.sample_in_gripper.get()
|
||||
if sample_in_gripper:
|
||||
raise FlomniError(
|
||||
"Cannot open gripper. There is still a sample in the gripper! Aborting."
|
||||
@@ -733,11 +768,8 @@ class FlomniSampleTransferMixin:
|
||||
|
||||
fsamx_pos = dev.fsamx.readback.get()
|
||||
if position == 0 and fsamx_pos > -160:
|
||||
user_input = input(
|
||||
"May the flomni stage be moved out for the sample change? Feedback will be disabled"
|
||||
" and alignment will be lost! [y/n]"
|
||||
)
|
||||
if user_input == "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"):
|
||||
print("good then")
|
||||
self.ftransfer_flomni_stage_out()
|
||||
else:
|
||||
@@ -1106,6 +1138,7 @@ class Flomni(
|
||||
FlomniAlignmentMixin,
|
||||
FlomniOpticsMixin,
|
||||
cSAXSBeamlineChecks,
|
||||
flomniGuiTools
|
||||
):
|
||||
def __init__(self, client):
|
||||
super().__init__()
|
||||
@@ -1128,13 +1161,20 @@ class Flomni(
|
||||
self.corr_pos_y_2 = []
|
||||
self.corr_angle_y_2 = []
|
||||
self.progress = {}
|
||||
self.progress["subtomo"] = 0
|
||||
self.progress["subtomo_projection"] = 0
|
||||
self.progress["subtomo_total_projections"] = 1
|
||||
self.progress["projection"] = 0
|
||||
self.progress["total_projections"] = 1
|
||||
self.progress["angle"] = 0
|
||||
self.progress["tomo_type"] = 0
|
||||
self.OMNYTools = OMNYTools(self.client)
|
||||
self.align = XrayEyeAlign(self.client, self)
|
||||
self.set_client(client)
|
||||
|
||||
def start_x_ray_eye_alignment(self):
|
||||
user_input = input(
|
||||
"Starting Xrayeye alignment. Deleting any potential existing alignment for this sample. [Y/n]"
|
||||
)
|
||||
if user_input == "y" or user_input == "":
|
||||
|
||||
if self.OMNYTools.yesno("Starting Xrayeye alignment. Deleting any potential existing alignment for this sample.", "y"):
|
||||
self.align = XrayEyeAlign(self.client, self)
|
||||
try:
|
||||
self.align.align()
|
||||
@@ -1570,6 +1610,9 @@ class Flomni(
|
||||
|
||||
def tomo_scan(self, subtomo_start=1, start_angle=None, projection_number=None):
|
||||
"""start a tomo scan"""
|
||||
|
||||
self.flomnigui_show_progress()
|
||||
|
||||
bec = builtins.__dict__.get("bec")
|
||||
scans = builtins.__dict__.get("scans")
|
||||
self._current_special_angles = self.special_angles.copy()
|
||||
@@ -1706,6 +1749,7 @@ class Flomni(
|
||||
print(f"Angle: ........................... {self.progress['angle']}")
|
||||
print(f"Current subtomo: ................. {self.progress['subtomo']}")
|
||||
print(f"Current projection within subtomo: {self.progress['subtomo_projection']}\x1b[0m")
|
||||
self._flomnigui_update_progress()
|
||||
|
||||
def add_sample_database(
|
||||
self, samplename, date, eaccount, scan_number, setup, sample_additional_info, user
|
||||
@@ -1795,7 +1839,7 @@ class Flomni(
|
||||
|
||||
def _write_tomo_scan_number(self, scan_number: int, angle: float, subtomo_number: int) -> None:
|
||||
tomo_scan_numbers_file = os.path.expanduser(
|
||||
"~/Data10/specES1/dat-files/tomography_scannumbers.txt"
|
||||
"~/tomography_scannumbers.txt"
|
||||
)
|
||||
with open(tomo_scan_numbers_file, "a+") as out_file:
|
||||
# pylint: disable=undefined-variable
|
||||
@@ -1894,8 +1938,8 @@ class Flomni(
|
||||
)
|
||||
print(f"\nSample name: {self.sample_name}\n")
|
||||
|
||||
user_input = input("Are these parameters correctly set for your scan? [Y/n]")
|
||||
if user_input == "y" or user_input == "":
|
||||
|
||||
if self.OMNYTools.yesno("Are these parameters correctly set for your scan?", "y"):
|
||||
print("... excellent!")
|
||||
else:
|
||||
self.tomo_countingtime = self._get_val("<ctime> s", self.tomo_countingtime, float)
|
||||
|
||||
150
csaxs_bec/bec_ipython_client/plugins/flomni/gui_tools.py
Normal file
150
csaxs_bec/bec_ipython_client/plugins/flomni/gui_tools.py
Normal file
@@ -0,0 +1,150 @@
|
||||
import builtins
|
||||
|
||||
from bec_widgets.cli.client import BECDockArea
|
||||
|
||||
# from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen, fshclose
|
||||
|
||||
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")
|
||||
|
||||
|
||||
class flomniGuiToolsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class flomniGuiTools:
|
||||
|
||||
def __init__(self):
|
||||
self.gui_window = None
|
||||
self.camera_gripper_image = None
|
||||
self.camera_overview_image = None
|
||||
self.progressbar = None
|
||||
self.text_box = None
|
||||
self.idle_text_box = None
|
||||
|
||||
def set_client(self, client):
|
||||
self.client = client
|
||||
self.gui = self.client.gui
|
||||
|
||||
def flomnigui_show_gui(self):
|
||||
if "flomni" in self.gui.windows:
|
||||
self.gui.flomni.show()
|
||||
else:
|
||||
self.gui.new("flomni")
|
||||
|
||||
def flomnigui_stop_gui(self):
|
||||
self.gui.flomni.hide()
|
||||
|
||||
def flomnigui_show_cameras(self):
|
||||
self.flomnigui_show_gui()
|
||||
if self.camera_gripper_image is None or self.camera_overview_image is None:
|
||||
self.flomnigui_remove_all_docks()
|
||||
self.camera_gripper_image = self.gui.flomni.new("camera_gripper").new("Image")
|
||||
if self._flomnicam_check_device_exists(dev.cam_flomni_gripper):
|
||||
self.camera_gripper_image.image(("cam_flomni_gripper", "preview"))
|
||||
self.camera_gripper_image.lock_aspect_ratio = True
|
||||
self.camera_gripper_image.enable_fps_monitor = True
|
||||
self.camera_gripper_image.enable_toolbar = False
|
||||
self.camera_gripper_image.outer_axes = False
|
||||
self.camera_gripper_image.inner_axes = False
|
||||
dev.cam_flomni_gripper.start_live_mode()
|
||||
else:
|
||||
print("Cannot open camera_gripper. Device does not exist.")
|
||||
self.camera_overview_image = self.gui.flomni.new("camera_overview").new("Image")
|
||||
if self._flomnicam_check_device_exists(dev.cam_flomni_overview):
|
||||
self.camera_overview_image.image(("cam_flomni_overview", "preview"))
|
||||
self.camera_overview_image.lock_aspect_ratio = True
|
||||
self.camera_overview_image.enable_fps_monitor = True
|
||||
self.camera_overview_image.enable_toolbar = False
|
||||
self.camera_overview_image.outer_axes = False
|
||||
self.camera_overview_image.inner_axes = False
|
||||
dev.cam_flomni_overview.start_live_mode()
|
||||
else:
|
||||
print("Cannot open camera_overview. Device does not exist.")
|
||||
|
||||
def flomnigui_remove_all_docks(self):
|
||||
dev.cam_flomni_overview.stop_live_mode()
|
||||
dev.cam_flomni_gripper.stop_live_mode()
|
||||
self.gui.flomni.delete_all()
|
||||
self.camera_gripper_image = None
|
||||
self.camera_overview_image = None
|
||||
self.progressbar = None
|
||||
self.text_box = None
|
||||
self.idle_text_box = None
|
||||
|
||||
def flomnigui_idle(self):
|
||||
self.flomnigui_show_gui()
|
||||
if self.idle_text_box is None:
|
||||
self.flomnigui_remove_all_docks()
|
||||
self.idle_text_box = self.gui.flomni.new("idle_textbox").new("TextBox")
|
||||
text = (
|
||||
"<pre>"
|
||||
+ " ,---.,--. ,-----. ,--. ,--.,--. ,--.,--. \n"
|
||||
+ "/ .-'| |' .-. '| `.' || ,'.| || | \n"
|
||||
+ "| `-,| || | | || |'.'| || |' ' || | \n"
|
||||
+ "| .-'| |' '-' '| | | || | ` || | \n"
|
||||
+ "`--' `--' `-----' `--' `--'`--' `--'`--' \n"
|
||||
+ "</pre>"
|
||||
)
|
||||
self.idle_text_box.set_html_text(text)
|
||||
|
||||
def _flomnicam_check_device_exists(self, device):
|
||||
try:
|
||||
device
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def flomnigui_show_progress(self):
|
||||
self.flomnigui_show_gui()
|
||||
if self.progressbar is None:
|
||||
self.flomnigui_remove_all_docks()
|
||||
# Add a new dock with a RingProgressBar widget
|
||||
self.progressbar = self.gui.flomni.new("progressbar").new("RingProgressBar")
|
||||
# Customize the size of the progress ring
|
||||
self.progressbar.set_line_widths(20)
|
||||
# Disable automatic updates and manually set the self.progressbar value
|
||||
self.progressbar.enable_auto_updates(False)
|
||||
# Set precision for the self.progressbar display
|
||||
self.progressbar.set_precision(1) # Display self.progressbar with one decimal places
|
||||
# Setting multiple rigns with different values
|
||||
self.progressbar.set_number_of_bars(3)
|
||||
self.progressbar.rings[0].set_update("manual")
|
||||
self.progressbar.rings[1].set_update("manual")
|
||||
self.progressbar.rings[2].set_update("scan")
|
||||
# Set the values of the rings to 50, 75, and 25 from outer to inner ring
|
||||
# self.progressbar.set_value([50, 75])
|
||||
# Add a new dock with a TextBox widget
|
||||
self.text_box = self.gui.flomni.new(name="progress_text").new("TextBox")
|
||||
|
||||
self._flomnigui_update_progress()
|
||||
|
||||
def _flomnigui_update_progress(self):
|
||||
if self.progressbar is not None:
|
||||
progress = self.progress["projection"] / self.progress["total_projections"] * 100
|
||||
subtomo_progress = (
|
||||
self.progress["subtomo_projection"]
|
||||
/ self.progress["subtomo_total_projections"]
|
||||
* 100
|
||||
)
|
||||
self.progressbar.set_value([progress, subtomo_progress, 0])
|
||||
|
||||
text = f"Progress report:\n Tomo type: ....................... {self.progress['tomo_type']}\n Projection: ...................... {self.progress['projection']:.0f}\n Total projections expected ....... {self.progress['total_projections']}\n Angle: ........................... {self.progress['angle']}\n Current subtomo: ................. {self.progress['subtomo']}\n Current projection within subtomo: {self.progress['subtomo_projection']}\n Total projections per subtomo: ... {self.progress['subtomo_total_projections']}"
|
||||
self.text_box.set_plain_text(text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from bec_lib.client import BECClient
|
||||
from bec_widgets.cli.client_utils import BECGuiClient
|
||||
|
||||
client = BECClient()
|
||||
client.start()
|
||||
client.gui = BECGuiClient()
|
||||
|
||||
flomni_gui = flomniGuiTools(client)
|
||||
flomni_gui.flomnigui_show_gui()
|
||||
flomni_gui.flomnigui_show_progress()
|
||||
@@ -213,6 +213,8 @@ ftransy:
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
userParameter:
|
||||
sensor_voltage: -2.4
|
||||
ftransz:
|
||||
description: Sample transer Z
|
||||
deviceClass: csaxs_bec.devices.omny.galil.fgalil_ophyd.FlomniGalilMotor
|
||||
@@ -333,8 +335,8 @@ rtx:
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
userParameter:
|
||||
low_signal: 11000
|
||||
min_signal: 10000
|
||||
low_signal: 10000
|
||||
min_signal: 9000
|
||||
rt_pid_voltage: -0.06219
|
||||
rty:
|
||||
description: flomni rt
|
||||
@@ -362,3 +364,57 @@ rtz:
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
|
||||
############################################################
|
||||
####################### Cameras ############################
|
||||
############################################################
|
||||
|
||||
cam_flomni_gripper:
|
||||
description: Camera sample changer
|
||||
deviceClass: csaxs_bec.devices.omny.webcam_viewer.WebcamViewer
|
||||
deviceConfig:
|
||||
url: http://flomnicamserver:5000/video_high
|
||||
num_rotation_90: 3
|
||||
transpose: false
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
|
||||
cam_flomni_overview:
|
||||
description: Camera flomni overview
|
||||
deviceClass: csaxs_bec.devices.omny.webcam_viewer.WebcamViewer
|
||||
deviceConfig:
|
||||
url: http://flomnicamserver:5001/video_high
|
||||
num_rotation_90: 3
|
||||
transpose: false
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: on_request
|
||||
|
||||
# cam_flomni_xeye:
|
||||
# description: Camera flOMNI Xray eye ID101
|
||||
# deviceClass: csaxs_bec.devices.ids_cameras.ids_camera.IDSCamera
|
||||
# deviceConfig:
|
||||
# camera_ID: 101
|
||||
# bits_per_pixel: 24
|
||||
# channels: 3
|
||||
# m_n_colormode: 1
|
||||
# enabled: true
|
||||
# onFailure: buffer
|
||||
# readOnly: false
|
||||
# readoutPriority: async
|
||||
|
||||
|
||||
# ############################################################
|
||||
# ################### flOMNI temperatures ####################
|
||||
# ############################################################
|
||||
flomni_temphum:
|
||||
description: flOMNI Temperatures and humidity
|
||||
deviceClass: csaxs_bec.devices.omny.flomni_temp_and_humidity.FlomniTempHum
|
||||
deviceConfig: {}
|
||||
enabled: true
|
||||
onFailure: buffer
|
||||
readOnly: false
|
||||
readoutPriority: baseline
|
||||
@@ -209,15 +209,7 @@ class IDSCamera(PSIDeviceBase):
|
||||
else:
|
||||
data = image.data * self.mask
|
||||
n_channels = 1
|
||||
self.roi_signal.put(
|
||||
{
|
||||
self.roi_signal.name: {
|
||||
"value": np.sum(data)
|
||||
/ (np.sum(self.mask) * n_channels), # TODO could be optimized
|
||||
"timestamp": time.time(),
|
||||
}
|
||||
}
|
||||
)
|
||||
self.roi_signal.put(np.sum(data) / (np.sum(self.mask) * n_channels))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -24,24 +24,25 @@ class FlomniSampleStorage(Device):
|
||||
SUB_VALUE = "value"
|
||||
_default_sub = SUB_VALUE
|
||||
sample_placed = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_flomni{i}:GET", {}) for i in range(21)
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_flomni{i}:GET", {"auto_monitor": True}) for i in range(21)
|
||||
}
|
||||
sample_placed = Dcpt(sample_placed)
|
||||
|
||||
sample_names = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_flomni{i}:GET.DESC", {"string": True})
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_flomni{i}:GET.DESC", {"string": True, "auto_monitor": True})
|
||||
for i in range(21)
|
||||
}
|
||||
sample_names = Dcpt(sample_names)
|
||||
|
||||
sample_in_gripper = Cpt(
|
||||
EpicsSignal, name="sample_in_gripper", read_pv="XOMNY-SAMPLE_DB_flomni100:GET"
|
||||
EpicsSignal, name="sample_in_gripper", read_pv="XOMNY-SAMPLE_DB_flomni100:GET", auto_monitor=True
|
||||
)
|
||||
sample_in_gripper_name = Cpt(
|
||||
EpicsSignal,
|
||||
name="sample_in_gripper_name",
|
||||
read_pv="XOMNY-SAMPLE_DB_flomni100:GET.DESC",
|
||||
string=True,
|
||||
auto_monitor=True
|
||||
)
|
||||
|
||||
def __init__(self, prefix="", *, name, **kwargs):
|
||||
|
||||
208
csaxs_bec/devices/omny/flomni_temp_and_humidity.py
Normal file
208
csaxs_bec/devices/omny/flomni_temp_and_humidity.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import time
|
||||
import datetime
|
||||
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import Device
|
||||
from ophyd import DynamicDeviceComponent as Dcpt
|
||||
from ophyd import EpicsSignal
|
||||
from prettytable import FRAME, PrettyTable
|
||||
import numpy as np
|
||||
|
||||
class FlomniTempHumError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class FlomniTempHum(Device):
|
||||
USER_ACCESS = [
|
||||
"show_all",
|
||||
"help",
|
||||
]
|
||||
SUB_VALUE = "value"
|
||||
_default_sub = SUB_VALUE
|
||||
|
||||
|
||||
temperature_mirror = Cpt(
|
||||
EpicsSignal, name="temperature_mirror", read_pv="XOMNI-TEMPHUM-MIRROR:0.VAL"
|
||||
)
|
||||
temperature_mirrorset_set = Cpt(
|
||||
EpicsSignal, name="temperature_mirrorset_set", read_pv="XOMNI-TEMPHUM-MIRRORSET_SET:0.VAL"
|
||||
)
|
||||
temperature_mirrorset_rb = Cpt(
|
||||
EpicsSignal, name="temperature_mirrorset_rb", read_pv="XOMNI-TEMPHUM-MIRRORSET_RB:0.VAL"
|
||||
)
|
||||
|
||||
temperature_osa = Cpt(
|
||||
EpicsSignal, name="temperature_osa", read_pv="XOMNI-TEMPHUM-OSA:0.VAL"
|
||||
)
|
||||
temperature_osaset_set = Cpt(
|
||||
EpicsSignal, name="temperature_osaset_set", read_pv="XOMNI-TEMPHUM-OSASET_SET:0.VAL"
|
||||
)
|
||||
temperature_osaset_rb = Cpt(
|
||||
EpicsSignal, name="temperature_osaset_rb", read_pv="XOMNI-TEMPHUM-OSASET_RB:0.VAL"
|
||||
)
|
||||
|
||||
omegactrl_alive = Cpt(
|
||||
EpicsSignal, name="omegactrl_alive", read_pv="XOMNI-TEMPHUM-OMEGACTRL-ALIVE:0.VAL"
|
||||
)
|
||||
galilctrl_alive = Cpt(
|
||||
EpicsSignal, name="galilctrl_alive", read_pv="XOMNI-TEMPHUM-GALILCTRL-ALIVE:0.VAL"
|
||||
)
|
||||
|
||||
temperature_heater = Cpt(
|
||||
EpicsSignal, name="temperature_heater", read_pv="XOMNI-TEMPHUM-HEATER:0.VAL"
|
||||
)
|
||||
temperature_heaterset_set = Cpt(
|
||||
EpicsSignal, name="temperature_heaterset_set", read_pv="XOMNI-TEMPHUM-HEATERSET_SET:0.VAL"
|
||||
)
|
||||
temperature_heaterset_rb = Cpt(
|
||||
EpicsSignal, name="temperature_heaterset_rb", read_pv="XOMNI-TEMPHUM-HEATERSET_RB:0.VAL"
|
||||
)
|
||||
temperature_heaterhousing = Cpt(
|
||||
EpicsSignal, name="temperature_heaterhousing", read_pv="XOMNI-TEMPHUM-HEATERHOUSE:0.VAL"
|
||||
)
|
||||
temperature_heaterhousing_alarm = Cpt(
|
||||
EpicsSignal, name="temperature_heaterhousing_alarm", read_pv="XOMNI-TEMPHUM-HEATERHOUSEALARM:0.VAL"
|
||||
)
|
||||
temperature_heater_enabled = Cpt(
|
||||
EpicsSignal, name="temperature_heater_enabled", read_pv="XOMNI-TEMPHUM-HEAT_EN:0.VAL"
|
||||
)
|
||||
|
||||
temperature_heater_enabled = Cpt(
|
||||
EpicsSignal, name="temperature_heater_enabled", read_pv="XOMNI-TEMPHUM-HEAT_EN:0.VAL"
|
||||
)
|
||||
|
||||
###### GALIL CONTROLLER
|
||||
|
||||
|
||||
humidity_sensor1 = Cpt(
|
||||
EpicsSignal, name="humidity_sensor1", read_pv="XOMNI-TEMPHUM-HUM1:0.VAL"
|
||||
)
|
||||
|
||||
humidity_sensor2 = Cpt(
|
||||
EpicsSignal, name="humidity_sensor2", read_pv="XOMNI-TEMPHUM-HUM2:0.VAL"
|
||||
)
|
||||
|
||||
humidity_sensor1_temperature = Cpt(
|
||||
EpicsSignal, name="humidity_sensor1_temperature", read_pv="XOMNI-TEMPHUM-TEMP1:0.VAL"
|
||||
)
|
||||
|
||||
humidity_sensor2_temperature = Cpt(
|
||||
EpicsSignal, name="humidity_sensor2_temperature", read_pv="XOMNI-TEMPHUM-TEMP2:0.VAL"
|
||||
)
|
||||
|
||||
humidity_sensor1_err = Cpt(
|
||||
EpicsSignal, name="humidity_sensor1_err", read_pv="XOMNI-TEMPHUM-ERR1:0.VAL"
|
||||
)
|
||||
|
||||
humidity_sensor2_err = Cpt(
|
||||
EpicsSignal, name="humidity_sensor2_err", read_pv="XOMNI-TEMPHUM-ERR2:0.VAL"
|
||||
)
|
||||
|
||||
flow = Cpt(
|
||||
EpicsSignal, name="flow", read_pv="XOMNI-TEMPHUM-FLOW:0.VAL"
|
||||
)
|
||||
|
||||
flowset = Cpt(
|
||||
EpicsSignal, name="flowset", read_pv="XOMNI-TEMPHUM-FLOWSET:0.VAL"
|
||||
)
|
||||
|
||||
flowset_set = Cpt(
|
||||
EpicsSignal, name="flowset_set", read_pv="XOMNI-TEMPHUM-FLOWSETSET:0.VAL"
|
||||
)
|
||||
|
||||
humidityset = Cpt(
|
||||
EpicsSignal, name="humidityset", read_pv="XOMNI-TEMPHUM-HUMSET:0.VAL"
|
||||
)
|
||||
|
||||
humidityset_set = Cpt(
|
||||
EpicsSignal, name="humidityset_set", read_pv="XOMNI-TEMPHUM-HUMSETSET:0.VAL"
|
||||
)
|
||||
|
||||
suction = Cpt(
|
||||
EpicsSignal, name="suction", read_pv="XOMNI-TEMPHUM-SUCTION:0.VAL"
|
||||
)
|
||||
|
||||
valvedry = Cpt(
|
||||
EpicsSignal, name="valvedry", read_pv="XOMNI-TEMPHUM-VALVEDRY:0.VAL"
|
||||
)
|
||||
|
||||
valvewet = Cpt(
|
||||
EpicsSignal, name="valvewet", read_pv="XOMNI-TEMPHUM-VALVEWET:0.VAL"
|
||||
)
|
||||
|
||||
setuptemp = Cpt(
|
||||
EpicsSignal, name="setuptemp", read_pv="XOMNI-TEMPHUM-SETUPTEMP:0.VAL"
|
||||
)
|
||||
|
||||
|
||||
|
||||
def omega_controller_running(self):
|
||||
time_diff = np.fabs(float(self.omegactrl_alive.get()) - time.time())
|
||||
if time_diff > 120:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def galil_controller_running(self):
|
||||
time_diff = np.fabs(float(self.galilctrl_alive.get()) - time.time())
|
||||
if time_diff > 120:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def __init__(self, prefix="", *, name, **kwargs):
|
||||
super().__init__(prefix, name=name, **kwargs)
|
||||
self.temperature_mirror.subscribe(self._emit_value, run=False)
|
||||
|
||||
def _emit_value(self, **kwargs):
|
||||
timestamp = kwargs.pop("timestamp", time.time())
|
||||
self._run_subs(sub_type=self.SUB_VALUE, timestamp=timestamp, obj=self)
|
||||
|
||||
|
||||
|
||||
def show_all(self):
|
||||
print("=== flOMNI Temperature & Humidity Overview ===")
|
||||
print("")
|
||||
print("Temperatures:")
|
||||
print(f" Mirror: {float(self.temperature_mirror.get()):7.2f} °C")
|
||||
print(f" Mirror Setpoint (RB): {float(self.temperature_mirrorset_rb.get()):7.2f} °C")
|
||||
print(f" OSA: {float(self.temperature_osa.get()):7.2f} °C")
|
||||
print(f" OSA Setpoint (RB): {float(self.temperature_osaset_rb.get()):7.2f} °C")
|
||||
print(f" Heater: {float(self.temperature_heater.get()):7.2f} °C")
|
||||
print(f" Heater Setpoint (RB): {float(self.temperature_heaterset_rb.get()):7.2f} °C")
|
||||
print(f" Heater Enabled: {float(self.temperature_heater_enabled.get()):.0f}")
|
||||
print(f" Heater Housing: {float(self.temperature_heaterhousing.get()):7.2f} °C")
|
||||
print(f" Heater Housing Alarm: {float(self.temperature_heaterhousing_alarm.get()):.0f}")
|
||||
print("")
|
||||
print("Humidity Sensors:")
|
||||
print(f" Sensor 1 Humidity: {float(self.humidity_sensor1.get()):7.2f} %RH")
|
||||
print(f" Sensor 1 Temperature: {float(self.humidity_sensor1_temperature.get()):7.2f} °C")
|
||||
print(f" Sensor 1 Error: {float(self.humidity_sensor1_err.get()):.0f}")
|
||||
print(f" Sensor 2 Humidity: {float(self.humidity_sensor2.get()):7.2f} %RH")
|
||||
print(f" Sensor 2 Temperature: {float(self.humidity_sensor2_temperature.get()):7.2f} °C")
|
||||
print(f" Sensor 2 Error: {float(self.humidity_sensor2_err.get()):.0f}")
|
||||
print(f" Humidity Setpoint: {float(self.humidityset.get()):7.2f} %RH")
|
||||
print("")
|
||||
print("Flow Control:")
|
||||
print(f" Flow: {float(self.flow.get()):7.2f} sccm")
|
||||
print(f" Flow Setpoint (RB): {float(self.flowset.get()):7.2f} sccm")
|
||||
print("")
|
||||
print("Suction:")
|
||||
print(f" Suction: {float(self.suction.get()):7.2f}")
|
||||
print("")
|
||||
print("Valves:")
|
||||
print(f" Dry Valve: {float(self.valvedry.get()):.0f}")
|
||||
print(f" Wet Valve: {float(self.valvewet.get()):.0f}")
|
||||
print("")
|
||||
print("Controller Heartbeats:")
|
||||
print(f" OMEGA Controller Alive: {self.omega_controller_running()}")
|
||||
print(f" GALIL Controller Alive: {self.galil_controller_running()}")
|
||||
print("==============================================")
|
||||
|
||||
|
||||
def help(self):
|
||||
print("Help for flOMNI temperature and humidity control system:")
|
||||
print("Available methods:")
|
||||
print(" show_all() - display all current values")
|
||||
@@ -37,84 +37,86 @@ class OMNYSampleStorage(Device):
|
||||
_default_sub = SUB_VALUE
|
||||
|
||||
sample_shuttle_A_placed = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_A:{i}", {}) for i in range(1, 7)
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_A:{i}", {"auto_monitor": True}) for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_A_placed = Dcpt(sample_shuttle_A_placed)
|
||||
|
||||
sample_shuttle_B_placed = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_B:{i}", {}) for i in range(1, 7)
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_B:{i}", {"auto_monitor": True}) for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_B_placed = Dcpt(sample_shuttle_B_placed)
|
||||
|
||||
sample_shuttle_C_placed = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_C:{i}", {}) for i in range(1, 7)
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_C:{i}", {"auto_monitor": True}) for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_C_placed = Dcpt(sample_shuttle_C_placed)
|
||||
|
||||
sample_shuttle_C_placed = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_C:{i}", {}) for i in range(1, 7)
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_C:{i}", {"auto_monitor": True}) for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_C_placed = Dcpt(sample_shuttle_C_placed)
|
||||
|
||||
parking_placed = {
|
||||
f"parking{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_parking:{i}", {}) for i in range(1, 7)
|
||||
f"parking{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_parking:{i}", {"auto_monitor": True}) for i in range(1, 7)
|
||||
}
|
||||
parking_placed = Dcpt(parking_placed)
|
||||
|
||||
sample_placed = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_omny:{i}", {})
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_omny:{i}", {"auto_monitor": True})
|
||||
for i in [10, 11, 12, 13, 14, 32, 33, 34, 100, 101]
|
||||
}
|
||||
sample_placed = Dcpt(sample_placed)
|
||||
|
||||
sample_shuttle_A_names = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_A:{i}.DESC", {"string": True})
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_A:{i}.DESC", {"string": True, "auto_monitor": True})
|
||||
for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_A_names = Dcpt(sample_shuttle_A_names)
|
||||
|
||||
sample_shuttle_B_names = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_B:{i}.DESC", {"string": True})
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_B:{i}.DESC", {"string": True, "auto_monitor": True})
|
||||
for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_B_names = Dcpt(sample_shuttle_B_names)
|
||||
|
||||
sample_shuttle_C_names = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_C:{i}.DESC", {"string": True})
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_shuttle_C:{i}.DESC", {"string": True, "auto_monitor": True})
|
||||
for i in range(1, 7)
|
||||
}
|
||||
sample_shuttle_C_names = Dcpt(sample_shuttle_C_names)
|
||||
|
||||
parking_names = {
|
||||
f"parking{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_parking:{i}.DESC", {"string": True})
|
||||
f"parking{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_parking:{i}.DESC", {"string": True, "auto_monitor": True})
|
||||
for i in range(1, 7)
|
||||
}
|
||||
parking_names = Dcpt(parking_names)
|
||||
|
||||
sample_names = {
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_omny:{i}.DESC", {"string": True})
|
||||
f"sample{i}": (EpicsSignal, f"XOMNY-SAMPLE_DB_omny:{i}.DESC", {"string": True, "auto_monitor": True})
|
||||
for i in [10, 11, 12, 13, 14, 32, 33, 34, 100, 101]
|
||||
}
|
||||
sample_names = Dcpt(sample_names)
|
||||
|
||||
sample_in_gripper = Cpt(
|
||||
EpicsSignal, name="sample_in_gripper", read_pv="XOMNY-SAMPLE_DB_omny:110.VAL"
|
||||
EpicsSignal, name="sample_in_gripper", read_pv="XOMNY-SAMPLE_DB_omny:110.VAL", auto_monitor=True
|
||||
)
|
||||
sample_in_gripper_name = Cpt(
|
||||
EpicsSignal,
|
||||
name="sample_in_gripper_name",
|
||||
read_pv="XOMNY-SAMPLE_DB_omny:110.DESC",
|
||||
string=True,
|
||||
auto_monitor=True
|
||||
)
|
||||
|
||||
sample_in_samplestage = Cpt(
|
||||
EpicsSignal, name="sample_in_samplestage", read_pv="XOMNY-SAMPLE_DB_omny:0.VAL"
|
||||
EpicsSignal, name="sample_in_samplestage", read_pv="XOMNY-SAMPLE_DB_omny:0.VAL", auto_monitor=True
|
||||
)
|
||||
sample_in_samplestage_name = Cpt(
|
||||
EpicsSignal,
|
||||
name="sample_in_samplestage_name",
|
||||
read_pv="XOMNY-SAMPLE_DB_omny:0.DESC",
|
||||
string=True,
|
||||
auto_monitor=True
|
||||
)
|
||||
|
||||
def __init__(self, prefix="", *, name, **kwargs):
|
||||
|
||||
@@ -392,6 +392,9 @@ class RtFlomniController(Controller):
|
||||
rtx = self.get_device_manager().devices.rtx
|
||||
min_signal = rtx.user_parameter.get("min_signal")
|
||||
low_signal = rtx.user_parameter.get("low_signal")
|
||||
print(f"low signal: {low_signal}")
|
||||
print(f"min signal: {min_signal}")
|
||||
print(f"signal: {signal}")
|
||||
if signal < min_signal:
|
||||
time.sleep(1)
|
||||
if signal < min_signal:
|
||||
|
||||
65
csaxs_bec/devices/omny/webcam_viewer.py
Normal file
65
csaxs_bec/devices/omny/webcam_viewer.py
Normal file
@@ -0,0 +1,65 @@
|
||||
import requests
|
||||
import threading
|
||||
import cv2
|
||||
import numpy as np
|
||||
from ophyd import Device, Component as Cpt
|
||||
from ophyd_devices import PreviewSignal
|
||||
import traceback
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
class WebcamViewer(Device):
|
||||
USER_ACCESS = ["start_live_mode", "stop_live_mode"]
|
||||
preview = Cpt(PreviewSignal, ndim=2, num_rotation_90=0, transpose=False)
|
||||
|
||||
def __init__(self, url:str, name:str, num_rotation_90=0, transpose=False, **kwargs) -> None:
|
||||
super().__init__(name=name, **kwargs)
|
||||
self.url = url
|
||||
self._connection = None
|
||||
self._update_thread = None
|
||||
self._buffer = b""
|
||||
self._shutdown_event = threading.Event()
|
||||
self.preview.num_rotation_90 = num_rotation_90
|
||||
self.preview.transpose = transpose
|
||||
|
||||
def start_live_mode(self) -> None:
|
||||
if self._connection is not None:
|
||||
return
|
||||
self._update_thread = threading.Thread(target=self._update_loop, daemon=True)
|
||||
self._update_thread.start()
|
||||
|
||||
def _update_loop(self) -> None:
|
||||
while not self._shutdown_event.is_set():
|
||||
try:
|
||||
self._connection = requests.get(self.url, stream=True)
|
||||
for chunk in self._connection.iter_content(chunk_size=1024):
|
||||
self._buffer += chunk
|
||||
start = self._buffer.find(b'\xff\xd8') # JPEG start
|
||||
end = self._buffer.find(b'\xff\xd9') # JPEG end
|
||||
if start == -1 or end == -1:
|
||||
continue
|
||||
jpg = self._buffer[start:end+2]
|
||||
self._buffer = self._buffer[end+2:]
|
||||
|
||||
image = cv2.imdecode(np.frombuffer(jpg, np.uint8), cv2.IMREAD_COLOR)
|
||||
if image is not None:
|
||||
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||
self.preview.put(image)
|
||||
except Exception as exc:
|
||||
content = traceback.format_exc()
|
||||
logger.error(f"Image update loop failed: {content}")
|
||||
|
||||
def stop_live_mode(self) -> None:
|
||||
if self._connection is None:
|
||||
return
|
||||
self._shutdown_event.set()
|
||||
if self._connection is not None:
|
||||
self._connection.close()
|
||||
self._connection = None
|
||||
if self._update_thread is not None:
|
||||
self._update_thread.join()
|
||||
self._update_thread = None
|
||||
|
||||
self._shutdown_event.clear()
|
||||
@@ -33,11 +33,11 @@ logger = bec_logger.logger
|
||||
|
||||
class FlomniFermatScan(SyncFlyScanBase):
|
||||
scan_name = "flomni_fermat_scan"
|
||||
scan_report_hint = "table"
|
||||
scan_type = "fly"
|
||||
required_kwargs = ["fovx", "fovy", "exp_time", "step", "angle"]
|
||||
arg_input = {}
|
||||
arg_bundle_size = {"bundle": len(arg_input), "min": None, "max": None}
|
||||
use_scan_progress_report = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -74,6 +74,7 @@ class FlomniFermatScan(SyncFlyScanBase):
|
||||
"""
|
||||
|
||||
super().__init__(parameter=parameter, **kwargs)
|
||||
self.show_live_table = False
|
||||
self.axis = []
|
||||
self.fovx = fovx
|
||||
self.fovy = fovy
|
||||
@@ -168,6 +169,7 @@ class FlomniFermatScan(SyncFlyScanBase):
|
||||
tracker_signal_status = yield from self.stubs.send_rpc_and_wait(
|
||||
"rtx", "controller.laser_tracker_check_signalstrength"
|
||||
)
|
||||
#self.device_manager.connector.send_client_info(tracker_signal_status)
|
||||
if tracker_signal_status == "low":
|
||||
self.device_manager.connector.raise_alarm(
|
||||
severity=0,
|
||||
|
||||
@@ -16,7 +16,7 @@ dependencies = [
|
||||
"bec_ipython_client",
|
||||
"bec_lib",
|
||||
"bec_server",
|
||||
"ophyd_devices",
|
||||
"ophyd_devices~=1.29",
|
||||
"std_daq_client",
|
||||
"jfjoch-client",
|
||||
"rich",
|
||||
@@ -24,6 +24,7 @@ dependencies = [
|
||||
"pyueye", # for the IDS uEye camera
|
||||
"bec_widgets",
|
||||
"zmq",
|
||||
"opencv-python",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
Reference in New Issue
Block a user