
DROID standardised the robot at 13 institutions and let the scenes vary. Here is what the LeRobot merge really enforces, what it silently accepts, and how to plan a multi-site recording fleet.
One arm on one desk produces a policy that works on that desk. That is the most repeatable result in low-cost manipulation learning, and it is why teams start looking for a second room. Recording the same task at three sites is not three times the data. It is a different kind of data, and it only pays off if the three recordings pour into one LeRobot dataset without anyone rewriting metadata by hand.
This page covers the mechanics: which fields the merge refuses to reconcile, which differences it accepts in silence, what the DROID team standardised across 13 institutions, and the commands that turn three site folders into one training set. Every LeRobot detail comes from lerobot 0.6.2 on main, read on 24 August 2026. Upstream moves, so check the version before copying flags.
What you need to know
- •Three things block a merge outright: fps, robot_type, and the feature dictionary (camera key names, tensor shapes, joint name lists). LeRobot raises ValueError and stops.
- •The video codec is compared too. video.codec and video.pix_fmt are read off the stream, not exempted as encoder settings, so two sites whose machines pick different encoders will not merge. Pin --dataset.rgb_encoder.vcodec.
- •Everything a policy needs in order to generalise is free to vary: lighting, background, table height, camera pose, operator, object instance, clutter.
- •DROID shipped the same Franka Panda, two Zed 2 cameras and a 15 Hz control loop to 13 institutions, then let 50 collectors choose their own scenes across 52 buildings. Its ablation: 7362 trajectories from the 20 densest scenes lost to 7362 uniformly sampled diverse ones out of distribution.
- •Merge with lerobot-edit-dataset --operation.type merge. It pools statistics correctly, but unifies task strings by exact match, so wording and casing must be agreed in advance.
- •You cannot hand a list of repo ids to lerobot-train. make_dataset raises NotImplementedError for MultiLeRobotDataset, so merging first is not optional.
- •GR00T is the exception: its fine-tune entry point takes several dataset roots separated by os.pathsep, with --ds-weights-alpha controlling the mixture.
What recording in several places actually buys
The strongest public evidence comes from DROID, designed as a distributed collection effort rather than a single-lab dataset. The team built one hardware platform and replicated it 18 times: a Franka Emika Panda 7 DoF arm with a Robotiq 2F-85 gripper, two adjustable Zed 2 stereo cameras on tripods, a wrist-mounted Zed Mini, all on a height-adjustable standing desk with wheels so the station could be pushed into a different room. Actions were recorded in both joint space and end-effector space at 15 Hz.
| Quantity | DROID value | What it implies for a small fleet |
|---|---|---|
| Successful trajectories | 76,000 | A further 16k were labelled not successful. They ship in the release but do not count toward the size of DROID |
| Interaction time | 350 hours | Collected over 12 months, so throughput per station was modest |
| Scenes | 564 | Collectors switched scene roughly every 20 minutes, up to about 100 trajectories per scene |
| Buildings | 52 | Scene diversity came from moving between buildings, not from rearranging one table |
| Tasks | 86 | A randomly sampled task per episode, so easy ones did not dominate. The arXiv listing abstract still says 84 |
| Institutions | 13 | Identical hardware at every one |
| Robots | 18 | One platform design, replicated, updates rolled out fleet-wide |
| Data collectors | 50 | North America, Asia and Europe |
| Camera viewpoints | 1417 | Third-person cameras were deliberately moved and re-calibrated during collection |
The number that matters is not the headline size, it is the ablation in section V-C, "How important is the scene diversity in DROID?". The authors built two subsets of equal size: 7362 trajectories from the 20 scenes with the most demonstrations each, against 7362 successful demonstrations sampled uniformly at random. Same trajectory count, very different scene coverage, and the diverse subset won out of distribution. In the headline comparison, across 6 tasks in 4 locations, co-training with full DROID beat the next best method by 22 percent absolute success rate in distribution and 17 percent out of distribution.
Hold on to that when someone proposes a second arm in the same lab. Two arms in one room give you throughput. Two arms in two buildings give you throughput plus the thing that actually fixes a policy that only works in one setup. If the budget covers exactly one extra arm, the second room is usually the better spend.
The three fields that must be identical
LeRobot does not guess. Before it copies a frame, the merge loads the metadata of every source and compares three things against the first in the list. If any differ, it raises and stops. The check itself, from src/lerobot/datasets/aggregate.py in lerobot 0.6.2:
fps = all_metadata[0].fps
robot_type = all_metadata[0].robot_type
features = all_metadata[0].features
for meta in tqdm.tqdm(all_metadata, desc="Validate all meta data"):
if fps != meta.fps:
raise ValueError(f"Same fps is expected, but got fps={meta.fps} instead of {fps}.")
if robot_type != meta.robot_type:
raise ValueError(
f"Same robot_type is expected, but got robot_type={meta.robot_type} instead of {robot_type}."
)
if not features_equal_for_merge(features, meta.features):
raise ValueError(
f"Same features is expected, but got features={meta.features} instead of {features}."
)| Property | Merge behaviour | Where it comes from |
|---|---|---|
| fps | ValueError if any source differs | The camera config at record time, written to meta/info.json |
| robot_type | ValueError if any source differs | --robot.type on the record command |
| Set of feature keys | ValueError if the key sets differ at all | Camera names from --robot.cameras, prefixed observation.images. |
| Feature dtype | ValueError if it differs | video versus image storage, float32 versus float64 state |
| Feature shape | ValueError if it differs | Camera resolution, e.g. [480, 640, 3], and state or action vector length |
| Feature names list | ValueError if it differs | Joint naming, e.g. main_shoulder_pan versus shoulder_pan.pos |
| video.codec, video.pix_fmt | ValueError if either differs | Derived from the stored stream, so the encoder each machine actually used |
| Six encoder tuning keys: g, crf, preset, fast_decode, extra_options, video_backend | Ignored during validation, reconciled afterwards | VIDEO_ENCODER_INFO_KEYS in configs/video.py. Keys the sources disagree on become null, with a warning |
| Task strings | Not validated. Unified by exact string match | --dataset.single_task, or whatever the operator typed |
The encoder exemption is narrower than it looks. features_equal_for_merge strips exactly six keys from a video feature before comparing: video.g, video.crf, video.preset, video.fast_decode, video.extra_options and video.video_backend. Two keys people assume are in that set are not. video.codec and video.pix_fmt are derived from the stored stream, so they stay in the comparison, and the recorder's vcodec resolves per machine: left on auto it takes the first available hardware encoder and falls back to libsvtav1 when there is none. Two sites running the same script on different machines can write two different codec strings, and that is a ValueError at merge time, not a harmless difference. Resolution is not exempt either, since it lives in the feature shape.
lerobot/svla_so100_pickplace and lerobot/svla_so101_pickplace are both 50-episode SO-100 class pick-and-place sets, both LeRobot v3.0, both 30 fps, both 640x480, both av1. They still carry three independent merge blockers, although validate_all_metadata only reports the first one it reaches: robot_type is so100 against so100_follower, the joint names are main_shoulder_pan style against shoulder_pan.pos style, and the camera keys are top plus wrist against up plus side. Fix the robot_type and the next run fails on the features instead. If the reference datasets drift this far apart, three volunteers recording in three cities certainly will.
// lerobot/svla_so100_pickplace meta/info.json (condensed)
"robot_type": "so100", "codebase_version": "v3.0", "fps": 30,
"features": {
"action": { "names": ["main_shoulder_pan", "main_shoulder_lift", "main_elbow_flex",
"main_wrist_flex", "main_wrist_roll", "main_gripper"] },
"observation.images.top": { "shape": [480, 640, 3], "info": { "video.codec": "av1" } },
"observation.images.wrist": { "shape": [480, 640, 3], "info": { "video.codec": "av1" } }
}
// lerobot/svla_so101_pickplace meta/info.json (condensed)
"robot_type": "so100_follower", "codebase_version": "v3.0", "fps": 30,
"features": {
"action": { "names": ["shoulder_pan.pos", "shoulder_lift.pos", "elbow_flex.pos",
"wrist_flex.pos", "wrist_roll.pos", "gripper.pos"] },
"observation.images.up": { "shape": [480, 640, 3], "info": { "video.codec": "av1" } },
"observation.images.side": { "shape": [480, 640, 3], "info": { "video.codec": "av1" } }
}What should vary, and by how much
Everything the validator does not look at is fair game, and most of it should move. DROID put this in the tooling rather than the guidelines: the collection GUI periodically prompted the operator to perform a randomly sampled scene augmentation, drawn from nudges to the mobile base, moving and re-calibrating the third-person cameras, changing the room lighting, and adding or removing items. Diversity was a scheduled interruption, not a hope.
- Room, table, and background. This is the whole point of a second site and costs nothing extra.
- Lighting. Window light at different times of day beats one ring light in three rooms.
- Third-person camera pose. DROID ended up with 1417 distinct viewpoints and treated that as a headline feature.
- Object instances. Same task, different mug, different cube colour.
- Clutter. DROID collectors were told to pick scenes with a healthy amount of it.
- Operator. Different hands produce different approach angles and pause patterns.
- Start pose randomisation, within whatever range your gripper can recover from.

