Robotics
LeRobot
Safetensors
act
imitation-learning
reinforcement-learning
grpo
mujoco
bimanual
roboeval
hybird-control
Sa74ll commited on
Commit
12f1b88
·
verified ·
1 Parent(s): 724b4f7

Submitted variant R: StackTwoBlocks hybrid_s2b4 (HOLD_T 1, RISE 0.15) + PickBook timing; official run 0.9866

Browse files
README.md CHANGED
@@ -20,7 +20,7 @@ datasets:
20
  # LocalModels / ACT-bimanual
21
 
22
  Entry **ACT-bimanual** by team **LocalModels** (Saleh Alsharideh, Independent) to the CoRL 2026 RoboEval Diagnostic
23
- Bimanual Challenge. **Official score 0.9861**, 399 of 400 episodes successful.
24
 
25
  Seven tasks run hand-designed RGB-D controllers (no learned weights); LiftPot runs an Action Chunking Transformer (ACT)
26
  trained on the demonstrations and fine-tuned in simulation with GRPO. Code, report and explainer videos:
@@ -50,14 +50,14 @@ python -m roboeval.challenge.evaluate --submission submission --workers W --gpus
50
  | Task | Policy | Successes | Score |
51
  |---|---|---|---|
52
  | CubeHandover | controller | 50 | 1.000 |
53
- | LiftPot | ACT | 50 | 0.999 |
54
  | LiftTray | controller | 50 | 1.000 |
55
  | PackBox | controller | 49 | 0.954 |
56
- | PickSingleBookFromTable | controller | 50 | 0.987 |
57
  | RotateValve | controller | 50 | 1.000 |
58
  | StackSingleBookShelf | controller | 50 | 1.000 |
59
- | StackTwoBlocks | controller | 50 | 0.948 |
60
- | **Suite** | | **399 / 400** | **0.9861** |
61
 
62
  Training data and every use of simulator state: the report, Sec. 3. The files here equal the submitted ones except
63
  three edits that do not change behaviour (no contact e-mail in `metadata.yaml`, local paths shortened in the LiftPot
 
20
  # LocalModels / ACT-bimanual
21
 
22
  Entry **ACT-bimanual** by team **LocalModels** (Saleh Alsharideh, Independent) to the CoRL 2026 RoboEval Diagnostic
23
+ Bimanual Challenge. **Official score 0.9866**, 399 of 400 episodes successful.
24
 
25
  Seven tasks run hand-designed RGB-D controllers (no learned weights); LiftPot runs an Action Chunking Transformer (ACT)
26
  trained on the demonstrations and fine-tuned in simulation with GRPO. Code, report and explainer videos:
 
50
  | Task | Policy | Successes | Score |
51
  |---|---|---|---|
52
  | CubeHandover | controller | 50 | 1.000 |
53
+ | LiftPot | ACT | 50 | 0.997 |
54
  | LiftTray | controller | 50 | 1.000 |
55
  | PackBox | controller | 49 | 0.954 |
56
+ | PickSingleBookFromTable | controller | 50 | 0.988 |
57
  | RotateValve | controller | 50 | 1.000 |
58
  | StackSingleBookShelf | controller | 50 | 1.000 |
59
+ | StackTwoBlocks | controller | 50 | 0.953 |
60
+ | **Suite** | | **399 / 400** | **0.9866** |
61
 
62
  Training data and every use of simulator state: the report, Sec. 3. The files here equal the submitted ones except
63
  three edits that do not change behaviour (no contact e-mail in `metadata.yaml`, local paths shortened in the LiftPot
SHA1SUMS.txt CHANGED
@@ -9,10 +9,10 @@ a6dd75ccc8e6a27c80d6991922a7e22115f7495d submission/checkpoint/LiftPot/policy_p
9
  cb6034b3f50ca44742f3bf2ac5967d64f605f999 submission/checkpoint/LiftPot/train_config.json
10
  6b0ae04424367b8f76c82975b28537e5649f2c5c submission/checkpoint/LiftTray/hybrid.json
11
  d1ff4f07d748ae3e1fb966861e3226c95360e23e submission/checkpoint/PackBox/hybrid.json
12
- 45d4627c1f0e46c897edff5e7e625cb2d4457962 submission/checkpoint/PickSingleBookFromTable/hybrid.json
13
  dff829d7ba30c5b42bd87ebebe28aa6d26351432 submission/checkpoint/RotateValve/hybrid.json
14
  2fb4f07db36ad5c35072bf7d0b35dd7a7509300e submission/checkpoint/StackSingleBookShelf/hybrid.json
15
- 85d64d4e492c33cab63ddc31cfb3fab175ff0362 submission/checkpoint/StackTwoBlocks/hybrid.json
16
  93f8e14655c81b4ee0cbd286cb26901dd32ec9e0 submission/metadata.yaml
17
  2125cc890e4f0935eca511c128ae4e50b671b5b7 submission/policy/hybrid_ch.py
18
  e79acc904c4d8fb9d4528ad013234fcb5efef526 submission/policy/hybrid_lt.py
@@ -21,13 +21,14 @@ fd0bc2f43f124d001be0a9b3f2653dde971a01ba submission/policy/hybrid_pk.py
21
  55ccea8e25b095cad39a955a3b11cda3f3073bd3 submission/policy/hybrid_rv.py
22
  ddbf36b8fa6d217497e5f5a297cbd93c8cbde4b1 submission/policy/hybrid_s2b.py
23
  ec9cc4f4c8fdc5ab029800ebda66bfaee08bb15d submission/policy/hybrid_s2b3.py
 
24
  04a7a59964da57c9f23186468e15007bcd6dd9ed submission/policy/hybrid_ss.py
25
  7f7edc19439f493753dc033117fcbe4144a6219d submission/policy/inference.py
26
  d502beeb4fef26e486a53f7fc7eb13134f314eac submission/policy/lt_perc.py
27
  a9ec953d09433a66fdd96699004fe1e287c99130 submission/policy/modeling_act.py
28
  659d71814c120324da315907a2dea13dc7f86e68 submission/policy/pk_ik.py
29
  fc873fe44fe2a4b25eb085f4b633d1190a6f1f62 submission/policy/pk_perception.py
30
- 933ab94fb12525df5a171c682160409f3a0794e0 submission/policy/policy.py
31
  d80819495655d02d18211a39509f0d51ca982cd1 submission/policy/requirements.txt
32
  0ebd43e61f2306de911a89156c35d28ef6220d70 submission/policy/rod_perc.py
33
  42fe921dc58da0eb6b25296bd26dd0f00fe5fee1 submission/policy/rv_perception.py
 
9
  cb6034b3f50ca44742f3bf2ac5967d64f605f999 submission/checkpoint/LiftPot/train_config.json
10
  6b0ae04424367b8f76c82975b28537e5649f2c5c submission/checkpoint/LiftTray/hybrid.json
11
  d1ff4f07d748ae3e1fb966861e3226c95360e23e submission/checkpoint/PackBox/hybrid.json
12
+ 919a76fb7988ab5d8f66b00e59ff15bb3a049b42 submission/checkpoint/PickSingleBookFromTable/hybrid.json
13
  dff829d7ba30c5b42bd87ebebe28aa6d26351432 submission/checkpoint/RotateValve/hybrid.json
14
  2fb4f07db36ad5c35072bf7d0b35dd7a7509300e submission/checkpoint/StackSingleBookShelf/hybrid.json
15
+ fcc61e40288e3963c3cdb3ca18b3c803321fda41 submission/checkpoint/StackTwoBlocks/hybrid.json
16
  93f8e14655c81b4ee0cbd286cb26901dd32ec9e0 submission/metadata.yaml
17
  2125cc890e4f0935eca511c128ae4e50b671b5b7 submission/policy/hybrid_ch.py
18
  e79acc904c4d8fb9d4528ad013234fcb5efef526 submission/policy/hybrid_lt.py
 
21
  55ccea8e25b095cad39a955a3b11cda3f3073bd3 submission/policy/hybrid_rv.py
22
  ddbf36b8fa6d217497e5f5a297cbd93c8cbde4b1 submission/policy/hybrid_s2b.py
23
  ec9cc4f4c8fdc5ab029800ebda66bfaee08bb15d submission/policy/hybrid_s2b3.py
24
+ 299a9121abcd6b327e69b69022f1e6d44b6c732b submission/policy/hybrid_s2b4.py
25
  04a7a59964da57c9f23186468e15007bcd6dd9ed submission/policy/hybrid_ss.py
26
  7f7edc19439f493753dc033117fcbe4144a6219d submission/policy/inference.py
27
  d502beeb4fef26e486a53f7fc7eb13134f314eac submission/policy/lt_perc.py
28
  a9ec953d09433a66fdd96699004fe1e287c99130 submission/policy/modeling_act.py
29
  659d71814c120324da315907a2dea13dc7f86e68 submission/policy/pk_ik.py
30
  fc873fe44fe2a4b25eb085f4b633d1190a6f1f62 submission/policy/pk_perception.py
31
+ 8f52ff609e77c15abb2809d1c9bdf7cb213a1dab submission/policy/policy.py
32
  d80819495655d02d18211a39509f0d51ca982cd1 submission/policy/requirements.txt
33
  0ebd43e61f2306de911a89156c35d28ef6220d70 submission/policy/rod_perc.py
34
  42fe921dc58da0eb6b25296bd26dd0f00fe5fee1 submission/policy/rv_perception.py
official_run/results.json CHANGED
@@ -122,56 +122,56 @@
122
  "std": 0.0
123
  },
124
  "tp": {
125
- "mean": 1.0,
126
- "std": 0.0
127
  },
128
  "bavd": {
129
- "mean": 0.2907428134024535,
130
- "std": 0.0962944705689577
131
  },
132
  "bgvd": {
133
- "mean": 0.010298816850591686,
134
- "std": 0.004452314091633235
135
  },
136
  "cpl": {
137
- "mean": 0.6699551633231444,
138
- "std": 0.0716183064311788
139
  },
140
  "ct": {
141
- "mean": 2.96,
142
- "std": 0.1726267650163207
143
  },
144
  "ecc": {
145
  "mean": 0.0,
146
  "std": 0.0
147
  },
148
  "jpl": {
149
- "mean": 4.076533994602647,
150
- "std": 0.47333641780431596
151
  },
152
  "mcj": {
153
- "mean": 9.526656728709378,
154
- "std": 1.6592578956263422
155
  },
156
  "mjj": {
157
- "mean": 55.416472157492855,
158
- "std": 10.668620699254578
159
  },
160
  "opl": {
161
- "mean": 2.2800774728779505,
162
- "std": 0.3668582821919849
163
  },
164
  "scc": {
165
- "mean": 0.02,
166
- "std": 0.13999999999999999
167
  },
168
  "sc": {
169
  "mean": 0.0,
170
  "std": 0.0
171
  },
172
  "tl": {
173
- "mean": 59.2,
174
- "std": 3.4525353003264136
175
  }
176
  },
