def execute_movement(self, button: QtWidgets.QPushButton, logger: QtWidgets.QPlainTextEdit, spin_boxes: QtWidgets.QDoubleSpinBox, index: int): """ This method is in charge of executing/canceling a movement by communicating it to the communications code through the handler object. This method is connected to a button widget, which triggers the execution of this function. When this function is executed, a future object is generated in orden to not freeze the GUI execution thread. When S2 completes the movement, the future object is trully returned, indicating if the movement was completed succesfully or if there was an error. :param button: button widget. :param logger: logger object instance, that is used to generate logs. :param spin_boxes: spinboxes object, used to get the values selected by the user. :param index: indicates whether the GUI coordinates are angular or cartesian. """ if button.State: self.progress_bar.show() button.setText("Cancel movement") button.State = False time_holder_val = AtomicFloat(initial_value=-1) self.progress_bar.run_worker(time_holder_val) ft = None if index == 0: ft = self.handler.move_to_thetas(spin_boxes[0].value(), spin_boxes[1].value(), spin_boxes[2].value(), time_holder_val) self.log.info(f'Sending joints to pArm: {{' f't0: {spin_boxes[0].value()}, ' f't1: {spin_boxes[1].value()}, ' f't2: {spin_boxes[2].value()}}}') elif index == 1: ft = self.handler.move_to_xyz(spin_boxes[0].value(), spin_boxes[1].value(), spin_boxes[2].value(), time_holder_val) self.log.info(f'Sending joints to pArm: {{' f'x: {spin_boxes[0].value()}, ' f'y: {spin_boxes[1].value()}, ' f'z: {spin_boxes[2].value()}}}') if ft: ft.add_done_callback( lambda fut: self.future_callback(fut, button)) else: self.progress_bar.hide() self.handler.cancel_movement() self.show_popup("Movement Cancelled") self.log.warning('Movement cancelled!') button.setText("Execute Movement") button.State = True
def future_callback(self, ft: Future, button: QtWidgets.QPushButton): """ This method is executed when the future object created in the execute movement process is finally returned, which means that this method is a call back. When the future object is finally returned, the GUI recieves it and decides whether the movement was completed succesfully or if there was an error. If the future object is an error type object, the GUI shows a pop up that notifys the error to the user. If the future object is an contro type object, the GUI uptades the value of the sliders and spin box with the data provided by the PCB and notifys the user that the movement was completed succesfully. :param ft: Future object instance that was finally returned. :param button: UI button that must be changed when finished movement. """ res = ft.result() self.progress_bar.hide() button.State = True button.setText("Execute Movement") if isinstance(res, ErrorData): self.show_popup(res.err_msg) self.log.error(f'Error happened during movement: {res.err_msg}') elif isinstance(res, ControlInterface): self.log.info('Movement was completed successfully') self.log.debug(f"Arm reported angles: " f"{(res.theta1, res.theta2, res.theta3)}") self.log.debug(f"Arm reported position: {(res.x, res.y, res.z)}") return if self.combo_box_coordinates.currentIndex() == 0: self.spin_box_1.setValue(res.theta1) self.spin_box_2.setValue(res.theta2) self.spin_box_3.setValue(res.theta3) elif self.combo_box_coordinates.currentIndex() == 1: self.spin_box_1.setValue(res.x) self.spin_box_2.setValue(res.y) self.spin_box_3.setValue(res.z)