From ec5aeb9981012052c98ad292d24002e367ca9aba Mon Sep 17 00:00:00 2001 From: Michael Mouchous Date: Wed, 12 Oct 2022 15:07:43 +0200 Subject: [PATCH 1/2] Uniformize the usage of "Vector" for "position" property in Tic and M3FS --- pystages/m3fs.py | 5 +++-- pystages/tic.py | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pystages/m3fs.py b/pystages/m3fs.py index 6cf9424..a2d3bb9 100644 --- a/pystages/m3fs.py +++ b/pystages/m3fs.py @@ -21,6 +21,7 @@ from binascii import hexlify from .exceptions import ConnectionFailure, ProtocolError, VersionNotSupported from .stage import Stage +from .vector import Vector class M3FS(Stage): @@ -145,7 +146,7 @@ def __get_closed_loop_status(self): return motor_status, position, error @property - def position(self): + def position(self) -> Vector: """ Stage position, in micrometers. @@ -156,7 +157,7 @@ def position(self): return Vector(position * self.resolution_um) @position.setter - def position(self, value): + def position(self, value: Vector): # To check dimension and range of the given value super(__class__, self.__class__).position.fset(self, value) diff --git a/pystages/tic.py b/pystages/tic.py index 88cae95..578a99c 100644 --- a/pystages/tic.py +++ b/pystages/tic.py @@ -137,7 +137,7 @@ def quick(self, command: TicCommand): """ self.dev.ctrl_transfer(0x40, command.value, 0, 0, 0) - def write_7(self, command: TicCommand, data): + def write_7(self, command: TicCommand, data: int): """ Write 7 bits. @@ -146,7 +146,7 @@ def write_7(self, command: TicCommand, data): """ self.dev.ctrl_transfer(0x40, command.value, data, 0, 0) - def write_32(self, command: TicCommand, data): + def write_32(self, command: TicCommand, data: int): """ Write 32 bits. @@ -155,7 +155,7 @@ def write_32(self, command: TicCommand, data): """ self.dev.ctrl_transfer(0x40, command.value, data & 0xFFFF, data >> 16, 0) - def block_read(self, command: TicCommand, offset, length): + def block_read(self, command: TicCommand, offset, length) -> bytes: """ Read data from the device. @@ -200,13 +200,13 @@ def go_home(self, direction: TicDirection, wait: bool = True): self.exit_safe_start() sleep(self.poll_interval) - def set_target_position(self, pos): + def set_target_position(self, pos: int): self.write_32(TicCommand.SET_TARGET_POSITION, pos) - def set_target_velocity(self, velocity): + def set_target_velocity(self, velocity: int): self.write_32(TicCommand.SET_TARGET_VELOCITY, velocity) - def get_variable(self, variable: TicVariable): + def get_variable(self, variable: TicVariable) -> int: offset, length, signed = variable.value return int.from_bytes( self.block_read(TicCommand.GET_VARIABLE, offset, length), @@ -215,30 +215,30 @@ def get_variable(self, variable: TicVariable): ) @property - def position(self): + def position(self) -> Vector: """ Motor position, in steps. :getter: Returns current target position. :setter: Set target position and wait until position is reached. """ - return self.get_variable(TicVariable.CURRENT_POSITION) + return Vector(self.get_variable(TicVariable.CURRENT_POSITION)) @position.setter def position(self, value: Vector): # To check dimension and range of the given value super(__class__, self.__class__).position.fset(self, value) self.target_position = value.x - while self.position != value.x: + while self.position.x != value.x: sleep(self.poll_interval) self.exit_safe_start() @property - def target_position(self) -> Vector: - return Vector(self.get_variable(TicVariable.TARGET_POSITION)) + def target_position(self) -> int: + return self.get_variable(TicVariable.TARGET_POSITION) @target_position.setter - def target_position(self, value): + def target_position(self, value: int): self.exit_safe_start() self.set_target_position(value) From dcb125d4178d3943f6e44496c823058cfa1f749c Mon Sep 17 00:00:00 2001 From: Michael Mouchous Date: Wed, 12 Oct 2022 15:29:57 +0200 Subject: [PATCH 2/2] Fix issue #12 --- pystages/cncrouter.py | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/pystages/cncrouter.py b/pystages/cncrouter.py index eb93c44..4f0451f 100644 --- a/pystages/cncrouter.py +++ b/pystages/cncrouter.py @@ -167,11 +167,25 @@ def get_current_status(self) -> Optional[Tuple[CNCStatus, dict]]: """ self.send("?", eol="") status = self.receive() + + # Sometimes, the CNC returns 'ok' and the actual response is following. + while status == "ok": + status = self.receive() + + # In the case there has been a communication error + if status is None: + return None + # The output # '' - # Remove the chevrons - status = status[1:-1] - elements = status.split("|") + + # Discard any unwanted format + if not (status.startswith("<") and status.endswith(">")): + print(f"Response to '?' is unexpected: {status}") + return None + + # Remove the chevrons and split all pipes. + elements = status[1:-1].split("|") # First element is the CNC status cncstatus = CNCStatus(elements[0]) @@ -245,11 +259,16 @@ def position(self) -> Vector: :getter: Query and return stage position. :setter: Move the stage. """ - status = {} - while "WCO" not in status: - status = self.get_current_status()[1] - mpos = Vector(*tuple(float(x) for x in status["MPos"])) - wco = Vector(*tuple(float(x) for x in status["WCO"])) + extra_dict = {} + # We loop until we get a current status providing 'WCO' which stores the + # origin. + while "WCO" not in extra_dict.keys(): + current_status = self.get_current_status() + extra_dict = current_status[1] if current_status is not None else {} + + mpos = Vector(*tuple(float(x) for x in extra_dict["MPos"])) + wco = Vector(*tuple(float(x) for x in extra_dict["WCO"])) + return mpos - wco @position.setter @@ -272,8 +291,9 @@ def is_moving(self) -> bool: :return: True if the CNC reports that a cycle is running (Run) or if it is in a middle of a homing cycle. """ - status = self.get_current_status()[0] - return status in [CNCStatus.RUN, CNCStatus.HOME] + while (status := self.get_current_status()) is None: + pass + return status[0] in [CNCStatus.RUN, CNCStatus.HOME] def set_origin(self) -> str: """