From 5933046d8393804e26903c74b05d2871332472bd Mon Sep 17 00:00:00 2001 From: jupfi Date: Fri, 8 Dec 2023 10:09:42 +0100 Subject: [PATCH] Implemented going to position. --- src/nqrduck_autotm/controller.py | 65 +++++++++++++++++++++++--------- src/nqrduck_autotm/model.py | 10 ++--- src/nqrduck_autotm/view.py | 31 ++++++++++++--- 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/nqrduck_autotm/controller.py b/src/nqrduck_autotm/controller.py index 657f0bf..4b3c6c6 100644 --- a/src/nqrduck_autotm/controller.py +++ b/src/nqrduck_autotm/controller.py @@ -8,7 +8,7 @@ from PyQt6 import QtSerialPort from PyQt6.QtCore import QThread, pyqtSignal, pyqtSlot, Qt from PyQt6.QtWidgets import QApplication from nqrduck.module.module_controller import ModuleController -from .model import S11Data, ElectricalLookupTable, MechanicalLookupTable, SavedPosition +from .model import S11Data, ElectricalLookupTable, MechanicalLookupTable, SavedPosition, Stepper logger = logging.getLogger(__name__) @@ -635,41 +635,50 @@ class AutoTMController(ModuleController): elif stepper == "matching": self.module.model.active_stepper = self.module.model.matching_stepper - def validate_position(self, future_position: int) -> bool: + def validate_position(self, future_position: int, stepper : Stepper) -> bool: """Validate the stepper's future position.""" if future_position < 0: self.module.view.add_error_text("Could not move stepper. Stepper position cannot be negative") return False - if future_position > self.module.model.active_stepper.MAX_STEPS: - self.module.view.add_error_text(f"Could not move stepper. Stepper position cannot be larger than {self.module.model.active_stepper.MAX_STEPS}") + if future_position > stepper.MAX_STEPS: + self.module.view.add_error_text(f"Could not move stepper. Stepper position cannot be larger than {stepper.MAX_STEPS}") return False return True - def calculate_steps_for_absolute_move(self, target_position: int) -> int: + def calculate_steps_for_absolute_move(self, target_position: int, stepper : Stepper) -> int: """Calculate the number of steps for an absolute move.""" - current_position = self.module.model.active_stepper.position + current_position = stepper.position return target_position - current_position - def send_stepper_command(self, steps: int) -> None: + def send_stepper_command(self, steps: int, stepper : Stepper) -> None: """Send a command to the stepper motor based on the number of steps.""" - motor_identifier = self.module.model.active_stepper.TYPE.lower()[0] + motor_identifier = stepper.TYPE.lower()[0] command = f"m{motor_identifier}{steps}" - self.send_command(command) + confirmation = self.send_command(command) + return confirmation - def on_relative_move(self, steps: str) -> None: + def on_relative_move(self, steps: str, stepper : Stepper = None ) -> None: """This method is called when the relative move button is pressed.""" - future_position = self.module.model.active_stepper.position + int(steps) - if self.validate_position(future_position): - self.send_stepper_command(int(steps)) # Convert the steps string to an integer + if stepper is None: + stepper = self.module.model.active_stepper - def on_absolute_move(self, steps: str) -> None: + future_position = stepper.position + int(steps) + if self.validate_position(future_position, stepper): + confirmation = self.send_stepper_command(int(steps), stepper) # Convert the steps string to an integer + return confirmation + + def on_absolute_move(self, steps: str, stepper : Stepper = None ) -> None: """This method is called when the absolute move button is pressed.""" + if stepper is None: + stepper = self.module.model.active_stepper + future_position = int(steps) - if self.validate_position(future_position): - actual_steps = self.calculate_steps_for_absolute_move(future_position) - self.send_stepper_command(actual_steps) + if self.validate_position(future_position, stepper): + actual_steps = self.calculate_steps_for_absolute_move(future_position, stepper) + confirmation = self.send_stepper_command(actual_steps, stepper) + return confirmation def load_positions(self, path : str) -> None: """Load the saved positions from a json file. @@ -679,7 +688,7 @@ class AutoTMController(ModuleController): """ # First clear the old positions self.module.model.saved_positions = [] - + with open(path, "r") as f: positions = json.load(f) for position in positions: @@ -709,5 +718,25 @@ class AutoTMController(ModuleController): logger.debug("Adding new position at %s MHz", frequency) self.module.model.add_saved_position(frequency, tuning_position, matching_position) + def on_go_to_position(self, position: SavedPosition) -> None: + """Go to the specified position. + + Args: + position (SavedPosition): The position to go to. + """ + logger.debug("Going to position: %s", position) + confirmation = self.on_absolute_move(position.tuning_position, self.module.model.tuning_stepper) + if confirmation: + self.on_absolute_move(position.matching_position, self.module.model.matching_stepper) + + def on_delete_position(self, position: SavedPosition) -> None: + """Delete the specified position. + + Args: + position (SavedPosition): The position to delete. + """ + logger.debug("Deleting position: %s", position) + self.module.model.delete_saved_position(position) + diff --git a/src/nqrduck_autotm/model.py b/src/nqrduck_autotm/model.py index c1d15ae..fa590d5 100644 --- a/src/nqrduck_autotm/model.py +++ b/src/nqrduck_autotm/model.py @@ -236,11 +236,6 @@ class SavedPosition(): "tuning_position": self.tuning_position, "matching_position": self.matching_position, } - - @classmethod - def from_json(cls, json): - logger.debug(json) - return cls(json[0], json[1], json[2]) class TuningStepper(Stepper): TYPE = "Tuning" @@ -361,6 +356,11 @@ class AutoTMModel(ModuleModel): self.saved_positions.append(SavedPosition(frequency, tuning_position, matching_position)) self.saved_positions_changed.emit(self.saved_positions) + def delete_saved_position(self, position: SavedPosition) -> None: + """Delete a saved position from the model.""" + self.saved_positions.remove(position) + self.saved_positions_changed.emit(self.saved_positions) + @property def measurement(self): """The measurement property is used to store the current measurement. diff --git a/src/nqrduck_autotm/view.py b/src/nqrduck_autotm/view.py index 14c6fbe..bcdcf3f 100644 --- a/src/nqrduck_autotm/view.py +++ b/src/nqrduck_autotm/view.py @@ -216,10 +216,16 @@ class AutoTMView(ModuleView): self._ui_form.decreaseButton.setEnabled(True) self._ui_form.increaseButton.setEnabled(True) self._ui_form.absoluteGoButton.setEnabled(True) + self._ui_form.positionButton.setEnabled(True) + self._ui_form.mechLUTButton.setEnabled(True) + self._ui_form.viewmechLUTButton.setEnabled(True) else: self._ui_form.decreaseButton.setEnabled(False) self._ui_form.increaseButton.setEnabled(False) self._ui_form.absoluteGoButton.setEnabled(False) + self._ui_form.positionButton.setEnabled(False) + self._ui_form.mechLUTButton.setEnabled(False) + self._ui_form.viewmechLUTButton.setEnabled(False) @pyqtSlot() def on_position_button_clicked(self) -> None: @@ -362,15 +368,16 @@ class AutoTMView(ModuleView): # Create table widget self.table_widget = QTableWidget() - self.table_widget.setColumnCount(4) + self.table_widget.setColumnCount(5) self.table_widget.setHorizontalHeaderLabels( - ["Frequency", "Tuning Position", "Matching Position", "Button"] + ["Frequency (MHz)", "Tuning Position", "Matching Position", "Button", "Delete"] ) - self.table_widget.setColumnWidth(0, 100) + self.table_widget.setColumnWidth(0, 150) self.table_widget.setColumnWidth(1, 200) self.table_widget.setColumnWidth(2, 200) self.table_widget.setColumnWidth(3, 100) + self.table_widget.setColumnWidth(4, 100) self.on_saved_positions_changed() # Add a 'Load Position' button (File selector) @@ -446,8 +453,22 @@ class AutoTMView(ModuleView): self.table_widget.setItem( row, 2, QTableWidgetItem(position.matching_position) ) - button = QPushButton("Go") - self.table_widget.setCellWidget(row, 3, button) + go_button = QPushButton("Go") + go_button.clicked.connect( + lambda _, position=position: self.module.controller.on_go_to_position( + position + ) + ) + self.table_widget.setCellWidget(row, 3, go_button) + + delete_button = QPushButton("Delete") + delete_button.clicked.connect( + lambda _, position=position: self.module.controller.on_delete_position( + position + ) + ) + self.table_widget.setCellWidget(row, 4, delete_button) + logger.debug("Updated saved positions table") class NewPositionWindow(QDialog):