ODE Policy (Euler solver) β R1 Lite "pick cup"
Checkpoints of the ODE policy trained on real-robot demonstrations of the Galaxea R1 Lite right arm
picking up a cup (task r1lite_pick_cup_multimodal). The policy learns a velocity field Θ§ = f(c, s, a)
over the arm's joint targets and produces each 8-step action chunk by integrating that field from the current
target. This run integrates with the explicit Euler solver (one field evaluation per control step) instead
of the RK4 default (four), training and inference alike; everything else is the standard real-robot ODE
configuration (same as the ODE_policy_euler_insert_two_flowers run).
Files
| Path | Content |
|---|---|
checkpoints/{50,100,150,200,250,300}.ckpt |
Full training checkpoints: model, ema_model, optimizer state dicts + the pickled Hydra config. Serve the EMA weights (the loader does this by default). |
config/config.yaml, config/overrides.yaml |
Resolved training config and the command-line overrides of this run |
logs/logs.json.txt |
Per-step / per-epoch training log (loss, lr, epoch time, val_loss every 5 epochs) |
SHA256SUMS |
Checksums of every uploaded file |
Checkpoints are torch.save(..., pickle_module=dill) payloads written by the ODE_Policy training runner.
Loading them needs that codebase (branch r1lite_exp; roboverse_learn.il.policies.ode.ode_image_policy.ODEImagePolicy)
and torch.load(..., pickle_module=dill, weights_only=False) β only load checkpoints you trust.
Data
at237299966/pick_cup_multimodal:
LeRobot v2.1, 200 episodes / 33,323 frames at 15 Hz (131β209 frames per episode), task "pick cup".
Right arm only: the left arm stays still and its gripper open in every episode; the right gripper closes
once and opens once per episode.
| Input / output | Definition |
|---|---|
| Cameras | head_rgb (720Γ1280) and right_wrist_rgb (360Γ640), padded to square then resized to 256Γ256 (same geometry as the robot client). head_right_rgb and left_wrist_rgb are not used. |
agent_pos |
right-arm joint positions (6, rad) + right gripper opening (1, mm) |
ODE state a |
right-arm absolute joint targets (6, rad). Row convention: a[t] = commanded target at tβ1 (episode start: measured joints) |
| Gripper head | binary, +1 close / β1 open; the label flips where the operator's gripper ramp starts |
| Window | 8 observation frames, 8-step action chunk |
Training
| Model | ResNet18 (GroupNorm, random crop) per camera, 8 frames β condition c (512); vector field = 4-layer FiLM-MLP, width 512; proprioception enters the field only (cond_use_s=false); separate gripper head |
| Integration | Euler, 1 substep, 8 control steps per chunk, vel_scale=0.05; observation fixed over the chunk (obs_update=fixed) |
| Start perturbation | 50% of samples, per-joint std [0.005, 0.0138, 0.005, 0.005, 0.005, 0.005] rad (β 3 typical steps of this dataset), decay 0.7 per step |
| Optimisation | AdamW, lr 1.5e-4, cosine schedule over 300 epochs, warm-up 500 steps, EMA |
| Batch | 2 Γ A100-40GB (DDP), 48 per GPU = 96 global; 32,975 training windows, 343 steps/epoch, 102,900 steps in total |
| Wall clock | 13 h 22 min (160 s/epoch), 25.3 GB per GPU |
| epoch | 0 | 10 | 50 | 100 | 150 | 200 | 250 | 300 |
|---|---|---|---|---|---|---|---|---|
| train loss | 0.86 | 0.36 | 0.069 | 0.044 | 0.031 | 0.023 | 0.018 | 0.017 |
| val loss | 0.37 | 0.43 | 0.43 | 0.43 | 0.43 | 0.47 | 0.46 | 0.46 (ep 295) |
The validation loss is a weak signal: one held-out episode, raw (non-EMA) weights, with the training start
perturbation still active. Its minimum is at epoch 5 (0.23); from epoch 40 on it stays within 0.39β0.50, so
compare early and late checkpoints on the robot before picking one. Full curves: logs/logs.json.txt.
Deployment
The robot side is the unmodified openpi-r1lite closed-loop client (main_r1lite_closedloop.py, 15 Hz,
executes row 0 of every (8, 14) reply). The server reads the solver from the checkpoint, re-integrates a
chunk every 8 ticks from the last target it sent and walks the client through it; the left arm is echoed
(held where it is):
python -m roboverse_learn.il.deploy.serve_policy \
--checkpoint checkpoints/100.ckpt --host 0.0.0.0 --port 8000 --device cuda:0 \
--gripper_close 0 --gripper_open 100 --gripper_ramp_ticks 24
python -m roboverse_learn.il.deploy.test_client --host 127.0.0.1 --port 8000 -n 40 --gripper_range 0 100 # pre-flight
Set the torso to the demonstrations' pose [-0.8039, 1.6626, 0.9447] rad before a run (median over all
frames; it is not part of the policy's state and differs from the insert-flower and microwave tasks). The
demonstrations start with the right arm at about [-0.052, 1.503, -1.141, 0.416, -0.040, -0.055] rad and
the right gripper open (100). Code: ODE_Policy repository, neural_ode/real/ (data + training) and
roboverse_learn/il/deploy/ (server).