1.原先程序启动后会先下发关闭位置,再开始闭环,现在启动后直接从当前阀门开度(默认全开)开始闭环。删除了safe_close相关的代码

2.新增open_loop.py进行开环控制,记录控流阀前后流量和压力数据,方便后面辨识拟合,以及观察动态特性。
3.新增README.md
This commit is contained in:
2026-08-19 17:23:02 +08:00
parent 90648f3d35
commit 0d85dd3c2c
6 changed files with 785 additions and 60 deletions
+119
View File
@@ -0,0 +1,119 @@
# 气体流量闭环控制系统
基于 **MT2-AM8 模拟量采集/输出模块** 的单回路气体流量 PID 闭环控制程序。
程序以 10 Hz 周期读取流量(可选读取压力),经增量式 PID 计算阀门开度,
映射为电机行程后通过 Modbus TCP 下发给执行机构,并在每次运行结束后自动
保存逐周期数据、生成三联曲线图与一次性的控制性能报告。
## 硬件与通讯
- 采集/输出模块:艾莫迅 **MT2-AM8**Modbus TCP,默认 `192.168.1.12:502`,站号 1
- 模拟量输入(AI):地址 `0x00~0x03`0~4095 对应 0~10V / 0~20mA
- 模拟量输出(AO):保持寄存器 `0x00~0x03`
- 流量计量程默认 300 SLM,压力表量程默认 400 kPa
- 电机行程与开度**反向作用**:行程越大开度越小,
`opening=0% → MOTOR_CLOSED_POSITION``opening=100% → MOTOR_OPEN_POSITION`
> 所有地址、通道、量程、行程端值均在 [config.py](config.py) 中集中配置,
> 首次连接真实设备前必须核对。
## 架构与模块职责
| 文件 | 职责 |
| --- | --- |
| [main.py](main.py) | 程序入口:解析参数、装配日志/控制器/记录器/报告器、主循环与安全退出 |
| [flow_control.py](flow_control.py) | 闭环控制层:`读取传感器 → PID → 开度/行程映射 → 下发电机位置`,含全部安全处理 |
| [controllers.py](controllers.py) | 通用增量式 PID 控制器 `IncrementalPID`(输出限幅 + 输出变化率限幅) |
| [config.py](config.py) | 集中配置与 `validate_config()` 启动前校验 |
| [data_logger.py](data_logger.py) | `FlowRunRecorder`:逐周期写 CSV,运行结束生成三联曲线图 |
| [performance_reporter.py](performance_reporter.py) | `PerformanceReporter`:滑窗稳态判定,输出一次性性能报告 |
| [PcControl.py](PcControl.py) | 硬件层:`MT2AM8Client` 等 Modbus 客户端(本项目实际使用 `MT2AM8Client` |
### 控制回路流程
```
读取流量/压力 (MT2-AM8)
IncrementalPID.update() ──► 开度百分比 0~100%
opening_to_motor_position() ──► 反向行程 0~1000
hardware.set_motor_position() ──► Modbus TCP 写 AO
```
`error = setpoint - measurement`;PID 输出累加后统一映射为阀门开度百分比,
再做行程换算,因此 PID 与执行机构解耦。
## 快速开始
```bash
python main.py --target 50
```
- `--target`:目标流量(SLM),必须在 `[TARGET_FLOW_MIN_SLM, TARGET_FLOW_MAX_SLM]` 内。
- 启动流程:连接 MT2-AM8 → 确认阀门关闭 → 读取初始流量 → 启动闭环。
- 停止:`Ctrl+C`;控制故障、未处理异常同样会触发安全关阀并断开设备。
## 运行输出
1. **终端/日志**:周期状态行(状态、目标/实际流量、压力、开度、行程、实际 dt),
日志同时写入 [logs/flow_control.log](logs/flow_control.log)。
2. **逐周期数据**:每次运行生成 `data/flow_run_<时间戳>.csv`
3. **曲线图**:与 CSV 同名的 PNG 三联图(流量响应 / 阀门开度 / 压力)。
4. **性能报告**:首次达到稳态时打印一次,包含:
- 本次 PID 参数(Kp / Ki / Kd
- 调节时间(至稳态,秒)
- 超调量(绝对 SLM + 相对目标百分比)
- 本次控制范围
稳态判定为两个条件**同时**满足:滑窗均值落在目标 ±`STEADY_STATE_BAND_PCT`% 误差带内,
且滑窗标准差低于 `STEADY_STATE_STD_PCT`% 目标流量阈值。
## 安全机制
- **启动前安全关阀**:控制开始前先确认阀门已关闭。
- **流量/压力越限关阀**:读数超出 `FLOW_VALID_*` 或超过 `MAX_PRESSURE_KPA` 立即关阀。
- **连续读取失败关阀**:短暂读取失败保持上一输出;连续达到阈值后关阀。
- **控制循环超时保护**:实际周期超过 `MAX_CONTROL_DT_S` 判定超时。
- **输出变化率限幅**`MAX_OPENING_RATE_PCT_S` 限制开度变化速度,防止阀门阶跃冲击。
- **退出安全关阀**:任何退出路径(含异常)都会再次尝试关阀并断开设备。
## 关键配置项
见 [config.py](config.py),常用项:
| 配置 | 默认值 | 说明 |
| --- | --- | --- |
| `MT2AM8_HOST` / `MT2AM8_PORT` / `MT2AM8_SLAVE_ID` | `192.168.1.12` / `502` / `1` | 模块地址 |
| `FLOW_INPUT_CHANNEL` / `PRESSURE_INPUT_CHANNEL` / `MOTOR_OUTPUT_CHANNEL` | `1` / `0` / `0` | AI/AO 通道(0 起始) |
| `FLOW_METER_RANGE_SLM` / `PRESSURE_RANGE_KPA` | `300` / `400` | 量程 |
| `CONTROL_PERIOD_S` | `0.1` | 控制周期(100 ms10 Hz |
| `PID_KP` / `PID_KI` / `PID_KD` | `0.5` / `0.1` / `0.0` | 安全起步 PI 参数,需现场整定 |
| `MOTOR_CLOSED_POSITION` / `MOTOR_OPEN_POSITION` | `1000` / `0` | 行程端值 |
| `MAX_PRESSURE_KPA` | `400` | 压力上限,须按管路额定压力确认 |
| `STEADY_STATE_WINDOW_S` / `STEADY_STATE_BAND_PCT` / `STEADY_STATE_STD_PCT` | `2.0` / `2.0` / `2.0` | 稳态判定参数 |
## 依赖
- Python 3
- [pymodbus](https://pymodbus.readthedocs.io/)`PcControl.py` 的 Modbus TCP 通讯)
- [matplotlib](https://matplotlib.org/)(曲线图生成,使用 `Agg` 后端,无显示器环境也可保存)
## 项目结构
```
flow_control/
├── main.py # 程序入口
├── flow_control.py # 闭环控制层
├── controllers.py # 增量式 PID
├── config.py # 集中配置与校验
├── data_logger.py # CSV 记录 + 曲线图
├── performance_reporter.py # 稳态判定 + 性能报告
├── PcControl.py # Modbus 硬件客户端
├── data/ # 每次运行的 CSV / PNG
└── logs/ # 运行日志
```