diff --git a/README.rst b/README.rst index 12d5969..c226617 100644 --- a/README.rst +++ b/README.rst @@ -38,10 +38,10 @@ Installation instructions The user has to install the drivers from ACS. The homing program provided with the stages must be stored in a buffer of the controller (buffer 1 by default, set with the -'Homing buffer' parameter of the plugin). The plugin never modifies the buffers of the -controller: the Home button starts this program (it homes all the axes at once); the move is done when the -program ends. Stop interrupts the homing program and halts all the axes: the stages must then be -homed again before any other move, as the program disables the limit switch protection while homing. +homing_buffer entry of the configuration file of the plugin). The plugin never modifies the buffers of the +controller: the Home button runs this program and waits for its end (about 20 s); it homes all the +axes at once. The homing cannot be interrupted from PyMoDAQ, as the program disables the limit switch +protection while homing: use the emergency stop of the controller if needed. It is recommended to keep a full backup of the controller application, made with the Application Wizard of SPiiPlus MMI Application Studio. Users are encouraged to check the compatibility of their ACS hardware with the latest version of the plugin, and to refer diff --git a/src/pymodaq_plugins_acs_motion/daq_move_plugins/daq_move_AcsXY.py b/src/pymodaq_plugins_acs_motion/daq_move_plugins/daq_move_AcsXY.py index c32ab5c..0d8c65e 100644 --- a/src/pymodaq_plugins_acs_motion/daq_move_plugins/daq_move_AcsXY.py +++ b/src/pymodaq_plugins_acs_motion/daq_move_plugins/daq_move_AcsXY.py @@ -4,6 +4,7 @@ main, DataActuatorType, DataActuator) from pymodaq_gui.parameter import Parameter +from pymodaq_utils.utils import ThreadCommand try: from pymodaq_plugins_acs_motion.hardware.acscontrol import Controller # ACS controller wrapper @@ -28,11 +29,11 @@ class DAQ_Move_AcsXY(DAQ_Move_base): The operating system used was Windows 11. Installation instructions: ACS drivers must be installed from the manufacturer's. The homing program provided with the stages must be stored in a buffer of the controller - (buffer 1 by default on the tested equipment, see the 'Homing buffer' parameter). + (buffer 1 on the tested equipment, set with the homing_buffer entry of the plugin configuration file). The plugin never modifies it. - The Home button starts this program (it homes all the axes at once); the move is done when the - program ends. Stop interrupts the homing program and halts all the axes: the stages must then be - homed again before any other move, as the program disables the limit switch protection while homing. + The Home button runs this program and waits for its end (about 20 s); it homes all the axes at once. + The homing cannot be interrupted from PyMoDAQ, as the program disables the limit switch protection + while homing: use the emergency stop of the controller if needed. Attributes: ----------- @@ -51,9 +52,7 @@ class DAQ_Move_AcsXY(DAQ_Move_base): data_actuator_type = DataActuatorType.DataActuator params = [ {'title': 'Serial Number', 'name': 'serial_num', 'type': 'str', - 'value': '', 'readonly': True,}, - {'title': 'Homing buffer', 'name': 'buff_num', 'type': 'int', - 'value': 1, 'limits': [0, 9],} + 'value': '', 'readonly': True,} ] + comon_parameters_fun(is_multiaxes, axis_names=_axis_names) def ini_attributes(self): @@ -110,6 +109,7 @@ def ini_stage(self, controller=None): self.controller = Controller(contype="ethernet", n_axes=2) self.controller.connect() # any object that will control the stages self.controller.enable_all() # enable all axes + self.controller.wait_all_enabled() #wait for axis enabled self.settings['serial_num']=self.controller.serial_number() @@ -129,27 +129,24 @@ def move_rel(self, value: DataActuator): self.move_abs(self.get_actuator_value() + value) def move_home(self): - """Start the homing program of the controller, without waiting for its end""" - buffer = self.settings['buff_num'] - if self.controller.is_program_running(buffer): - return # homing already in progress: ignore the repeated request - self.controller.run_buffer(buffer) - home = DataActuator(data=0, units=self.axis_unit) - self.target_value = self.get_position_with_scaling(home) - - def user_condition_to_reach_target(self) -> bool: - """A move is done only when the homing program is not running""" - return not self.controller.is_program_running(self.settings['buff_num']) + """Run the homing program of the controller (all axes) and wait for its end. + The homing cannot be interrupted from PyMoDAQ: the program disables the limit switch + protection while homing, so stopping it midway would leave the stages unprotected. + """ + if self.controller.is_program_running(self.controller.homing_buffer): + self.emit_status(ThreadCommand('Update_Status', ['Homing already in progress'])) + return + self.emit_status(ThreadCommand('Update_Status', + ['Homing all axes (about 20 s), it cannot be interrupted...'])) + try: + self.controller.home() + except Exception as e: # timeout or communication error: the move is over in any case + self.emit_status(ThreadCommand('Update_Status', [f'Homing error: {e}'])) + self.move_done(self.get_actuator_value()) def stop_motion(self): - """Stop the homing program if it is running, then halt the axes""" - buffer = self.settings['buff_num'] - if self.controller.is_program_running(buffer): - self.controller.stop_buffer(buffer) - for axis in self.controller.axes: - axis.halt() # the program may have left any axis jogging - else: - self.controller.axes[self.axis_value].halt() + """Stop the current axis and emit the move_done signal""" + self.controller.axes[self.axis_value].halt() self.move_done() diff --git a/src/pymodaq_plugins_acs_motion/hardware/acscontrol.py b/src/pymodaq_plugins_acs_motion/hardware/acscontrol.py index 2652106..6015a17 100644 --- a/src/pymodaq_plugins_acs_motion/hardware/acscontrol.py +++ b/src/pymodaq_plugins_acs_motion/hardware/acscontrol.py @@ -7,6 +7,10 @@ """ from __future__ import division, print_function from acspy import acsc +from ctypes import c_int +from pymodaq_utils.config import GlobalConfig + +config = GlobalConfig() class Controller(object): @@ -35,7 +39,21 @@ def run_buffer(self, buffer_number=1): def is_program_running(self, buffer_number=1): """Returns True while the program of the buffer is running.""" return bool(acsc.getProgramState(self.hc, buffer_number) & self.PST_RUN) - + + def wait_program_end(self, buffer_number=1, timeout=60000): + """Waits until the program of the buffer has finished (timeout in ms).""" + acsc.waitProgramEnd(self.hc, buffer_number, timeout) + + @property + def homing_buffer(self) -> int: + """Buffer storing the homing program, as set in the configuration file of the plugin""" + return config('acs_motion', 'homing_buffer') + + def home(self, timeout=60000): + """Runs the homing program provided with the stages and waits for its end (timeout in ms)""" + self.run_buffer(self.homing_buffer) + self.wait_program_end(self.homing_buffer, timeout) + def stop_buffer(self, buffer_number=1): """Stops the program running in the buffer.""" acsc.stopBuffer(self.hc, buffer_number) @@ -49,6 +67,11 @@ def enable_all(self, wait=acsc.SYNCHRONOUS): for a in self.axes: a.enable() + def wait_all_enabled(self, timeout=5000): + """Waits until all axes are enabled (timeout in ms for each axis).""" + for a in self.axes: + a.wait_enabled(timeout) + def disable_all(self, wait=acsc.SYNCHRONOUS): """Disables all axes.""" for a in self.axes: @@ -74,6 +97,12 @@ def enable(self, wait=acsc.SYNCHRONOUS): def disable(self, wait=acsc.SYNCHRONOUS): acsc.disable(self.controller.hc, self.axisno, wait) + def wait_enabled(self, timeout=5000): + """Waits until the axis is enabled (timeout in ms), raises an AcscError on timeout. + acsc_WaitMotorEnabled is not exposed by ACSpy, so it is called directly.""" + acsc.call_acsc(acsc.acs.acsc_WaitMotorEnabled, self.controller.hc, + c_int(self.axisno), c_int(1), c_int(timeout)) + def ptp(self, target, coordinates="absolute", wait=acsc.SYNCHRONOUS): """Performs a point to point move in either relative or absolute (default) coordinates.""" diff --git a/src/pymodaq_plugins_acs_motion/resources/config_template.toml b/src/pymodaq_plugins_acs_motion/resources/config_template.toml index 92cde44..10175e4 100644 --- a/src/pymodaq_plugins_acs_motion/resources/config_template.toml +++ b/src/pymodaq_plugins_acs_motion/resources/config_template.toml @@ -1,2 +1,3 @@ title = 'this is the configuration file of the plugin pymodaq_plugins_acs_motion' +homing_buffer = 1 # buffer of the controller storing the homing program provided with the stages