File size: 3,422 Bytes
1e1de0b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9b38f2b
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# ManiGuard datagen-v1 robot config -- single-arm Franka (7 arm joints + 1 gripper), 2 cameras.
#
# Maps the datagen LeRobot v2.1 features to LingBot's unified feature space. The datagen
# datasets ship FLAT keys (state / actions / image_left / wrist_image) instead of the
# observation.* names used by the RoboTwin sample. That is fine: `origin_keys` is a
# free-form lookup into the LeRobot item (see lingbotvla/data/vla_data/utils.py --
# `out_item[target_key] = item[convert_info['origin_keys']]`), and check_robot_config only
# validates the TARGET side (the unified names must be declared in the training config's
# data.joints / data.cameras). So no dataset conversion is required: the six datagen
# datasets stay read-only and byte-identical to the ones the pi0.5 / pi0 / GR00T / SmolVLA
# tracks train on -- the whole point of the ManiGuard benchmark's same-data guarantee.
#
# 8-D layout of both `state` and `actions`: [arm_q(7), gripper(1)]
#   arm.position      <- [0:7)
#   effector.position <- [7:8)
# The unified vector is 55-D; the dims we do not fill are padded/masked by the loader
# (data.joints keeps the pretraining-aligned sizes, incl. an unused end.position entry).
#
# subtract_state: False on BOTH features -- the model learns ABSOLUTE joint targets.
# This follows LingBot's own simulation recipe (configs/robot_configs/robotwin.yaml, where
# both features use False; state-relative arm actions are the recommendation for REAL-robot
# data) and matches our datasets, whose `actions` are absolute joint positions.
# => At eval the server's output is fed straight to the JointController with NO
#    delta/un-relative step (same contract as SmolVLA; pi0.5/pi0/GR00T do add state back).
#
# Cameras: the policy consumes 2 views -- the `left` overview + wrist -- identical to the
# other four base models (benchmark parity). The datagen datasets also ship three more
# overviews (image_opposite / image_right / image_left_shoulder); they are simply not mapped.
#
# norm_stats below is a DEFAULT: every family has its own statistics, so run_sft.sh passes
# `--data.norm_stats_file assets/norm_stats/maniguard_<family>.json` per run, which takes
# precedence (FeatureTransform: an explicit norm_stats_path overrides the robot config's).

states:
  - observation.state.arm.position:
      origin_keys:
        - state:
            start: 0
            end: 7

  - observation.state.effector.position:
      origin_keys:
        - state:
            start: 7
            end: 8

actions:
  - action.arm.position:
      origin_keys:
        - actions:
            start: 0
            end: 7
      subtract_state: False

  - action.effector.position:
      origin_keys:
        - actions:
            start: 7
            end: 8
      subtract_state: False

images:
  - observation.images.camera_top:
      origin_keys: image_left
  - observation.images.camera_wrist_left:
      origin_keys: wrist_image

# norm_stats points at THIS checkpoint's own statistics (the file shipped beside this
# one). It must stay present even when a loader passes an explicit path: LingBot's
# FeatureTransform does `robot_config.pop('norm_stats')` with no default on both
# branches, so a missing key raises KeyError. The path is relative to this checkpoint's
# root -- resolve it yourself, or pass an absolute `norm_stats_path`
# (maniguard/serve/lingbot_native.py does the latter).
norm_stats: maniguard/norm_stats.json