One variation looks harmless and is not: wrist camera mounting. The wrist view is what most policies use to decide when to close the gripper, so a rotated wrist camera at one site is not scene diversity, it is a conflicting sensor definition wearing the same feature key. Nothing in the merge catches it, because the shape and the key name are unchanged. Fix the mount with a printed part and a photograph in the contract sheet.
Write the site contract before anyone records
The merge validator is a late, blunt check: it tells you the datasets are incompatible after three people have each spent a week recording. The cheap version is a one-page contract every site signs off before episode zero, plus a five-minute verification run per site that produces a metadata dump you can diff.
| Contract item | Fixed by | Verify with |
|---|---|---|
| Arm model and firmware | Buying the same arm, e.g. all sites on the SO-100 | Photo of the build plus a calibration file per arm |
| robot_type string | The exact --robot.type value, written down verbatim | jq -r .robot_type meta/info.json |
| Camera count and key names | The --robot.cameras dictionary, copy-pasted between sites | jq -r '.features | keys' meta/info.json |
| Camera resolution | width and height in the camera config | The shape field of each observation.images.* feature |
| Video codec | --dataset.rgb_encoder.vcodec pinned to one value, never left on auto | The video.codec and video.pix_fmt keys under each camera feature |
| fps | fps in the camera config | jq -r .fps meta/info.json |
| Joint naming | Same lerobot version at every site | The names list under action and observation.state |
| Task string | --dataset.single_task, agreed character for character | meta/tasks.parquet |
| Episode length policy | A written rule, e.g. stop at 20 seconds or on success | Average episode time from the info operation |
| Success labelling | A written rule for what counts as a success | Your own notes. LeRobot carries no success flag by default |
A fleet means arms assembled by people you are not standing next to. Feetech STS3215 servos on the SO-100 and SO-101 run on 7.4 V. Feeding them 12 V destroys them. The Koch v1.1 uses 5 V and 12 V rails and the LeKiwi mixes a 7.4 V arm with a 12 V base, so a shared box of power bricks across a mixed fleet is a genuine hazard. Label every brick, and check the label at each site before anyone plugs anything in.
- Scene diversity, which the DROID ablation shows matters more than raw trajectory count at equal size
- Parallel throughput: three operators produce three times the episodes in the same week
- A natural held-out site, if you decline to merge one of them
- Hardware failures do not stop the effort, because the other sites keep recording
- Different operators contribute real variation in approach angle and timing
- Every site is one more chance for a metadata mismatch that only surfaces at merge time
- Calibration drift is invisible remotely and pollutes the pooled normalisation statistics
- Task strings diverge unless someone owns them centrally
- Coordinating three people is a management job, not a technical one
- Storage and transfer cost multiplies, and video is the bulk of it
Merging: the actual commands
The tool is lerobot-edit-dataset, a console script in the lerobot package. It exposes nine operations: delete_episodes, split, merge, remove_feature, modify_tasks, convert_image_to_video, recompute_stats, reencode_videos and info. Merge runs aggregate_datasets underneath. Note the ordering: fix the strings and drop the bad episodes first, because the merge rewrites episode indices and afterwards you no longer know which came from where.
- 1Install and read all three datasets before touching anything
The info operation prints repo id, total episodes, total tasks, total frames, average frames per episode, average episode time, fps and size on disk. With show_features it dumps the feature dictionary as JSON, which is what you diff between sites. It does not print robot_type, so read that from meta/info.json separately.
bashpip install 'lerobot[dataset]' for SITE in berlin lisbon tallinn; do echo "===== $SITE" lerobot-edit-dataset \ --repo_id myorg/pickplace_$SITE \ --operation.type info \ --operation.show_features true jq -r '.robot_type, .fps' ~/.cache/huggingface/lerobot/myorg/pickplace_$SITE/meta/info.json done - 2Normalise the task strings
The merge builds its task table with pd.concat(...).index.unique(), so two spellings of one instruction survive as two tasks and a task-conditioned policy treats them as two goals. This operation modifies in place, so copy first if you care.
bashlerobot-edit-dataset \ --repo_id myorg/pickplace_lisbon \ --operation.type modify_tasks \ --operation.task_replacements '{"pick up the cube and put it in the box": "Pick up the cube and place it in the box."}' - 3Delete the episodes you already know are broken
Blocked cameras, a servo that sagged, a run where the operator gave up. Do it per site, while the episode indices still mean something locally.
bashlerobot-edit-dataset \ --repo_id myorg/pickplace_tallinn \ --new_repo_id myorg/pickplace_tallinn_clean \ --operation.type delete_episodes \ --operation.episode_indices "[7, 19, 20, 41]" - 4Merge
new_repo_id is required for merge, and repo_id is the one argument that is not. Pass roots when the datasets sit at explicit local paths rather than under $HF_LEROBOT_HOME. Episode and frame indices get constant offsets in the order you list the sources, task indices are recomputed from the stable task strings, and video timestamps are shifted per source file.
bashlerobot-edit-dataset \ --new_repo_id myorg/pickplace_fleet \ --new_root /data/pickplace_fleet \ --operation.type merge \ --operation.repo_ids "['myorg/pickplace_berlin', 'myorg/pickplace_lisbon', 'myorg/pickplace_tallinn_clean']" \ --operation.roots "['/data/berlin', '/data/lisbon', '/data/tallinn_clean']" - 5Check the totals and the task table
Total episodes should equal the sum of the three sources. Total tasks should equal the number of distinct instructions you intended, not the number of sites. If it came out as three when you meant one, step two did not take.
bashlerobot-edit-dataset \ --repo_id myorg/pickplace_fleet \ --root /data/pickplace_fleet \ --operation.type info \ --operation.show_features false - 6Push it, or keep it local
push_to_hub is a top-level flag and every operation honours it, merge included, so add it to the merge rather than running a second command. Do not use recompute_stats as a way to push: with neither --new_repo_id nor --new_root set it copies the dataset to <repo_id>_recomputed_stats and pushes that instead, and in-place recomputation refuses to run without --operation.overwrite true.
bash# push straight from the merge, rather than as a second step lerobot-edit-dataset \ --new_repo_id myorg/pickplace_fleet \ --new_root /data/pickplace_fleet \ --operation.type merge \ --operation.repo_ids "['myorg/pickplace_berlin', 'myorg/pickplace_lisbon', 'myorg/pickplace_tallinn_clean']" \ --operation.roots "['/data/berlin', '/data/lisbon', '/data/tallinn_clean']" \ --push_to_hub true
finalize_aggregation calls aggregate_stats over the source stats: new min is the min of the mins, new max the max of the maxes, mean and standard deviation pooled weighted by each source's sample count. Correct pooling, and also why one miscalibrated arm quietly widens the normalisation range for every site. Quantiles are the documented exception: they cannot be recovered exactly from per-source summaries, so lerobot keeps a conservative envelope, min for lower quantiles and max for upper ones, and the code calls those bounds rather than global estimates. If a joint at one site reads ten degrees off from a bad calibration, the merged stats absorb the offset and every batch is normalised against it. Check the per-site min and max before merging, not after.
Weighting the sites, and why you usually cannot
Once merged, the sites are indistinguishable. There is no site column and no sampler that draws evenly from three unequal contributions. If Berlin recorded 300 episodes and Tallinn managed 60, the merged set is 83 percent Berlin and your policy learns Berlin's lighting as the default world. There are two honest ways around it and both have a cost.
| Approach | How | Cost |
|---|---|---|
| Cap before merging | Use the split operation on the large site and merge only one split | You throw away real data |
| Duplicate the small site | Merge the small dataset in twice | Pooled statistics skew toward it, and identical frames appear twice per epoch |
| Let it be unbalanced | Merge as recorded | Honest, and often fine if the small site is at least 20 percent of the total |
| Use GR00T's mixture flags | Pass several dataset roots and set --ds-weights-alpha | GR00T only, and it changes how the loader samples rather than what the dataset contains |
That last row is the one real escape hatch, and it belongs to NVIDIA rather than LeRobot. The GR00T N1.7 fine-tune entry point takes dataset_path, documented as "Path to one dataset root, or an os.pathsep-separated list of dataset roots", and ds_weights_alpha, a power-law exponent where each dataset's sampling weight is len(dataset) to the power alpha and per-dataset mix_ratio values are ignored once it is set. Alpha of 1 samples in proportion to size, which is what merging gives you anyway. Alpha of 0 makes every weight 1, so every site is sampled equally. The default is None, so the flag is off unless you set it.
# Isaac-GR00T, gr00t/experiment/launch_finetune.py
# dataset_path is split on os.pathsep (":" on Linux)
python -m gr00t.experiment.launch_finetune \
--base-model-path nvidia/GR00T-N1.7-3B \
--dataset-path /data/berlin:/data/lisbon:/data/tallinn \
--embodiment-tag new_embodiment \
--ds-weights-alpha 0.0 \
--output-dir /data/outFor every other policy, merging is mandatory. In lerobot 0.6.2 make_dataset raises NotImplementedError when repo_id is not a string, with the MultiLeRobotDataset branch sitting unreachable behind it. Passing a list of datasets to SmolVLA or ACT training is not a supported path today, whatever older tutorials suggest.

