FFW SG2 · wave-right · proprioception-only Diffusion Policy

Diffusion Policy (LeRobot 0.6.1) trained on the wave-right task of omkarpatil/wave-traj (15 teleop episodes, ROBOTIS AI Worker ffw_sg2_rev1, instruction "wave using the right hand"). The policy conditions on joint state only — no cameras.

Inputs observation.state (22): arm_l ×7, gripper_l, arm_r ×7, gripper_r, head ×2, lift, cmd_vel linear_x / linear_y / angular_z
Outputs action (22), same layout, published to /leader/*/joint_trajectory and /cmd_vel
Chunking n_obs_steps=1, horizon=32, n_action_steps=16 at 15 Hz (= 2.1 s predicted, 1.07 s executed per chunk)
Inference DDPM, num_inference_steps=10 (≈ 70 ms on an A5000; 100 steps gives the same accuracy at ~650 ms)
Training 30 k steps, batch 64, lr 1e-4 cosine, seed 1000; final loss 1e-3; offline 16-step open-loop MAE 0.002 rad

Initial state for inference

The demonstrations all start from the pose below (mean over 15 episodes; std is the spread across demos). Put the robot at this pose before issuing START — the policy has never seen states far from it, and in MuJoCo rollouts it waved reliably from starts up to ~0.24 rad (per joint) away from the nearest demo start. Head and lift were fixed during collection, so use exactly those values. Base velocity dims must read ~0.

joint mean [rad] std range over demos
arm_l_joint1 -0.138 0.061 [-0.222, -0.036]
arm_l_joint2 +0.168 0.027 [+0.114, +0.203]
arm_l_joint3 -0.081 0.052 [-0.180, -0.004]
arm_l_joint4 -1.452 0.112 [-1.669, -1.298]
arm_l_joint5 +0.198 0.054 [+0.104, +0.281]
arm_l_joint6 +0.079 0.096 [-0.126, +0.233]
arm_l_joint7 +0.018 0.034 [-0.037, +0.109]
gripper_l_joint1 +0.254 0.063 [+0.163, +0.345]
arm_r_joint1 -0.161 0.079 [-0.304, -0.045]
arm_r_joint2 -0.069 0.024 [-0.106, -0.024]
arm_r_joint3 +0.025 0.056 [-0.075, +0.142]
arm_r_joint4 -1.402 0.125 [-1.627, -1.232]
arm_r_joint5 -0.026 0.047 [-0.115, +0.053]
arm_r_joint6 -0.012 0.093 [-0.206, +0.113]
arm_r_joint7 -0.015 0.119 [-0.252, +0.130]
gripper_r_joint1 +0.258 0.161 [+0.054, +0.503]
head_joint1 -0.204 0.000 [-0.204, -0.204]
head_joint2 -0.292 0.000 [-0.292, -0.292]
lift_joint -0.000 0.001 [-0.002, +0.000]
linear_x -0.000 0.000 [-0.000, +0.000]
linear_y +0.000 0.000 [-0.000, +0.000]
angular_z +0.000 0.000 [-0.001, +0.000]

The same numbers are in initial_state.json (initial_state_mean is the vector to command, in joint_names order; final_state_mean is where the demos end, i.e. the rest pose the policy returns to).

Running it with cyclo_intelligence

  • Set the task's inference_hz = 15 (default) and control_hz = 100 in the UI; ActionChunkProcessor spaces the chunk's 16 steps at 1/inference_hz, so 15 Hz must match the dataset fps this policy was trained at.
  • Stock LeRobot refuses to build a Diffusion Policy without an image/environment-state input, and the container engine sends a single (B, D) state per request. Both are handled by cyclo_brain/policy/lerobot/lerobot_engine/diffusion_compat.py (loaded automatically by the engine's loading.py / prediction.py) — the policy container needs that version of the bind-mounted lerobot_engine/. Loading in plain LeRobot: call diffusion_compat.allow_state_only_diffusion() first, then DiffusionPolicy.from_pretrained(...), and add the time axis with expand_obs_time_dim(batch, 1) before predict_action_chunk.

MuJoCo rollouts

10/10 full waves from sampled initial states in the lerobot-mujoco-tutorial FFW SG2 model (right-arm joint range 88 % of the demonstrations', left arm quiet, 0.012 rad servo tracking error).

Downloads last month
5
Safetensors
Model size
0.2B params
Tensor type
F32
·
Video Preview
loading

Dataset used to train omkarpatil/ffw_sg2_wave-right_diffusion_state