Files
dtm-py-all/架构设计文档.md

568 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数字孪生跌落机监控系统 (DTMGT) - 架构设计文档
## 1. 系统概述
本系统是一个工业自动化跌落试验管理系统实现了PC上位机与PLC控制器之间的实时通信、数据采集、本地存储和远程上传功能。
---
## 2. 系统架构分层
### 2.1 三层架构设计
```
┌─────────────────────────────────────────────────────────────┐
│ 前端展示层 (Web UI) │
│ 技术栈: HTML + JavaScript + Eel.js / Socket.io │
│ 功能: 设备监控、参数配置、测试管理、数据展示 │
└─────────────────────────────────────────────────────────────┘
↕ WebSocket / HTTP
┌─────────────────────────────────────────────────────────────┐
│ 应用服务层 (Python Backend) │
│ 核心服务: │
│ ├─ Flask HTTP Server (api_route.py) - REST API服务 │
│ ├─ WebSocket Server - 实时数据推送 │
│ ├─ DtmMachineService - 核心业务逻辑 │
│ ├─ LMISUploadSystem - LMIS数据上传服务 │
│ └─ SQLite数据库访问层 │
└─────────────────────────────────────────────────────────────┘
↕ Modbus TCP
┌─────────────────────────────────────────────────────────────┐
│ 通信网关层 (Gateway Process) │
│ 独立进程: ModbusServer (modbus_server.py) │
│ 功能: │
│ ├─ Modbus TCP Server (对上位机提供服务) │
│ └─ Modbus RTU Client (与PLC串口通信) │
└─────────────────────────────────────────────────────────────┘
↕ RS-485/RS-232
┌─────────────────────────────────────────────────────────────┐
│ 设备控制层 (PLC) │
│ 支持协议: │
│ ├─ 三菱MHI协议 (mhi_plc.py) │
│ └─ 信捷Modbus协议 (modbus_plc.py) │
└─────────────────────────────────────────────────────────────┘
```
---
## 3. 核心模块详解
### 3.1 主程序入口 (dtmgtApp.py)
**职责**:
- 系统初始化与多线程管理
- 启动各服务组件 (Flask, WebSocket, Modbus Server)
- 进程生命周期管理
**关键组件**:
```python
├─ Flask HTTP Server (端口5050) - REST API接口
├─ WebSocket Server (端口5080) - 实时数据推送
├─ Modbus Server (独立进程, 端口5020) - PLC网关
├─ LMIS上传服务 (线程池) - 异步上传测试结果
└─ 本地数据存储线程 - SQLite批量写入
```
---
### 3.2 业务服务层 (dtMachineService.py)
**核心类**: `DtmMachineService`
**主要功能**:
1. **设备管理**: 管理多台跌落机及其工位状态
2. **数据轮询**: 每个设备独立线程轮询PLC数据 (0.6秒间隔)
3. **状态同步**: PLC状态与工位状态双向同步
4. **测试结果处理**: 解析PLC测试结果并触发存储/上传
**关键方法**:
```python
- machine_poll() # PLC数据轮询主循环
- handle_status_sync_with_plc() # PLC状态同步到工位
- machine_poll_test_result_bulk() # 批量读取测试结果
- handle_test_result_registers_value() # 解析测试结果
- dtStationAttachDut() # 工位绑定测试样品
```
**设计模式**: 观察者模式 (ObservableDict监听数据变化)
---
### 3.3 通信网关层 (modbus_server.py)
**架构特点**: 独立进程部署,支持跨机器扩展
**核心类**: `ModbusServer` (继承自`multiprocessing.Process`)
**工作流程**:
```
1. 主服务启动 → 创建ModbusServer进程
2. ModbusServer初始化:
├─ 根据机台配置创建PLC设备实例 (MitsubishiPLC/ModbusPLC)
├─ 为每个机台创建CustomDataBlock
└─ 启动Modbus TCP Server (异步事件循环)
3. 主服务 → Modbus TCP Client连接 → Modbus Server
4. CustomDataBlock拦截读写请求 → 转发到物理PLC
```
**CustomDataBlock设计**:
- 重写`getValues()` - 读取时触发PLC通信
- 重写`setValues()` - 写入时触发PLC通信
- 线程锁保护串口访问 (`plc_comm_lock`)
---
### 3.4 PLC通信抽象层
#### 3.4.1 三菱MHI协议 (mhi_plc.py)
**协议特点**: ASCII帧格式 + 自定义校验和
**核心方法**:
```python
- plc_read_frame() # 构建读请求帧
- plc_write_frame() # 构建写请求帧
- frame_is_valid() # 校验响应帧
- plc_read_words() # 读寄存器
- plc_write_words() # 写寄存器
```
#### 3.4.2 信捷Modbus协议 (modbus_plc.py)
**特点**:
- 使用pymodbus库标准Modbus RTU协议
- 后台线程轮询PLC连接状态 (500ms间隔)
- 连接状态缓存机制 (`_connect_state_cache`)
**优化设计**:
```python
def _poll_connect_state():
"""后台线程定期更新连接状态缓存"""
while not self._stop_event.is_set():
# 读取D10寄存器的5个值 [连接状态, 工位1, 工位2, 工位3, 工位4]
result = self.read_holding_registers(10, 5, slave)
if success:
self._connect_state_cache = result['data']
```
---
### 3.5 Modbus虚拟设备层 (dtMachine_modbus.py)
**核心类**: `ModbusDtMachine`
**职责**: 封装Modbus TCP Client屏蔽底层通信细节
**寄存器映射**:
```python
# 三菱PLC地址转换
'D0160' Modbus地址: 160
'M0016' Modbus Coil地址: 16
# 信捷PLC地址转换
'HD0160' Modbus地址: 41088 + 160
```
**关键功能**:
```python
- set_station_dropheight() # 设置跌落高度
- set_station_cycles() # 设置跌落次数
- set_station_dutInfo() # 传输样品信息(最多4个)
- read_station_dutInfo() # 读取样品信息
- read_station_result_counter() # 读取结果计数器
- read_station_cyclesFinishedBulk() # 批量读取测试结果
```
---
### 3.6 数据存储与上传
#### 3.6.1 本地SQLite存储
**线程设计**:
```python
# 主线程
result_to_localDB_queue.put(test_result) # 非阻塞入队
# 专用写入线程 (run_insert_result)
while True:
records = []
while not queue.empty():
records.append(queue.get())
if records:
dtMachineService.insertTableRecords('TestReq', records) # 批量写入
time.sleep(2) # 2秒间隔
```
#### 3.6.2 LMIS远程上传
**架构**: 线程池 + 重试队列
**核心类**: `LMISUploadSystem`
**特性**:
- 20线程并发上传
- 失败自动重试 (最多5次, 间隔60秒)
- 优先级队列管理重试任务
- HTTP连接池复用 (`requests.Session`)
**工作流程**:
```
1. cb_insert_result() 触发
2. 数据进入上传系统 → executor.submit()
3. 成功 → 结束
4. 失败 → 放入retry_queue (优先级队列)
5. 后台监控线程检测到达重试时间 → 重新提交
```
---
## 4. 数据流图
### 4.1 测试结果采集流程
```
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ PLC │────>│ Modbus Server│────>│dtMachineService│
│ (跌落机) │ │ (网关进程) │ │ (轮询线程) │
└──────────┘ └──────────────┘ └──────┬───────┘
┌─────────────────────┴─────────────────┐
│ handle_test_result_registers_value() │
│ 解析寄存器 → PLCTestReqResultData │
└─────────────────┬─────────────────────┘
┌─────────────────┴─────────────────┐
│ cb_insert_result() 回调 │
└─────┬───────────────────┬─────────┘
│ │
┌─────────↓──────┐ ┌───────↓─────────┐
│ SQLite队列入库 │ │ LMIS上传队列 │
│ (2秒批量写) │ │ (线程池异步) │
└────────────────┘ └─────────────────┘
```
### 4.2 前端实时数据推送
```
┌──────────────┐ ┌──────────────┐ ┌──────────┐
│machine_poll()│────>│cb_machine_data│────>│WebSocket │
│ (PLC轮询) │ │ _change() │ │消息队列 │
└──────────────┘ └──────────────┘ └────┬─────┘
┌──────↓──────┐
│ws_dispatcher│
│ (消息合并) │
└──────┬──────┘
┌──────↓──────┐
│ Web前端 │
│ (实时刷新) │
└─────────────┘
```
---
## 5. 关键设计决策
### 5.1 网关独立进程设计
**优点**:
- 支持跨机器部署
- 隔离PLC通信故障
- 便于横向扩展
**缺点**:
- 进程间通信开销
- 调试复杂度增加
### 5.2 轮询 vs 事件驱动
**当前采用**: 定时轮询 (0.6秒)
**原因**:
- PLC不支持主动推送
- 简化并发控制
- 满足实时性要求
### 5.3 双缓冲结果读取
**设计**: PLC维护A/B两块结果缓冲区
**优势**:
- 避免读写冲突
- 提高数据一致性
**实现**: 通过`result_index_read`切换 (0~9循环)
---
## 6. 并发控制策略
### 6.1 线程锁使用
| 位置 | 锁类型 | 保护资源 |
|------|--------|---------|
| modbus_plc.py | threading.Lock | 串口读写操作 |
| modbus_server.py | threading.Lock | PLC通信访问 |
| dtMachineService.py | busy_flag | 机器操作互斥 |
### 6.2 队列通信
| 队列 | 生产者 | 消费者 | 用途 |
|------|--------|--------|------|
| result_to_localDB_queue | cb_insert_result | run_insert_result | 本地存储 |
| ws_message_send_queue | 数据回调 | ws_dispatcher | WebSocket推送 |
| LMISUploadSystem.retry_queue | 上传失败 | 重试监控线程 | 延迟重试 |
---
## 7. 配置管理
### 7.1 PLC通信配置
**存储位置**: SQLite `dtMachine`
**关键字段**:
```python
{
'SN': '设备序列号',
'com': 'com2', # 串口号
'plcAddress': '01', # PLC站地址
'type': 'xinjie', # PLC类型
'baudrate': {...}, # 波特率配置
'register01': {...}, # 工位1寄存器配置
'register02': {...}, # 工位2寄存器配置
# ...
}
```
### 7.2 寄存器映射示例
```python
drop_register = {
'01': {
"height": "D0160", # 跌落高度
"cycles": "D0200", # 设定次数
"cyclesFinished": "D0202", # 完成次数
"start": "M0016", # 启动位
"stop": "M0008", # 停止位
"runStatus": "M0010", # 运行状态
"stationResultCounter": "D0300", # 结果计数器
"dutBasic": "D0400" # 样品信息起始地址
}
}
```
---
## 8. 异常处理机制
### 8.1 PLC通信异常
**策略**: 捕获异常 + 连接状态缓存
```python
# modbus_plc.py
try:
result = self.client.read_holding_registers(...)
if result.isError():
return {"status": "error"}
except ModbusException:
if self.reconnect(): # 尝试重连
return self.read_holding_registers(...) # 重试
```
### 8.2 数据上传异常
**策略**: 最多重试5次, 每次间隔60秒
```python
# LMISUploadSystem
retry_count = 0
while retry_count < 5:
try:
response = requests.post(url, ...)
if success:
break
except Exception:
retry_count += 1
time.sleep(60)
```
---
## 9. 性能优化点
1. **批量数据库写入** - 2秒间隔批量提交
2. **连接状态缓存** - 避免频繁读取PLC
3. **HTTP连接池** - requests.Session复用TCP连接
4. **WebSocket消息合并** - 相同设备的多次更新合并为一次
5. **线程池上传** - 20并发上传LMIS
---
## 10. 扩展性设计
### 10.1 多PLC协议支持
**抽象接口**:
```python
# 统一的PLC接口
class PLCInterface:
def plc_read_words(plc_no, address, length)
def plc_write_words(plc_no, address, length, data)
def plc_read_bits(plc_no, address, length)
def plc_write_bit(plc_no, address, data)
```
**实现**:
- `MitsubishiPLC` - 三菱MHI协议
- `ModbusPLC` - 标准Modbus RTU协议
### 10.2 多设备并发
**设计**: 每台设备独立线程轮询
```python
for machine in machines:
thread = threading.Thread(target=machine_poll, args=[machine])
thread.start()
```
---
## 11. 数据模型
### 11.1 核心数据结构
#### 测试样品 (DUT)
```python
{
'SN': '样品序列号',
'name': '样品名称',
'project': '项目代码',
'phase': '项目阶段',
'weeks': '测试周次',
'workOrder': '工单号',
'testReqList': [...] # 测试项列表
}
```
#### 测试结果 (TestReqResult)
```python
{
'SN': '样品SN',
'machine_sn': '设备SN',
'station_no': '工位号',
'dropDirection': '跌落方向',
'dropHeight_int': '跌落高度(mm)',
'dropSpeed': '跌落速度',
'dutDropCycles': '样品累计次数',
'itemCurrentCycles': '方向累计次数',
'stationDropCycles': '工位累计次数',
'startTime': '开始时间',
'endTime': '结束时间'
}
```
### 11.2 状态机
**工位状态流转**:
```
idle → dutAttached → running → pause → running → finished → idle
↓ ↑ ↓
(绑定样品) (恢复试验) (暂停)
```
**PLC-工位状态映射**:
```python
TRANSITION_TABLE = {
(0, 'idle'): ('none', None, False), # 一致
(0, 'running'): ('detach', 'stop_by_plc', False), # PLC停止
(1, 'idle'): ('attach_dut', 'resync_with_plc_run', True), # 重新同步
(1, 'running'): ('none', None, False), # 一致
(1, 'pause'): ('attach', 'resume_by_plc', False), # PLC恢复
(2, 'pause'): ('none', None, False), # 一致
(3, 'running'): ('finish', None, False), # 试验完成
}
```
---
## 12. 技术栈总结
| 层级 | 技术 | 用途 |
|------|------|------|
| 前端 | HTML + JavaScript + Eel.js | 桌面化Web界面 |
| 通信 | WebSocket + Socket.io | 实时数据推送 |
| 后端 | Flask + Flask-CORS | REST API服务 |
| 数据库 | SQLite | 本地数据存储 |
| 工业通信 | pymodbus + pyserial | Modbus协议 |
| 并发 | threading + multiprocessing | 多线程/多进程 |
| 异步 | asyncio + gevent | 异步IO |
| HTTP | requests (Session) | HTTP客户端 |
---
## 13. 部署架构
### 13.1 单机部署
```
┌────────────────────────────────────────┐
│ Windows PC (上位机) │
│ ┌────────────────────────────────┐ │
│ │ dtmgtApp.py (主进程) │ │
│ │ ├─ Flask (5050) │ │
│ │ ├─ WebSocket (5080) │ │
│ │ └─ Eel WebView │ │
│ └────────┬───────────────────────┘ │
│ │ │
│ ┌────────↓───────────────────────┐ │
│ │ ModbusServer (子进程) │ │
│ │ └─ Modbus TCP (5020) │ │
│ └────────┬───────────────────────┘ │
│ │ │
│ ┌────↓────┐ │
│ │ COM口 │ │
└──────┴─────────┴──────────────────────┘
RS-485/RS-232
┌────↓────┐
│ PLC │
└─────────┘
```
### 13.2 分布式部署 (未来扩展)
```
┌────────────┐ ┌────────────┐
│ 上位机1 │ │ 上位机2 │
│ dtmgtApp │ │ dtmgtApp │
└─────┬──────┘ └─────┬──────┘
│ │
└─────────────┬───────────────────┘
│ HTTP/WebSocket
┌─────↓──────┐
│ 中心服务器 │
│ (统一管理) │
└─────┬──────┘
┌───────────┼───────────┐
│ │ │
┌────↓────┐ ┌───↓────┐ ┌───↓────┐
│Gateway1 │ │Gateway2│ │Gateway3│
└────┬────┘ └───┬────┘ └───┬────┘
│ │ │
PLC1 PLC2 PLC3
```
---
**文档版本**: v1.0
**最后更新**: 2025-11-19
**维护者**: 系统架构团队