Skip to content

feat(teleop): motion_scale on VRFrame + clutch-and-scale in worker + --motion-scale CLI flag#46

Open
shared-twolabs wants to merge 3 commits into
almond-bot:mainfrom
shared-twolabs:feat/motion-scale
Open

feat(teleop): motion_scale on VRFrame + clutch-and-scale in worker + --motion-scale CLI flag#46
shared-twolabs wants to merge 3 commits into
almond-bot:mainfrom
shared-twolabs:feat/motion-scale

Conversation

@shared-twolabs

Copy link
Copy Markdown

Summary

Adds a per-frame teleop motion multiplier so VR controllers don't need huge motions to cover the arm's full range. Companion to almond-bot/axol-vr PR that surfaces this in the headset UI via a slider panel and controller-driven sphere-calibration gesture.

What changes

  • almond_axol/vr/models.pyVRFrame.motion_scale: float = 1.0 (additive, backwards compatible — clients that don't send it get identity behavior)
  • almond_axol/teleop/worker.py_relative_target_np now optionally takes a motion_scale factor and applies it to controller-frame position deltas; IKWorker.step() resolves an effective_scale per frame (client wins unless 1.0, then CLI fallback applies). Both EE and elbow deltas are scaled with the same factor — unscaled elbow with scaled EE would give the IK solver impossible geometry and degrade posture
  • almond_axol/teleop/config.pyVRTeleopConfig.motion_scale: float = 1.0 (server-side fallback when the client sends identity)
  • almond_axol/cli/teleop.py--motion-scale FLOAT flag (plumbs into config)

Why scale both EE and elbow deltas

The elbow target is computed as snap_elbow_fk + (elbow_curr - snap_elbow_ctrl). If only the EE delta were magnified, the relative EE-to-elbow geometry would diverge from the operator's actual arm posture as scale moves away from 1.0, and the IK solver would have to reach for impossible configurations. Scaling both keeps the inputs self-consistent.

Reuse of existing clutch

The existing _engage_snap flow is already a rising-edge clutch on l_lock && r_lock. Rather than add a parallel per-arm clutch state machine, this PR adds the scale factor into the existing snap-and-relative-delta computation. Behavior at motion_scale=1.0 is bit-identical to today.

Resolution rule (small sharp edge worth flagging)

effective_scale = client_scale if client_scale != 1.0 else cli_fallback. This matches the original task spec. The sharp edge: a future client that wants to actively request identity while the CLI fallback is 0.5 cannot — exact equality with 1.0 always defers to fallback. If that becomes important, switching the wire type to Optional[float] = None and resolving None → fallback would fix it cleanly. Not changing it now since identity-vs-fallback equivalence at 1.0 has no observable difference today.

Test plan

  • Smoke 6/6: VRFrame parses with and without motion_scale; worker math correctly scales EE delta (0.5×, 2.0×, 1.0×); orientation untouched; config plumbing; effective-scale resolution
  • CLI: axol teleop --help shows --motion-scale S
  • Ruff lint + format clean across all 4 modified files
  • Live test with the companion axol-vr PR + a real arm

Companion

Web/headset side: https://github.com/almond-bot/axol-vr (the floating-dashboard PR).

🤖 Generated with Claude Code

…ising-edge

Adds an optional motion_scale parameter to _relative_target_np that
multiplies the controller-frame position delta. Default 1.0 preserves
prior identity mapping. Values <1.0 magnify VR→arm motion so the
operator can drive the full arm workspace while their controllers
stay inside the headset's tracking volume (compensates for tracking
drift at extreme reach).

IKWorker.step() resolves an effective scale per frame: client-sent
frame.motion_scale wins unless it's exactly 1.0, in which case the
new VRTeleopConfig.motion_scale CLI fallback applies. Position
scaling is applied uniformly to both EE delta and elbow delta so
their targets stay self-consistent for IK posture. Orientation is
intentionally NOT scaled — rotation passes through 1:1 so wrist
twist always matches.

The existing clutch (rising-edge grip → engage_snap captures VR pose
and arm FK) is already a clutch; this change scales the delta drawn
from those snaps.
Adds a --motion-scale FLOAT flag (default 1.0) to the axol teleop
subcommand. Plumbs it into VRTeleopConfig.motion_scale, which the
IK worker uses as a server-side fallback when the incoming VRFrame
leaves motion_scale at its 1.0 default. Lets operators run with a
magnified VR→arm mapping without a client-side change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant