diff --git a/README.md b/README.md index ccdb03a..c08fd83 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,20 @@ # 腾智微丝产线包装系统 -## 项目架构分析 +## 项目概述 -这是一个基于PySide6(Qt for Python)开发的腾智微丝产线包装系统,采用了典型的MVC(模型-视图-控制器)架构: +腾智微丝产线包装系统是一个基于PySide6(Qt for Python)开发的工业自动化控制系统,用于管理和监控微丝产线的包装过程。该系统集成了相机监控、称重、条码扫描、PLC通信等功能,为微丝产品的质量控制与包装提供全面的解决方案。 + +## 项目架构 + +系统采用典型的MVC(模型-视图-控制器)架构: 1. **模型层(Model)**: - - 使用DAO(数据访问对象)模式访问数据库 + - 采用DAO(数据访问对象)模式访问数据库 - 支持多种数据库(SQLite、PostgreSQL、MySQL) - 主要数据表包括用户表、检验配置表、检验数据表、电力消耗表等 2. **视图层(View)**: - - 使用PySide6构建UI界面 + - 基于PySide6构建UI界面 - 主要界面包括登录界面、主窗口、设置界面等 - 采用分离的UI类设计,如LoginUI、MainWindowUI等 @@ -25,11 +29,9 @@ 5. **硬件集成层**: - **相机子系统**:基于海康威视SDK进行集成 - - 相机管理器(CameraManager):单例模式,管理相机生命周期 - - 相机显示组件(CameraDisplayWidget):用于实时显示相机画面 - - 相机设置控制器(CameraSettingsWidget):管理相机参数设置 - **串口通信**:与称重设备、扫描器等外设通信 - **Modbus通信**:与PLC设备通信 + - **本地图像模式**:支持离线使用本地图像序列进行模拟测试 ## 技术栈 @@ -38,18 +40,18 @@ - 使用Qt的信号槽机制实现组件间通信 2. **后端技术**: - - Python作为主要开发语言 - - SQLite作为默认数据库,支持PostgreSQL和MySQL - - Modbus协议用于与设备通信 + - Python 3.7+作为主要开发语言 + - 支持SQLite、PostgreSQL和MySQL数据库 + - Modbus协议用于与PLC设备通信 - 多线程处理耗时操作 3. **通信技术**: - Modbus TCP用于与PLC设备通信 - 串口通信用于与称重设备、条码扫描器等外设通信 - - 海康威视SDK用于相机图像采集和处理 + - 支持键盘监听用于扫码枪等输入设备 4. **设计模式**: - - 单例模式(配置加载器、监控器、相机管理器等) + - 单例模式(配置加载器、电力监控器、相机管理器等) - DAO模式(数据访问) - 观察者模式(信号槽) - 工厂模式(数据库连接) @@ -65,122 +67,158 @@ - `config/`:包含配置文件 - `logs/`:包含日志文件 - `camera/`:包含相机模块和SDK接口类 + - `apis/`:API接口(用于接口模式) 2. **核心文件**: - `main.py`:程序入口点 - - `widgets/login_widget.py`:登录窗口控制器 - - `widgets/main_window.py`:主窗口控制器 - - `widgets/camera_manager.py`:相机管理器 - - `widgets/camera_display_widget.py`:相机显示组件 - - `widgets/camera_settings_widget.py`:相机设置控制器 + - `modbus_server.py`:Modbus服务器模拟 - `utils/config_loader.py`:配置加载器 - - `utils/modbus_utils.py`:Modbus通信工具 - - `utils/sql_utils.py`:数据库工具 - - `camera/CamOperation_class.py`:相机操作类 - - `camera/MvCameraControl_class.py`:海康威视相机控制SDK - `utils/local_image_player.py`:本地图像序列播放器 + - `widgets/camera_manager.py`:相机管理器 + - `dao/login_dao.py`:用户认证数据访问 -3. **应用流程**: - - 程序启动后初始化日志系统和配置 - - 创建和初始化各子系统(数据库、电力监控器等) - - 显示登录窗口 - - 验证登录后显示主窗口 - - 主窗口中进行产线包装系统的操作,包括: - - 产品检测和包装 - - 实时相机监控 - - 数据采集和报表生成 - - 设备状态监控和控制 +## 系统特点与功能 -## 相机子系统详解 +1. **两种运行模式**: + - 单机模式(standalone):完整的独立系统 + - 接口模式(api):作为其他系统的接口组件运行 -1. **架构设计**: - - 采用分层设计,将相机SDK封装在底层,提供简洁API供上层使用 - - 相机管理采用单例模式,确保全局只有一个相机实例 - - 使用信号槽机制实现相机状态与UI的松耦合通信 - -2. **核心组件**: - - `CameraManager`:单例类,负责相机设备枚举、开关、参数设置等 - - `CameraDisplayWidget`:显示组件,负责在UI中显示相机画面 - - `CameraSettingsWidget`:设置控制器,负责参数调整界面交互 - - `CamOperation_class`:相机操作封装类,直接与海康SDK交互 - - `LocalImagePlayer`:本地图像序列播放器,提供基于本地图片序列的视频模拟功能 - -3. **工作流程**: - - 系统启动时初始化相机SDK - - 用户界面显示时枚举并连接可用的相机设备 - - 启动相机图像采集并在UI中显示 - - 用户可通过设置界面调整相机参数(曝光、增益、帧率等) - - 系统关闭时正确释放相机资源 - -4. **配置管理**: - - 相机参数保存在`config/app_config.json`的`camera`部分 - - 包括默认曝光时间、增益、帧率等参数 - - 用户调整的参数可保存至配置文件持久化 - -5. **本地图像模式**: - - 支持本地图像序列播放,可用于模拟相机实时画面 - - 用户可选择包含图像序列的文件夹,系统自动按时间顺序播放 - - 可调整播放帧率、设置循环播放等参数 +2. **本地图像模式**: + - 支持本地图像序列播放,模拟相机实时画面 - 适用于开发测试和演示场景,无需连接实际相机设备 - - 配置参数保存在`config/app_config.json`的`camera.local_mode`部分 + - 可调整播放帧率、设置循环播放等参数 -## 功能特点 +3. **相机管理**: + - 支持海康威视相机设备管理 + - 自动发现和枚举可用相机设备 + - 相机参数设置和保存(曝光、增益、帧率等) -1. **用户认证**:支持用户登录和权限控制 -2. **产线监控**:实时监控产线状态、电力消耗等 -3. **数据采集**:采集称重数据、检验数据等 -4. **相机集成**:支持实时图像采集、显示和参数调整 -5. **报表生成**:生成各类统计报表 -6. **设备通信**:与PLC、称重设备等通信 -7. **多模式支持**:支持单机模式和接口模式 +4. **Modbus通信**: + - 与PLC设备进行Modbus TCP通信 + - 支持自动模式和手动模式切换 + - 内置Modbus服务器模拟功能,便于开发测试 -## 运行环境 +5. **电力监控**: + - 实时监控和记录电力消耗数据 + - 数据可视化和统计分析 +6. **数据管理**: + - 支持用户认证和权限控制 + - 检验数据的采集、存储和分析 + - 托盘类型管理 + +7. **日志系统**: + - 详细的日志记录 + - 自动日志轮换 + - 支持多级日志级别 + +## 安装与运行 + +### 系统要求 - Python 3.7+ -- PySide6 -- 支持的数据库:SQLite、PostgreSQL、MySQL -- 操作系统:Windows、macOS、Linux +- 支持Windows、macOS、Linux操作系统 -## 安装与配置 +### 安装步骤 1. 安装依赖: ``` pip install -r requirements.txt ``` -2. 配置数据库: +2. 配置应用: + - 配置文件位于`config/app_config.json` - 默认使用SQLite数据库,位于`db/jtDB.db` - - 可在`config/app_config.json`中配置其他数据库 + - 可配置数据库连接、相机参数、Modbus设置等 -3. 配置相机: - - 在`config/app_config.json`中的`camera`部分调整相机参数 - - 默认参数: - ```json - "camera": { - "enabled": false, - "default_exposure": 20000, - "default_gain": 10, - "default_framerate": 30, - "local_mode": { - "enabled": false, - "folder_path": "", - "framerate": 15, - "loop": true, - "file_patterns": [".jpg", ".jpeg", ".png", ".bmp"] - } - } - ``` - -4. 运行程序: +3. 运行应用: ``` python main.py ``` +### 配置说明 + +1. **数据库配置**: + ```json + "database": { + "default": "sqlite", + "sources": { + "sqlite": { + "path": "db/jtDB.db", + "description": "默认SQLite数据库" + }, + "postgresql": { + "host": "localhost", + "port": "5432", + "user": "postgres", + "password": "", + "name": "jtDB" + } + } + } + ``` + +2. **本地图像模式配置**: + ```json + "local_image_mode": { + "enabled": true, + "folder_path": "/path/to/images", + "framerate": 15, + "loop": true + } + ``` + +3. **应用模式配置**: + ```json + "app": { + "mode": "standalone", // 或 "api" + "features": { + "enable_serial_ports": false, + "enable_keyboard_listener": false, + "enable_camera": false + } + } + ``` + ## 开发与扩展 系统采用模块化设计,可以方便地进行功能扩展: -1. 添加新的数据源:扩展`utils/sql_utils.py` -2. 添加新的设备通信协议:参考`utils/modbus_utils.py` -3. 添加新的UI界面:在`ui/`目录下创建新的UI类,在`widgets/`目录下创建对应的控制器类 -4. 扩展相机功能:修改`widgets/camera_manager.py`和`camera/CamOperation_class.py` \ No newline at end of file +1. **添加新的数据源**:扩展DAO层,实现对应的数据访问对象 + +2. **添加新的硬件支持**: + - 参考`widgets/camera_manager.py`添加新的硬件管理器 + - 参考`utils/local_image_player.py`添加新的设备模拟器 + +3. **扩展UI界面**: + - 在`ui/`目录下创建新的UI类 + - 在`widgets/`目录下创建对应的控制器类 + +4. **添加新的通信协议**:参考`modbus_server.py`实现新的通信接口 + +## 注意事项 + +1. 首次运行时,系统将自动创建默认配置和数据库 + +2. 日志文件位于`logs/`目录,按日期自动轮换 + +3. 如果使用相机功能,需确保已安装海康威视SDK + +4. 在测试环境中,可使用本地图像模式替代实际相机 + +## 故障排除 + +1. **日志查看**: + - 检查`logs/`目录下的日志文件 + - 日志格式为`app_YYYY-MM-DD.log` + +2. **数据库问题**: + - 确认数据库配置正确 + - 查看数据库连接错误日志 + +3. **相机连接问题**: + - 确认相机驱动已正确安装 + - 尝试启用本地图像模式进行测试 + +4. **Modbus通信问题**: + - 检查PLC设备IP和端口配置 + - 使用`modbus_server.py`进行通信测试 \ No newline at end of file diff --git a/config/app_config.json b/config/app_config.json index 2ab4087..ab3bf0a 100644 --- a/config/app_config.json +++ b/config/app_config.json @@ -115,6 +115,6 @@ } }, "electricity": { - "auto_start": true + "auto_start": false } } \ No newline at end of file diff --git a/widgets/main_window.py b/widgets/main_window.py index 3175e2b..dd5ebae 100644 --- a/widgets/main_window.py +++ b/widgets/main_window.py @@ -2744,6 +2744,75 @@ class MainWindow(MainWindowUI): # 更新UI显示,实时回显最新测量值 self.statusBar().showMessage(f"线径数据: {xj_value:.3f}", 2000) + # 实时更新到微丝产线表格中 + try: + # 查找线径对应的检验项配置 + xj_config = None + xj_column = None + enabled_configs = self.inspection_manager.get_enabled_configs() + + # 查找线径配置和对应的列索引 + for i, config in enumerate(enabled_configs): + if config.get('name') == 'xj' or config.get('display_name') == '线径': + xj_config = config + xj_column = 2 + i # 检验列从第3列开始 + break + + if xj_config and xj_column is not None: + # 找到当前选中的行或第一个有效行 + current_row = self.process_table.currentRow() + target_row = None + + # 如果当前选中了有效行,优先使用 + if current_row >= 2: + order_id_item = self.process_table.item(current_row, 1) + if order_id_item and order_id_item.text().strip(): + target_row = current_row + + # 如果没有选中行,查找第一个有效行 + if target_row is None: + for row in range(2, self.process_table.rowCount()): + order_id_item = self.process_table.item(row, 1) + if order_id_item and order_id_item.text().strip(): + target_row = row + break + + # 如果找到了有效行,更新线径值 + if target_row is not None: + # 暂时断开信号连接,避免触发cellChanged信号 + try: + self.process_table.cellChanged.disconnect(self.handle_inspection_cell_changed) + except: + pass + + # 创建显示项目并设置颜色 + formatted_value = f"{xj_value:.3f}" + item = QTableWidgetItem(formatted_value) + item.setTextAlignment(Qt.AlignCenter) + + # 设置单元格数据,包括配置ID + item.setData(Qt.UserRole, xj_config.get('id')) + + # 如果当前值不为0,设置为临时值颜色(灰色) + if xj_value > 0: + item.setForeground(QBrush(QColor("#666666"))) + item.setToolTip("临时测量值,产品取走后将保存最终值") + + # 更新表格单元格 + self.process_table.setItem(target_row, xj_column, item) + + # 高亮显示更新的单元格 + self.process_table.setCurrentCell(target_row, xj_column) + + # 重新连接单元格变更信号 + self.process_table.cellChanged.connect(self.handle_inspection_cell_changed) + + logging.info(f"已将线径值 {xj_value:.3f} 实时更新到表格 [行 {target_row}, 列 {xj_column}]") + else: + logging.warning("未找到线径对应的检验项配置或列索引") + except Exception as e: + logging.error(f"更新线径值到表格失败: {str(e)}") + # 如果当前值不为0,记录为最后一次有效值 if xj_value > 0: self._last_diameter_value = xj_value