Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)"不够,照那个做仍会误判。

### 笛卡尔运动

Expand Down
4 changes: 2 additions & 2 deletions docs/DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
4 changes: 2 additions & 2 deletions docs/DEVELOPER_GUIDE.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
8 changes: 5 additions & 3 deletions src/litearm/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}`), 不是
Expand Down
Loading