From 2265ebae35d375a5f59ee0b374d7d79ff0ebdb9b Mon Sep 17 00:00:00 2001 From: Johnhaug223 <147444860+Johnhaug223@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:20:36 -0500 Subject: [PATCH 1/3] Update asi_tiger_controller.py On John's system, there are other types of cards that are not included with our other Tiger Controller builds. This includes piezos, for example, which do not recognize some of the commands we use to set the speed as a percent of the max speed. This fix now goes through all of the stages and removes those that do not qualify. https://www.asiimaging.com/docs/products/serial_commands#commandbuild_bu --- .../devices/APIs/asi/asi_tiger_controller.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py b/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py index b0172173c..71764da7f 100644 --- a/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py +++ b/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py @@ -179,6 +179,10 @@ def connect_to_serial( def get_default_motor_axis_sequence(self) -> None: """Get the default motor axis sequence from the ASI device + Only returns stage types XYMotor, ZMotor, Theta. Avoids problems associated + with other tiger controller cards, which could include piezos, filter wheels, + logic cards, etc. + Returns ------- list[str] @@ -189,13 +193,23 @@ def get_default_motor_axis_sequence(self) -> None: lines = response.split("\r") for line in lines: if line.startswith("Motor Axes:"): - default_axes_sequence = line[line.index(":") + 2 :].split(" ")[:-2] - self.report_to_console( - "Get the default axes sequence from the ASI device " "successfully!" - ) - break + motor_axes = line.split("Motor Axes:")[1].split() + + if line.startswith("Axis Types:"): + axis_types = line.split("Axis Types:")[1].split() + + if motor_axes is None or axis_types is None: + raise TigerException(":N-5") + + if len(motor_axes) != len(axis_types): + raise TigerException(":N-5") + + for i in range(len(axis_types) - 1, -1, -1): + # Iterate in reverse to safely remove elements by index. + if axis_types[i] not in ["x", "z", "t"]: + motor_axes.pop(i) - return default_axes_sequence + return motor_axes ##### TODO: Modify these to accept dictionaries and send a # single command for all axes From 286abcfa673d8b1e85c9818bccba0cfb6eee01a8 Mon Sep 17 00:00:00 2001 From: Kevin Dean <42547789+AdvancedImagingUTSW@users.noreply.github.com> Date: Thu, 19 Sep 2024 18:19:19 -0500 Subject: [PATCH 2/3] Update asi_tiger_controller.py --- .../model/devices/APIs/asi/asi_tiger_controller.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py b/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py index 71764da7f..57854114c 100644 --- a/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py +++ b/src/navigate/model/devices/APIs/asi/asi_tiger_controller.py @@ -176,7 +176,7 @@ def connect_to_serial( #: list[str]: Default axes sequence of the Tiger Controller self.default_axes_sequence = self.get_default_motor_axis_sequence() - def get_default_motor_axis_sequence(self) -> None: + def get_default_motor_axis_sequence(self) -> list[str]: """Get the default motor axis sequence from the ASI device Only returns stage types XYMotor, ZMotor, Theta. Avoids problems associated @@ -191,24 +191,22 @@ def get_default_motor_axis_sequence(self) -> None: self.send_command("BU X") response = self.read_response() lines = response.split("\r") + motor_axes, axis_types = [], [] for line in lines: if line.startswith("Motor Axes:"): motor_axes = line.split("Motor Axes:")[1].split() - if line.startswith("Axis Types:"): axis_types = line.split("Axis Types:")[1].split() - if motor_axes is None or axis_types is None: + if len(motor_axes) == 0 or len(axis_types) == 0: raise TigerException(":N-5") if len(motor_axes) != len(axis_types): raise TigerException(":N-5") for i in range(len(axis_types) - 1, -1, -1): - # Iterate in reverse to safely remove elements by index. if axis_types[i] not in ["x", "z", "t"]: motor_axes.pop(i) - return motor_axes ##### TODO: Modify these to accept dictionaries and send a @@ -340,12 +338,12 @@ def report_to_console(self, message: str) -> None: if self.verbose: print(message) - def send_command(self, cmd: bytes) -> None: + def send_command(self, cmd: str) -> None: """Send a serial command to the device. Parameters ---------- - cmd : bytes + cmd : str Serial command to send to the device """ # always reset the buffers before a new command is sent From 6f3f279f3c55bbfb067af5ffae568761d8b32013 Mon Sep 17 00:00:00 2001 From: Kevin Dean <42547789+AdvancedImagingUTSW@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:32:09 -0500 Subject: [PATCH 3/3] Update test_asi.py Path get_default_motor_axis_sequence in unit tests to pass the tests. --- test/model/devices/stages/test_asi.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/model/devices/stages/test_asi.py b/test/model/devices/stages/test_asi.py index 07e1443d8..164699f79 100644 --- a/test/model/devices/stages/test_asi.py +++ b/test/model/devices/stages/test_asi.py @@ -148,6 +148,14 @@ def build_device_connection(self): port = self.stage_configuration["stage"]["hardware"]["port"] baudrate = self.stage_configuration["stage"]["hardware"]["baudrate"] + # Patch TigerController.get_default_motor_axis_sequence + TigerController.get_default_motor_axis_sequence = lambda self: [ + "X", + "Y", + "Z", + "M", + "N", + ] asi_stage = TigerController(port, baudrate) asi_stage.serial_port = self.asi_serial_device asi_stage.connect_to_serial()