fix jogging stepping by holding one velocity instead of re-arming
`set_cartesian_velocity` passed `duration=velocity_command_ttl_s` on every message, so each one re-armed a timed segment and the controller re-planned the same motion. On a real Lite6 that is not smooth travel: the arm moves in steps. Reducing how often the velocity is sent does not help — re-arming four times a second still steps — so it now uses `duration=0`, the SDK's "always effective, will not stop automatically", and skips a velocity that has not changed. One command stands until a different one replaces it. That removes the controller-side expiry, which `_expire_jog` was relying on: it flipped `_jogging` and reported `ready` without commanding anything, because the controller's own timer had already stopped the arm. With the velocity held indefinitely that would leave an arm travelling while the node reported idle, so `_expire_jog` now queues the stop itself. It goes through the job queue rather than the driver, since it runs on the reporter thread and the control thread owns the driver. `VELOCITY_COMMAND_TTL_S` is unchanged in value and meaning to a caller, but it is now enforced here rather than by the controller. Both halves are one commit on purpose: `duration=0` without the stop in `_expire_jog` is an arm that never stops when its sender dies. Adds tests/test_driver.py — the driver had no direct coverage, because FakeArm replaces it everywhere else, which is why this was invisible to the suite.
This commit is contained in:
@@ -123,8 +123,7 @@ you see `done`. Sending them all at once does not queue them; the last one wins.
|
||||
|
||||
## Jogging
|
||||
|
||||
`jog` is a topic, not a service: a velocity command expires on the controller's own TTL,
|
||||
so a sender keeps sending and nobody waits for an answer.
|
||||
`jog` is a topic, not a service: a sender keeps sending and nobody waits for an answer.
|
||||
|
||||
```python
|
||||
node.send_output("jog", pa.array([{"velocity": [20.0, 0, 0, 0, 0, 0]}]))
|
||||
@@ -132,9 +131,18 @@ node.send_output("jog", pa.array([{"velocity": [20.0, 0, 0, 0, 0, 0]}]))
|
||||
|
||||
It still drives the arm, so it behaves like a motion where that matters: the first
|
||||
non-zero jog preempts a motion in play and `robot_state` turns to `moving`. A zero
|
||||
velocity stops it, and so does simply going quiet — the node returns to `ready` once
|
||||
`VELOCITY_COMMAND_TTL_S` has passed, because that is when the controller has expired the
|
||||
command.
|
||||
velocity stops it, and so does simply going quiet — the node stops the arm and returns to
|
||||
`ready` once `VELOCITY_COMMAND_TTL_S` has passed.
|
||||
|
||||
**The velocity is set once and held.** The controller is given a velocity with no
|
||||
duration, so it keeps it until a different one arrives: re-sending an unchanged velocity
|
||||
does not reach the arm at all. Sending it repeatedly re-armed a timed segment and made the
|
||||
controller re-plan the same motion, which on a real arm is felt as stepping rather than
|
||||
travel — even at four messages a second.
|
||||
|
||||
That also means **the controller no longer stops the arm on its own**, so
|
||||
`VELOCITY_COMMAND_TTL_S` is enforced here instead. It is a real deadman now rather than a
|
||||
description of one: a sender that dies mid-jog is what it exists for.
|
||||
|
||||
## Telemetry
|
||||
|
||||
@@ -239,13 +247,13 @@ left where it stood.
|
||||
| `READY_TIMEOUT_S` | `3.0` | How long `recover` waits for a movable state |
|
||||
| `HOME_TIMEOUT_S` | `20.0` | How long homing may take |
|
||||
| `TOOL_SETTLE_S` | `2.0` | How long to wait for suction to build or fingers to close |
|
||||
| `VELOCITY_COMMAND_TTL_S` | `0.5` | The controller's own expiry for one `jog` command |
|
||||
| `VELOCITY_COMMAND_TTL_S` | `0.5` | How long a `jog` stream may go quiet before this node stops the arm |
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
uv sync --group dev
|
||||
uv run pytest # 86 tests, no robot needed
|
||||
uv run pytest # 92 tests, no robot needed
|
||||
uv run ruff check .
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user