## 1. 采用的系统/方法 仓库是一个混合工程:Web 前端(HTML/CSS/JS)+ Python3 本地调试服务器,以及通过外部脚本触发的 ESP-IDF 固件构建。没有 Makefile、Dockerfile、CI 流水线或统一的包管理器;构建由**多个独立的 Windows 批处理脚本和 Python 启动器**拼凑而成,分别承担不同的构建目标。 ### 1.1 前端静态服务与桌面窗口 - 核心运行体 `esp32_server.py` 用 stdlib `http.server.ThreadingHTTPServer` 在本地提供静态页面,并实现 `/ecat/api/*` 反向代理到 `tools/ecat/build_native/ecat_native.exe`(端口 8090–8095 自动探测)。 - 三种启动入口: - `serve.bat`:控制台模式,默认端口 2625,输出日志方便调试。 - `esp32_app.vbs`:`pythonw.exe` 启动 pywebview 桌面窗口(无控制台),子进程承载 HTTP 服务,避免 pythonw 后台线程被杀。 - `esp32_web.vbs`:`pythonw.exe` 启动后默认打开浏览器标签页。 - 窗口模式下服务端向 HTML 响应注入 `_reload.html`,为 WebView2 补充 F5 / Ctrl+R 刷新能力。 ### 1.2 ESP-IDF 固件构建 - `scripts/build_mem.bat` 通过 Git Bash 调用 `idf.py build` 构建 `G:\Robot_v2\DCU\ESP32_COMM` 下的 DCU/ESP32 固件。 - 预先 `unset MSYSTEM*` / `MINGW_*` 环境变量绕过 ESP-IDF 的 MSys 检测,并将工具链路径固定到 `C:\Espressif` 与 `F:\software\.espressif\v6.0\esp-idf\export.bat`——路径硬编码于脚本中。 ### 1.3 GD32 OTA / 刷写 - `scripts/flash_gd32.py`:经本服务的 Web API 把 GD32 固件中继下载到设备侧 Flash。 - EtherCAT 链路依赖 `tools/ecat/build_native/ecat_native.exe`(由 `build_native.bat` 编译,需 VS2022 + Npcap),首次请求时由 `esp32_server.py` 的 `_ecat_autostart` 自动拉起(带 `--parent-pid` 防止清场已有实例),未找到时用端口扫描复用已运行的进程。 ## 2. 关键文件 | 文件 | 角色 | |------|------| | `esp32_server.py` | 静态文件服务、EtherCAT 反向代理、app 窗口租约、ECAT 守护进程管理 | | `serve.bat` | 控制台模式启动器(Python 标准输出可见) | | `esp32_app.vbs` | pywebview 桌面窗口启动器(隐藏控制台) | | `esp32_web.vbs` | 默认浏览器 tab 启动器(隐藏控制台) | | `scripts/build_mem.bat` | 通过 ESP-IDF 构建 ESP32 端固件 | | `scripts/flash_gd32.py` | 通过本服务中继刷写 GD32 固件 | | `README.md` | 记录目录约定、双链路架构与三处构建依赖 | ## 3. 架构与约定 - **分层清晰**:前端是纯静态资源,不碰硬件;业务 API 跨域访问 ESP32 固件的 80 端口;只有 EtherCAT 后端需要本机 C/SOEM 守护进程。 - **同源代理解 CORS**:ECAT 后端绑 127.0.0.1 且禁止预检,所有 POST JSON 请求统一走 `/ecat/api/*` 同源转发,页面与两个仓库(前端 + ecat)互不耦合。 - **自动生命周期管理**:ECAT 守护进程首次代理时才拉起,`--parent-pid` 保证父退出后自杀;已存在进程直接复用(端口 8090–8095 轮询探测),避免重复拉起触发对从站的 INIT 清理。 - **单实例锁**:多双击 `esp32_app.vbs` 时通过 `/api/focus` 聚焦已有实例而非创建新窗口。 - **版本化缓存**:README 明确“改 CSS/JS 后必须 bump 引用处的 `?v=` 缓存版本”,否则浏览器加载旧代码。 - **模块组织**:新增功能页放 `pages/` 并在 `tabs.html` 的 TABS 数组登记;一次性实验页放 `lab/` 保持自包含。 ## 4. 约束与规则 - **ESP32 固件构建依赖外仓路径**:`scripts/build_mem.bat` 将 `ESP_IDF_EXPORT` 指向 `F:\software\.espressif\v6.0\esp-idf\export.bat`,并 cd 到 `G:\Robot_v2\DCU\ESP32_COMM` 再 `idf.py build`——这要求开发者拥有与仓库一致的磁盘布局,不是可移植构建。 - **ECAT 后端必须先存在或可由本服务拉起**:若未找到 `tools/ecat/build_native/ecat_native.exe`,电机链路会报错提示“请先运行 tools\ecat\build_native.bat”;前端 `js/motor/main.js` 对错误消息中包含 `build_native`/Npcap 的情况做归类。 - **WebSocket 租约决定循环启停**:`ws/app-lease` 上所有 app 窗口断开则自动停止 EtherCAT PDO 循环并把从站退回 INIT。 - **刷新率上限与链路绑定**:WiFi 链路默认 250ms、最低 50ms;ECAT 链路默认 50ms、最低 1ms(受限于 Python Event.wait 与 GIL)。切链路时各记一份 `state.refreshByTp` 并立即重排节拍。 - **1ms ECAT 档位 ≠ 1000Hz**:底层以 UNTHROTTLED_MAX_MS=20 作为“不限速”阈值,1ms 档实际约 125 Hz;低于 20ms 要同时关掉理论值与 tickStuck 统计,否则界面会撒谎。 ## 5. 不存在的内容 - 没有 Makefile / Gradle / npm scripts / Dockerfile / CI YAML — 该项目在 Windows 环境内用批处理与 VBScript 手工组装构建/发布流程。 - 无统一的版本号定义文件(版本号来源于 Git tag / changelog 和设备端 SHA-256)。 - 无交叉编译配置:ESP-IDF 构建路径硬编码,ECAT native 产物预期在 Windows 上由 VS2022 构建。