Files
2026-07-31 14:19:48 +08:00

175 lines
13 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.
# ReinLoop 功能与接口
本文档描述 `ReinLoop/` Python 客户端当前提供的运行时功能与接口。
## 约定
- 业务服务端地址由 `REINLOOP_API_URL` 指定,未设置时使用
`REINLOOP_SERVER_URL`;默认地址为
`https://ReinLoop.dominatedconvergence.com`
- 新许可证的设备标识为 `<company_code>/<production_line_code>`,在代码中通过
`api.the_folder` 使用。旧许可证才回退到 `REINLOOP_DEVICE_ID`
- 所有服务端业务请求均使用 `POST /`,通过请求体的 `type` 字段分发。
- 公司、产线、许可证签发/撤销、模型删除、审核反馈及配置提交均为
ControlPanel 管理端能力,客户端不提供对应的管理接口。旧微信云函数和其管理脚本
已移除。
## 应用与设备连接
| 功能 | 接口 | 返回或行为 |
| --- | --- | --- |
| 启动桌面程序 | `main.main()` | 初始化 PySide6 主窗口、全局日志及异常处理。 |
| 连接 MT2-AM8 | `ConnectionManager.connect(tcp_ip, tcp_port, pressure_addr, motor_addr, flowmeter_addr, pressure_range=400, flow_range=100)` | 返回 `bool`。建立 Modbus TCP 连接并保存模拟量通道配置。 |
| 断开设备 | `ConnectionManager.disconnect()` | 关闭连接并通知状态回调。 |
| 查询连接状态 | `ConnectionManager.is_connected()` | 返回 `bool`。 |
| 读取压力 | `ConnectionManager.read_pressure()` | 返回压力值 `kPa`,失败时为 `None`。 |
| 读取流量 | `ConnectionManager.read_flow()` | 返回流量 `L/min`;未配置流量计或失败时为 `None`。 |
| 设置电机位置 | `ConnectionManager.set_motor_position(xa)` | 将目标行程写入模拟量输出,返回 `bool`。 |
| 日志和连接回调 | `set_log_callback(callback)``set_status_callback(callback)` | 回调签名分别为 `callback(message)``callback(connected, status_text)`。 |
主运行路径使用 `ConnectionManager`。底层调试或独立脚本还可使用
`PcControl.py` 中的 `MT2AM8Client``Easy521ModbusClient`
`MotorModbusRTUClient``PressureModbusRTUClient`
## 压力控制
| 功能 | 接口 | 返回或行为 |
| --- | --- | --- |
| 创建控制器 | `ControlEngine(pid)` | `pid``IncrementalPID` 实例。 |
| 注入依赖 | `set_connection_manager(mgr)``set_model_manager(mgr)``set_data_collector(collector)` | 配置设备、RL 模型和数据采集服务。 |
| 启动控制 | `ControlEngine.start()` | 要求设备已连接;RL 模式还要求模型已加载。 |
| 执行一个周期 | `ControlEngine.control_tick()` | 读取压力、执行 PID/RL/手动控制、写入电机并更新显示。由 GUI 的 QTimer 调用。 |
| 停止控制 | `ControlEngine.stop()` | 停止循环,并触发 `DataCollector.finalize_and_upload()`。 |
| 查询运行状态 | `ControlEngine.is_running` | 只读属性,返回 `bool`。 |
| 切换模式 | `engine.mode = "PID" / "RL" / "MANUAL"` | PID 闭环、RL 调参增强闭环或直接设置阀门开度。 |
| 更新 PID 参数 | `IncrementalPID.update_parameters(kp, ki, kd)` | 重算增量 PID 系数。 |
| 执行 PID 单步 | `IncrementalPID.update_pressure_values(current, target)``update(du_max=None)` | `update()` 返回受限后的阀门开度百分比。 |
| 重置 PID 状态 | `IncrementalPID.reset()` | 清除误差历史与输出状态。 |
| 设置单步限幅 | `IncrementalPID.set_du_max(value)` | 设置 PID 输出增量上限。 |
`ControlEngine` 的常用配置字段包括 `target_pressure``flow``volume`
`manual_valve``collect_data``dz``motor_max``xa_full`
`pressure_alpha`
## RL 模型管理
| 功能 | 接口 | 服务端请求 |
| --- | --- | --- |
| 刷新模型列表 | `ModelManager.scan_models()` | `listModels`,目录为 `<deviceId>/model_config`。异步执行。 |
| 加载 SAC 模型 | `ModelManager.load_model(model_name)` | `downloadModel` 获取临时 URL,再下载并以 `SAC.load()` 加载。 |
| 检查模型状态 | `ModelManager.is_model_loaded()` | 返回 `bool`。 |
| 回调注册 | `set_models_loaded_callback(callback)``set_load_complete_callback(callback)` | 回调签名分别为 `callback(file_names)``callback(success, message)`。 |
RL 模式下,`ControlEngine` 使用模型根据流量、当前压力和压力误差预测 `Kp/Ki`,随后继续使用 PID 计算阀门开度。
## 控制过程数据采集与上传
| 功能 | 接口 | 返回或行为 |
| --- | --- | --- |
| 初始化一轮采集 | `DataCollector.reset()` | 清空 Episode 缓存。 |
| 记录控制点 | `DataCollector.record_step(cycle_count, current_pressure, target_pressure, valve_opening, kp, ki, kd, q_in, v)` | 目标压力变化时自动切分 Episode。 |
| 停止后异步上传 | `DataCollector.finalize_and_upload(flow, vol)` | 分片上传 Pickle 数据和 manifest 到 `<deviceId>/data_record/data_<flow>SLM_<volume>L`。清单含 `data_type: "control_episode"``run_id`、分片元数据和总 Episode 数。 |
| 申请上传地址并上传 | `DataCollector._upload_to_server(data_bytes, filename, folder)` | 内部接口;先向 ReinLoop 云服务器申请一次性上传地址,再以 multipart 上传文件。 |
| 上传结果通知 | `DataCollector.set_upload_complete_callback(callback)` | 注册 `callback(success, manifest, error)`;在后台上传线程完成时调用。 |
上传地址通过服务端 `uploadDataFile` 获取。单个 Episode 数据文件超过约 5 MB 时会自动拆分。
### 控制数据服务端约定
控制数据上传目录固定以 `<deviceId>/data_record/` 为前缀;每次停止控制会上传
若干 `.pkl` 分片和一个同名时间戳的 `_manifest.json`。服务端在接收二步上传的文件后,
应保留文件元数据,并向管理端提供以下仅管理员可调用的接口:
| `type` | 请求字段 | 成功响应 | 服务端行为 |
| --- | --- | --- | --- |
| `listControlFiles` | `deviceId`、可选 `page``pageSize` | `files``total``page``pageSize` | 仅返回 `folder``<deviceId>/data_record/` 开头的记录;每条至少有 `fileID``fileName``folder``uploadTime``size`。 |
| `getControlFileDownload` | `fileID` | `fileID``fileName``url` | 仅允许下载控制数据目录内的文件,并返回短期签名下载 URL。 |
| `deleteControlFile` | `fileID` | `deletedCount` | 仅允许删除控制数据目录内的文件;同时删除文件本体及对应元数据。 |
上述三个接口必须校验管理端令牌,并根据 `fileID` 对应记录的目录验证设备边界,不能仅信任
调用方传入的设备标识。Panel 可直接展示 JSON manifest`.pkl` 为 Python pickle 二进制,
应仅供下载,不应在管理端进程中反序列化。
## 系统辨识
| 功能 | 接口 | 返回或行为 |
| --- | --- | --- |
| 下载辨识配置 | `download_identification_config(timeout=20)` | 下载并返回已校验的九参数配置字典。 |
| 校验配置对象 | `validate_identification_config(config)` | 规范化后返回字典,非法参数抛出 `ValueError`。 |
| 解析配置 CSV | `parse_identification_config_csv(csv_text)` | 解析 `parameter,value` 两列 CSV 并完成校验。 |
| 启动辨识 | `IdentificationManager.start_identification(conn_mgr=..., running_flag_check=..., q_in_val=..., dt=..., n_order=..., t_c=..., levels=..., dead_area=..., xa_full=..., V_val=..., repeat=2)` | 返回 `bool`;后台依次执行行程预扫描、PRBS 采集并上传 CSV。 |
| 停止辨识 | `IdentificationManager.stop()` | 请求正在运行的辨识/容积任务停止。 |
| 查询任务状态 | `IdentificationManager.is_running` | 返回 `bool`。 |
| 生成 PRBS | `generate_prbs(n_order=7, low_val=40, high_val=60, samples_per_bit=20, levels=None)` | 返回 NumPy 激励序列。 |
| 生成复合激励 | `generate_composite_sequence(dt, n_order, t_c, levels)` | 返回闭阀、全开和多电平 PRBS 组合序列。 |
| 执行 PRBS 采集 | `collect_data_with_prbs(conn_mgr, q_in_val, dt=0.05, n_order=7, t_c=1.0, levels=None, dead_area=240, xa_full=1062.5, V_val=None, should_stop=None, log=print, on_sample=None, repeat=2)` | 返回含 `t``u``p``csv_data``filename``samples``success` 的字典。 |
辨识流程会先按 `1000``0` 的行程档位扫描稳定压力,将结果上传到
`<deviceId>/ind_data`;随后上传 PRBS CSV 到同一目录。
### 辨识审核反馈
| 功能 | 接口 | 服务端请求 | 返回 |
| --- | --- | --- | --- |
| 登记结果 | `register_identification_result(run_id, timeout=10)` | `registerIdentificationResult` | 成功时返回 `None`。 |
| 查询审核 | `get_identification_feedback(run_id, timeout=10)` | `getIdentificationFeedback` | 未就绪返回 `None`;就绪返回 `0``1`。 |
| 确认清理 | `acknowledge_identification_feedback(run_id, timeout=10)` | `ackIdentificationFeedback` | 成功时返回 `None`。 |
## 容积测量
| 功能 | 接口 | 返回或行为 |
| --- | --- | --- |
| 读取本地配置 | `load_volume_config(path=None)` | 读取 JSON 并返回八参数配置。 |
| 校验配置 | `validate_volume_config(config)` | 返回规范化配置;错误时抛出 `ValueError`。 |
| 执行单次测量 | `measure_volume(conn_mgr, q_in_slm=50.0, dt=0.1, xa=1000, p_max=200.0, fit_low=50.0, fit_high=150.0, T_delta=30.0, should_stop=None, log=print, on_sample=None)` | 返回拟合斜率、截距、`c1``volume_L`、原始压力曲线和 `success`。 |
| 启动多次测量 | `IdentificationManager.start_volume_measurement(conn_mgr=..., running_flag_check=..., q_in_val=..., dt=..., p_max=..., fit_low=..., fit_high=..., T_delta=..., xa_full=1000, num_runs=3)` | 返回 `bool`;后台多次测量、计算平均值并上传 JSON。 |
| 创建配置请求 | `create_volume_config_request(timeout=10)` | 返回 `{"request_id", "expires_at_ms"}`。 |
| 查询配置请求 | `poll_volume_config_request(request_id, timeout=10)` | 返回 `{"ready", "expired"}`;就绪时额外包含 `config`。 |
| 确认配置请求 | `acknowledge_volume_config_request(request_id, timeout=10)` | 成功时返回 `None`。 |
容积测量汇总结果上传到 `<deviceId>/V_config`。容积参数请求与确认是客户端和 ControlPanel 的一次性协作流程。
## 许可证与设备标识
| 功能 | 接口 | 返回或行为 |
| --- | --- | --- |
| 本地验签 | `verify_license(lic_path=None)` | 验证 RSA-PSS/SHA-256 签名、载荷和有效期,返回许可证载荷。 |
| 启动许可证检查 | `check_license(lic_path=None)` | 本地校验、在线校验并启动唯一的后台巡检线程;失败时退出程序。 |
| 获取已验证载荷 | `get_verified_license()` | 返回缓存载荷副本,未验证时返回 `None`。 |
| 在线校验 | `validate_license_online(payload)` | 调用 `validateLicense`;明确无效时抛出 `ExpiredError`。 |
| 启动后台巡检 | `start_license_watchdog(interval_minutes=5)` | 幂等启动,最短巡检间隔为 5 分钟。 |
| 注册生命周期回调 | `set_on_expired(callback)``set_on_grace(callback)``set_on_log(callback)` | 接收失效信息、宽限期小时数或许可证日志。 |
新许可证必须包含 `license_id``company_id``production_line_id`
`device_id``device_id` 必须是两个安全路径段组成的
`<company>/<production-line>`。旧许可证仍可本地验签,但不支持在线撤销。
网络故障不会立即中断控制;离线时限由 `REINLOOP_LICENSE_OFFLINE_HOURS` 配置,默认 72 小时。
## 客户端服务端协议
所有业务请求都发送至 `POST /`。业务成功响应应至少包含 `success: true`
| `type` | 请求关键字段 | 用途 |
| --- | --- | --- |
| `validateLicense` | `licenseId`, `deviceId` | 校验许可证是否为 `active` 状态。 |
| `listModels` | `folder` | 列出 `<deviceId>/model_config` 中的模型。 |
| `downloadModel` | `fileID` | 获取模型临时下载 URL。 |
| `uploadDataFile` | `fileName`, `folder` | 获取对象存储直传凭证。 |
| `getIdentificationConfig` | `deviceId` | 获取九项辨识参数 CSV 的下载 URL。 |
| `registerIdentificationResult` | `deviceId`, `runId`, `fileName` | 登记待审核的辨识 CSV。 |
| `getIdentificationFeedback` | `deviceId`, `runId` | 查询辨识审核结果。 |
| `ackIdentificationFeedback` | `deviceId`, `runId` | 确认并清理已消费的审核结果。 |
| `createVolumeConfigRequest` | `deviceId` | 创建一次性容积配置请求。 |
| `getVolumeConfigRequest` | `deviceId`, `requestId` | 查询请求状态;就绪时取得配置下载 URL。 |
| `ackVolumeConfigRequest` | `deviceId`, `requestId` | 确认或清理容积配置请求。 |
## 配置环境变量
| 变量 | 用途 |
| --- | --- |
| `REINLOOP_SERVER_URL` | 服务端根地址。 |
| `REINLOOP_API_URL` | 完整 API 地址,优先级高于根地址。 |
| `REINLOOP_DEVICE_ID` | 旧许可证或开发测试设备标识;新许可证中必须与 `device_id` 一致。 |
| `REINLOOP_LICENSE_OFFLINE_HOURS` | 许可证在线校验的最大离线时长,默认 `72`。 |
| `REINLOOP_VOLUME_CONFIG` | 本地容积配置 JSON 的覆盖路径。 |