black; added push events to rt_lamni

This commit is contained in:
wakonig_k 2022-07-25 19:03:53 +02:00
parent 069887c5cb
commit 98a1426a98
5 changed files with 204 additions and 157 deletions

View File

@ -1,5 +1,4 @@
import functools import functools
import logging
import threading import threading
import time import time
from typing import List from typing import List
@ -12,9 +11,9 @@ from ophyd.utils import ReadOnlyError, LimitError
from ophyd_devices.utils.controller import Controller, threadlocked from ophyd_devices.utils.controller import Controller, threadlocked
from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected
from prettytable import PrettyTable from prettytable import PrettyTable
from bec_utils import bec_logger
logger = logging.getLogger("galil") logger = bec_logger.logger
class GalilCommunicationError(Exception): class GalilCommunicationError(Exception):
pass pass
@ -546,7 +545,6 @@ class GalilMotor(Device, PositionerBase):
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
mock = False mock = False
if not mock: if not mock:

View File

@ -1,4 +1,3 @@
import logging
import threading import threading
import time import time
from typing import List from typing import List
@ -10,8 +9,9 @@ from ophyd.utils import ReadOnlyError
from ophyd_devices.utils.controller import Controller from ophyd_devices.utils.controller import Controller
from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected
from prettytable import PrettyTable from prettytable import PrettyTable
from bec_utils import bec_logger
logger = logging.getLogger("galil") logger = bec_logger.logger
class GalilCommunicationError(Exception): class GalilCommunicationError(Exception):
@ -460,7 +460,6 @@ class GalilMotor(Device, PositionerBase):
if __name__ == "__main__": if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
mock = True mock = True
if not mock: if not mock:

View File