177
  "terminations": {
@@ -266,52 +266,52 @@
266
  "std": 0.0
267
  },
268
  "bavd": {
269
- "mean": 0.47659149680466034,
270
- "std": 0.06612239480233566
271
  },
272
  "bgvd": {
273
- "mean": 0.03871852373226772,
274
- "std": 0.010070250904216971
275
  },
276
  "cpl": {
277
- "mean": 1.393348353983685,
278
- "std": 0.11070235493408716
279
  },
280
  "ct": {
281
- "mean": 4.7059999999999995,
282
- "std": 0.9259935204956891
283
  },
284
  "ecc": {
285
  "mean": 0.0,
286
  "std": 0.0
287
  },
288
  "jpl": {
289
- "mean": 5.1804237300377345,
290
- "std": 0.49917056182326575
291
  },
292
  "mcj": {
293
- "mean": 11.365047787780853,
294
- "std": 1.6817120614731258
295
  },
296
  "mjj": {
297
- "mean": 48.364897931621236,
298
- "std": 6.518151965555668
299
  },
300
  "opl": {
301
- "mean": 1.0293364681009989,
302
- "std": 0.36731588405171467
303
  },
304
  "scc": {
305
- "mean": 0.06,
306
- "std": 0.23748684174075835
307
  },
308
  "sc": {
309
  "mean": 0.0,
310
  "std": 0.0
311
  },
312
  "tl": {
313
- "mean": 94.12,
314
- "std": 18.519870409913782
315
  }
316
  },
317
  "terminations": {
@@ -546,52 +546,52 @@
546
  "std": 0.0
547
  },
548
  "bavd": {
549
- "mean": 0.8746218460586408,
550
- "std": 0.18118555529842803
551
  },
552
  "bgvd": {
553
- "mean": 0.2089795572862352,
554
- "std": 0.037816234640574944
555
  },
556
  "cpl": {
557
- "mean": 1.1386401663938843,
558
- "std": 0.4402695894254054
559
  },
560
  "ct": {
561
- "mean": 6.579,
562
- "std": 2.364531454643816
563
  },
564
  "ecc": {
565
  "mean": 0.0,
566
  "std": 0.0
567
  },
