# 气体流量闭环控制系统 基于 **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 ms,10 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/ # 运行日志 ```