Implemented going to position.

This commit is contained in:
jupfi 2023-12-08 10:09:42 +01:00
parent 6920b7545a
commit 5933046d83
3 changed files with 78 additions and 28 deletions

View file

@ -8,7 +8,7 @@ from PyQt6 import QtSerialPort
from PyQt6.QtCore import QThread, pyqtSignal, pyqtSlot, Qt from PyQt6.QtCore import QThread, pyqtSignal, pyqtSlot, Qt
from PyQt6.QtWidgets import QApplication from PyQt6.QtWidgets import QApplication
from nqrduck.module.module_controller import ModuleController 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__) logger = logging.getLogger(__name__)
@ -635,41 +635,50 @@ class AutoTMController(ModuleController):
elif stepper == "matching": elif stepper == "matching":
self.module.model.active_stepper = self.module.model.matching_stepper 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.""" """Validate the stepper's future position."""
if future_position < 0: if future_position < 0:
self.module.view.add_error_text("Could not move stepper. Stepper position cannot be negative") self.module.view.add_error_text("Could not move stepper. Stepper position cannot be negative")
return False return False
if future_position > 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 {self.module.model.active_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 False
return True 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.""" """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 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.""" """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}" 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.""" """This method is called when the relative move button is pressed."""
future_position = self.module.model.active_stepper.position + int(steps) if stepper is None:
if self.validate_position(future_position): stepper = self.module.model.active_stepper
self.send_stepper_command(int(steps)) # Convert the steps string to an integer
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.""" """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) future_position = int(steps)
if self.validate_position(future_position): if self.validate_position(future_position, stepper):
actual_steps = self.calculate_steps_for_absolute_move(future_position) actual_steps = self.calculate_steps_for_absolute_move(future_position, stepper)
self.send_stepper_command(actual_steps) confirmation = self.send_stepper_command(actual_steps, stepper)
return confirmation
def load_positions(self, path : str) -> None: def load_positions(self, path : str) -> None:
"""Load the saved positions from a json file. """Load the saved positions from a json file.
@ -679,7 +688,7 @@ class AutoTMController(ModuleController):
""" """
# First clear the old positions # First clear the old positions
self.module.model.saved_positions = [] self.module.model.saved_positions = []
with open(path, "r") as f: with open(path, "r") as f:
positions = json.load(f) positions = json.load(f)
for position in positions: for position in positions:
@ -709,5 +718,25 @@ class AutoTMController(ModuleController):
logger.debug("Adding new position at %s MHz", frequency) logger.debug("Adding new position at %s MHz", frequency)
self.module.model.add_saved_position(frequency, tuning_position, matching_position) 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)

View file

@ -236,11 +236,6 @@ class SavedPosition():
"tuning_position": self.tuning_position, "tuning_position": self.tuning_position,
"matching_position": self.matching_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): class TuningStepper(Stepper):
TYPE = "Tuning" TYPE = "Tuning"
@ -361,6 +356,11 @@ class AutoTMModel(ModuleModel):
self.saved_positions.append(SavedPosition(frequency, tuning_position, matching_position)) self.saved_positions.append(SavedPosition(frequency, tuning_position, matching_position))
self.saved_positions_changed.emit(self.saved_positions) 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 @property
def measurement(self): def measurement(self):
"""The measurement property is used to store the current measurement. """The measurement property is used to store the current measurement.

View file

@ -216,10 +216,16 @@ class AutoTMView(ModuleView):
self._ui_form.decreaseButton.setEnabled(True) self._ui_form.decreaseButton.setEnabled(True)
self._ui_form.increaseButton.setEnabled(True) self._ui_form.increaseButton.setEnabled(True)
self._ui_form.absoluteGoButton.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: else:
self._ui_form.decreaseButton.setEnabled(False) self._ui_form.decreaseButton.setEnabled(False)
self._ui_form.increaseButton.setEnabled(False) self._ui_form.increaseButton.setEnabled(False)
self._ui_form.absoluteGoButton.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() @pyqtSlot()
def on_position_button_clicked(self) -> None: def on_position_button_clicked(self) -> None:
@ -362,15 +368,16 @@ class AutoTMView(ModuleView):
# Create table widget # Create table widget
self.table_widget = QTableWidget() self.table_widget = QTableWidget()
self.table_widget.setColumnCount(4) self.table_widget.setColumnCount(5)
self.table_widget.setHorizontalHeaderLabels( 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(1, 200)
self.table_widget.setColumnWidth(2, 200) self.table_widget.setColumnWidth(2, 200)
self.table_widget.setColumnWidth(3, 100) self.table_widget.setColumnWidth(3, 100)
self.table_widget.setColumnWidth(4, 100)
self.on_saved_positions_changed() self.on_saved_positions_changed()
# Add a 'Load Position' button (File selector) # Add a 'Load Position' button (File selector)
@ -446,8 +453,22 @@ class AutoTMView(ModuleView):
self.table_widget.setItem( self.table_widget.setItem(
row, 2, QTableWidgetItem(position.matching_position) row, 2, QTableWidgetItem(position.matching_position)
) )
button = QPushButton("Go") go_button = QPushButton("Go")
self.table_widget.setCellWidget(row, 3, button) 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") logger.debug("Updated saved positions table")
class NewPositionWindow(QDialog): class NewPositionWindow(QDialog):