568
  "jpl": {
569
- "mean": 7.037501694745319,
570
- "std": 2.6676240288092647
571
  },
572
  "mcj": {
573
- "mean": 3.090320483869577,
574
- "std": 0.6059852680293215
575
  },
576
  "mjj": {
577
- "mean": 19.545081228674544,
578
- "std": 5.690199966980306
579
  },
580
  "opl": {
581
- "mean": 2.265703850679821,
582
- "std": 0.8937329228062022
583
  },
584
  "scc": {
585
  "mean": 0.0,
586
  "std": 0.0
587
  },
588
  "sc": {
589
- "mean": 0.0,
590
- "std": 0.0
591
  },
592
  "tl": {
593
- "mean": 131.58,
594
- "std": 47.290629092876316
595
  }
596
  },
597
  "terminations": {
@@ -678,19 +678,19 @@
678
  "per_family": {
679
  "LiftPot": {
680
  "success": 1.0,
681
- "tp": 1.0,
682
- "bavd": 0.2907428134024535,
683
- "bgvd": 0.010298816850591686,
684
- "cpl": 0.6699551633231444,
685
- "ct": 2.96,
686
  "ecc": 0.0,
687
- "jpl": 4.076533994602647,
688
- "mcj": 9.526656728709378,
689
- "mjj": 55.416472157492855,
690
- "opl": 2.2800774728779505,
691
- "scc": 0.02,
692
  "sc": 0.0,
693
- "tl": 59.2
694
  },
695
  "LiftTray": {
696
  "success": 1.0,
@@ -711,18 +711,18 @@
711
  "StackTwoBlocks": {
712
  "success": 1.0,
713
  "tp": 1.0,
714
- "bavd": 0.47659149680466034,
715
- "bgvd": 0.03871852373226772,
716
- "cpl": 1.393348353983685,
717
- "ct": 4.7059999999999995,
718
  "ecc": 0.0,
719
- "jpl": 5.1804237300377345,
720
- "mcj": 11.365047787780853,
721
- "mjj": 48.364897931621236,
722
- "opl": 1.0293364681009989,
723
- "scc": 0.06,
724
  "sc": 0.0,
725
- "tl": 94.12
726
  },
727
  "StackSingleBookShelf": {
728
  "success": 1.0,
@@ -775,18 +775,18 @@
775
  "PickSingleBookFromTable": {
776
  "success": 1.0,
777
  "tp": 1.0,
778
- "bavd": 0.8746218460586408,
779
- "bgvd": 0.2089795572862352,
780
- "cpl": 1.1386401663938843,
781
- "ct": 6.579,
782
  "ecc": 0.0,
783
- "jpl": 7.037501694745319,
784
- "mcj": 3.090320483869577,
785
- "mjj": 19.545081228674544,
786
- "opl": 2.265703850679821,
787
  "scc": 0.0,
788
- "sc": 0.0,
789
- "tl": 131.58
790
  },
791
  "RotateValve": {
792
  "success": 1.0,
@@ -807,36 +807,36 @@
807
  },
808
  "suite": {
809
  "success": 0.9975,
810
- "tp": 0.9984999999999999,
811
- "bavd": 0.385797970625376,
812
- "bgvd": 0.05534312049866838,
813
- "cpl": 1.1892187237546599,
814
- "ct": 5.168875,
815
  "ecc": 0.615,
816
- "jpl": 5.621928409623091,
817
- "mcj": 6.046500063456854,
818
- "mjj": 31.444098766035214,
819
- "opl": 1.9007309543642936,
820
- "scc": 0.01,
821
- "sc": 0.0,
822
- "tl": 103.3775
823
  }
824
  },
825
  "score": {
826
  "overall": {
827
- "score": 0.9860614995491191,
828
- "outcome": 0.9978,
829
- "safety": 0.9862526043187881,
830
- "efficiency": 0.9634561864853971,
831
- "coordination": 0.9963121054446111
832
  },
833
  "tasks": {
834
  "LiftPot": {
835
- "outcome": 1.0,
836
- "safety": 0.996078431372549,
837
  "efficiency": 1.0,
838
  "coordination": 1.0,
839
- "score": 0.9988235294117648
840
  },
841
  "LiftTray": {
842
  "outcome": 1.0,
@@ -847,10 +847,10 @@
847
  },
848
  "StackTwoBlocks": {
849
  "outcome": 1.0,
850
- "safety": 0.9886792452830189,
851
- "efficiency": 0.7719269711090793,
852
- "coordination": 0.9704968435568894,
853
- "score": 0.9480388521624105
854
  },
855
  "StackSingleBookShelf": {
856
  "outcome": 1.0,
@@ -875,10 +875,10 @@
875
  },
876
  "PickSingleBookFromTable": {
877
  "outcome": 1.0,
878
- "safety": 1.0,
879
- "efficiency": 0.9374136483938355,
880
  "coordination": 1.0,
881
- "score": 0.9874827296787672
882
  },
883
  "RotateValve": {
884
  "outcome": 1.0,
@@ -890,7 +890,7 @@
890
  }
891
  },
892
  "provenance": {
893
- "created_utc": "2026-10-28T23:00:08+00:00",
894
  "roboeval_version": "4.1.0",
895
  "roboeval_metrics_version": "0.1.0",
896
  "git_commit": "c8b79598c9fb9021652128020517d1847abe4c95",
@@ -915,6 +915,6 @@
915
  "MKL_CBWR": "COMPATIBLE"
916
  }
917
  },
918
- "command": "/home/user/roboeval_orch/RoboEval/roboeval/challenge/evaluate.py --submission submission_pick22 --workers 6 --gpus 0"
919
  }
920
  }
 
122
  "std": 0.0
123
  },
124
  "tp": {
125
+ "mean": 0.99,
126
+ "std": 0.06999999999999999
127
  },
128
  "bavd": {
129
+ "mean": 0.29281951315243276,
130
+ "std": 0.09462814601254968
131
  },
132
  "bgvd": {
133
+ "mean": 0.010165391094207603,
134
+ "std": 0.0046259623922256694
135
  },
136
  "cpl": {
137
+ "mean": 0.6704045530620671,
138
+ "std": 0.07377597417639128
139
  },
140
  "ct": {
141
+ "mean": 2.967,
142
+ "std": 0.1891057904983346
143
  },
144
  "ecc": {
145
  "mean": 0.0,
146
  "std": 0.0
147
  },
148
  "jpl": {
149
+ "mean": 4.098847958860526,
150
+ "std": 0.5163070688299158
151
  },
152
  "mcj": {
153
+ "mean": 9.31802731270813,
154
+ "std": 1.8950421588022368
155
  },