@ -1,24 +1,21 @@
import functools import functools
import threading import threading
import time import time
import numpy as np
from typing import List from typing import List
from ophyd import PositionerBase, Device, Component as Cpt
from prettytable import PrettyTable
from ophyd_devices.utils.controller import Controller
from ophyd_devices.utils.socket import (
SocketIO,
raise_if_disconnected,
SocketSignal,
)
from bec_utils import bec_logger
from ophyd.utils import ReadOnlyError,LimitError
from ophyd.status import wait as status_wait
from ophyd import Signal
import numpy as np
from bec_utils import BECMessage, MessageEndpoints, bec_logger
from ophyd import Component as Cpt
from ophyd import Device, PositionerBase, Signal
from ophyd.status import wait as status_wait
from ophyd.utils import LimitError, ReadOnlyError
from ophyd_devices.utils.controller import Controller
from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected
from prettytable import PrettyTable
logger = bec_logger.logger logger = bec_logger.logger
def threadlocked(fcn): def threadlocked(fcn):
"""Ensure that thread acquires and releases the lock.""" """Ensure that thread acquires and releases the lock."""
@ -29,6 +26,7 @@ def threadlocked(fcn):
return wrapper return wrapper
class RtLamniCommunicationError(Exception): class RtLamniCommunicationError(Exception):
pass pass
@ -36,9 +34,11 @@ class RtLamniCommunicationError(Exception):
class RtLamniError(Exception): class RtLamniError(Exception):
pass pass
class BECConfigError(Exception): class BECConfigError(Exception):
pass pass
def retry_once(fcn): def retry_once(fcn):
"""Decorator to rerun a function in case a CommunicationError was raised. This may happen if the buffer was not empty.""" """Decorator to rerun a function in case a CommunicationError was raised. This may happen if the buffer was not empty."""
@ -66,8 +66,9 @@ class RtLamniController(Controller):
"_set_axis_velocity", "_set_axis_velocity",
"_set_axis_velocity_maximum_speed", "_set_axis_velocity_maximum_speed",
"_position_sampling_single_read", "_position_sampling_single_read",
"_position_sampling_single_reset_and_start_sampling" "_position_sampling_single_reset_and_start_sampling",
] ]
def __init__( def __init__(
self, self,
*, *,
@ -90,14 +91,14 @@ class RtLamniController(Controller):
labels=labels, labels=labels,
kind=kind, kind=kind,
) )
self.readout_metadata = {}
def on(self, controller_num=0) -> None: def on(self, controller_num=0) -> None:
"""Open a new socket connection to the controller""" """Open a new socket connection to the controller"""
if not self.connected: if not self.connected:
try: try:
self.sock.open() self.sock.open()
#discuss - after disconnect takes a while for the server to be ready again # discuss - after disconnect takes a while for the server to be ready again
welcome_message = self.sock.receive() welcome_message = self.sock.receive()
self.connected = True self.connected = True
except ConnectionRefusedError as conn_error: except ConnectionRefusedError as conn_error:
@ -140,22 +141,22 @@ class RtLamniController(Controller):
return self.socket_get() return self.socket_get()
def is_axis_moving(self, axis_Id) -> bool: def is_axis_moving(self, axis_Id) -> bool:
#this checks that axis is on target # this checks that axis is on target
axis_is_on_target = bool(float(self.socket_put_and_receive(f"o"))) axis_is_on_target = bool(float(self.socket_put_and_receive(f"o")))
return not axis_is_on_target return not axis_is_on_target
# def is_thread_active(self, thread_id: int) -> bool: # def is_thread_active(self, thread_id: int) -> bool:
# val = float(self.socket_put_and_receive(f"MG_XQ{thread_id}")) # val = float(self.socket_put_and_receive(f"MG_XQ{thread_id}"))
# if val == -1: # if val == -1:
# return False # return False
# return True # return True
def _remove_trailing_characters(self, var) -> str: def _remove_trailing_characters(self, var) -> str:
if len(var) > 1: if len(var) > 1:
return var.split("\r\n")[0] return var.split("\r\n")[0]
return var return var
def set_rotation_angle(self, val:float): def set_rotation_angle(self, val: float):
self.socket_put(f"a{(val-300+30.538)/180*np.pi}") self.socket_put(f"a{(val-300+30.538)/180*np.pi}")
def stop_all_axes(self): def stop_all_axes(self):
@ -164,11 +165,11 @@ class RtLamniController(Controller):
def feedback_disable(self): def feedback_disable(self):
self.socket_put("J0") self.socket_put("J0")
logger.info("LamNI Feedback disabled.") logger.info("LamNI Feedback disabled.")
#motor_par("lsamx","disable",0) # motor_par("lsamx","disable",0)
#motor_par("lsamy","disable",0) # motor_par("lsamy","disable",0)
#motor_par("loptx","disable",0) # motor_par("loptx","disable",0)
#motor_par("lopty","disable",0) # motor_par("lopty","disable",0)
#motor_par("loptz","disable",0) # motor_par("loptz","disable",0)
def _set_axis_velocity(self, um_per_s): def _set_axis_velocity(self, um_per_s):
self.socket_put(f"V{um_per_s}") self.socket_put(f"V{um_per_s}")
@ -176,57 +177,64 @@ class RtLamniController(Controller):
def _set_axis_velocity_maximum_speed(self): def _set_axis_velocity_maximum_speed(self):
self.socket_put(f"V0") self.socket_put(f"V0")
#for developement of soft continuous scanning # for developement of soft continuous scanning
def _position_sampling_single_reset_and_start_sampling(self): def _position_sampling_single_reset_and_start_sampling(self):
self.socket_put(f"Ss") self.socket_put(f"Ss")
def _position_sampling_single_read(self): def _position_sampling_single_read(self):
(number_of_samples,sum0,sum0_2,sum1,sum1_2,sum2,sum2_2) = self.socket_put_and_receive(f"Sr").split(",") (number_of_samples, sum0, sum0_2, sum1, sum1_2, sum2, sum2_2) = self.socket_put_and_receive(
avg_x = float(sum1)/int(number_of_samples) f"Sr"
avg_y = float(sum0)/int(number_of_samples) ).split(",")
stdev_x = np.sqrt(float(sum1_2)/int(number_of_samples)-np.power(float(sum1)/int(number_of_samples),2)) avg_x = float(sum1) / int(number_of_samples)
stdev_y = np.sqrt(float(sum0_2)/int(number_of_samples)-np.power(float(sum0)/int(number_of_samples),2)) avg_y = float(sum0) / int(number_of_samples)
return(avg_x,avg_y,stdev_x,stdev_y) stdev_x = np.sqrt(
float(sum1_2) / int(number_of_samples)
- np.power(float(sum1) / int(number_of_samples), 2)
)
stdev_y = np.sqrt(
float(sum0_2) / int(number_of_samples)
- np.power(float(sum0) / int(number_of_samples), 2)
)
return (avg_x, avg_y, stdev_x, stdev_y)
def feedback_enable_without_reset(self): def feedback_enable_without_reset(self):
#read current interferometer position # read current interferometer position
return_table = (self.socket_put_and_receive(f"J4")).split(",") return_table = (self.socket_put_and_receive(f"J4")).split(",")
x_curr=float(return_table[2]) x_curr = float(return_table[2])
y_curr=float(return_table[1]) y_curr = float(return_table[1])
#set these as closed loop target position # set these as closed loop target position
self.socket_put(f"pa0,{x_curr:.4f}") self.socket_put(f"pa0,{x_curr:.4f}")
self.socket_put(f"pa1,{y_curr:.4f}") self.socket_put(f"pa1,{y_curr:.4f}")
self.socket_put("J5") self.socket_put("J5")
logger.info("LamNI Feedback enabled (without reset).") logger.info("LamNI Feedback enabled (without reset).")
#motor_par("lsamx","disable",1) # motor_par("lsamx","disable",1)
#motor_par("lsamy","disable",1) # motor_par("lsamy","disable",1)
#motor_par("loptx","disable",1) # motor_par("loptx","disable",1)
#motor_par("lopty","disable",1) # motor_par("lopty","disable",1)
#motor_par("loptz","disable",1) # motor_par("loptz","disable",1)
#umv rtx x_curr rty y_curr # umv rtx x_curr rty y_curr
def feedback_disable_and_even_reset_lamni_angle_interferometer(self): def feedback_disable_and_even_reset_lamni_angle_interferometer(self):
self.socket_put("J6") self.socket_put("J6")
logger.info("LamNI Feedback disabled including the angular interferometer.") logger.info("LamNI Feedback disabled including the angular interferometer.")
#motor_par("lsamx","disable",0) # motor_par("lsamx","disable",0)
#motor_par("lsamy","disable",0) # motor_par("lsamy","disable",0)
#motor_par("loptx","disable",0) # motor_par("loptx","disable",0)
#motor_par("lopty","disable",0) # motor_par("lopty","disable",0)
#motor_par("loptz","disable",0) # motor_par("loptz","disable",0)
def get_device_manager(self): def get_device_manager(self):
for axis in self._axis: for axis in self._axis:
if hasattr(axis, 'device_manager') and axis.device_manager: if hasattr(axis, "device_manager") and axis.device_manager:
return axis.device_manager return axis.device_manager
raise BECConfigError('Could not access the device_manager') raise BECConfigError("Could not access the device_manager")
def get_axis_by_name(self, name): def get_axis_by_name(self, name):
for axis in self._axis: for axis in self._axis:
if axis: if axis:
if axis.name == name: if axis.name == name:
return axis return axis
raise RuntimeError(f'Could not find an axis with name {name}') raise RuntimeError(f"Could not find an axis with name {name}")
def clear_trajectory_generator(self): def clear_trajectory_generator(self):
self.socket_put("sc") self.socket_put("sc")
@ -240,35 +248,42 @@ class RtLamniController(Controller):
if pos_index > 100: if pos_index > 100:
parent._min_scan_buffer_reached = True parent._min_scan_buffer_reached = True
parent._min_scan_buffer_reached = True parent._min_scan_buffer_reached = True
threading.Thread(target=send_positions, args=(self, positions), daemon=True).start() threading.Thread(target=send_positions, args=(self, positions), daemon=True).start()
@retry_once @retry_once
def get_scan_status(self): def get_scan_status(self):
return_table = (self.socket_put_and_receive(f"sr")).split(",") return_table = (self.socket_put_and_receive(f"sr")).split(",")
if len(return_table)!=3: if len(return_table) != 3:
raise RtLamniCommunicationError(f"Expected to receive 3 return values. Instead received {return_table}") raise RtLamniCommunicationError(
mode=int(return_table[0]) f"Expected to receive 3 return values. Instead received {return_table}"
#mode 0: direct positioning )
#mode 1: running internal timer (not tested/used anymore) mode = int(return_table[0])
#mode 2: rt point scan running # mode 0: direct positioning
#mode 3: rt point scan starting # mode 1: running internal timer (not tested/used anymore)
#mode 5/6: rt continuous scanning (not available in LamNI) # mode 2: rt point scan running
number_of_positions_planned=int(return_table[1]) # mode 3: rt point scan starting
current_position_in_scan=int(return_table[2]) # mode 5/6: rt continuous scanning (not available in LamNI)
return (mode,number_of_positions_planned,current_position_in_scan) number_of_positions_planned = int(return_table[1])
current_position_in_scan = int(return_table[2])
return (mode, number_of_positions_planned, current_position_in_scan)
def start_scan(self): def start_scan(self):
interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0]) interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0])
if interferometer_feedback_not_running == 1: if interferometer_feedback_not_running == 1:
logger.error("Cannot start scan because feedback loop is not running or there is an interferometer error.") logger.error(
raise RtLamniError("Cannot start scan because feedback loop is not running or there is an interferometer error.") "Cannot start scan because feedback loop is not running or there is an interferometer error."
#here exception )
(mode,number_of_positions_planned,current_position_in_scan)=self.get_scan_status() raise RtLamniError(
"Cannot start scan because feedback loop is not running or there is an interferometer error."
)
# here exception
(mode, number_of_positions_planned, current_position_in_scan) = self.get_scan_status()
if number_of_positions_planned == 0: if number_of_positions_planned == 0:
logger.error("Cannot start scan because no target positions are planned.") logger.error("Cannot start scan because no target positions are planned.")
raise RtLamniError("Cannot start scan because no target positions are planned.") raise RtLamniError("Cannot start scan because no target positions are planned.")
#hier exception # hier exception
# start a point-by-point scan (for cont scan in flomni it would be "sa") # start a point-by-point scan (for cont scan in flomni it would be "sa")
self.socket_put_and_receive("sd") self.socket_put_and_receive("sd")
@ -276,18 +291,17 @@ class RtLamniController(Controller):
readout = threading.Thread(target=self.read_positions_from_sampler) readout = threading.Thread(target=self.read_positions_from_sampler)
readout.start() readout.start()
def kickoff(self, metadata):
def kickoff(self): self.readout_metadata = metadata
while not self._min_scan_buffer_reached: while not self._min_scan_buffer_reached:
time.sleep(0.001) time.sleep(0.001)
self.start_scan() self.start_scan()
time.sleep(0.1) time.sleep(0.1)
self.start_readout() self.start_readout()
def read_positions_from_sampler(self): def read_positions_from_sampler(self):
#this was for reading after the scan completed # this was for reading after the scan completed
number_of_samples_to_read = 1 #self.get_scan_status()[1] #number of valid samples, will be updated upon first data read number_of_samples_to_read = 1 # self.get_scan_status()[1] #number of valid samples, will be updated upon first data read
read_counter = 0 read_counter = 0
previous_point_in_scan = 0 previous_point_in_scan = 0
@ -296,46 +310,70 @@ class RtLamniController(Controller):
average_stdeviations_y_st_fzp = 0 average_stdeviations_y_st_fzp = 0
average_lamni_angle = 0 average_lamni_angle = 0
mode,number_of_positions_planned,current_position_in_scan = self.get_scan_status() mode, number_of_positions_planned, current_position_in_scan = self.get_scan_status()
#if not (mode==2 or mode==3): # if not (mode==2 or mode==3):
# error # error
#while scan is running # while scan is running
while mode>0: while mode > 0:
#logger.info(f"Current scan position {current_position_in_scan} out of {number_of_positions_planned}") # logger.info(f"Current scan position {current_position_in_scan} out of {number_of_positions_planned}")
mode,number_of_positions_planned,current_position_in_scan = self.get_scan_status() mode, number_of_positions_planned, current_position_in_scan = self.get_scan_status()
time.sleep(.01) time.sleep(0.01)
if (current_position_in_scan>5): if current_position_in_scan > 5:
while current_position_in_scan > read_counter: while current_position_in_scan > read_counter:
return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",") return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",")
#logger.info(f"{return_table}") # logger.info(f"{return_table}")
logger.info(f"Read {read_counter} out of {number_of_positions_planned}") logger.info(f"Read {read_counter} out of {number_of_positions_planned}")
read_counter = read_counter+1 read_counter = read_counter + 1
average_stdeviations_x_st_fzp=average_stdeviations_x_st_fzp+float(return_table[5]) average_stdeviations_x_st_fzp = average_stdeviations_x_st_fzp + float(
average_stdeviations_y_st_fzp=average_stdeviations_y_st_fzp+float(return_table[8]) return_table[5]
average_lamni_angle = average_lamni_angle+float(return_table[19]) )
average_stdeviations_y_st_fzp = average_stdeviations_y_st_fzp + float(
time.sleep(.05) return_table[8]
)
average_lamni_angle = average_lamni_angle + float(return_table[19])
#DataPoint TotalPoints Target_x Average_x_st_fzp Stdev_x_st_fzp Target_y Average_y_st_fzp Stdev_y_st_fzp Average_cap1 Stdev_cap1 Average_cap2 Stdev_cap2 Average_cap3 Stdev_cap3 Average_cap4 Stdev_cap4 Average_cap5 Stdev_cap5 Average_angle_interf_ST Stdev_angle_interf_ST
# TODO!!
signals = {
"target_x":
"average_stdeviations_x_st_fzp": {"value": average_stdeviations_x_st_fzp},
"average_stdeviations_y_st_fzp": {"value": average_stdeviations_y_st_fzp},
"average_lamni_angle": {"value": average_lamni_angle},
}
self.publish_device_data(signals=signals, pointID=current_position_in_scan)
#read the last samples even though scan is finished already time.sleep(0.05)
# read the last samples even though scan is finished already
while number_of_positions_planned > read_counter: while number_of_positions_planned > read_counter:
return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",") return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",")
logger.info(f"Read {read_counter} out of {number_of_positions_planned}") logger.info(f"Read {read_counter} out of {number_of_positions_planned}")
#logger.info(f"{return_table}") # logger.info(f"{return_table}")
read_counter = read_counter+1 read_counter = read_counter + 1
average_stdeviations_x_st_fzp=average_stdeviations_x_st_fzp+float(return_table[5]) average_stdeviations_x_st_fzp = average_stdeviations_x_st_fzp + float(return_table[5])
average_stdeviations_y_st_fzp=average_stdeviations_y_st_fzp+float(return_table[8]) average_stdeviations_y_st_fzp = average_stdeviations_y_st_fzp + float(return_table[8])
average_lamni_angle = average_lamni_angle+float(return_table[19]) average_lamni_angle = average_lamni_angle + float(return_table[19])
logger.info(f"LamNI statistics: Average of all standard deviations: x {average_stdeviations_x_st_fzp/number_of_samples_to_read}, y {average_stdeviations_y_st_fzp/number_of_samples_to_read}, angle {average_lamni_angle/number_of_samples_to_read}.") logger.info(
f"LamNI statistics: Average of all standard deviations: x {average_stdeviations_x_st_fzp/number_of_samples_to_read}, y {average_stdeviations_y_st_fzp/number_of_samples_to_read}, angle {average_lamni_angle/number_of_samples_to_read}."
)
def publish_device_data(self, signals, pointID):
self.get_device_manager().producer.send(
MessageEndpoints.device_read("rt_lamni"),
BECMessage.DeviceMessage(
signals=signals,
metadata={"pointID": pointID, **self.readout_metadata},
).dumps(),
)
def feedback_status_angle_lamni(self) -> bool: def feedback_status_angle_lamni(self) -> bool:
return_table = (self.socket_put_and_receive(f"J7")).split(",") return_table = (self.socket_put_and_receive(f"J7")).split(",")
logger.debug(f"LamNI angle interferomter status {bool(return_table[0])}, position {float(return_table[1])}, signal {float(return_table[2])}") logger.debug(
f"LamNI angle interferomter status {bool(return_table[0])}, position {float(return_table[1])}, signal {float(return_table[2])}"
)
return bool(return_table[0]) return bool(return_table[0])
def feedback_enable_with_reset(self): def feedback_enable_with_reset(self):
@ -344,39 +382,51 @@ class RtLamniController(Controller):
logger.info(f"LamNI resetting interferometer inclusive angular interferomter.") logger.info(f"LamNI resetting interferometer inclusive angular interferomter.")
else: else:
self.feedback_disable() self.feedback_disable()
logger.info(f"LamNI resetting interferomter except angular interferometer which is already running.") logger.info(
f"LamNI resetting interferomter except angular interferometer which is already running."
)
#set these as closed loop target position # set these as closed loop target position
self.socket_put(f"pa0,0") self.socket_put(f"pa0,0")
self.get_axis_by_name('rtx').user_setpoint.setpoint = 0 self.get_axis_by_name("rtx").user_setpoint.setpoint = 0
self.socket_put(f"pa1,0") self.socket_put(f"pa1,0")
self.get_axis_by_name('rty').user_setpoint.setpoint = 0 self.get_axis_by_name("rty").user_setpoint.setpoint = 0
self.socket_put(f"pa2,0") #we set all three outputs of the traj. gen. although in LamNI case only 0,1 are used self.socket_put(
f"pa2,0"
) # we set all three outputs of the traj. gen. although in LamNI case only 0,1 are used
self.clear_trajectory_generator() self.clear_trajectory_generator()
self.get_device_manager().devices.lsamrot.obj.move(0, wait=True) self.get_device_manager().devices.lsamrot.obj.move(0, wait=True)
galil_controller_rt_status = self.get_device_manager().devices.lsamx.obj.controller.lgalil_is_air_off_and_orchestra_enabled() galil_controller_rt_status = (
self.get_device_manager().devices.lsamx.obj.controller.lgalil_is_air_off_and_orchestra_enabled()
)
if galil_controller_rt_status == 0: if galil_controller_rt_status == 0:
logger.error("Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller.") logger.error(
raise RtLamniError("Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller.") "Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller."
)
raise RtLamniError(
"Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller."
)
time.sleep(0.03) time.sleep(0.03)
#needs to be changed to configurable center psoition # needs to be changed to configurable center psoition
self.get_device_manager().devices.lsamx.obj.move(8.866, wait=True) self.get_device_manager().devices.lsamx.obj.move(8.866, wait=True)
self.get_device_manager().devices.lsamy.obj.move(10.18, wait=True) self.get_device_manager().devices.lsamy.obj.move(10.18, wait=True)
self.socket_put("J1") self.socket_put("J1")
_waitforfeedbackctr=0 _waitforfeedbackctr = 0
interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0]) interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0])
while interferometer_feedback_not_running == 1 and _waitforfeedbackctr<100: while interferometer_feedback_not_running == 1 and _waitforfeedbackctr < 100:
time.sleep(0.01) time.sleep(0.01)
_waitforfeedbackctr = _waitforfeedbackctr + 1 _waitforfeedbackctr = _waitforfeedbackctr + 1
interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0]) interferometer_feedback_not_running = int(
(self.socket_put_and_receive("J2")).split(",")[0]
)
# motor_par("lsamx","disable",1) # motor_par("lsamx","disable",1)
# motor_par("lsamy","disable",1) # motor_par("lsamy","disable",1)
@ -384,13 +434,16 @@ class RtLamniController(Controller):
# motor_par("lopty","disable",1) # motor_par("lopty","disable",1)
# motor_par("loptz","disable",1) # motor_par("loptz","disable",1)
if interferometer_feedback_not_running == 1: if interferometer_feedback_not_running == 1:
logger.error("Cannot start scan because feedback loop is not running or there is an interferometer error.") logger.error(
raise RtLamniError("Cannot start scan because feedback loop is not running or there is an interferometer error.") "Cannot start scan because feedback loop is not running or there is an interferometer error."
)
raise RtLamniError(
"Cannot start scan because feedback loop is not running or there is an interferometer error."
)
time.sleep(0.01) time.sleep(0.01)
#ptychography_alignment_done = 0 # ptychography_alignment_done = 0
class RtLamniSignalBase(SocketSignal): class RtLamniSignalBase(SocketSignal):
@ -442,10 +495,6 @@ class RtLamniSetpointSignal(RtLamniSignalBase):
Returns: Returns:
float: setpoint / target value float: setpoint / target value
""" """
return self.setpoint return self.setpoint
@ -463,11 +512,15 @@ class RtLamniSetpointSignal(RtLamniSignalBase):
""" """
target_val = val * self.parent.sign target_val = val * self.parent.sign
self.setpoint = target_val self.setpoint = target_val
interferometer_feedback_not_running = int((self.controller.socket_put_and_receive("J2")).split(",")[0]) interferometer_feedback_not_running = int(
(self.controller.socket_put_and_receive("J2")).split(",")[0]
)
if interferometer_feedback_not_running == 0: if interferometer_feedback_not_running == 0:
self.controller.socket_put(f"pa{self.parent.axis_Id_numeric},{target_val:.4f}") self.controller.socket_put(f"pa{self.parent.axis_Id_numeric},{target_val:.4f}")
else: else:
raise RtLamniError("The interferometer feedback is not running. Either it is turned off or and interferometer error occured.") raise RtLamniError(
"The interferometer feedback is not running. Either it is turned off or and interferometer error occured."
)
class RtLamniMotorIsMoving(RtLamniSignalRO): class RtLamniMotorIsMoving(RtLamniSignalRO):
@ -477,7 +530,8 @@ class RtLamniMotorIsMoving(RtLamniSignalRO):
def get(self): def get(self):
val = super().get() val = super().get()
if val is not None: if val is not None:
self._run_subs(sub_type=self.SUB_VALUE, self._run_subs(
sub_type=self.SUB_VALUE,
value=val, value=val,
timestamp=time.time(), timestamp=time.time(),
) )
@ -489,22 +543,19 @@ class RtLamniFeedbackRunning(RtLamniSignalRO):
if int((self.controller.socket_put_and_receive("J2")).split(",")[0]) == 0: if int((self.controller.socket_put_and_receive("J2")).split(",")[0]) == 0:
return 1 return 1
else: else:
return 0 return 0
class RtLamniMotor(Device, PositionerBase): class RtLamniMotor(Device, PositionerBase):
USER_ACCESS = [ USER_ACCESS = ["controller"]
"controller"
]
readback = Cpt( readback = Cpt(
RtLamniReadbackSignal, RtLamniReadbackSignal,
signal_name="readback", signal_name="readback",
kind="hinted", kind="hinted",
) )
user_setpoint = Cpt(RtLamniSetpointSignal, signal_name="setpoint") user_setpoint = Cpt(RtLamniSetpointSignal, signal_name="setpoint")
motor_is_moving = Cpt( motor_is_moving = Cpt(RtLamniMotorIsMoving, signal_name="motor_is_moving", kind="normal")
RtLamniMotorIsMoving, signal_name="motor_is_moving", kind="normal"
)
high_limit_travel = Cpt(Signal, value=0, kind="omitted") high_limit_travel = Cpt(Signal, value=0, kind="omitted")
low_limit_travel = Cpt(Signal, value=0, kind="omitted") low_limit_travel = Cpt(Signal, value=0, kind="omitted")
@ -527,7 +578,7 @@ class RtLamniMotor(Device, PositionerBase):
sign=1, sign=1,
socket_cls=SocketIO, socket_cls=SocketIO,
device_manager=None, device_manager=None,
limits = None, limits=None,
**kwargs, **kwargs,
): ):
self.axis_Id = axis_Id self.axis_Id = axis_Id
@ -581,12 +632,10 @@ class RtLamniMotor(Device, PositionerBase):
for walk in self.walk_signals(): for walk in self.walk_signals():
walk.item._metadata["connected"] = self.controller.connected walk.item._metadata["connected"] = self.controller.connected
def _forward_readback(self, **kwargs): def _forward_readback(self, **kwargs):
kwargs.pop("sub_type") kwargs.pop("sub_type")
self._run_subs(sub_type="readback", **kwargs) self._run_subs(sub_type="readback", **kwargs)
@raise_if_disconnected @raise_if_disconnected
def move(self, position, wait=True, **kwargs): def move(self, position, wait=True, **kwargs):
"""Move to a specified position, optionally waiting for motion to """Move to a specified position, optionally waiting for motion to
@ -626,7 +675,8 @@ class RtLamniMotor(Device, PositionerBase):
while self.motor_is_moving.get(): while self.motor_is_moving.get():
print("motor is moving") print("motor is moving")
val = self.readback.read() val = self.readback.read()
self._run_subs(sub_type=self.SUB_READBACK, self._run_subs(
sub_type=self.SUB_READBACK,
value=val, value=val,
timestamp=time.time(), timestamp=time.time(),
) )
@ -672,12 +722,15 @@ class RtLamniMotor(Device, PositionerBase):
else: else:
raise TypeError(f"Expected value of type int but received {type(val)}") raise TypeError(f"Expected value of type int but received {type(val)}")
def kickoff(self, metadata) -> None:
self.controller.kickoff(metadata)
@property @property
def egu(self): def egu(self):
"""The engineering units (EGU) for positions""" """The engineering units (EGU) for positions"""
return "um" return "um"
# how is this used later? # how is this used later?
def stage(self) -> List[object]: def stage(self) -> List[object]:
self.controller.on() self.controller.on()
@ -710,12 +763,7 @@ if __name__ == "__main__":
else: else:
from ophyd_devices.utils.socket import SocketMock from ophyd_devices.utils.socket import SocketMock
rtx = RtLamniMotor( rtx = RtLamniMotor("A", name="rtx", host="mpc2680.psi.ch", port=3333, socket_cls=SocketMock)
"A", name="rtx", host="mpc2680.psi.ch", port=3333, socket_cls=SocketMock rty = RtLamniMotor("B", name="rty", host="mpc2680.psi.ch", port=3333, socket_cls=SocketMock)
)
rty = RtLamniMotor(
"B", name="rty", host="mpc2680.psi.ch", port=3333, socket_cls=SocketMock
)
rtx.stage() rtx.stage()
# rty.stage() # rty.stage()

