yincheng.zhong
2025-11-23 212ccb49d3e7c7fa138c5f9d335d0b8c5a08d2a3
python/realtime_control.py
@@ -351,13 +351,14 @@
            info_scroll.setMinimumWidth(320)
            right_layout.addWidget(info_scroll, stretch=1)
            self.path_browse_btn.clicked.connect(self._browse_path_file)
            self.path_load_btn.clicked.connect(self._load_path_from_ui)
            self.origin_update_btn.clicked.connect(self._update_origin_from_ui)
            self.port_refresh_btn.clicked.connect(lambda: self._refresh_serial_ports(initial=False))
            self.serial_toggle_btn.clicked.connect(self._toggle_serial_connection)
            self.start_button.clicked.connect(self._start_control)
            self.stop_button.clicked.connect(self._stop_control)
            if self.controller is not None:
                self.path_browse_btn.clicked.connect(self._browse_path_file)
                self.path_load_btn.clicked.connect(self._load_path_from_ui)
                self.origin_update_btn.clicked.connect(self._update_origin_from_ui)
                self.port_refresh_btn.clicked.connect(lambda: self._refresh_serial_ports(initial=False))
                self.serial_toggle_btn.clicked.connect(self._toggle_serial_connection)
                self.start_button.clicked.connect(self._start_control)
                self.stop_button.clicked.connect(self._stop_control)
        def _apply_saved_values(self):
            path_file = self.gui_state.get("path_file", "")
@@ -541,69 +542,16 @@
            self.port_combo.blockSignals(False)
        def _toggle_serial_connection(self):
            if self.controller.is_connected():
                if self.controller.is_running():
                    QtWidgets.QMessageBox.warning(self, "串口", "请先停止运动控制,再关闭串口。")
                    return
                self.controller.disconnect()
                QtWidgets.QMessageBox.information(self, "串口", "串口已关闭。")
            else:
                port = self.port_combo.currentText().strip()
                if not port:
                    QtWidgets.QMessageBox.warning(self, "串口", "没有可用串口,请先连接设备。")
                    return
                try:
                    self.controller.set_port(port)
                except RuntimeError as exc:
                    QtWidgets.QMessageBox.warning(self, "串口", str(exc))
                    return
                if not self.controller.connect():
                    QtWidgets.QMessageBox.warning(self, "串口", "串口打开失败,请检查连接。")
                    return
                self._save_state({"serial_port": port})
                QtWidgets.QMessageBox.information(self, "串口", f"串口 {port} 已打开。")
            self._update_serial_ui()
            self._update_control_buttons()
            QtWidgets.QMessageBox.warning(self, "串口", "HITL 模式下该操作由仿真器控制")
        def _start_control(self):
            if self._is_control_running():
                return
            if not self.controller.mower_ctrl:
                QtWidgets.QMessageBox.warning(self, "控制", "请先加载路径文件。")
                return
            if not self.controller.is_connected():
                QtWidgets.QMessageBox.warning(self, "控制", "请先打开串口。")
                return
            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)
            def control_entry():
                try:
                    self.controller.run()
                except Exception as exc:
                    print(f"[ERROR] 控制线程异常: {exc}")
                    QtCore.QMetaObject.invokeMethod(
                        self,
                        "_show_error_message",
                        QtCore.Qt.QueuedConnection,
                        QtCore.Q_ARG(str, f"控制线程异常: {exc}"),
                    )
                finally:
                    QtCore.QMetaObject.invokeMethod(self, "_on_control_finished", QtCore.Qt.QueuedConnection)
            self.control_thread = threading.Thread(target=control_entry, daemon=True)
            self.control_thread.start()
            self._update_control_buttons()
            QtWidgets.QMessageBox.warning(self, "控制", "HITL 模式下请通过仿真器启动")
        def _stop_control(self):
            if not self._is_control_running():
                return
            self.controller.stop()
            self.stop_button.setEnabled(False)
            QtWidgets.QMessageBox.warning(self, "控制", "HITL 模式下请通过仿真器停止")
        def _is_control_running(self) -> bool:
            return bool(self.control_thread and self.control_thread.is_alive())
            return False
        def _save_state(self, updates: Dict[str, str]):
            self.gui_state.update(updates)
@@ -611,32 +559,23 @@
                self.persist_state_cb(updates)
        def _update_serial_ui(self):
            connected = self.controller.is_connected()
            self.serial_toggle_btn.setText("关闭串口" if connected else "打开串口")
            self.port_combo.setEnabled(not connected)
            self.port_refresh_btn.setEnabled(not connected)
            self.serial_toggle_btn.setEnabled(False)
            self.port_combo.setEnabled(False)
            self.port_refresh_btn.setEnabled(False)
        def _update_control_buttons(self):
            can_start = bool(self.controller.mower_ctrl and self.controller.is_connected() and not self._is_control_running())
            self.start_button.setEnabled(can_start)
            self.stop_button.setEnabled(self._is_control_running())
            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(False)
        @QtCore.pyqtSlot()
        def _on_control_finished(self):
            self.control_thread = None
            self._update_control_buttons()
            self.stop_button.setEnabled(False)
            pass
        @QtCore.pyqtSlot(str)
        def _show_error_message(self, message: str):
            QtWidgets.QMessageBox.warning(self, "错误", message)
        def closeEvent(self, event):
            self._stop_control()
            if self.control_thread:
                self.control_thread.join(timeout=3.0)
            if self.controller.is_connected():
                self.controller.disconnect()
            super().closeEvent(event)
else:
    QtRealtimeDashboard = None