Skip to main content
Connects a VR headset to the robot (or simulator) for teleoperation. IK runs in a dedicated subprocess to keep JAX off the asyncio event loop. The pipeline is: VR frames → One Euro filtering → IK solve → EMA smoothing → trapezoidal velocity profiling → motion_control().
from almond_axol.teleop import VRTeleop, VRTeleopConfig
import asyncio
from almond_axol.robot import Axol
from almond_axol.teleop import VRTeleop

async def main():
    async with VRTeleop(Axol()) as teleop:
        await teleop.run()  # blocking; Ctrl+C to exit

asyncio.run(main())
Use step() instead of run() to integrate teleoperation into your own control loop:
async with VRTeleop(axol) as teleop:
    while True:
        left_q, right_q = teleop.step()  # returns latest smoothed (8,) arrays
        # ... custom logic ...
        await asyncio.sleep(1 / 120)
To show camera feeds in the headset, register frame sources after the session is enabled — VRTeleop.set_video_sources() forwards them to the VR server’s WebRTC relay (requires the video extra; see almond_axol.vr):
async with VRTeleop(axol) as teleop:
    teleop.set_video_sources({"overhead": lambda: cam.read_latest(max_age_ms=1000)})
    await teleop.run()
See the teleop CLI command for the equivalent command-line entry point (--zed_host wires the ZED cameras up automatically).

VRTeleopConfig fields

FieldDefaultDescription
frequency120 HzControl loop rate used by run() and reset trajectory density
teleop_max_vel1.0 rev/sTrapezoidal filter velocity cap during normal teleoperation
teleop_max_accel3.5 rev/s²Trapezoidal filter acceleration cap
engage_max_vel0.1 rev/sSlower velocity limit when teleop is first engaged after a reset
engage_duration1.0 sHow long engage_max_vel is held before restoring teleop_max_vel
ik_alpha0.5EMA blend factor on IK output; 1.0 disables smoothing
pose_min_cutoff1.5 HzOne Euro Filter tremor cutoff for raw VR poses
pose_beta5.0One Euro Filter speed coefficient (raises cutoff during fast moves)
position_multiplier1.0Scale on hand position (not orientation): the EE target moves this many times as far as the hand. >1 extends reach when the arm is longer than the operator’s
rotation_multiplier1.0Scale on hand orientation (not position): the EE target rotates this many times as far as the hand. >1 rotates the arm further than the wrist
reset_speed0.1 rev/sAverage joint velocity of the worst-case joint during return-to-rest (peak is 1.5× this)
reset_min_duration1.5 sFloor on return-to-rest duration so near-rest starts don’t snap home
rest_pose_left / rest_pose_rightnear-zeroReset target for each arm, shape (7,) in ARM_JOINTS order
Engage toggle behaviour. Grip is a toggle, not a hold. Press both grip buttons together to enable arm movement; press either grip alone to freeze the arms. A rising edge on the reset button triggers a collision-aware trajectory back to the rest pose.