Do it yourself, or do it here
You own the arms, the machines and the merge. Each site runs lerobot-record against its own arm, ships the folder, and one person runs the merge and the training. Fewest moving parts, most manual coordination.
# Run this identical command at every site.
# Only --robot.port, --robot.id and the camera indices may differ.
lerobot-record \
--robot.type=so100_follower \
--robot.port=/dev/ttyACM0 \
--robot.id=site_berlin_follower \
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, wrist: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}" \
--teleop.type=so100_leader \
--teleop.port=/dev/ttyACM1 \
--teleop.id=site_berlin_leader \
--dataset.repo_id=myorg/pickplace_berlin \
--dataset.num_episodes=100 \
--dataset.single_task="Pick up the cube and place it in the box." \
--dataset.rgb_encoder.vcodec=h264- One GPU or a rented one per training run, plus somewhere to hold three copies of the video before merging.
- A person who owns the contract sheet and checks each site's meta/info.json before recording starts in earnest.
- Pin the version and the extras. lerobot-record needs
pip install 'lerobot[core_scripts]', lerobot-edit-dataset needspip install 'lerobot[dataset]'. Nothing stops a site upgrading lerobot mid-collection and changing the joint naming convention under you.
The platform covers the recording and training ends, not the merge. The desktop client from the download page records LeRobot datasets straight out of a teleoperation session, so each site produces the same format without anyone assembling a command line. Operator work is how you staff sites you do not sit in yourself.
Once merged, the dataset can come from a Hugging Face repo id or from your own machine, and the training form picks a model and hyperparameters and rents a GPU on a spot market sized by the required VRAM. The CLI and the MCP server expose the same operations if you would rather script it.
There is no fleet merge button. The lerobot-edit-dataset steps above are yours to run, on your own machine, before you point a training run at the result. The platform's contribution to multi-site work is that every site's client writes the same LeRobot format, which removes the most common cause of merge failure rather than the merge step itself.
Where multi-site collection does not help
Three sites will not rescue a task a single site cannot demonstrate cleanly. If the policy fails because the gripper cannot hold the object or the wrist camera cannot see the contact point, adding rooms multiplies the same flaw. Fix the task at one site, get a working checkpoint, and only then scale. The data quality guide is the prerequisite for this page.
Three further limits are worth stating plainly, because none are fixed by adding sites. The third catches teams who assume a distributed dataset implies a distributed deployment.
- No held-out site. The merged dataset has no site column, and lerobot's eval_split holds out the last ceil(n * eval_split) episodes per task rather than a sample per location. Because the merge appends sources in the order you list them and offsets episode indices by a constant, that tail is mostly whichever site you merged last: an accidental held-out site, not a chosen one. For a real cross-environment test, leave one site unmerged and evaluate on its arm.
- No seed in GR00T. Its fine-tune entry point exposes none, so two runs on two site mixtures are not bit-for-bit comparable and a small success-rate gap may be run-to-run noise. lerobot's default seed is 1000, so ACT, SmolVLA and Pi0.5 comparisons are on firmer ground.
- Unchanged inference latency. The control loop is 20 to 485 ms per action step depending on the model, and running the policy on a cloud GPU while the arm sits in another country adds public-internet round trips on top. Workable for slow pick-and-place, not for fast reactive motion, whatever the training data looked like.
There is also a format trap on the way in. GR00T N1.7 and N1.5 want LeRobot v2.0 or v2.1, and a v3.0 dataset crashes the GR00T loader, so a freshly merged v3.0 fleet dataset has to be converted down before a GR00T run. Pi0.5, SmolVLA and ACT take v3.0 directly, and the dataset rejected as v3 page covers the conversion. How heterogeneous data behaves once pooled is the subject of Open X-Embodiment, which pooled 60 datasets from 34 labs into 22 embodiments and had to coarsely align action spaces to do it, accepting that camera observations still varied substantially across sources.
Staff the second site without buying a second building
Operators drive real SO-100 arms over the internet and record LeRobot episodes from wherever they are. That is the labour half of multi-site collection, and it is the half that is hardest to hire locally.
See how operator work runsHow many sites do I actually need?▾
No threshold in the literature applies to a two-arm setup. What DROID showed is that at a fixed trajectory count, spreading trajectories across many scenes beat concentrating them in 20 scenes out of distribution. Two rooms is meaningfully better than one. The platform minimums are per policy and count pooled episodes, not sites: 50 episodes for GR00T N1.7, GR00T N1.5, Pi0.5 and ACT, 30 for SmolVLA.
Can I merge datasets recorded on an SO-100 and an SO-101?▾
Only if both were recorded with the same robot_type string, joint names, camera keys, resolution and codec. The arms are mechanically close enough that people assume this works, but LeRobot compares the recorded metadata, not the hardware. The two official svla pick-and-place datasets are the cautionary example: same class of arm, three separate mismatches, no merge.
Do I have to recompute statistics after merging?▾
No. finalize_aggregation pools the source statistics: min of mins, max of maxes, count-weighted mean and standard deviation. Quantiles are pooled as a conservative envelope rather than exact global values, which the code documents. Run recompute_stats if you deleted episodes afterwards, or want relative-action statistics. Watch the output path: without --new_repo_id it writes to
What if one site records at 60 fps and the rest at 30?▾
The merge refuses. Re-record that site, or treat it as a separate dataset and train separately. There is no downsampling operation in lerobot-edit-dataset as of 0.6.2. This is why fps belongs in the contract sheet rather than in the recording script's defaults, and the same argument applies to the video codec, since video.codec is compared as well.
Can I keep track of which site each episode came from?▾
Not through a dedicated field. The usual workaround encodes the site in the task string, which makes it visible in meta/tasks.parquet but splits your task table and changes what a task-conditioned policy sees. The cleaner one is to record the episode ranges per site before merging, since episode indices are offset by a constant per source and stay in source order.
Does the platform merge my site datasets for me?▾
No. Recording, training and inference are covered; the merge is a lerobot-edit-dataset step you run yourself. What the platform removes is the more common failure, three sites producing three different formats, because every desktop client writes the same LeRobot structure from a teleoperation session.
Sources
- DROID: A Large-Scale In-The-Wild Robot Manipulation Dataset (arXiv listing; its abstract field still states 84 tasks)
- DROID v2 full text: hardware platform, 15 Hz control loop, 52 buildings, and the 7362-trajectory scene diversity ablation in section V-C
- DROID project page: same hardware setup across all 13 institutions, 86 tasks, 1417 camera viewpoints
- DROID documentation: hardware shopping list, software setup, camera calibration workflow
- Open X-Embodiment full text: 60 datasets from 34 labs, 22 embodiments, RLDS, coarsely aligned action spaces
- lerobot aggregate.py: validate_all_metadata, aggregate_datasets, finalize_aggregation, and the task table built with pd.concat(...).index.unique()
- lerobot-edit-dataset: the nine operations, their verbatim usage examples, and the recompute_stats output-path rule
- lerobot feature_utils.py: features_equal_for_merge and the exact scope of the video encoder exemption
- lerobot configs/video.py: VIDEO_ENCODER_INFO_KEYS, and the note that vcodec and pix_fmt are derived from the stream rather than exempted
- lerobot factory.py: make_dataset raises NotImplementedError for MultiLeRobotDataset, and the per-task eval_split rule
- lerobot compute_stats.py: aggregate_stats pools min, max and a count-weighted mean, and bounds quantiles
- lerobot-record: the recording flags used at each site, including --dataset.rgb_encoder.vcodec
- lerobot/svla_so100_pickplace meta/info.json: robot_type so100, main_* joint names, top and wrist cameras
- lerobot/svla_so101_pickplace meta/info.json: robot_type so100_follower, *.pos joint names, up and side cameras
- Isaac-GR00T FinetuneConfig: dataset_path as an os.pathsep-separated list, ds_weights_alpha, and no seed field
Sources
- DROID: A Large-Scale In-The-Wild Robot Manipulation Dataset (arXiv listing; its abstract field still states 84 tasks)
- DROID v2 full text: hardware platform, 15 Hz control loop, 52 buildings, and the 7362-trajectory scene diversity ablation in section V-C
- DROID project page: same hardware setup across all 13 institutions, 86 tasks, 1417 camera viewpoints
- DROID documentation: hardware shopping list, software setup, camera calibration workflow
- Open X-Embodiment full text: 60 datasets from 34 labs, 22 embodiments, RLDS, coarsely aligned action spaces
- lerobot aggregate.py: validate_all_metadata, aggregate_datasets, finalize_aggregation, and the task table built with pd.concat(...).index.unique()
- lerobot-edit-dataset: the nine operations, their verbatim usage examples, and the recompute_stats output-path rule
- lerobot feature_utils.py: features_equal_for_merge and the exact scope of the video encoder exemption
- lerobot configs/video.py: VIDEO_ENCODER_INFO_KEYS, and the note that vcodec and pix_fmt are derived from the stream rather than exempted
- lerobot factory.py: make_dataset raises NotImplementedError for MultiLeRobotDataset, and the per-task eval_split rule
- lerobot compute_stats.py: aggregate_stats pools min, max and a count-weighted mean, and bounds quantiles
- lerobot-record: the recording flags used at each site, including --dataset.rgb_encoder.vcodec
- lerobot/svla_so100_pickplace meta/info.json: robot_type so100, main_* joint names, top and wrist cameras
- lerobot/svla_so101_pickplace meta/info.json: robot_type so100_follower, *.pos joint names, up and side cameras
- Isaac-GR00T FinetuneConfig: dataset_path as an os.pathsep-separated list, ds_weights_alpha, and no seed field
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started