156
  "mjj": {
157
+ "mean": 54.52174808567004,
158
+ "std": 10.309689388763909
159
  },
160
  "opl": {
161
+ "mean": 2.3032091026371906,
162
+ "std": 0.39533000540578506
163
  },
164
  "scc": {
165
+ "mean": 0.0,
166
+ "std": 0.0
167
  },
168
  "sc": {
169
  "mean": 0.0,
170
  "std": 0.0
171
  },
172
  "tl": {
173
+ "mean": 59.34,
174
+ "std": 3.7821158099666907
175
  }
176
  },
177
  "terminations": {
 
266
  "std": 0.0
267
  },
268
  "bavd": {
269
+ "mean": 0.4634347306747833,
270
+ "std": 0.06790829309211645
271
  },
272
  "bgvd": {
273
+ "mean": 0.043299860935331065,
274
+ "std": 0.009997325279898706
275
  },
276
  "cpl": {
277
+ "mean": 1.3696363340760127,
278
+ "std": 0.11070404465857603
279
  },
280
  "ct": {
281
+ "mean": 4.625,
282
+ "std": 0.9430402960637472
283
  },
284
  "ecc": {
285
  "mean": 0.0,
286
  "std": 0.0
287
  },
288
  "jpl": {
289
+ "mean": 5.087932775288036,
290
+ "std": 0.49603342150285495
291
  },
292
  "mcj": {
293
+ "mean": 11.400662600540763,
294
+ "std": 1.663938478009395
295
  },
296
  "mjj": {
297
+ "mean": 48.49792000217093,
298
+ "std": 6.861249973787576
299
  },
300
  "opl": {
301
+ "mean": 1.0252549571857066,
302
+ "std": 0.35946942711610996
303
  },
304
  "scc": {
305
+ "mean": 0.02,
306
+ "std": 0.13999999999999999
307
  },
308
  "sc": {
309
  "mean": 0.0,
310
  "std": 0.0
311
  },
312
  "tl": {
313
+ "mean": 92.5,
314
+ "std": 18.860805921274945
315
  }
316
  },
317
  "terminations": {
 
546
  "std": 0.0
547
  },
548
  "bavd": {
549
+ "mean": 0.9597556843993951,
550
+ "std": 0.25022324245165284
551
  },
552
  "bgvd": {
553
+ "mean": 0.21264552731291023,
554
+ "std": 0.03902639572426828
555
  },
556
  "cpl": {
557
+ "mean": 1.1374091543412113,
558
+ "std": 0.44072051299774695
559
  },
560
  "ct": {
561
+ "mean": 6.22,
562
+ "std": 2.3655866080107915
563
  },
564
  "ecc": {
565
  "mean": 0.0,
566
  "std": 0.0
567
  },
568
  "jpl": {
569
+ "mean": 7.1145422603480055,
570
+ "std": 2.5897285047632086
571
  },
572
  "mcj": {
573
+ "mean": 3.726751704228263,
574
+ "std": 0.6317925151914751
575
  },
576
  "mjj": {
577
+ "mean": 24.362044697427763,
578
+ "std": 8.632357968377242
579
  },
580
  "opl": {
581
+ "mean": 2.344576096088616,
582
+ "std": 0.8547016352563385
583
  },
584
  "scc": {
585
  "mean": 0.0,
586
  "std": 0.0
587
  },
588
  "sc": {
589
+ "mean": 0.02,
590
+ "std": 0.13999999999999999
591
  },
592
  "tl": {
593
+ "mean": 124.4,
594
+ "std": 47.31173216021582
595
  }
596
  },
