From d3c86b07a0985208da00a2e617e2e093b265f6aa Mon Sep 17 00:00:00 2001 From: Holler Mirko Date: Tue, 1 Oct 2024 15:36:10 +0200 Subject: [PATCH] introduce 25 deg offset in osamroy to have 0 to 360 initial work on omny class --- .../bec_ipython_client/plugins/omny/omny.py | 25 +- .../plugins/omny/omny_rt.py | 9 + .../omny/omny_sample_transfer_mixin.py | 8 +- .../plugins/omny/x_ray_eye_align.py | 237 ++++++++++++++++++ csaxs_bec/devices/omny/galil/ogalil_ophyd.py | 12 +- csaxs_bec/devices/omny/rt/rt_omny_ophyd.py | 6 +- 6 files changed, 277 insertions(+), 20 deletions(-) create mode 100644 csaxs_bec/bec_ipython_client/plugins/omny/x_ray_eye_align.py diff --git a/csaxs_bec/bec_ipython_client/plugins/omny/omny.py b/csaxs_bec/bec_ipython_client/plugins/omny/omny.py index b9a2fde..3676cf1 100644 --- a/csaxs_bec/bec_ipython_client/plugins/omny/omny.py +++ b/csaxs_bec/bec_ipython_client/plugins/omny/omny.py @@ -17,7 +17,7 @@ from csaxs_bec.bec_ipython_client.plugins.omny.omny_alignment_mixin import OMNYA from csaxs_bec.bec_ipython_client.plugins.omny.omny_general_tools import OMNYTools from csaxs_bec.bec_ipython_client.plugins.omny.omny_sample_transfer_mixin import OMNYSampleTransferMixin from csaxs_bec.bec_ipython_client.plugins.omny.omny_rt import OMNY_rt_client -#from csaxs_bec.bec_ipython_client.plugins.flomni.x_ray_eye_align import XrayEyeAlign +from csaxs_bec.bec_ipython_client.plugins.omny.x_ray_eye_align import XrayEyeAlign logger = bec_logger.logger @@ -38,7 +38,7 @@ class OMNYError(Exception): class OMNYInitStagesMixin: - def enable_all_devices(): + def enable_all_devices(self): dev.ofzpx.enabled = True dev.ofzpy.enabled = True dev.ofzpz.enabled = True @@ -438,7 +438,7 @@ class OMNYInitStagesMixin: # dev.rtz.limits = [-250, 250] dev.osamx.limits = [-1, 1] dev.osamy.limits = [2.3000, 3.0000] - dev.osamroy.limits = [-27.0000, 337.0000] + dev.osamroy.limits = [-2.0000, 362.0000] dev.oeyex.limits = [-48.0000, 10.0000] dev.oeyez.limits = [-85.0000, 10.0000] dev.oeyey.limits = [-61.0000, 1.0000] @@ -542,6 +542,7 @@ class OMNY( self.progress = {} self.OMNYTools = OMNYTools(self.client) OMNY_rt_client.__init__(self) + self.align = XrayEyeAlign(self.client, self) def start_x_ray_eye_alignment(self): if self.OMNYTools.yesno( @@ -1403,14 +1404,16 @@ class OMNY( # header = "" header = ( " \n" * 3 - + " .d888 888 .d88888b. 888b d888 888b 888 8888888 \n" - + ' d88P" 888 d88P" "Y88b 8888b d8888 8888b 888 888 \n' - + " 888 888 888 888 88888b.d88888 88888b 888 888 \n" - + " 888888 888 888 888 888Y88888P888 888Y88b 888 888 \n" - + " 888 888 888 888 888 Y888P 888 888 Y88b888 888 \n" - + " 888 888 888 888 888 Y8P 888 888 Y88888 888 \n" - + ' 888 888 Y88b. .d88P 888 " 888 888 Y8888 888 \n' - + ' 888 888 "Y88888P" 888 888 888 Y888 8888888 \n' + + " ,o888888o. ,8. ,8. b. 8 `8.`8888. ,8' \n" + + " . 8888 `88. ,888. ,888. 888o. 8 `8.`8888. ,8' \n" + + ",8 8888 `8b .`8888. .`8888. Y88888o. 8 `8.`8888. ,8' \n" + + "88 8888 `8b ,8.`8888. ,8.`8888. .`Y888888o. 8 `8.`8888.,8' \n" + + "88 8888 88 ,8'8.`8888,8^8.`8888. 8o. `Y888888o. 8 `8.`88888' \n" + + "88 8888 88 ,8' `8.`8888' `8.`8888. 8`Y8o. `Y88888o8 `8. 8888 \n" + + "88 8888 ,8P ,8' `8.`88' `8.`8888. 8 `Y8o. `Y8888 `8 8888 \n" + + "`8 8888 ,8P ,8' `8.`' `8.`8888. 8 `Y8o. `Y8 8 8888 \n" + + " ` 8888 ,88' ,8' `8 `8.`8888. 8 `Y8o.` 8 8888 \n" + + " `8888888P' ,8' ` `8.`8888. 8 `Yo 8 8888 \n" ) padding = 20 fovxy = f"{self.fovx:.2f}/{self.fovy:.2f}" diff --git a/csaxs_bec/bec_ipython_client/plugins/omny/omny_rt.py b/csaxs_bec/bec_ipython_client/plugins/omny/omny_rt.py index d46a540..ebcf739 100644 --- a/csaxs_bec/bec_ipython_client/plugins/omny/omny_rt.py +++ b/csaxs_bec/bec_ipython_client/plugins/omny/omny_rt.py @@ -398,6 +398,15 @@ class OMNY_rt_client: def feedback_disable(self): dev.rtx.controller.feedback_disable() + def laser_tracker_on(self): + dev.rtx.controller.laser_tracker_on() + + def laser_tracker_off(self): + dev.rtx.controller.laser_tracker_off() + + def laser_tracker_show_all(self): + dev.rtx.controller.laser_tracker_show_all + def omny_interferometer_align_tracking(self): self.mirror_channel=6 signal = dev.rtx.controller._omny_interferometer_get_signalsample(self.mirror_parameters[self.mirror_channel]["opt_signalchannel"], self.mirror_parameters[self.mirror_channel]["opt_averaging_time"]) diff --git a/csaxs_bec/bec_ipython_client/plugins/omny/omny_sample_transfer_mixin.py b/csaxs_bec/bec_ipython_client/plugins/omny/omny_sample_transfer_mixin.py index 7a3efa0..188e63a 100644 --- a/csaxs_bec/bec_ipython_client/plugins/omny/omny_sample_transfer_mixin.py +++ b/csaxs_bec/bec_ipython_client/plugins/omny/omny_sample_transfer_mixin.py @@ -825,7 +825,7 @@ class OMNYSampleTransferMixin: #old gripper motor #check ST position and move gripper to ST #umv otransz -18 - #umv osamroy -25 osamy 2.7 osamx 0 otransx -213 + #umv osamroy 0 osamy 2.7 osamx 0 otransx -213 #umv otransz 0 #umv otransx -458.5000 @@ -867,13 +867,13 @@ class OMNYSampleTransferMixin: if oosaz_current<0.1 and oosax_current < -1.5: oeyey_current = dev.oeyey.get().readback if oeyey_current < -40: - umv(dev.osamroy, -25, dev.osamy, 2.7, dev.osamx, 0, dev.otransx, -350, dev.oeyex, 0, dev.oeyey, -15) + umv(dev.osamroy, 0, dev.osamy, 2.7, dev.osamx, 0, dev.otransx, -350, dev.oeyex, 0, dev.oeyey, -15) else: - umv(dev.osamroy, -25, dev.osamy, 2.7, dev.osamx, 0, dev.otransx, -350, dev.oeyex, 0) + umv(dev.osamroy, 0, dev.osamy, 2.7, dev.osamx, 0, dev.otransx, -350, dev.oeyex, 0) umv(dev.oshield, 0, dev.otransx, -458.1545+0.05, dev.oeyey, -4.8) umv(dev.oshield, -12, dev.otransz, -45.6494) else: - umv(dev.osamroy, -25, dev.osamy, 2.7, dev.osamx, 0, dev.otransx, -458.1545+0.05, dev.oeyex, 0, dev.oeyey, -4.8) + umv(dev.osamroy, 0, dev.osamy, 2.7, dev.osamx, 0, dev.otransx, -458.1545+0.05, dev.oeyex, 0, dev.oeyey, -4.8) self.oeye_cam_in() diff --git a/csaxs_bec/bec_ipython_client/plugins/omny/x_ray_eye_align.py b/csaxs_bec/bec_ipython_client/plugins/omny/x_ray_eye_align.py new file mode 100644 index 0000000..5140e6b --- /dev/null +++ b/csaxs_bec/bec_ipython_client/plugins/omny/x_ray_eye_align.py @@ -0,0 +1,237 @@ +from __future__ import annotations + +import builtins +import os +import time +from typing import TYPE_CHECKING + +from bec_lib import bec_logger + +from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_get, epics_put, fshopen + +logger = bec_logger.logger +# import builtins to avoid linter errors +bec = builtins.__dict__.get("bec") +dev = builtins.__dict__.get("dev") +umv = builtins.__dict__.get("umv") +umvr = builtins.__dict__.get("umvr") + +if TYPE_CHECKING: + from bec_ipython_client.plugins.omny import OMNY + + +class XrayEyeAlign: + # pixel calibration, multiply to get mm + PIXEL_CALIBRATION = 0.1 / 113 # .2 with binning + + def __init__(self, client, omny: OMNY) -> None: + self.client = client + self.omny = omny + self.device_manager = client.device_manager + self.scans = client.scans + self.alignment_values = {} + self.omny.reset_correction() + self.omny.reset_tomo_alignment_fit() + + def _reset_init_values(self): + self.shift_xy = [0, 0] + self._xray_fov_xy = [0, 0] + + def save_frame(self): + epics_put("XOMNYI-XEYE-SAVFRAME:0", 1) + + def update_frame(self): + epics_put("XOMNYI-XEYE-ACQDONE:0", 0) + # start live + epics_put("XOMNYI-XEYE-ACQ:0", 1) + # wait for start live + while epics_get("XOMNYI-XEYE-ACQDONE:0") == 0: + time.sleep(0.5) + print("waiting for live view to start...") + fshopen() + + epics_put("XOMNYI-XEYE-ACQDONE:0", 0) + + while epics_get("XOMNYI-XEYE-ACQDONE:0") == 0: + print("waiting for new frame...") + time.sleep(0.5) + + time.sleep(0.5) + # stop live view + epics_put("XOMNYI-XEYE-ACQ:0", 0) + time.sleep(1) + # fshclose + print("got new frame") + + def update_fov(self, k: int): + self._xray_fov_xy[0] = max(epics_get(f"XOMNYI-XEYE-XWIDTH_X:{k}"), self._xray_fov_xy[0]) + self._xray_fov_xy[1] = max(0, self._xray_fov_xy[0]) + + @property + def movement_buttons_enabled(self): + return [epics_get("XOMNYI-XEYE-ENAMVX:0"), epics_get("XOMNYI-XEYE-ENAMVY:0")] + + @movement_buttons_enabled.setter + def movement_buttons_enabled(self, enabled: bool): + enabled = int(enabled) + epics_put("XOMNYI-XEYE-ENAMVX:0", enabled) + epics_put("XOMNYI-XEYE-ENAMVY:0", enabled) + + def send_message(self, msg: str): + epics_put("XOMNYI-XEYE-MESSAGE:0.DESC", msg) + + def align(self): + # reset shift xy and fov params + self._reset_init_values() + + self.flomni.lights_off() + + self.tomo_rotate(0) + epics_put("XOMNYI-XEYE-ANGLE:0", 0) + + self.flomni.feye_in() + + self.flomni.laser_tracker_on() + + self.flomni.rt_feedback_enable_with_reset() + + # disable movement buttons + self.movement_buttons_enabled = False + + sample_name = self.flomni.sample_get_name(0) + epics_put("XOMNYI-XEYE-SAMPLENAME:0.DESC", sample_name) + + # this makes sure we are in a defined state + self.flomni.rt_feedback_disable() + + epics_put("XOMNYI-XEYE-PIXELSIZE:0", self.PIXEL_CALIBRATION) + + self.flomni.fosa_out() + + fsamx_in = self.flomni._get_user_param_safe("fsamx", "in") + umv(dev.fsamx, fsamx_in - 0.25) + + self.flomni.ffzp_in() + self.update_frame() + + # enable submit buttons + self.movement_buttons_enabled = False + epics_put("XOMNYI-XEYE-SUBMIT:0", 0) + epics_put("XOMNYI-XEYE-STEP:0", 0) + self.send_message("Submit center value of FZP.") + + k = 0 + while True: + if epics_get("XOMNYI-XEYE-SUBMIT:0") == 1: + val_x = epics_get(f"XOMNYI-XEYE-XVAL_X:{k}") / 2 * self.PIXEL_CALIBRATION # in mm + self.alignment_values[k] = val_x + print(f"Clicked position {k}: x {self.alignment_values[k]}") + rtx_position = dev.rtx.readback.get() / 1000 + print(f"Current rtx position {rtx_position}") + self.alignment_values[k] -= rtx_position + print(f"Corrected position {k}: x {self.alignment_values[k]}") + + if k == 0: # received center value of FZP + self.send_message("please wait ...") + self.movement_buttons_enabled = False + epics_put("XOMNYI-XEYE-SUBMIT:0", -1) # disable submit button + + self.flomni.rt_feedback_disable() + fsamx_in = self.flomni._get_user_param_safe("fsamx", "in") + umv(dev.fsamx, fsamx_in) + + self.flomni.foptics_out() + + self.flomni.rt_feedback_disable() + umv(dev.fsamx, fsamx_in - 0.25) + + self.update_frame() + epics_put("XOMNYI-XEYE-RECBG:0", 1) + while epics_get("XOMNYI-XEYE-RECBG:0") == 1: + time.sleep(0.5) + print("waiting for background frame...") + + umv(dev.fsamx, fsamx_in) + time.sleep(0.5) + self.flomni.rt_feedback_enable_with_reset() + + self.update_frame() + self.send_message("Adjust sample height and submit center") + epics_put("XOMNYI-XEYE-SUBMIT:0", 0) + self.movement_buttons_enabled = True + + elif 1 <= k < 5: # received sample center value at samroy 0 ... 315 + self.send_message("please wait ...") + epics_put("XOMNYI-XEYE-SUBMIT:0", -1) + self.movement_buttons_enabled = False + + umv(dev.rtx, 0) + self.tomo_rotate(k * 45) + epics_put("XOMNYI-XEYE-ANGLE:0", self.get_tomo_angle()) + self.update_frame() + self.send_message("Submit sample center") + epics_put("XOMNYI-XEYE-SUBMIT:0", 0) + epics_put("XOMNYI-XEYE-ENAMVX:0", 1) + self.update_fov(k) + + elif k == 5: # received sample center value at samroy 270 and done + self.send_message("done...") + epics_put("XOMNYI-XEYE-SUBMIT:0", -1) # disable submit button + self.movement_buttons_enabled = False + self.update_fov(k) + break + + k += 1 + epics_put("XOMNYI-XEYE-STEP:0", k) + + _xrayeyalignmvx = epics_get("XOMNYI-XEYE-MVX:0") + if _xrayeyalignmvx != 0: + umvr(dev.rtx, _xrayeyalignmvx) + print(f"Current rtx position {dev.rtx.readback.get() / 1000}") + epics_put("XOMNYI-XEYE-MVX:0", 0) + if k > 0: + epics_put(f"XOMNYI-XEYE-STAGEPOSX:{k}", dev.rtx.readback.get() / 1000) + time.sleep(3) + self.update_frame() + + if k < 2: + # allow movements, store movements to calculate center + _xrayeyalignmvy = epics_get("XOMNYI-XEYE-MVY:0") + if _xrayeyalignmvy != 0: + self.flomni.rt_feedback_disable() + umvr(dev.fsamy, _xrayeyalignmvy / 1000) + time.sleep(2) + epics_put("XOMNYI-XEYE-MVY:0", 0) + self.flomni.rt_feedback_enable_with_reset() + self.update_frame() + time.sleep(0.2) + + self.write_output() + fovx = self._xray_fov_xy[0] * self.PIXEL_CALIBRATION * 1000 / 2 + fovy = self._xray_fov_xy[1] * self.PIXEL_CALIBRATION * 1000 / 2 + + self.tomo_rotate(0) + + umv(dev.rtx, 0) + + # free camera + epics_put("XOMNYI-XEYE-ACQ:0", 2) + + print( + f"The largest field of view from the xrayeyealign was \nfovx = {fovx:.0f} microns, fovy" + f" = {fovy:.0f} microns" + ) + print("Use the matlab routine to FIT the current alignment...") + + print("Then LOAD ALIGNMENT PARAMETERS by running flomni.read_alignment_offset()\n") + + def write_output(self): + file = os.path.expanduser("~/Data10/specES1/internal/xrayeye_alignmentvalues") + if not os.path.exists(file): + os.makedirs(os.path.dirname(file), exist_ok=True) + with open(file, "w") as alignment_values_file: + alignment_values_file.write("angle\thorizontal\n") + for k in range(1, 6): + fovx_offset = self.alignment_values[0] - self.alignment_values[k] + print(f"Writing to file new alignment: number {k}, value x {fovx_offset}") + alignment_values_file.write(f"{(k-1)*45}\t{fovx_offset*1000}\n") diff --git a/csaxs_bec/devices/omny/galil/ogalil_ophyd.py b/csaxs_bec/devices/omny/galil/ogalil_ophyd.py index 5358aa9..29991ae 100644 --- a/csaxs_bec/devices/omny/galil/ogalil_ophyd.py +++ b/csaxs_bec/devices/omny/galil/ogalil_ophyd.py @@ -65,19 +65,27 @@ class OMNYGalilReadbackSignal(GalilSignalRO): current_pos = float(self.controller.socket_put_and_receive(f"TP{self.parent.axis_Id}")) current_pos *= self.parent.sign step_mm = self.parent.motor_resolution.get() - return current_pos / step_mm + #here we introduce an offset of 25 to the rotation axis + #when setting a position this is taken into account in the controller + #that way we just do tomography from 0 to 180 degrees + if self.parent.axis_Id_numeric == 2 and self.sock.port == 8083: + return (current_pos / step_mm)+25 + else: + return current_pos / step_mm def read(self): self._metadata["timestamp"] = time.time() val = super().read() #if reading rotation stage angle if self.parent.axis_Id_numeric == 2 and self.sock.port == 8083: + try: rt = self.parent.device_manager.devices["rtx"] if rt.enabled: rt.obj.controller.set_rotation_angle(val[self.parent.name]["value"]) except KeyError: - logger.warning("Failed to set RT value during ogalil readback.") + logger.warning("Failed to set RT value during ogalil readback.") +# val[self.parent.name]["value"] = val[self.parent.name]["value"]+25 return val diff --git a/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py b/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py index bcee9ee..9c35a0f 100644 --- a/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py +++ b/csaxs_bec/devices/omny/rt/rt_omny_ophyd.py @@ -182,9 +182,9 @@ class RtOMNYController(Controller): osamroy = self.get_device_manager().devices.osamroy # the following read will also upate the angle in rt during readout readback = osamroy.obj.readback.get() - if (np.fabs(readback + 25) > 0.1): + if (np.fabs(readback) > 0.1): self.get_device_manager().connector.send_client_info(f"Rotating to zero", scope="feedback enable", show_asap=True) - osamroy.obj.move(-25, wait=True) + osamroy.obj.move(0, wait=True) osamx = self.get_device_manager().devices.osamx @@ -245,7 +245,7 @@ class RtOMNYController(Controller): def laser_tracker_off(self): if self.feedback_is_running(): print( - "Interferometer feedback is running. Cannot disable the tracker. First disable the feedback using rt_feedback_disable()" + "Interferometer feedback is running. Cannot disable the tracker. First disable the feedback using omny.feedback_disable()" ) else: self.socket_put("T0")