diff --git a/config/app_config.json b/config/app_config.json index d348eb8..2786c98 100644 --- a/config/app_config.json +++ b/config/app_config.json @@ -49,8 +49,8 @@ "default_framerate": 30 }, "modbus": { - "host": "localhost", - "port": "5020" + "host": "192.168.2.88", + "port": "502" }, "serial": { "keyboard": { diff --git a/db/jtDB.db b/db/jtDB.db index f7cd1ac..a9149d9 100644 Binary files a/db/jtDB.db and b/db/jtDB.db differ diff --git a/from pymodbus.py b/from pymodbus.py index b5453bb..e5a97c5 100644 --- a/from pymodbus.py +++ b/from pymodbus.py @@ -16,6 +16,6 @@ client.write_registers(address=3, values=[0]) # client.write_registers(address=13, values=[1]) -result = client.read_holding_registers(address=3, count=1) +result = client.read_holding_registers(address=109, count=1) print(result.registers[0],"123===") client.close() \ No newline at end of file diff --git a/utils/modbus_monitor.py b/utils/modbus_monitor.py index 9281f78..96d2489 100644 --- a/utils/modbus_monitor.py +++ b/utils/modbus_monitor.py @@ -77,7 +77,7 @@ class ModbusMonitor(QObject): def _initialize_registers(self): """初始化要监控的寄存器列表""" # 默认监控的寄存器地址 - register_addresses = [5, 6, 11, 13, 20, 21, 22, 23, 24, 30] # 添加寄存器30用于电力监控 + register_addresses = [5, 6, 11, 13, 20, 21, 22, 23, 24, 25, 30] for address in register_addresses: self.registers[address] = RegisterValue(address) diff --git a/utils/register_handlers.py b/utils/register_handlers.py index f2b44a8..99ff385 100644 --- a/utils/register_handlers.py +++ b/utils/register_handlers.py @@ -243,4 +243,23 @@ class NGHandler(RegisterHandler): #如果有回调函数,则调用 if self.callback: - self.callback(value) \ No newline at end of file + self.callback(value) + + +class EmergencyStopHandler(RegisterHandler): + """寄存器D25处理器,处理急停信号""" + def __init__(self, callback=None): + super().__init__() + self.callback = callback + self.status_map = { + 0: "正常", + 1: "急停触发" + } + + def handle_change(self, value): + status = self.status_map.get(value, f"未知状态({value})") + logging.info(f"急停信号: {status}") + + # 如果有回调函数,则调用 + if self.callback and value == 1: + self.callback(value, "监听到急停信号") \ No newline at end of file diff --git a/widgets/main_window.py b/widgets/main_window.py index 36caf7b..48637c6 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -19,7 +19,8 @@ from utils.register_handlers import ( Error2Handler, Error3Handler, UnloadingLevelHandler, - UnloadingPositionHandler + UnloadingPositionHandler, + EmergencyStopHandler ) from utils.electricity_monitor import ElectricityHandler # 导入PySide6 @@ -53,6 +54,7 @@ class MainWindow(MainWindowUI): unloading_feedback_signal = Signal(str, str) # 参数:status_type, desc unloading_level_ui_signal = Signal(int) # 用于在主线程中更新下料层数UI unloading_position_ui_signal = Signal(int) # 用于在主线程中更新下料位置UI + emergency_stop_signal = Signal(int, str) # 用于在主线程中处理急停信号 def __init__(self, user_id=None, user_name=None, corp_name=None, corp_id=None): """初始化主窗口""" @@ -75,12 +77,7 @@ class MainWindow(MainWindowUI): self._loading_info = None # 存储上料对话框的信息 self._is_loading_active = False # 标识上料任务是否正在进行 - # 连接信号到槽 - self.loading_feedback_signal.connect(self._handle_loading_feedback_ui) - self.unloading_feedback_signal.connect(self._handle_unloading_feedback_ui) - # 连接新增的信号 - self.unloading_level_ui_signal.connect(self.handle_unloading_level_ui) - self.unloading_position_ui_signal.connect(self.handle_unloading_position_ui) + # 信号的连接在connect_signals方法中统一处理,不在这里连接 # 称重相关变量 self._current_weight = None # 当前称重值(千克) @@ -109,17 +106,12 @@ class MainWindow(MainWindowUI): self.output_form_layout = QFormLayout() self.output_content_layout.addLayout(self.output_form_layout) - # 只有在相机启用时创建相机显示组件 - if self.camera_enabled: - # 创建相机显示组件并添加到上料区 - self.camera_display = CameraDisplayWidget() - self.material_content_layout.addWidget(self.camera_display) - else: - # 在上料区添加占位标签 - self.material_placeholder = QLabel("相机功能已禁用") - self.material_placeholder.setAlignment(Qt.AlignCenter) - self.material_placeholder.setStyleSheet("color: #888888; background-color: #f0f0f0;") - self.material_content_layout.addWidget(self.material_placeholder) + # 创建相机显示组件和占位标签 + self.camera_display = None + self.material_placeholder = None + + # 初始化上料区显示 + self.init_camera_display() # 为下料区添加占位标签,确保它保持为空 self.output_placeholder = QWidget() @@ -266,6 +258,19 @@ class MainWindow(MainWindowUI): # 连接报表按钮点击事件 self.report_button.clicked.connect(self.on_report) + + # 连接加载反馈信号 + self.loading_feedback_signal.connect(self._handle_loading_feedback_ui) + + # 连接下料反馈信号 + self.unloading_feedback_signal.connect(self._handle_unloading_feedback_ui) + + # 连接下料层数和位置UI更新信号 + self.unloading_level_ui_signal.connect(self.handle_unloading_level_ui) + self.unloading_position_ui_signal.connect(self.handle_unloading_position_ui) + + # 连接急停信号 + self.emergency_stop_signal.connect(self._handle_emergency_stop_ui) def update_inspection_columns(self): """更新检验列配置 - 使用检验配置管理器获取启用的列数和标题""" @@ -300,12 +305,25 @@ class MainWindow(MainWindowUI): # 加载未完成的检验数据 self._safe_load_data() - # 只有在相机启用时处理相机显示 - if self.camera_enabled and hasattr(self, 'camera_display'): - # 如果相机已连接,直接开始显示相机画面 - if self.camera_display.camera_manager.isOpen: - if not self.camera_display.camera_manager.isGrabbing: - self.camera_display.start_display() + # 处理相机显示 + if self.camera_enabled and self.camera_display: + from widgets.camera_manager import CameraManager + camera_manager = CameraManager.get_instance() + + # 检查相机是否已打开 + if camera_manager.isOpen: + # 更新UI显示相机画面 + self.update_camera_ui(True) + + # 如果相机未在采集,则开始采集 + if not camera_manager.isGrabbing: + # 使用内部方法启动相机显示 + QTimer.singleShot(100, self._start_camera_display) + logging.info("主页面显示:启动相机显示") + else: + # 如果相机未打开,尝试重新初始化 + QTimer.singleShot(100, self.initialize_camera) + logging.info("主页面显示:尝试初始化相机") # 加载托盘号列表 self.load_pallet_codes() @@ -660,8 +678,13 @@ class MainWindow(MainWindowUI): """处理相机状态变化""" if is_connected: logging.info("相机已连接并显示") + self.update_camera_ui(True) else: logging.warning(f"相机显示问题: {message}") + # 更新占位符文本 + if self.material_placeholder: + self.material_placeholder.setText(f"相机错误: {message}" if message else "相机未连接") + self.update_camera_ui(False) def handle_camera_connection(self, is_connected, message): """处理相机连接状态变化""" @@ -695,10 +718,20 @@ class MainWindow(MainWindowUI): logging.info("停止Modbus监控") self.modbus_monitor.stop() - # 只有在相机启用时处理相机关闭 - if self.camera_enabled and hasattr(self, 'camera_display'): + # 处理相机关闭 + if self.camera_enabled and self.camera_display: # 停止相机显示 self.camera_display.stop_display() + + # 关闭相机设备 + try: + from widgets.camera_manager import CameraManager + camera_manager = CameraManager.get_instance() + if camera_manager.isOpen: + camera_manager.close_device() + logging.info("相机设备已关闭") + except Exception as e: + logging.error(f"关闭相机设备失败: {str(e)}") # 停止串口监听 self.serial_manager.stop_keyboard_listener() @@ -1637,6 +1670,9 @@ class MainWindow(MainWindowUI): monitor.register_handler(23, Error2Handler(self.machine_handlers.handle_error_2)) monitor.register_handler(24, Error3Handler(self.machine_handlers.handle_error_3)) + # 注册急停信号处理器 + monitor.register_handler(25, EmergencyStopHandler(self.handle_emergency_stop)) + # 注册下料层数和位置处理器 monitor.register_handler(4, UnloadingLevelHandler(self.handle_unloading_level)) monitor.register_handler(5, UnloadingPositionHandler(self.handle_unloading_position)) @@ -2188,8 +2224,7 @@ class MainWindow(MainWindowUI): # 如果有故障,显示提示 if error_code in (2, 3): QMessageBox.warning(self, "机器人视觉报警", f"机器人视觉报警: {detailed_desc}") - # error_1 属于上料故障 - self.show_operation_status("异常", "", detailed_desc) + # 移除在下料区域显示异常信息的代码 @Slot(int, str) @@ -2204,9 +2239,8 @@ class MainWindow(MainWindowUI): self._update_error_status() # 如果有故障,显示提示 - if error_code > 0: - # error_2 属于下料故障 - self.show_operation_status("异常", "", detailed_desc) + # 移除在下料区域显示异常信息的代码 + @Slot(int, str) def handle_error_3(self, error_code, error_desc): """拆码垛报警""" @@ -2224,11 +2258,11 @@ class MainWindow(MainWindowUI): QMessageBox.warning(self, "异常", f"异常: {detailed_desc}") modbus.write_register_until_success(client, 2, 0) modbus.close_client(client) - self.show_operation_status("异常", "", detailed_desc) + # 移除在下料区域显示异常信息的代码 elif error_code == 2: QMessageBox.warning(self, "异常", f"异常: {detailed_desc}") modbus.write_register_until_success(client, 3, 0) - modbus.close_client(client) + modbus.close_client(client) @Slot(int) def handle_unloading_level(self, level): """处理下料层数信息(来自Modbus)""" @@ -2661,4 +2695,200 @@ class MainWindow(MainWindowUI): dialog.exec_() except Exception as e: logging.error(f"打开报表对话框失败: {str(e)}") - QMessageBox.warning(self, "错误", f"打开报表对话框失败: {str(e)}") \ No newline at end of file + QMessageBox.warning(self, "错误", f"打开报表对话框失败: {str(e)}") + + def init_camera_display(self): + """初始化相机显示区域""" + try: + # 清理之前的组件(如果有) + if self.camera_display: + self.material_content_layout.removeWidget(self.camera_display) + self.camera_display.deleteLater() + self.camera_display = None + + if self.material_placeholder: + self.material_content_layout.removeWidget(self.material_placeholder) + self.material_placeholder.deleteLater() + self.material_placeholder = None + + # 清空布局中的所有项目 + while self.material_content_layout.count(): + item = self.material_content_layout.takeAt(0) + if item.widget(): + item.widget().deleteLater() + + # 创建占位标签 + self.material_placeholder = QLabel("相机初始化中..." if self.camera_enabled else "相机功能已禁用") + self.material_placeholder.setAlignment(Qt.AlignCenter) + self.material_placeholder.setStyleSheet("color: #888888; background-color: #f0f0f0;") + self.material_content_layout.addWidget(self.material_placeholder) + + # 创建相机显示组件 + self.camera_display = CameraDisplayWidget() + self.camera_display.signal_camera_status.connect(self.handle_camera_status) + + # 先隐藏相机组件,直到确认相机可用 + self.material_content_layout.addWidget(self.camera_display) + self.camera_display.hide() + + # 如果相机功能已启用,尝试初始化相机 + if self.camera_enabled: + # 启动相机初始化过程 + QTimer.singleShot(500, self.initialize_camera) + logging.info("相机初始化已安排") + else: + logging.info("相机功能已禁用,不进行初始化") + self.material_placeholder.show() + self.camera_display.hide() + except Exception as e: + logging.error(f"初始化相机显示区域失败: {str(e)}") + + def initialize_camera(self): + """初始化相机并显示画面""" + try: + if not self.camera_enabled: + return + + logging.info("开始初始化相机...") + + # 获取相机管理器实例 + from widgets.camera_manager import CameraManager + camera_manager = CameraManager.get_instance() + + # 枚举设备 + devices = camera_manager.enum_devices() + if not devices or len(devices) == 0: + self.material_placeholder.setText("未检测到相机设备") + logging.warning("未检测到相机设备") + return + + # 打开第一个相机设备 + device_index = 0 + success = camera_manager.open_device(device_index) + + if success: + logging.info(f"相机已成功打开,设备索引: {device_index}") + # 更新UI + self.update_camera_ui(True) + + # 立即开始显示相机画面 + QTimer.singleShot(100, lambda: self._start_camera_display()) + else: + self.material_placeholder.setText("相机打开失败") + logging.error("相机打开失败") + + except Exception as e: + self.material_placeholder.setText("相机初始化错误") + logging.error(f"初始化相机失败: {str(e)}") + + def _start_camera_display(self): + """开始显示相机画面(内部方法)""" + try: + if self.camera_display and self.camera_enabled: + # 确保相机组件可见 + self.camera_display.setVisible(True) + self.camera_display.raise_() + + # 开始显示 + success = self.camera_display.start_display() + + if success: + # 确保占位符隐藏 + if self.material_placeholder: + self.material_placeholder.setVisible(False) + logging.info("相机显示已成功启动") + else: + # 如果启动失败,显示占位符 + if self.material_placeholder: + self.material_placeholder.setText("相机显示启动失败") + self.material_placeholder.setVisible(True) + logging.error("相机显示启动失败") + except Exception as e: + logging.error(f"启动相机显示失败: {str(e)}") + + def update_camera_ui(self, is_camera_ready): + """更新相机UI显示 + + Args: + is_camera_ready: 相机是否准备就绪 + """ + try: + if is_camera_ready and self.camera_enabled: + # 显示相机画面,隐藏占位符 + if self.camera_display: + self.camera_display.setVisible(True) + self.camera_display.raise_() # 确保相机组件在最上层 + if self.material_placeholder: + self.material_placeholder.setVisible(False) + logging.info("相机UI已更新:显示相机画面") + else: + # 隐藏相机画面,显示占位符 + if self.camera_display: + self.camera_display.setVisible(False) + if self.material_placeholder: + self.material_placeholder.setVisible(True) + self.material_placeholder.raise_() # 确保占位符在最上层 + if not self.camera_enabled: + self.material_placeholder.setText("相机功能已禁用") + elif not is_camera_ready: + self.material_placeholder.setText("相机未就绪") + logging.info(f"相机UI已更新:显示占位符 (相机启用={self.camera_enabled}, 相机就绪={is_camera_ready})") + except Exception as e: + logging.error(f"更新相机UI失败: {str(e)}") + + def handle_camera_status(self, is_connected, message): + """处理相机状态变化""" + if is_connected: + logging.info("相机已连接并显示") + self.update_camera_ui(True) + else: + logging.warning(f"相机显示问题: {message}") + # 更新占位符文本 + if self.material_placeholder: + self.material_placeholder.setText(f"相机错误: {message}" if message else "相机未连接") + self.update_camera_ui(False) + + @Slot(int, str) + def handle_emergency_stop(self, value, desc): + """处理急停信号""" + logging.info(f"[处理] 急停信号: {desc}") + + # 保存一个急停状态变量 + self.emergency_stop = value + + # 当急停信号为1时,重置D2和D3寄存器 + if value == 1: + try: + modbus = ModbusUtils() + client = modbus.get_client() + + # 重置D2和D3寄存器 + modbus.write_register_until_success(client, 2, 0) + modbus.write_register_until_success(client, 3, 0) + + # 通过信号在主线程中处理UI更新 + self.emergency_stop_signal.emit(value, desc) + + modbus.close_client(client) + except Exception as e: + logging.error(f"处理急停信号失败: {str(e)}") + else: + # 急停信号解除,在主线程中恢复错误状态显示 + self.emergency_stop_signal.emit(value, desc) + + def _handle_emergency_stop_ui(self, value, desc): + """在主线程中处理急停信号UI更新""" + try: + if value == 1: + # 显示警告对话框 + QMessageBox.warning(self, "急停警告", "监听到急停信号") + + # 更新错误状态标签 + self.error_status_label.setText("故障: 急停") + self.error_status_label.setToolTip("急停按钮被触发") + self.error_status_label.setStyleSheet("color: red; font-weight: bold;") + else: + # 急停信号解除,恢复错误状态显示 + self._update_error_status() + except Exception as e: + logging.error(f"处理急停UI更新失败: {str(e)}") \ No newline at end of file