View File

@ -3,12 +3,13 @@ import time as ttime
import warnings import warnings
import numpy as np import numpy as np
from bec_utils import BECMessage, MessageEndpoints from bec_utils import BECMessage, MessageEndpoints, bec_logger
from ophyd import Component as Cpt from ophyd import Component as Cpt
from ophyd import Device, DeviceStatus, PositionerBase, Signal from ophyd import Device, DeviceStatus, PositionerBase, Signal
from ophyd.sim import _ReadbackSignal, _SetpointSignal from ophyd.sim import _ReadbackSignal, _SetpointSignal
from ophyd.utils import LimitError, ReadOnlyError from ophyd.utils import LimitError, ReadOnlyError
logger = bec_logger.logger
class DeviceStop(Exception): class DeviceStop(Exception):
pass pass

View File

@ -11,8 +11,9 @@ from ophyd.utils import ReadOnlyError, LimitError
from ophyd_devices.smaract.smaract_controller import SmaractController from ophyd_devices.smaract.smaract_controller import SmaractController
from ophyd_devices.smaract.smaract_errors import SmaractCommunicationError, SmaractError from ophyd_devices.smaract.smaract_errors import SmaractCommunicationError, SmaractError
from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected from ophyd_devices.utils.socket import SocketIO, SocketSignal, raise_if_disconnected
from bec_utils import bec_logger
logger = logging.getLogger("smaract") logger = bec_logger.logger
class SmaractSignalBase(SocketSignal): class SmaractSignalBase(SocketSignal):