diff --git a/README.md b/README.md index e266cd1..2ae9e4d 100644 --- a/README.md +++ b/README.md @@ -132,8 +132,10 @@ arm.home() # go home ``` **Do not** read `get_state().enabled` on the line after `enable()`. It returns before the -state stream reflects the change — measured 2.0-2.7 ms to return against 7.0-7.8 ms for the -flag to turn true — so the check reads `False` and means nothing. Wait a frame before judging. +state stream reflects the change — **2.0-3.1 ms** to return, while the flag takes +**17.6-48.5 ms** to turn true (n=11; one earlier run on the same unit read 7.0-7.8 ms — +the lag is state-dependent, but always several frames, never one). So the check reads +`False` and means nothing. **Poll until it flips** — a fixed 10 ms wait is not enough. ### Cartesian motion diff --git a/README.zh-CN.md b/README.zh-CN.md index 72f224c..6e3c34e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -123,8 +123,10 @@ arm.home() # 回零 ``` ⚠ **别在 `enable()` 的下一行读 `get_state().enabled`。** 它在状态帧反映之前就返回—— -实测返回耗时 2.0~2.7 ms,而那个标志变真要到 7.0~7.8 ms——所以读到的是 `False`, -那个值没有任何意义。判定前先等一拍。 +实测它 **2.0~3.1 ms** 就返回了,而那个标志变真要到 **17.6~48.5 ms**(n=11;同一台机 +另有一轮量到 7.0~7.8 ms——滞后随臂/固件状态而变,但**始终是好几拍**,不是一拍)。 +所以读到的是 `False`,那个值没有任何意义。判据请**轮询到它变真**—— +⚠ 写"固定等一拍(约 10 ms)"不够,照那个做仍会误判。 ### 笛卡尔运动 diff --git a/docs/DEVELOPER_GUIDE.md b/docs/DEVELOPER_GUIDE.md index 5ee59c2..02e1e69 100644 --- a/docs/DEVELOPER_GUIDE.md +++ b/docs/DEVELOPER_GUIDE.md @@ -234,8 +234,8 @@ park() | Method | Caveat | | --- | --- | -| `enable(attempts=12)` | Enables all joints. Retries are whitelisted: **only `(0x10, 0x03)` is retried**. ⚠ **It returns before the state stream confirms it** — measured 2.0-2.7 ms to return against 7.0-7.8 ms for `get_state().enabled` to turn true, so `enable(); get_state().value.enabled` reads `False` and means nothing. Wait a frame (or ~10 ms) before judging | -| `disable()` | Cuts the position loop. The arm is no longer held | +| `enable(attempts=12)` | Enables all joints. Retries are whitelisted: **only `(0x10, 0x03)` is retried**. ⚠ **It returns before the state stream confirms it** — measured **2.0-3.1 ms** to return against **17.6-48.5 ms** for `get_state().enabled` to turn true (n=11; an earlier run on the same unit read 7.0-7.8 ms — state-dependent, but always several frames), so `enable(); get_state().value.enabled` reads `False` and means nothing. **Poll until it flips** — a fixed ~10 ms wait is not enough | +| `disable()` | Cuts the position loop. The arm is no longer held. Unlike `enable()` it has **no long lag** — measured 2.9-3.1 ms to return against 3.0-3.1 ms for `enabled` to read `False`. A single immediate read can still return the previous frame (≤1 status frame), so poll if the answer matters | | `emergency_stop()` | Single frame, one-way, does not read state — the only entry point with no preconditions | | `reset()` | A software state reset, **not an MCU reboot**; the same object stays usable | | `clear_faults()` | Clears RAM fault bits only, does not write flash | diff --git a/docs/DEVELOPER_GUIDE.zh-CN.md b/docs/DEVELOPER_GUIDE.zh-CN.md index ff6e3f6..5ac74c5 100644 --- a/docs/DEVELOPER_GUIDE.zh-CN.md +++ b/docs/DEVELOPER_GUIDE.zh-CN.md @@ -226,8 +226,8 @@ park() | 方法 | 注意 | | --- | --- | -| `enable(attempts=12)` | 使能全部关节。重试是白名单,**只有 `(0x10, 0x03)` 会重试**。⚠ **它在状态帧反映之前就返回**——实测返回耗时 2.0~2.7 ms,而 `get_state().enabled` 变真要到 7.0~7.8 ms,所以 `enable(); get_state().value.enabled` 读到的是 `False`,那个值没有任何意义。判定前先等一拍(约 10 ms) | -| `disable()` | 切断位置环。此后机械臂不再被托住 | +| `enable(attempts=12)` | 使能全部关节。重试是白名单,**只有 `(0x10, 0x03)` 会重试**。⚠ **它在状态帧反映之前就返回**——实测返回耗时 **2.0~3.1 ms**,而 `get_state().enabled` 变真要到 **17.6~48.5 ms**(n=11;同一台机另有一轮量到 7.0~7.8 ms——随状态而变,但始终是好几拍),所以 `enable(); get_state().value.enabled` 读到的是 `False`,那个值没有任何意义。判据请**轮询到它变真**——固定等 10 ms 不够 | +| `disable()` | 切断位置环。此后机械臂不再被托住。与 `enable()` 不同,它**没有长滞后**——实测返回 2.9~3.1 ms、`enabled` 读到 `False` 是 3.0~3.1 ms。但紧接着单读一次仍可能拿到上一帧(≤1 拍),要紧就轮询 | | `emergency_stop()` | 单帧、单向、不读状态,唯一没有前置条件的入口 | | `reset()` | 软件状态复位,**不是 MCU 重启**,同一对象仍可用 | | `clear_faults()` | 只清 RAM 故障位,不写 flash | diff --git a/src/litearm/arm.py b/src/litearm/arm.py index 458ba91..c3f4742 100644 --- a/src/litearm/arm.py +++ b/src/litearm/arm.py @@ -1474,10 +1474,12 @@ def enable(self, attempts: int = 12) -> None: """使能全关节 (`CMD_ENABLE 0x10`), 必要时重试。 ⚠⚠ **本方法在状态帧反映之前就返回。** 真机实测 (yd 机整臂, `Litearm1.10.0-7J`): - 返回耗时 **2.0~2.7 ms**, 而 `get_state().enabled` 首次为真要到 **7.0~7.8 ms**。 + 返回耗时 **2.0~3.1 ms**, 而 `get_state().enabled` 首次为真要到 **17.6~48.5 ms** + (**n=11**; 同一台机另有一轮量到 **7.0~7.8 ms** —— 该滞后随臂/固件状态而变, + 但**始终是好几拍**, 不是一拍)。 ⇒ **`enable(); get_state().value.enabled` 读到的是 `False`, 那个值没有任何意义** - (6 轮实测每次都这样, 不是偶发)。要判定使能是否成立就**隔一拍再读** - (约 10 ms, 或等一条新的状态帧)。 + (每次都这样, 不是偶发)。要判定使能是否成立只能**轮询到它变真**: + ⚠ **"等一拍(约 10 ms)再读"不够** —— 实测最长 48.5 ms, 照那个做仍会误判。 ⚠ **只有固件明说"可重试"的码才重试** —— 判据是白名单 :data:`litearm.errors.ENABLE_RETRYABLE_CODES` (= `{0x03}`), 不是