online changes; added bec logger; added limits to custom devices
This commit is contained in:
parent
3b971336ee
commit
6e541cc0d0
@ -6,9 +6,9 @@ from typing import List
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from ophyd import Component as Cpt
|
from ophyd import Component as Cpt
|
||||||
from ophyd import Device, PositionerBase
|
from ophyd import Device, PositionerBase, Signal
|
||||||
from ophyd.status import wait as status_wait
|
from ophyd.status import wait as status_wait
|
||||||
from ophyd.utils import ReadOnlyError
|
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
|
||||||
@ -29,7 +29,7 @@ class BECConfigError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def retry_once(fcn):
|
def retry_once(fcn):
|
||||||
"""Decorator to rerun a function in case a SmaractCommunicationError was raised. This may happen if the buffer was not empty."""
|
"""Decorator to rerun a function in case a Galil communication error was raised. This may happen if the buffer was not empty."""
|
||||||
|
|
||||||
@functools.wraps(fcn)
|
@functools.wraps(fcn)
|
||||||
def wrapper(self, *args, **kwargs):
|
def wrapper(self, *args, **kwargs):
|
||||||
@ -49,6 +49,7 @@ class GalilController(Controller):
|
|||||||
"galil_show_all",
|
"galil_show_all",
|
||||||
"socket_put_and_receive",
|
"socket_put_and_receive",
|
||||||
"socket_put_confirmed",
|
"socket_put_confirmed",
|
||||||
|
"lgalil_is_air_off_and_orchestra_enabled"
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -347,6 +348,8 @@ class GalilMotor(Device, PositionerBase):
|
|||||||
motor_resolution = Cpt(GalilMotorResolution, signal_name="resolution", kind="config")
|
motor_resolution = Cpt(GalilMotorResolution, signal_name="resolution", kind="config")
|
||||||
motor_is_moving = Cpt(GalilMotorIsMoving, signal_name="motor_is_moving", kind="normal")
|
motor_is_moving = Cpt(GalilMotorIsMoving, signal_name="motor_is_moving", kind="normal")
|
||||||
all_axes_referenced = Cpt(GalilAxesReferenced, signal_name="all_axes_referenced", kind="config")
|
all_axes_referenced = Cpt(GalilAxesReferenced, signal_name="all_axes_referenced", kind="config")
|
||||||
|
high_limit_travel = Cpt(Signal, value=0, kind="omitted")
|
||||||
|
low_limit_travel = Cpt(Signal, value=0, kind="omitted")
|
||||||
|
|
||||||
SUB_READBACK = "readback"
|
SUB_READBACK = "readback"
|
||||||
SUB_CONNECTION_CHANGE = "connection_change"
|
SUB_CONNECTION_CHANGE = "connection_change"
|
||||||
@ -364,6 +367,7 @@ class GalilMotor(Device, PositionerBase):
|
|||||||
parent=None,
|
parent=None,
|
||||||
host="mpc2680.psi.ch",
|
host="mpc2680.psi.ch",
|
||||||
port=8081,
|
port=8081,
|
||||||
|
limits=None,
|
||||||
sign=1,
|
sign=1,
|
||||||
socket_cls=SocketIO,
|
socket_cls=SocketIO,
|
||||||
device_manager=None,
|
device_manager=None,
|
||||||
@ -399,6 +403,30 @@ class GalilMotor(Device, PositionerBase):
|
|||||||
self._update_connection_state()
|
self._update_connection_state()
|
||||||
# self.readback.subscribe(self._forward_readback, event_type=self.readback.SUB_VALUE)
|
# self.readback.subscribe(self._forward_readback, event_type=self.readback.SUB_VALUE)
|
||||||
|
|
||||||
|
if limits is not None:
|
||||||
|
assert len(limits) == 2
|
||||||
|
self.low_limit_travel.put(limits[0])
|
||||||
|
self.high_limit_travel.put(limits[1])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def limits(self):
|
||||||
|
return (self.low_limit_travel.get(), self.high_limit_travel.get())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def low_limit(self):
|
||||||
|
return self.limits[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def high_limit(self):
|
||||||
|
return self.limits[1]
|
||||||
|
|
||||||
|
def check_value(self, pos):
|
||||||
|
"""Check that the position is within the soft limits"""
|
||||||
|
low_limit, high_limit = self.limits
|
||||||
|
|
||||||
|
if low_limit < high_limit and not (low_limit <= pos <= high_limit):
|
||||||
|
raise LimitError(f"position={pos} not within limits {self.limits}")
|
||||||
|
|
||||||
def _update_connection_state(self, **kwargs):
|
def _update_connection_state(self, **kwargs):
|
||||||
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
|
||||||
@ -438,7 +466,7 @@ class GalilMotor(Device, PositionerBase):
|
|||||||
If motion fails other than timing out
|
If motion fails other than timing out
|
||||||
"""
|
"""
|
||||||
self._started_moving = False
|
self._started_moving = False
|
||||||
timeout = kwargs.pop("timeout", 4)
|
timeout = kwargs.pop("timeout", 100)
|
||||||
status = super().move(position, timeout=timeout, **kwargs)
|
status = super().move(position, timeout=timeout, **kwargs)
|
||||||
self.user_setpoint.put(position, wait=False)
|
self.user_setpoint.put(position, wait=False)
|
||||||
|
|
||||||
|
@ -12,8 +12,10 @@ from ophyd_devices.utils.socket import (
|
|||||||
SocketSignal,
|
SocketSignal,
|
||||||
)
|
)
|
||||||
from bec_utils import bec_logger
|
from bec_utils import bec_logger
|
||||||
from ophyd.utils import ReadOnlyError
|
from ophyd.utils import ReadOnlyError,LimitError
|
||||||
from ophyd.status import wait as status_wait
|
from ophyd.status import wait as status_wait
|
||||||
|
from ophyd import Signal
|
||||||
|
|
||||||
|
|
||||||
logger = bec_logger.logger
|
logger = bec_logger.logger
|
||||||
|
|
||||||
@ -60,7 +62,11 @@ class RtLamniController(Controller):
|
|||||||
"feedback_disable_and_even_reset_lamni_angle_interferometer",
|
"feedback_disable_and_even_reset_lamni_angle_interferometer",
|
||||||
"feedback_enable_with_reset",
|
"feedback_enable_with_reset",
|
||||||
"add_pos_to_scan",
|
"add_pos_to_scan",
|
||||||
"clear_trajectory_generator"
|
"clear_trajectory_generator",
|
||||||
|
"_set_axis_velocity",
|
||||||
|
"_set_axis_velocity_maximum_speed",
|
||||||
|
"_position_sampling_single_read",
|
||||||
|
"_position_sampling_single_reset_and_start_sampling"
|
||||||
]
|
]
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -75,6 +81,7 @@ class RtLamniController(Controller):
|
|||||||
if not hasattr(self, "_initialized") or not self._initialized:
|
if not hasattr(self, "_initialized") or not self._initialized:
|
||||||
self._rtlamni_axis_per_controller = 3
|
self._rtlamni_axis_per_controller = 3
|
||||||
self._axis = [None for axis_num in range(self._rtlamni_axis_per_controller)]
|
self._axis = [None for axis_num in range(self._rtlamni_axis_per_controller)]
|
||||||
|
self._min_scan_buffer_reached = False
|
||||||
super().__init__(
|
super().__init__(
|
||||||
name=name,
|
name=name,
|
||||||
socket=socket,
|
socket=socket,
|
||||||
@ -83,14 +90,19 @@ class RtLamniController(Controller):
|
|||||||
labels=labels,
|
labels=labels,
|
||||||
kind=kind,
|
kind=kind,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
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:
|
||||||
self.sock.open()
|
try:
|
||||||
#discuss - after disconnect takes a while for the server to be ready again
|
self.sock.open()
|
||||||
welcome_message = self.sock.receive()
|
#discuss - after disconnect takes a while for the server to be ready again
|
||||||
self.connected = True
|
welcome_message = self.sock.receive()
|
||||||
|
self.connected = True
|
||||||
|
except ConnectionRefusedError as conn_error:
|
||||||
|
logger.error("Failed to open a connection to RTLamNI.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info("The connection has already been established.")
|
logger.info("The connection has already been established.")
|
||||||
# warnings.warn(f"The connection has already been established.", stacklevel=2)
|
# warnings.warn(f"The connection has already been established.", stacklevel=2)
|
||||||
@ -146,8 +158,8 @@ class RtLamniController(Controller):
|
|||||||
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) -> str:
|
def stop_all_axes(self):
|
||||||
return 0 #self.socket_put_and_receive(f"XQ#STOP,1")
|
self.socket_put("sc")
|
||||||
|
|
||||||
def feedback_disable(self):
|
def feedback_disable(self):
|
||||||
self.socket_put("J0")
|
self.socket_put("J0")
|
||||||
@ -158,6 +170,25 @@ class RtLamniController(Controller):
|
|||||||
#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):
|
||||||
|
self.socket_put(f"V{um_per_s}")
|
||||||
|
|
||||||
|
def _set_axis_velocity_maximum_speed(self):
|
||||||
|
self.socket_put(f"V0")
|
||||||
|
|
||||||
|
#for developement of soft continuous scanning
|
||||||
|
def _position_sampling_single_reset_and_start_sampling(self):
|
||||||
|
self.socket_put(f"Ss")
|
||||||
|
|
||||||
|
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(",")
|
||||||
|
avg_x = float(sum1)/int(number_of_samples)
|
||||||
|
avg_y = float(sum0)/int(number_of_samples)
|
||||||
|
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(",")
|
||||||
@ -201,11 +232,21 @@ class RtLamniController(Controller):
|
|||||||
self.socket_put("sc")
|
self.socket_put("sc")
|
||||||
logger.info("LamNI scan stopped and deleted, moving to start position")
|
logger.info("LamNI scan stopped and deleted, moving to start position")
|
||||||
|
|
||||||
def add_pos_to_scan(self, posx, posy) -> int:
|
def add_pos_to_scan(self, positions) -> None:
|
||||||
self.socket_put_and_receive(f"s{posx},{posy},0")
|
def send_positions(parent, positions):
|
||||||
|
parent._min_scan_buffer_reached = False
|
||||||
|
for pos_index, pos in enumerate(positions):
|
||||||
|
parent.socket_put_and_receive(f"s{pos[0]},{pos[1]},0")
|
||||||
|
if pos_index > 100:
|
||||||
|
parent._min_scan_buffer_reached = True
|
||||||
|
parent._min_scan_buffer_reached = True
|
||||||
|
threading.Thread(target=send_positions, args=(self, positions), daemon=True).start()
|
||||||
|
|
||||||
|
@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:
|
||||||
|
raise RtLamniCommunicationError(f"Expected to receive 3 return values. Instead received {return_table}")
|
||||||
mode=int(return_table[0])
|
mode=int(return_table[0])
|
||||||
#mode 0: direct positioning
|
#mode 0: direct positioning
|
||||||
#mode 1: running internal timer (not tested/used anymore)
|
#mode 1: running internal timer (not tested/used anymore)
|
||||||
@ -219,12 +260,14 @@ class RtLamniController(Controller):
|
|||||||
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.info("Cannot start scan because feedback loop is not running or there is an interferometer error.")
|
logger.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.")
|
||||||
#here exception
|
#here exception
|
||||||
(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 number_of_positions_planned == 0:
|
if number_of_positions_planned == 0:
|
||||||
logger.info("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.")
|
||||||
#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")
|
||||||
@ -235,28 +278,59 @@ class RtLamniController(Controller):
|
|||||||
|
|
||||||
|
|
||||||
def kickoff(self):
|
def kickoff(self):
|
||||||
time.sleep(0.3)
|
while not self._min_scan_buffer_reached:
|
||||||
|
time.sleep(0.001)
|
||||||
self.start_scan()
|
self.start_scan()
|
||||||
while self.get_scan_status()[0]!=0:
|
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):
|
||||||
number_of_samples_to_read = self.get_scan_status()[1] #number of valid samples, will be updated upon first data read
|
#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
|
||||||
|
|
||||||
read_counter = 0
|
read_counter = 0
|
||||||
|
previous_point_in_scan = 0
|
||||||
|
|
||||||
average_stdeviations_x_st_fzp = 0
|
average_stdeviations_x_st_fzp = 0
|
||||||
average_stdeviations_y_st_fzp = 0
|
average_stdeviations_y_st_fzp = 0
|
||||||
average_lamni_angle = 0
|
average_lamni_angle = 0
|
||||||
while number_of_samples_to_read > read_counter:
|
|
||||||
#fprintf(dname,"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\n")
|
mode,number_of_positions_planned,current_position_in_scan = self.get_scan_status()
|
||||||
# 0 1 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
||||||
|
#if not (mode==2 or mode==3):
|
||||||
|
# error
|
||||||
|
|
||||||
|
#while scan is running
|
||||||
|
while mode>0:
|
||||||
|
#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()
|
||||||
|
time.sleep(.01)
|
||||||
|
if (current_position_in_scan>5):
|
||||||
|
while current_position_in_scan > read_counter:
|
||||||
|
return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",")
|
||||||
|
#logger.info(f"{return_table}")
|
||||||
|
logger.info(f"Read {read_counter} out of {number_of_positions_planned}")
|
||||||
|
|
||||||
|
read_counter = read_counter+1
|
||||||
|
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_lamni_angle = average_lamni_angle+float(return_table[19])
|
||||||
|
|
||||||
|
time.sleep(.05)
|
||||||
|
|
||||||
|
#read the last samples even though scan is finished already
|
||||||
|
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"{return_table}")
|
logger.info(f"Read {read_counter} out of {number_of_positions_planned}")
|
||||||
|
#logger.info(f"{return_table}")
|
||||||
|
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])
|
||||||
read_counter=read_counter+1
|
|
||||||
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 feedback_status_angle_lamni(self) -> bool:
|
def feedback_status_angle_lamni(self) -> bool:
|
||||||
@ -283,48 +357,39 @@ class RtLamniController(Controller):
|
|||||||
|
|
||||||
self.get_device_manager().devices.lsamrot.obj.move(0, wait=True)
|
self.get_device_manager().devices.lsamrot.obj.move(0, wait=True)
|
||||||
|
|
||||||
#!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()
|
||||||
|
|
||||||
# try:
|
if galil_controller_rt_status == 0:
|
||||||
### self.parent.device_manager.devices[
|
logger.error("Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller.")
|
||||||
# self.parent.galil
|
raise RtLamniError("Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller.")
|
||||||
# ].obj.controller.set_rotation_angle(val[self.parent.name]["value"])
|
|
||||||
# except KeyError:
|
|
||||||
# logger.warning("Failed to set RT value during readback.")
|
|
||||||
# lgalil_is_air_off_and_orchestra_enabled
|
|
||||||
#Cannot enable feedback. The small rotation air is on and/or orchestra disabled by the motor controller.
|
|
||||||
#exit with failure
|
|
||||||
|
|
||||||
time.sleep(0.03)
|
time.sleep(0.03)
|
||||||
#global _lsamx_center
|
#needs to be changed to configurable center psoition
|
||||||
#global _lsamy_center
|
|
||||||
#umv lsamx _lsamx_center
|
|
||||||
#umv lsamy _lsamy_center
|
|
||||||
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
|
||||||
|
|
||||||
#this is implemented as class and not function. why? RtLamniFeedbackRunning
|
interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0])
|
||||||
|
|
||||||
# while self.RtLamniFeedbackRunning _rt_status_feedback(self) == 1 && _waitforfeedbackctr<100)
|
while interferometer_feedback_not_running == 1 and _waitforfeedbackctr<100:
|
||||||
# {
|
time.sleep(0.01)
|
||||||
# sleep(0.01)
|
_waitforfeedbackctr = _waitforfeedbackctr + 1
|
||||||
# _waitforfeedbackctr++
|
interferometer_feedback_not_running = int((self.socket_put_and_receive("J2")).split(",")[0])
|
||||||
# #p _waitforfeedbackctr
|
|
||||||
# }
|
|
||||||
# motor_par("lsamx","disable",1)
|
|
||||||
# motor_par("lsamy","disable",1)
|
|
||||||
# motor_par("loptx","disable",1)
|
|
||||||
# motor_par("lopty","disable",1)
|
|
||||||
# motor_par("loptz","disable",1)
|
|
||||||
# rt_feedback_status
|
|
||||||
|
|
||||||
|
# motor_par("lsamx","disable",1)
|
||||||
|
# motor_par("lsamy","disable",1)
|
||||||
|
# motor_par("loptx","disable",1)
|
||||||
|
# motor_par("lopty","disable",1)
|
||||||
|
# motor_par("loptz","disable",1)
|
||||||
|
if interferometer_feedback_not_running == 1:
|
||||||
|
logger.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)
|
||||||
|
|
||||||
|
#ptychography_alignment_done = 0
|
||||||
#ptychography_alignment_done = 0
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -440,6 +505,8 @@ class RtLamniMotor(Device, PositionerBase):
|
|||||||
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")
|
||||||
|
low_limit_travel = Cpt(Signal, value=0, kind="omitted")
|
||||||
|
|
||||||
SUB_READBACK = "readback"
|
SUB_READBACK = "readback"
|
||||||
SUB_CONNECTION_CHANGE = "connection_change"
|
SUB_CONNECTION_CHANGE = "connection_change"
|
||||||
@ -460,6 +527,7 @@ class RtLamniMotor(Device, PositionerBase):
|
|||||||
sign=1,
|
sign=1,
|
||||||
socket_cls=SocketIO,
|
socket_cls=SocketIO,
|
||||||
device_manager=None,
|
device_manager=None,
|
||||||
|
limits = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
self.axis_Id = axis_Id
|
self.axis_Id = axis_Id
|
||||||
@ -483,8 +551,31 @@ class RtLamniMotor(Device, PositionerBase):
|
|||||||
self._update_connection_state, event_type=self.SUB_CONNECTION_CHANGE
|
self._update_connection_state, event_type=self.SUB_CONNECTION_CHANGE
|
||||||
)
|
)
|
||||||
self._update_connection_state()
|
self._update_connection_state()
|
||||||
# self.readback.subscribe(self._forward_readback, event_type=self.readback.SUB_VALUE)
|
|
||||||
|
|
||||||
|
# self.readback.subscribe(self._forward_readback, event_type=self.readback.SUB_VALUE)
|
||||||
|
if limits is not None:
|
||||||
|
assert len(limits) == 2
|
||||||
|
self.low_limit_travel.put(limits[0])
|
||||||
|
self.high_limit_travel.put(limits[1])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def limits(self):
|
||||||
|
return (self.low_limit_travel.get(), self.high_limit_travel.get())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def low_limit(self):
|
||||||
|
return self.limits[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def high_limit(self):
|
||||||
|
return self.limits[1]
|
||||||
|
|
||||||
|
def check_value(self, pos):
|
||||||
|
"""Check that the position is within the soft limits"""
|
||||||
|
low_limit, high_limit = self.limits
|
||||||
|
|
||||||
|
if low_limit < high_limit and not (low_limit <= pos <= high_limit):
|
||||||
|
raise LimitError(f"position={pos} not within limits {self.limits}")
|
||||||
|
|
||||||
def _update_connection_state(self, **kwargs):
|
def _update_connection_state(self, **kwargs):
|
||||||
for walk in self.walk_signals():
|
for walk in self.walk_signals():
|
||||||
@ -527,7 +618,7 @@ class RtLamniMotor(Device, PositionerBase):
|
|||||||
If motion fails other than timing out
|
If motion fails other than timing out
|
||||||
"""
|
"""
|
||||||
self._started_moving = False
|
self._started_moving = False
|
||||||
timeout = kwargs.pop("timeout", 4)
|
timeout = kwargs.pop("timeout", 100)
|
||||||
status = super().move(position, timeout=timeout, **kwargs)
|
status = super().move(position, timeout=timeout, **kwargs)
|
||||||
self.user_setpoint.put(position, wait=False)
|
self.user_setpoint.put(position, wait=False)
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ from typing import List
|
|||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from ophyd import Component as Cpt
|
from ophyd import Component as Cpt
|
||||||
from ophyd import Device, PositionerBase
|
from ophyd import Device, PositionerBase, Signal
|
||||||
from ophyd.status import wait as status_wait
|
from ophyd.status import wait as status_wait
|
||||||
from ophyd.utils import ReadOnlyError
|
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
|
||||||
@ -93,7 +93,8 @@ class SmaractMotor(Device, PositionerBase):
|
|||||||
# )
|
# )
|
||||||
|
|
||||||
motor_is_moving = Cpt(SmaractMotorIsMoving, signal_name="motor_is_moving", kind="normal")
|
motor_is_moving = Cpt(SmaractMotorIsMoving, signal_name="motor_is_moving", kind="normal")
|
||||||
|
high_limit_travel = Cpt(Signal, value=0, kind="omitted")
|
||||||
|
low_limit_travel = Cpt(Signal, value=0, kind="omitted")
|
||||||
# all_axes_referenced = Cpt(
|
# all_axes_referenced = Cpt(
|
||||||
# SmaractAxesReferenced, signal_name="all_axes_referenced", kind="config"
|
# SmaractAxesReferenced, signal_name="all_axes_referenced", kind="config"
|
||||||
# )
|
# )
|
||||||
@ -114,6 +115,7 @@ class SmaractMotor(Device, PositionerBase):
|
|||||||
parent=None,
|
parent=None,
|
||||||
host="mpc2680.psi.ch",
|
host="mpc2680.psi.ch",
|
||||||
port=8085,
|
port=8085,
|
||||||
|
limits=None,
|
||||||
sign=1,
|
sign=1,
|
||||||
socket_cls=SocketIO,
|
socket_cls=SocketIO,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
@ -138,6 +140,29 @@ class SmaractMotor(Device, PositionerBase):
|
|||||||
self._update_connection_state, event_type=self.SUB_CONNECTION_CHANGE
|
self._update_connection_state, event_type=self.SUB_CONNECTION_CHANGE
|
||||||
)
|
)
|
||||||
self._update_connection_state()
|
self._update_connection_state()
|
||||||
|
if limits is not None:
|
||||||
|
assert len(limits) == 2
|
||||||
|
self.low_limit_travel.put(limits[0])
|
||||||
|
self.high_limit_travel.put(limits[1])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def limits(self):
|
||||||
|
return (self.low_limit_travel.get(), self.high_limit_travel.get())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def low_limit(self):
|
||||||
|
return self.limits[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def high_limit(self):
|
||||||
|
return self.limits[1]
|
||||||
|
|
||||||
|
def check_value(self, pos):
|
||||||
|
"""Check that the position is within the soft limits"""
|
||||||
|
low_limit, high_limit = self.limits
|
||||||
|
|
||||||
|
if low_limit < high_limit and not (low_limit <= pos <= high_limit):
|
||||||
|
raise LimitError(f"position={pos} not within limits {self.limits}")
|
||||||
|
|
||||||
def _update_connection_state(self, **kwargs):
|
def _update_connection_state(self, **kwargs):
|
||||||
for walk in self.walk_signals():
|
for walk in self.walk_signals():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user