feat: 添加局域网设备发现功能和链路胶囊优化
- 实现局域网设备发现面板,支持探测ESP32中继板并自动切换端点 - 添加POST /api/lan/probe接口用于设备探测,返回三态判决结果 - 实现快扫和全段扫描两种模式,支持种子地址优先探测 - 添加端点唯一写手机制,防止多处同时修改设备IP - 优化链路胶囊UI显示WiFi/EtherCAT/BLE连接状态和设备名称 - 修复EtherCAT链路OTA刷写期间PDO循环暂停和AL状态处理问题 - 调整PDO周期设置范围为0.125-4ms,支持亚毫秒显示为微秒 - 添加ESP32 WiFi使能开关控件样式和数据来源角标显示
This commit is contained in:
+20
-8
@@ -471,11 +471,11 @@
|
||||
<button id="btnPeriod">热改周期</button>
|
||||
<span id="runPill" class="pill"><span class="indicator"></span>空闲</span>
|
||||
</div>
|
||||
<div class="hint">
|
||||
<div class="hint">
|
||||
热改周期走 <code>/api/motor/period</code>(循环每拍重读的变量,全程喂狗不断流,随时可调、可反复调)。
|
||||
<b>低于 1ms 档后端自动用自旋节拍,会占满一个 CPU 核</b>;从站固件修好前别低于 1ms —— 实测
|
||||
0.25 / 0.125ms 档 GD32 顶到 99.5%,CAN 到帧率 λ 从 4000/s 塌到 149/s(瓶颈在从站不在主站,
|
||||
只看主站达成率会整条看漏)。<br>
|
||||
合法档位 <b>0.125–4 ms</b>,DC SYNC0 与 period 始终同值;选完立刻生效,回读以状态栏为准。
|
||||
低于 1ms 档后端自动用自旋节拍,会占满一个 CPU 核;极快档(0.25/0.125)对 GD32 SSC 压力大,
|
||||
极慢档(≥1ms)发送出口延迟会变长 —— 都是可接受的代价,不是被钉死。<br>
|
||||
<b>观测默认 10Hz</b>。逐拍环 / 原始窗口 / 每拍重建都在各自模块卡片里开关(默认关)。标签页切到后台会自动暂停。
|
||||
</div>
|
||||
</div>
|
||||
@@ -2267,20 +2267,32 @@ $("#btnPeriod").onclick = async () => {
|
||||
try {
|
||||
const r = await eapi("motor/period", { period_ms: v }, 8000);
|
||||
if (r.ok !== true) throw new Error((r.log || []).join(" / ") || "被拒");
|
||||
const apiEff = (typeof r.period_ms === "number") ? r.period_ms : null;
|
||||
/* 热调是异步落到循环线程的,必须回读确认,不能拿下发值当生效值 */
|
||||
let eff = null;
|
||||
for (let i = 0; i < 8; i++) {
|
||||
await wsleep(250);
|
||||
eff = (await eapi("motor/state", {}, 4000)).period_ms;
|
||||
if (isNum(eff) && Math.abs(eff - v) < 1e-6) break;
|
||||
if (isNum(eff) && apiEff != null && Math.abs(eff - apiEff) < 1e-6) break;
|
||||
}
|
||||
const ok = isNum(eff) && Math.abs(eff - v) < 1e-6;
|
||||
if (ok) {
|
||||
const hitReq = isNum(eff) && Math.abs(eff - v) < 1e-6;
|
||||
const hitApi = isNum(eff) && apiEff != null && Math.abs(eff - apiEff) < 1e-6;
|
||||
if (hitReq) {
|
||||
writePeriodShared(eff);
|
||||
saveUiOpts();
|
||||
runBusy("ok", "已生效 " + eff + "ms(" + f0(1000 / eff) + "Hz 档)");
|
||||
} else if (hitApi && apiEff != null && Math.abs(apiEff - v) >= 1e-6) {
|
||||
/* 后端钳到合法档并回了生效值 —— 不是别人劫持 */
|
||||
writePeriodShared(apiEff);
|
||||
saveUiOpts();
|
||||
runBusy("warn", "下发 " + v + "ms,后端钳制为 " + apiEff + "ms"
|
||||
+ ((r.log && r.log.length) ? ":" + r.log.join(" / ") : ""));
|
||||
} else {
|
||||
runBusy("bad", "下发 " + v + "ms 但回读 " + eff
|
||||
+ (apiEff != null ? "ms(API 回 " + apiEff + "ms)" : "ms")
|
||||
+ " —— 生效值与请求不一致(他端热改或后端未接受)");
|
||||
}
|
||||
runBusy(ok ? "ok" : "bad", ok ? ("已生效 " + eff + "ms(" + f0(1000 / eff) + "Hz 档)")
|
||||
: ("下发 " + v + "ms 但回读 " + eff + "ms —— 有他端在设周期(localStorage 劫持)"));
|
||||
} catch (e) { runBusy("bad", "失败:" + e.message); }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user