597
  "terminations": {
 
678
  "per_family": {
679
  "LiftPot": {
680
  "success": 1.0,
681
+ "tp": 0.99,
682
+ "bavd": 0.29281951315243276,
683
+ "bgvd": 0.010165391094207603,
684
+ "cpl": 0.6704045530620671,
685
+ "ct": 2.967,
686
  "ecc": 0.0,
687
+ "jpl": 4.098847958860526,
688
+ "mcj": 9.31802731270813,
689
+ "mjj": 54.52174808567004,
690
+ "opl": 2.3032091026371906,
691
+ "scc": 0.0,
692
  "sc": 0.0,
693
+ "tl": 59.34
694
  },
695
  "LiftTray": {
696
  "success": 1.0,
 
711
  "StackTwoBlocks": {
712
  "success": 1.0,
713
  "tp": 1.0,
714
+ "bavd": 0.4634347306747833,
715
+ "bgvd": 0.043299860935331065,
716
+ "cpl": 1.3696363340760127,
717
+ "ct": 4.625,
718
  "ecc": 0.0,
719
+ "jpl": 5.087932775288036,
720
+ "mcj": 11.400662600540763,
721
+ "mjj": 48.49792000217093,
722
+ "opl": 1.0252549571857066,
723
+ "scc": 0.02,
724
  "sc": 0.0,
725
+ "tl": 92.5
726
  },
727
  "StackSingleBookShelf": {
728
  "success": 1.0,
 
775
  "PickSingleBookFromTable": {
776
  "success": 1.0,
777
  "tp": 1.0,
778
+ "bavd": 0.9597556843993951,
779
+ "bgvd": 0.21264552731291023,
780
+ "cpl": 1.1374091543412113,
781
+ "ct": 6.22,
782
  "ecc": 0.0,
783
+ "jpl": 7.1145422603480055,
784
+ "mcj": 3.726751704228263,
785
+ "mjj": 24.362044697427763,
786
+ "opl": 2.344576096088616,
787
  "scc": 0.0,
788
+ "sc": 0.02,
789
+ "tl": 124.4
790
  },
791
  "RotateValve": {
792
  "success": 1.0,
 
807
  },
808
  "suite": {
809
  "success": 0.9975,
810
+ "tp": 0.99725,
811
+ "bavd": 0.39505469212048305,
812
+ "bgvd": 0.056357355682837666,
813
+ "cpl": 1.186157018476982,
814
+ "ct": 5.11475,
815
  "ecc": 0.615,
816
+ "jpl": 5.6227863565119485,
817
+ "mcj": 6.104427140596522,
818
+ "mjj": 31.951006449470228,
819
+ "opl": 1.9129712498958864,
820
+ "scc": 0.0025,
821
+ "sc": 0.0025,
822
+ "tl": 102.295
823
  }
824
  },
825
  "score": {
826
  "overall": {
827
+ "score": 0.9865902931563009,
828
+ "outcome": 0.997425,
829
+ "safety": 0.9871775025799794,
830
+ "efficiency": 0.9658262433878773,
831
+ "coordination": 0.9978352329278946
832
  },
833
  "tasks": {
834
  "LiftPot": {
835
+ "outcome": 0.9969999999999999,
836
+ "safety": 1.0,
837
  "efficiency": 1.0,
838
  "coordination": 1.0,
839
+ "score": 0.9969999999999999
840
  },
841
  "LiftTray": {
842
  "outcome": 1.0,
 
847
  },
848
  "StackTwoBlocks": {
849
  "outcome": 1.0,
850
+ "safety": 0.996078431372549,
851
+ "efficiency": 0.7805334499711347,
852
+ "coordination": 0.9826818634231562,
853
+ "score": 0.9531984057483073
854
  },
855
  "StackSingleBookShelf": {
856
  "outcome": 1.0,
 
875
  },
876
  "PickSingleBookFromTable": {
877
  "outcome": 1.0,
878
+ "safety": 0.996078431372549,
879
+ "efficiency": 0.947767624751622,
880
  "coordination": 1.0,
881
+ "score": 0.9883770543620891
882
  },
883
  "RotateValve": {
884
  "outcome": 1.0,
 
890
  }
891
  },
892
  "provenance": {
893
+ "created_utc": "2026-11-02T11:29:21+00:00",
894
  "roboeval_version": "4.1.0",
895
  "roboeval_metrics_version": "0.1.0",
896
  "git_commit": "c8b79598c9fb9021652128020517d1847abe4c95",
 
915
  "MKL_CBWR": "COMPATIBLE"
916
  }
917
  },
918
+ "command": "/home/user/roboeval_orch/RoboEval/roboeval/challenge/evaluate.py --submission submission_pick22r --workers 6 --gpus 0"
919
  }
920
  }
submission/checkpoint/PickSingleBookFromTable/hybrid.json CHANGED
@@ -1 +1 @@
1
- {"policy": "hybrid_pk", "cfg": {}}
 
1
+ {"policy": "hybrid_pk", "cfg": {"t_reach": [0.5, 1.6], "t_in": 0.4}}
submission/checkpoint/StackTwoBlocks/hybrid.json CHANGED
@@ -1 +1 @@
1
- {"policy": "hybrid_s2b3"}
 
1
+ {"policy": "hybrid_s2b4", "cfg": {"HOLD_T": 1, "RISE": 0.15}}
submission/policy/hybrid_s2b4.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Hybrid StackTwoBlocks policy v4 (Oct 26 15:20) = v3 with its speeds, heights, waits and step-aside distances as constructor
2
+ options (hybrid.json "cfg"); the defaults are v3's values, so v4 with no cfg is v3. For tuning efficiency (path length, time)
3
+ on training seeds. v3 (Oct 24 21:00): both arms act, so the episode reaches the task's stage 2 (both blocks held
4
+ at the same time; the scorer's task progression counts it, 30% of the outcome term) and the arms move together (the
5
+ coordination metrics compare the two arms' velocities). Perception and kinematics as v2 (hybrid_s2b.py).
6
+
7
+ Plan (from the perceived blocks at the start):
8
+ Mode A (the stacking arm s reaches both blocks): s picks P and stacks it on B; meanwhile the helper arm b grips B where it
9
+ stands, holds it until s holds P (both held: stage 2), opens, rises and goes home; s waits above until b is clear
10
+ and B has been seen again, then stacks.
11
+ Mode B (no single arm reaches both: blocks far apart on opposite sides): both arms pick their own block; b sets B down at
12
+ a meeting point M mid-table and goes home; s, holding P at its side meanwhile, then stacks P on B.
13
+ Actions: 14-D end-effector deltas [dp_L dr_L | dp_R dr_R | g_L g_R] (world frame), grippers 0 open / 1 closed."""
14
+ import numpy as np
15
+
16
+ try:
17
+ from .hybrid_s2b import fk, locate, wrap, BASE_Y, H_GRASP, H_APPROACH, H_CARRY, VMAX, KP, RMAX, KR, NTOP_MIN, Z_TABLE
18
+ except ImportError:
19
+ from hybrid_s2b import fk, locate, wrap, BASE_Y, H_GRASP, H_APPROACH, H_CARRY, VMAX, KP, RMAX, KR, NTOP_MIN, Z_TABLE
20
+
21
+ REACH_A = 0.64 # Mode A if the stacking arm's pick and place both lie within this horizontal distance of its base
22
+ H_GRASP3 = 0.110 # v2's 0.100 put the fingertip pads on the table (an environment collision for the scorer)
23
+ VMAX_FAST = 0.016 # transit speed while > 5 cm from the target (v2: 0.012 everywhere)
24
+ ASIDE = 0.12 # after letting go, arm b moves this far (xy) from B toward its own side
25
+ HOME = (np.array([0.40, 0.32, 1.15]), np.array([0.40, -0.32, 1.15]))
26
+ CLEAR_XY = 0.14 # the stacking arm waits this far (xy) from B while the other arm works there
27
+ DEFAULTS = dict(H_APPROACH=H_APPROACH, H_CARRY=H_CARRY, H_GRASP3=H_GRASP3, VMAX=VMAX, VMAX_FAST=VMAX_FAST, FAST_R=0.05, KP=KP,
28
+ RMAX=RMAX, KR=KR, ASIDE=ASIDE, CLEAR_XY=CLEAR_XY, GRASP_N=10, RELEASE_N=10, RISE=H_APPROACH, HOLD_T=3)
29
+
30
+
31
+ def _reach(arm, xy):
32
+ return float(np.hypot(xy[0], xy[1] - BASE_Y[arm]))
33
+
34
+
35
+ class _Arm:
36
+ def __init__(self, k):
37
+ self.k, self.phase, self.count, self.off, self.zhist, self.recov, self.hold_t = k, "idle", 0, None, [], 0, 0
38
+ self.aside = None
39
+
40
+
41
+ class HybridS2B4:
42
+ carry_queue = False # the bundle's policy.py resets every episode
43
+
44
+ def __init__(self, log=False, **cfg):
45
+ bad = set(cfg) - set(DEFAULTS)
46
+ assert not bad, f"unknown options {bad}"
47
+ self.c = {**DEFAULTS, **cfg}
48
+ self.log = log
49
+ self.reset()
50
+
51
+ def reset(self, episode=None):
52
+ self.t, self.mode, self.s, self.b, self.P, self.B, self.M = 0, None, None, None, None, None, None
53
+ self.blk = [None, None]
54
+ self.arms = [_Arm(0), _Arm(1)]
55
+ self.dirtyB = False # B was gripped or moved by arm b: lower onto it only after a fresh estimate
56
+ self.b_done_t = None # step at which arm b reached "done"
57
+ self.z_rest = Z_TABLE
58
+ self.trace = []
59
+
60
+ # -- helpers --------------------------------------------------------------------------------------------------
61
+ @property
62
+ def arm(self):
63
+ return self.s
64
+
65
+ @property
66
+ def phase(self):
67
+ return self.arms[self.s].phase if self.s is not None else "start"
68
+
69
+ @property
70
+ def recoveries(self):
71
+ return sum(a.recov for a in self.arms)
72
+
73
+ @property
74
+ def plan(self):
75
+ return [self.mode] if self.mode == "A" else [self.mode, self.mode]
76
+
77
+ def _holding(self, obs, k):
78
+ f = float(np.asarray(obs["proprioception_grippers"])[k])
79
+ return 0.15 < f < 0.8
80
+
81
+ def _perceive(self, obs, G, held):
82
+ est = locate(obs)
83
+ if not est:
84
+ return
85
+ if self.P in held and self.B not in held and self.arms[self.b].phase in ("home", "done"):
86
+ low = [e for e in est if e["z"] < Z_TABLE + 0.03 and e["ntop"] >= NTOP_MIN
87
+ and not any(np.linalg.norm(g[0][:2] - e["xy"]) < 0.10 and g[0][2] < e["z"] + 0.16 for g in G)]
88
+ if len(low) == 1:
89
+ self.blk[self.B] = low[0]
90
+ self.dirtyB = False
91
+ return
92
+ for i in (0, 1):
93
+ if i in held:
94
+ continue
95
+ b = self.blk[i]
96
+ e = min(est, key=lambda e: np.linalg.norm(e["xy"] - b["xy"]))
97
+ if np.linalg.norm(e["xy"] - b["xy"]) > 0.04 or e["ntop"] < NTOP_MIN:
98
+ continue
99
+ if any(np.linalg.norm(g[0][:2] - b["xy"]) < 0.10 and g[0][2] < b["z"] + 0.16 for g in G):
100
+ continue
101
+ self.blk[i] = e
102
+ if i == self.B and self.dirtyB and self.arms[self.b].phase in ("home", "done"):
103
+ self.dirtyB = False
104
+
105
+ def _plan(self, G):
106
+ best = None
107
+ for s in (0, 1):
108
+ for P in (0, 1):
109
+ B = 1 - P
110
+ if _reach(s, self.blk[P]["xy"]) > REACH_A or _reach(s, self.blk[B]["xy"]) > REACH_A:
111
+ continue
112
+ cost = np.linalg.norm(G[s][0][:2] - self.blk[P]["xy"]) + np.linalg.norm(self.blk[P]["xy"] - self.blk[B]["xy"]) \
113
+ + 0.5 * np.linalg.norm(G[1 - s][0][:2] - self.blk[B]["xy"])
114
+ if best is None or cost < best[0]:
115
+ best = (cost, s, P, B)
116
+ if best is not None:
117
+ _, self.s, self.P, self.B = best
118
+ self.mode = "A"
119
+ else:
120
+ own = [int(np.argmin([_reach(k, self.blk[i]["xy"]) for k in (0, 1)])) for i in (0, 1)]
121
+ if own[0] == own[1]:
122
+ own[1] = 1 - own[0]
123
+ # the stacking arm: the one nearer its own block (it waits holding it)
124
+ P = int(np.argmin([np.linalg.norm(G[own[i]][0][:2] - self.blk[i]["xy"]) for i in (0, 1)]))
125
+ self.P, self.B, self.s = P, 1 - P, own[P]
126
+ self.mode = "B"
127
+ bx = float(np.clip(self.blk[self.B]["xy"][0], 0.45, 0.55))
128
+ My = BASE_Y[self.s] + np.sign(self.blk[self.B]["xy"][1] - BASE_Y[self.s]) * 0.32
129
+ self.M = np.array([bx, My])
130
+ self.b = 1 - self.s
131
+ if self.mode == "A" and np.linalg.norm(self.blk[self.P]["xy"] - self.blk[self.B]["xy"]) < 0.12:
132
+ self.arms[self.b].phase = "late" # blocks close together: grip B only once P is lifted out of the way
133
+ else:
134
+ self.arms[self.b].phase = "approach"
135
+ self.arms[self.s].phase = "approach"
136
+
137
+ # -- one arm's step -------------------------------------------------------------------------------------------
138
+ def _pick(self, A, gp, gy, gR, i, holding, nxt):
139
+ """approach/descend/grasp block i; returns (target, yaw_ref, grip); on a held grasp sets A.phase = nxt"""
140
+ X = self.blk[i]
141
+ pp, py = np.r_[X["xy"], X["z"]], X["yaw"]
142
+ grip = 0.0
143
+ if A.phase == "approach":
144
+ target, yaw_ref = np.r_[pp[:2], pp[2] + self.c["H_APPROACH"]], py
145
+ if np.linalg.norm(target - gp) < 0.012 and abs(wrap(py - gy, np.pi / 2)) < np.radians(6):
146
+ A.phase = "descend"
147
+ elif A.phase == "descend":
148
+ target, yaw_ref = np.r_[pp[:2], pp[2] + self.c["H_GRASP3"]], py
149
+ if abs(wrap(py - gy, np.pi / 2)) > np.radians(12) and gp[2] < pp[2] + self.c["H_GRASP3"] + 0.02:
150
+ A.phase = "approach"
151
+ elif abs(gp[2] - target[2]) < 0.006 and np.linalg.norm(gp[:2] - pp[:2]) < 0.01:
152
+ A.phase, A.count = "grasp", 0
153
+ elif A.phase == "grasp":
154
+ target, yaw_ref, grip = gp, None, 1.0
155
+ A.count += 1
156
+ if A.count >= self.c["GRASP_N"]:
157
+ if holding:
158
+ rel = gR.T @ (pp - gp)
159
+ rel[1] = 0.0 # the fingers centre the block along the gripper's y axis
160
+ A.off = gR @ rel
161
+ A.phase, A.count = nxt, 0
162
+ else:
163
+ A.recov += 1
164
+ A.phase, A.count = "reopen", 0
165
+ else: # reopen: open, rise, re-approach
166
+ target, yaw_ref = np.r_[gp[:2], pp[2] + self.c["H_APPROACH"]], None
167
+ A.count += 1
168
+ if A.count >= 6 and gp[2] > pp[2] + self.c["H_APPROACH"] - 0.03:
169
+ A.phase = "approach"
170
+ return target, yaw_ref, grip
171
+
172
+ def _place(self, A, gp, pp, dest_xy, z_place, nxt):
173
+ """carry the held block over dest_xy at carry height, lower to z_place, open; then A.phase = nxt"""
174
+ grip = 1.0
175
+ if A.phase == "carry":
176
+ target = np.r_[gp[:2] + (dest_xy - pp[:2]), Z_TABLE + self.c["H_CARRY"]]
177
+ if np.linalg.norm(pp[:2] - dest_xy) < 0.008:
178
+ A.phase, A.zhist = "lower", []
179
+ elif A.phase == "lower":
180
+ target = np.r_[gp[:2] + (dest_xy - pp[:2]), gp[2] - (pp[2] - z_place)]
181
+ A.zhist.append(gp[2])
182
+ blocked = len(A.zhist) > 6 and A.zhist[-7] - gp[2] < 0.002 and pp[2] < z_place + 0.03
183
+ if pp[2] < z_place + 0.004 or blocked:
184
+ A.phase, A.count = "release", 0
185
+ else: # release
186
+ target, grip = gp, 0.0
187
+ A.count += 1
188
+ if A.count >= self.c["RELEASE_N"]:
189
+ A.phase, A.count = nxt, 0
190
+ return target, None, grip
191
+
192
+ def _go_home(self, A, gp, base_z):
193
+ """after letting go of B: straight up until the fingers clear it, then step aside toward this arm's side"""
194
+ Bxy = self.blk[self.B]["xy"]
195
+ if A.phase == "rise":
196
+ target = np.r_[gp[:2], base_z + self.c["RISE"]]
197
+ if gp[2] > base_z + self.c["RISE"] - 0.01:
198
+ A.phase = "home"
199
+ A.aside = np.r_[Bxy[0] - 0.03, Bxy[1] + np.sign(BASE_Y[A.k]) * self.c["ASIDE"], base_z + self.c["RISE"]]
200
+ elif A.phase == "home":
201
+ target = A.aside
202
+ if np.linalg.norm(gp[:2] - Bxy) > self.c["ASIDE"] - 0.01:
203
+ A.phase = "done"
204
+ else: # done
205
+ target = gp
206
+ return target, None, 0.0
207
+
208
+ # -- policy -------------------------------------------------------------------------------------------------------
209
+ def act(self, obs):
210
+ self.t += 1
211
+ a = np.zeros(14, np.float32)
212
+ G = [fk(np.asarray(obs["proprioception"], np.float64)[9 * k:9 * k + 7], k) for k in (0, 1)]
213
+ if self.s is None: # start: no-op; perceive and plan
214
+ est = locate(obs)
215
+ if len(est) < 2:
216
+ est = (est * 2)[:2] if est else [{"xy": np.array([0.5, 0.1]), "z": Z_TABLE, "yaw": 0.0, "ntop": 0, "n": 0},
217
+ {"xy": np.array([0.5, -0.1]), "z": Z_TABLE, "yaw": 0.0, "ntop": 0, "n": 0}]
218
+ self.blk = list(est)
219
+ self._plan(G)
220
+ return a
221
+ S, Bm = self.arms[self.s], self.arms[self.b]
222
+ hold_s, hold_b = self._holding(obs, self.s), self._holding(obs, self.b)
223
+ held = set()
224
+ if S.off is not None:
225
+ held.add(self.P)
226
+ if Bm.off is not None or Bm.phase in ("grasp", "hold"):
227
+ held.add(self.B)
228
+ self._perceive(obs, G, held)
229
+
230
+ # ---- arm b: helper (A) or mover (B) ----
231
+ gp, gy, gR = G[self.b]
232
+ if Bm.phase == "late": # wait (still) until the stacking arm has lifted P clear of the table
233
+ if S.phase in ("wait", "carry") or (S.phase == "lift" and G[self.s][0][2] > Z_TABLE + self.c["H_CARRY"] - 0.06):
234
+ Bm.phase = "approach"
235
+ elif self.t > 150:
236
+ Bm.phase = "done"
237
+ if Bm.phase == "late":
238
+ tb = (gp, None, 0.0)
239
+ elif Bm.phase in ("approach", "descend", "grasp", "reopen"):
240
+ if Bm.phase == "grasp":
241
+ self.dirtyB = True
242
+ nxt = "hold" if self.mode == "A" else "lift"
243
+ tb = self._pick(Bm, gp, gy, gR, self.B, hold_b, nxt)
244
+ if self.mode == "A" and Bm.phase == "reopen": # a helper miss: give up the helper role
245
+ Bm.phase, Bm.count = "release", 0
246
+ elif Bm.phase == "hold": # helper: keep B gripped until the stacking arm holds P (both held)
247
+ tb = (gp, None, 1.0)
248
+ Bm.count += 1
249
+ if (S.off is not None and hold_s and S.phase in ("lift", "wait", "carry")) or Bm.count > 60:
250
+ Bm.hold_t += 1
251
+ if Bm.hold_t >= self.c["HOLD_T"] or Bm.count > 60:
252
+ Bm.phase, Bm.count = "release", 0
253
+ elif Bm.phase == "release" and self.mode == "A":
254
+ tb = (gp, None, 0.0)
255
+ Bm.count += 1
256
+ f = float(np.asarray(obs["proprioception_grippers"])[self.b])
257
+ if (Bm.count >= 5 and f > 0.85) or Bm.count >= 15:
258
+ Bm.phase, Bm.off = "rise", None
259
+ elif Bm.phase == "lift": # mover
260
+ tb = (np.r_[gp[:2], Z_TABLE + self.c["H_CARRY"]], None, 1.0)
261
+ if gp[2] > Z_TABLE + self.c["H_CARRY"] - 0.012:
262
+ Bm.phase = "carry"
263
+ if not hold_b:
264
+ Bm.recov += 1; Bm.off = None; Bm.phase, Bm.count = "reopen", 0
265
+ elif Bm.phase in ("carry", "lower", "release"): # mover: set B down at M
266
+ ppb = gp + Bm.off
267
+ if Bm.phase != "release" and not hold_b:
268
+ Bm.recov += 1; Bm.off = None; Bm.phase, Bm.count = "reopen", 0
269
+ tb = (gp, None, 0.0)
270
+ else:
271
+ was = Bm.phase
272
+ tb = self._place(Bm, gp, ppb, self.M, self.z_rest + 0.002, "rise")
273
+ if was == "release" and Bm.phase == "rise":
274
+ self.blk[self.B] = {"xy": ppb[:2].copy(), "z": Z_TABLE, "yaw": 0.0, "ntop": 0, "n": 0}
275
+ Bm.off = None
276
+ self.dirtyB = True
277
+ else: # rise / home / done
278
+ tb = self._go_home(Bm, gp, Z_TABLE)
279
+ if Bm.phase == "done" and self.b_done_t is None:
280
+ self.b_done_t = self.t
281
+ self._write(a, self.b, gp, gy, *tb)
282
+
283
+ # ---- arm s: stack P on B ----
284
+ gp, gy, gR = G[self.s]
285
+ Bx = self.blk[self.B]
286
+ if S.phase in ("approach", "descend", "grasp", "reopen"):
287
+ ts = self._pick(S, gp, gy, gR, self.P, hold_s, "lift")
288
+ if S.phase == "lift":
289
+ self.z_rest = float(self.blk[self.P]["z"])
290
+ elif S.phase in ("lift", "wait", "carry", "lower") and not hold_s:
291
+ S.recov += 1; S.off = None; S.phase, S.count = "reopen", 0
292
+ ts = (gp, None, 0.0)
293
+ elif S.phase == "lift":
294
+ ts = (np.r_[gp[:2], Z_TABLE + self.c["H_CARRY"]], None, 1.0)
295
+ if gp[2] > Z_TABLE + self.c["H_CARRY"] - 0.012:
296
+ S.phase = "wait"
297
+ elif S.phase == "wait": # until arm b is out of the way and B has been seen again
298
+ pp = gp + S.off
299
+ if self.mode == "A": # B stays put: wait CLEAR_XY from it on this side (back off if closer)
300
+ d = pp[:2] - Bx["xy"]
301
+ n = np.linalg.norm(d)
302
+ stop = Bx["xy"] + d / max(n, 1e-6) * self.c["CLEAR_XY"]
303
+ else: # B is being moved to M by arm b: hold P on this arm's own side
304
+ stop = np.array([pp[0], BASE_Y[self.s] * 0.5]) if abs(pp[1] - BASE_Y[self.s]) > 0.15 else pp[:2]
305
+ ts = (np.r_[gp[:2] + (stop - pp[:2]), Z_TABLE + self.c["H_CARRY"]], None, 1.0)
306
+ far = np.linalg.norm(G[self.b][0][:2] - Bx["xy"]) > self.c["ASIDE"] - 0.02
307
+ ready = Bm.phase in ("home", "done") and far and not self.dirtyB
308
+ if ready or (self.b_done_t is not None and self.t - self.b_done_t > 20):
309
+ S.phase = "carry"
310
+ elif S.phase in ("carry", "lower", "release"):
311
+ pp = gp + S.off
312
+ ts = self._place(S, gp, pp, Bx["xy"], Bx["z"] + 0.042, "retreat")
313
+ else: # retreat
314
+ ts = (np.r_[gp[:2], Z_TABLE + self.c["H_CARRY"]], None, 0.0)
315
+ self._write(a, self.s, gp, gy, *ts)
316
+ if self.log:
317
+ self.trace.append((self.t, self.mode, S.phase, Bm.phase, G[self.s][0].round(3).tolist(), G[self.b][0].round(3).tolist(),
318
+ int(hold_s), int(hold_b)))
319
+ return a
320
+
321
+ def _write(self, a, k, gp, gy, target, yaw_ref, grip):
322
+ off = 6 * k
323
+ e = np.asarray(target) - gp
324
+ c = self.c
325
+ vmax = c["VMAX_FAST"] if np.linalg.norm(e) > c["FAST_R"] else c["VMAX"]
326
+ a[off:off + 3] = np.clip(c["KP"] * e, -vmax, vmax)
327
+ if yaw_ref is not None and np.isfinite(yaw_ref):
328
+ a[off + 5] = np.clip(c["KR"] * wrap(yaw_ref - gy, np.pi / 2), -c["RMAX"], c["RMAX"])
329
+ a[12 + k] = grip
submission/policy/policy.py CHANGED
@@ -23,6 +23,7 @@ except ImportError:
23
  from inference import ACTInference # harness context: policy/ is on sys.path
24
  try: # hand-designed controllers (classical RGB-D perception + scripted control), selected by checkpoint/<family>/hybrid.json
25
  from .hybrid_s2b3 import HybridS2B3
 
26
  from .hybrid_rv import HybridRV
27
  from .hybrid_pb import HybridPB
28
  from .hybrid_ch import HybridCH
@@ -31,13 +32,14 @@ try: # hand-designed controllers (classical RGB-D perception + scripted control
31
  from .hybrid_ss import HybridSS
32
  except ImportError:
33
  from hybrid_s2b3 import HybridS2B3
 
34
  from hybrid_rv import HybridRV
35
  from hybrid_pb import HybridPB
36
  from hybrid_ch import HybridCH
37
  from hybrid_lt import HybridLT
38
  from hybrid_pk import HybridPK
39
  from hybrid_ss import HybridSS
40
- HYBRIDS = {"hybrid_s2b3": HybridS2B3, "hybrid_rv": HybridRV, "hybrid_pb": HybridPB, "hybrid_ch": HybridCH, "hybrid_lt": HybridLT, "hybrid_pk": HybridPK, "hybrid_ss": HybridSS}
41
  class _Policy:
42
  def __init__(self, checkpoint_dir):
43
  self._checkpoint_dir = Path(checkpoint_dir)
 
23
  from inference import ACTInference # harness context: policy/ is on sys.path
24
  try: # hand-designed controllers (classical RGB-D perception + scripted control), selected by checkpoint/<family>/hybrid.json
25
  from .hybrid_s2b3 import HybridS2B3
26
+ from .hybrid_s2b4 import HybridS2B4
27
  from .hybrid_rv import HybridRV
28
  from .hybrid_pb import HybridPB
29
  from .hybrid_ch import HybridCH
 
32
  from .hybrid_ss import HybridSS
33
  except ImportError:
34
  from hybrid_s2b3 import HybridS2B3
35
+ from hybrid_s2b4 import HybridS2B4
36
  from hybrid_rv import HybridRV
37
  from hybrid_pb import HybridPB
38
  from hybrid_ch import HybridCH
39
  from hybrid_lt import HybridLT
40
  from hybrid_pk import HybridPK
41
  from hybrid_ss import HybridSS
42
+ HYBRIDS = {"hybrid_s2b3": HybridS2B3, "hybrid_s2b4": HybridS2B4, "hybrid_rv": HybridRV, "hybrid_pb": HybridPB, "hybrid_ch": HybridCH, "hybrid_lt": HybridLT, "hybrid_pk": HybridPK, "hybrid_ss": HybridSS}
43
  class _Policy:
44
  def __init__(self, checkpoint_dir):
45
  self._checkpoint_dir = Path(checkpoint_dir)