feat(motor): 新增 EtherCAT 周期速率扫描分析工具链,支持 sweep 脚本、指标校准、绘图与 HTML 报告生成

This commit is contained in:
cbb
2026-09-10 03:02:14 +08:00
parent 4e018af168
commit 81096d0425
20 changed files with 4544 additions and 219 deletions
+13 -9
View File
@@ -142,11 +142,12 @@ g_ecat_port = None # 记住上次探到的端口, 避免每次请求都从 809
# 换成原生守护进程 build_native\
# ecat_native.exe (C/SOEM, 由 build_native.bat 编译)。路由/JSON 契约与 Python
# 逐字段对齐, 见 tools/ecat/MIGRATION.md。三条必须小心的地方(native 原样镜像了这套契约):
# 1) **必须先探测再拉起**。native 独立启动(无 --parent-pid)会清场: 对
# 1) **必须先探测再拉起**。native 启动时**无条件清场**(后起的独占): 对
# 8090..8095 的旧实例逐个调 /api/shutdown(从站回 INIT)再兜底强杀。
# 所以已有实例时只复用, 绝不重复拉起。
# 2) 拉起时**必须带 --parent-pid**: 一是跳过上面那个清场逻辑, 二是让它在
# 本服务退出后自我了断, 不留孤儿进程占着 Npcap 适配器和端口。
# 已有实例时仍只复用不重复拉起 —— 清场是给"并发拉起撞上"兜底的,
# 不该被用来每次踢掉用户手开的实例。
# 2) 拉起时**必须带 --parent-pid**: 让 native 在本服务退出后自我了断,
# 不留孤儿进程占着 Npcap 适配器和端口。(与清场无关, 清场总是执行)
# 3) 不再需要 venv/pythonw —— 单文件 exe, 无 Python 运行时依赖。
ECAT_DIR = os.path.normpath(os.path.join(BASE_DIR, "..", "ecat"))
ECAT_NATIVE_EXE = os.path.join(ECAT_DIR, "build_native", "ecat_native.exe")
@@ -226,11 +227,14 @@ def _ecat_autostart():
g_ecat_child = None
if g_ecat_child is None:
try:
# --parent-pid: 跳过 native 侧的清场逻辑, 并让它在本服务退出后
# 自我了断(不留孤儿占 Npcap/端口)。
# --mask 0x10: PDO 自旋线程钉 LP4(i7-14700K P核2), 避开 DPC 集中的
# 核0 与 E 核, 与 ecat_web.bat 同值, 换机需按拓扑改。不钉的话
# 自旋线程随调度器漂移, 1ms 档周期抖动明显放大。
# --parent-pid: 让 native 在本服务退出后自我了断(不留孤儿占
# Npcap/端口)。native 侧的清场与它无关, 启动时无条件执行。
# --mask 0x10: PDO 自旋线程钉单个 LP4(i7-14700K P核2), 避开 DPC
# 集中的核0 与 E 核, 与 ecat_web.bat 同值, 换机需按拓扑改。
# 掩码**只能给单比特**: 多比特(如 0x50=LP4|LP6)不是"两个核一起
# 自旋", 而是授权调度器在这一个线程上来回迁移, 迁移期间的迟到拍
# 由 skip_total 计入、直接压低周期达成率。不钉的话随调度器漂移,
# 1ms 档周期抖动明显放大。
# cwd=tools/ecat: --web 的相对路径(src/web)按此解析。
g_ecat_child = subprocess.Popen(
[ECAT_NATIVE_EXE, "--substr", "I210", "--mask", "0x10",