
Episode length only means something next to chunk size. What the LeRobot defaults do, why k/T predicts trouble, and how much supervision padding quietly removes.
What you need to know
- •lerobot-record ships with episode_time_s=60, reset_time_s=60, fps=30 and num_episodes=50. The 60 seconds is a timeout you hit by accident, not a length anybody recommends.
- •Real LeRobot reference datasets are much shorter. lerobot/svla_so101_pickplace averages 238.8 frames per episode, which is 8.0 seconds at 30 fps.
- •Episode length means nothing on its own. The number that predicts trouble is k/T: chunk size divided by episode length in frames.
- •ACT's default chunk_size of 100 covers 3.33 seconds at 30 fps. On an 8 second episode that is 42 percent of the entire task predicted from one camera frame.
- •The last chunk_size minus 1 frames of every episode produce a partly padded target. At k=100 on a 240 frame episode that is 41 percent of your frames.
- •Padded steps are masked out of the ACT loss, so they do not corrupt training. They quietly remove supervision instead: 21 percent of all action steps in that same case.
- •Longer is not automatically better. Long episodes add reset drift, operator fatigue and several valid solutions to the same task, which a single-observation policy cannot tell apart.
What an episode actually is, in frames
An episode is one uninterrupted attempt at the task: you press record, you drive the arm through the pick, you stop. In a LeRobot dataset it is not a file any more. Since the v3.0 format, many episodes live inside the same Parquet and MP4 shards, and the episode boundaries are resolved through meta/episodes/ records that carry per-episode lengths and byte offsets. What you get back when you index the dataset is a frame, not an episode. The dataset length is the total frame count, not the episode count.
That distinction is the whole article. Every training sample is one frame plus a window of future actions hanging off it. How long your episodes are decides how many of those windows fit inside an episode, and how many of them run off the end. For imitation learning that is the difference between a dataset that teaches a horizon and one that teaches a fragment.
# Episode statistics of any LeRobot dataset on the Hub, without downloading it
curl -sL https://huggingface.co/datasets/lerobot/svla_so101_pickplace/resolve/main/meta/info.json \
| python3 -c 'import json,sys; d=json.load(sys.stdin); \
print(d["codebase_version"], d["robot_type"], d["fps"], "fps"); \
print(d["total_episodes"], "episodes,", d["total_frames"], "frames"); \
print(round(d["total_frames"]/d["total_episodes"],1), "frames/ep =", \
round(d["total_frames"]/d["total_episodes"]/d["fps"],1), "s")'
# v3.0 so100_follower 30 fps
# 50 episodes, 11939 frames
# 238.8 frames/ep = 8.0 sThree reference datasets, read from their meta/info.json on the same day, give a useful sense of the real range. All three carry exactly 50 episodes, which is also the ACT minimum on this platform and the lerobot recording default.
| Dataset | Format | Episodes | Frames | fps | Frames / episode | Seconds / episode |
|---|---|---|---|---|---|---|
| lerobot/svla_so101_pickplace | v3.0 | 50 | 11,939 | 30 | 238.8 | 8.0 |
| lerobot/svla_so100_pickplace | v3.0 | 50 | 19,631 | 30 | 392.6 | 13.1 |
| lerobot/aloha_sim_insertion_human | v3.0 | 50 | 25,000 | 50 | 500.0 | 10.0 |
The simulated ALOHA set is exactly 500 frames per episode because simulation episodes are cut at a fixed length. The two real SO-100 sets are averages, and they sit at 8 and 13 seconds. Nobody recorded for a minute.
The recording defaults are a ceiling, not a target
Here is what teleoperation recording gives you if you change nothing. These are the field defaults in src/lerobot/configs/dataset.py on the lerobot main branch, read on 24 August 2026 at version 0.6.2 in development. The last release on PyPI at that point was 0.6.1, published 3 August 2026.
| Field | Default | What it means in practice |
|---|---|---|
| fps | 30 | One frame and one action row every 33.3 ms |
| episode_time_s | 60 | Hard stop at 1800 frames per episode |
| reset_time_s | 60 | A minute of unrecorded time to put the scene back |
| num_episodes | 50 | Same as the platform minimum for ACT, GR00T and Pi0.5 |
| video | true | Camera frames encoded to MP4 rather than kept as PNG |
| push_to_hub | true | Uploads when you finish unless you turn it off |
| streaming_encoding | false | Off by default; turning it on makes save_episode near instant |
| num_image_writer_threads_per_camera | 4 | Four writer threads per camera |
During recording the keyboard listener maps right arrow to end the current episode early, left arrow to end it and re-record it, and Esc to stop the session. That is why real datasets average 8 to 13 seconds while the default is 60: the operator finishes the pick and taps right arrow. If you never touch the arrow keys, every episode runs the full 1800 frames and the tail is the robot sitting still.
Left alone, the defaults also set your wall clock. Fifty episodes at 60 seconds of recording plus 60 seconds of reset is 100 minutes at the arm, and a large fraction of the frames you paid for with that time will be the arm holding a finished pose. Set the two timers deliberately instead.
lerobot-record \
--robot.type=so100_follower \
--robot.port=/dev/tty.usbmodem58760431541 \
--robot.id=my_follower \
--robot.cameras="{front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
--teleop.type=so100_leader \
--teleop.port=/dev/tty.usbmodem58760431551 \
--teleop.id=my_leader \
--dataset.repo_id=${HF_USER}/pick-cube-short \
--dataset.single_task="Pick up the red cube and drop it in the bin" \
--dataset.num_episodes=50 \
--dataset.fps=30 \
--dataset.episode_time_s=15 \
--dataset.reset_time_s=10 \
--dataset.streaming_encoding=true \
--dataset.encoder_threads=2 \
--display_data=true
Action chunking is the other half of the equation
A chunked policy predicts a block of future actions from one observation. Action chunking came out of the ACT paper, which framed it as a way to cut the effective horizon of a task. The paper's phrasing is direct: predicting the next k timesteps instead of one reduces the effective horizon of the task by k-fold, which is what keeps compounding error under control. Their ablation is the number everyone quotes: success rises from 1 percent at k=1 to 44 percent at k=100, then tapers slightly at k=200 and k=400 as the policy approaches fully open-loop control.
Every policy on this platform chunks, but they chunk at very different scales. These are the config defaults in lerobot main, plus the action horizon in NVIDIA's own SO-100 example config for GR00T.
| Policy | Chunk size | Executed steps | Observation steps | Seconds of motion at 30 fps |
|---|---|---|---|---|
| ACT | 100 | 100 | 1 | 3.33 |
| SmolVLA | 50 | 50 | 1 | 1.67 |
| Pi0.5 | 50 | 50 | 1 | 1.67 |
| GR00T N1.7 / N1.5 (SO-100 example config) | 16 | 16 | 1 | 0.53 |
Note the observation column. All four use n_obs_steps=1: one camera frame, one joint state, no history. The GR00T SO-100 config makes this explicit, with delta_indices=[0] for both video and state and range(0, 16) for the action. There is no context window in the language-model sense. The only temporal context these policies have is the chunk they are about to emit.
The learnable horizon is shorter than the episode
It is tempting to read episode length as how much of the task the policy learns. It is not. What a chunked policy learns is a mapping from one observation to the next k actions, and nothing longer. The episode contributes two things on top of that: it decides how many such mappings exist, and it decides how consistent they are with each other. A 60 second episode does not teach a 60 second behaviour. It teaches eighteen overlapping 3.33 second behaviours that happen to be stitched together by the fact that they came from one continuous attempt.
This is why effective horizon is the right phrase and context is the wrong one. There is no context window being filled. The policy re-reads the world every k steps and starts again from whatever it sees. Continuity across an episode is something you get by accident, because consecutive observations look similar and the demonstrations were consistent, not because the architecture carries state. When people say a policy lost track of the task, what usually happened is that two points in the episode looked alike from the camera and the policy picked the wrong continuation. Longer episodes make that collision more likely, not less.
The ratio that predicts trouble: k over T
Call the chunk size k and the episode length in frames T. Two derived numbers follow, and both of them are more useful than either input on its own. T/k is how many independent decision points the policy gets per episode. k/T is how much of the task it commits to from a single frame.
fps, episode_s, chunk = 30, 8, 100
T = int(episode_s * fps)
print(f"frames per episode T = {T}")
print(f"chunks per episode T/k = {T/chunk:.1f}")
print(f"ratio k/T = {chunk/T:.2f}")
print(f"frames with padding (k-1)/T = {(chunk-1)/T:.1%}")
print(f"action steps masked (k-1)/2T = {(chunk-1)/(2*T):.1%}")
# frames per episode T = 240
# chunks per episode T/k = 2.4
# ratio k/T = 0.42
# frames with padding (k-1)/T = 41.2%
# action steps masked (k-1)/2T = 20.6%Worked out across the episode lengths people actually record on an SO-100, at 30 fps:
| Episode | T (frames) | ACT k=100: T/k | ACT k=100: k/T | SmolVLA / Pi0.5 k=50: T/k | k=50: k/T | GR00T k=16: T/k | k=16: k/T |
|---|---|---|---|---|---|---|---|
| 8 s | 240 | 2.4 | 0.42 | 4.8 | 0.21 | 15.0 | 0.067 |
| 13 s | 390 | 3.9 | 0.26 | 7.8 | 0.13 | 24.4 | 0.041 |
| 20 s | 600 | 6.0 | 0.17 | 12.0 | 0.083 | 37.5 | 0.027 |
| 30 s | 900 | 9.0 | 0.11 | 18.0 | 0.056 | 56.3 | 0.018 |
| 60 s | 1800 | 18.0 | 0.056 | 36.0 | 0.028 | 112.5 | 0.0089 |
The ACT chunk ablation was run on the two simulated ALOHA tasks. The lerobot copy of one of them, lerobot/aloha_sim_insertion_human, is a fixed 500 frames per episode, so take T = 500 as the reference. There, k=100 sits at k/T = 0.20, which was the best point, and the dip started at k=200, or k/T = 0.40. An 8 second SO-100 episode at 30 fps is 240 frames, so lerobot's default k=100 lands at k/T = 0.42. In the paper's own terms that is past the peak and into the region where performance fell off. This mapping is arithmetic on their numbers, not a claim the paper makes, but it explains a lot of disappointing first ACT runs. If your episodes are 8 seconds, try chunk_size in the 30 to 50 range before you blame the data.
The platform exposes chunkSize and nActionSteps directly in the ACT on SO-100 training form, both defaulting to 100, so this is a field you change rather than a code edit. The other four policies do not expose it, which is worth knowing before you pick a model on the policies page.
What happens in the last k-1 frames of every episode
Ask a dataset for the frame 30 steps from the end with a chunk size of 100 and you are asking for 70 actions that do not exist. LeRobot does not error and it does not skip the sample. It clamps the query indices to the episode boundary and records a mask.
# src/lerobot/datasets/dataset_reader.py, DatasetReader._get_query_indices
ep_start = ep["dataset_from_index"]
ep_end = ep["dataset_to_index"]
query_indices = {
key: [max(ep_start, min(ep_end - 1, abs_idx + delta)) for delta in delta_idx]
for key, delta_idx in self.delta_indices.items()
}
padding = {
f"{key}_is_pad": torch.BoolTensor(
[(abs_idx + delta < ep_start) | (abs_idx + delta >= ep_end) for delta in delta_idx]
)
for key, delta_idx in self.delta_indices.items()
}The mask is then honoured by the loss, so those repeats do not teach the policy to freeze at the end of a chunk. ACT divides by the count of valid steps rather than the full tensor size, which means a heavily padded batch is not down-weighted either. It simply carries less signal.
# src/lerobot/policies/act/modeling_act.py, ACTPolicy.forward
abs_err = F.l1_loss(batch[ACTION], actions_hat, reduction="none")
valid_mask = ~batch["action_is_pad"].unsqueeze(-1)
num_valid = valid_mask.sum() * abs_err.shape[-1]
l1_loss = (abs_err * valid_mask).sum() / num_valid.clamp_min(1)So the honest version of the story is not that short episodes poison the loss. It is that they spend a large share of your recording effort on targets that get thrown away. Exactly k-1 frames per episode produce a partly padded window, and the total share of masked action steps is (k-1)/2T.
| Episode at 30 fps | Policy | Frames with a padded target | Share of all action steps masked out |
|---|---|---|---|
| 8 s (240 frames) | ACT, k=100 | 99 of 240, 41.2 % | 20.6 % |
| 8 s (240 frames) | SmolVLA / Pi0.5, k=50 | 49 of 240, 20.4 % | 10.2 % |
| 8 s (240 frames) | GR00T, k=16 | 15 of 240, 6.2 % | 3.1 % |
| 13 s (390 frames) | ACT, k=100 | 99 of 390, 25.4 % | 12.7 % |
| 30 s (900 frames) | ACT, k=100 | 99 of 900, 11.0 % | 5.5 % |
| 60 s (1800 frames) | ACT, k=100 | 99 of 1800, 5.5 % | 2.8 % |
With a 16 step horizon, GR00T only loses 15 frames per episode to padding no matter how short the episode is. That is 6 percent of an 8 second episode against ACT's 41 percent. If you have already recorded short episodes and cannot re-record, that is a real argument for GR00T N1.7 over ACT, independent of model quality. It is also why the platform sets the GR00T minimum at 50 episodes and the SmolVLA minimum at 30.
Short and clean against long and messy
The angle people usually want settled: is it better to record thirty crisp eight-second picks or ten sixty-second sequences where you fumble twice and recover? Both produce a working dataset. They fail in different ways, and the failure modes are not symmetric. Short episodes fail quietly, by handing the optimiser less signal than you think you gave it. Long episodes fail loudly, by teaching contradictory actions for visually similar states.
There is also a bookkeeping difference that people underestimate. Training length is counted in gradient steps over frames, not over episodes. Fifty episodes of 8 seconds at 30 fps is about 12,000 frames; fifty of 60 seconds is 90,000. At the ACT defaults this platform sends, batch size 8 over 100,000 steps, the short dataset is seen roughly 67 times and the long one roughly 9 times. Neither number is automatically wrong, but they are very different regimes, and if you shorten your episodes without adjusting anything you have quietly changed how many epochs your training steps add up to.
- More episodes per hour at the arm, so more independent starting configurations for the same effort.
- Fewer chances for the scene to drift away from its reset state mid-episode.
- Each episode shows one solution to one problem, which is easier for a single-observation policy to fit.
- Failed attempts are cheap to discard: you lose 8 seconds, not a minute.
- Matches what the reference datasets actually contain, so published hyperparameters transfer better.
- A large fraction of frames sit near the episode end, where the action window is padded and partly masked.
- Chunk sizes tuned on longer episodes, including ACT's default 100, are too large relative to T.
- The policy never sees recovery behaviour, because you re-record instead of recovering.
- Total frame count drops fast: 50 episodes of 8 seconds is 12,000 frames, against 90,000 for 60 second episodes.
- Tasks with a genuine multi-stage structure get cut into pieces that no longer make sense alone.
- Padding becomes negligible: 5.5 percent of frames at ACT's default chunk size on a 60 second episode.
- More frames per episode, so a smaller episode count still fills a training set.
- Recovery from a bad grasp is in the data, which is the only way a chunked policy learns to recover.
- Multi-stage tasks stay intact, so the language instruction still describes the whole episode.
- Long episodes contain several valid solutions to the same visual state, and a policy with n_obs_steps=1 has no way to tell which one it is in.
- Operator fatigue shows up as inconsistent speed, which turns into inconsistent action magnitudes.
- Scene drift accumulates: by second 45 the workspace no longer matches the reset state you calibrated for.
- One bad episode costs a minute of recording plus a minute of reset.
- Dead time at the end, where the arm holds a finished pose, teaches the policy to stop moving.
What the published datasets actually chose
It helps to see how much the accepted answer varies. These figures come from the papers and project pages, fetched and checked on 24 August 2026. The seconds-per-episode column is arithmetic on the totals the sources state, not a number the sources publish directly.
| Dataset | Scale | Control rate | Seconds per episode (derived) |
|---|---|---|---|
| ALOHA real tasks (ACT paper) | 50 demos per task, 100 for Thread Velcro | 50 Hz | 8 to 14, stated directly; 400 to 700 timesteps |
| BridgeData V2 | 60,096 trajectories, 24 environments, 13 skills | 5 Hz | 7.6 (38 timesteps / 5 Hz) |
| DROID | 76,000 trajectories, 350 hours, 564 scenes, 84 tasks | not stated on the project page | 16.6 (350 h / 76k) |
| SmolVLA community pretraining set | 481 datasets, 22.9K episodes, 10.6M frames | mixed | 462.9 frames per episode; 15.4 at 30 fps |
Two things stand out. The first is that the spread is narrow given how differently these datasets were built: a lab with two arms and a fixed protocol, a distributed collection effort across three continents, and a pile of hobbyist uploads all landed between about 8 and 17 seconds. The second is that control rate and episode length move together. BridgeData V2 runs at 5 Hz and averages 38 steps; ALOHA runs at 50 Hz and averages 400 to 700. In seconds those are close. In frames they differ by more than an order of magnitude, and it is the frame count that your chunk size has to live inside.
Nothing published sits at a minute. The DROID collection and BridgeData V2 went about it very differently and still landed in the same band. If you want the wider view on what makes a demonstration usable at all, the data collection guide covers the parts that are not about length.

Picking an episode length for your task
- 1Time the task by hand first
Do the pick with the leader arm five times and note the wall clock. That median, plus about half again for the attempts that go badly, is your episode_time_s ceiling. Do not start from 60.
bash# 8 s median, 15 s ceiling --dataset.episode_time_s=15 --dataset.reset_time_s=10 - 2Convert to frames and check k/T
Multiply by fps. Then divide your policy's chunk size by that number. Aim for k/T at or below roughly 0.2, which is where the ACT ablation peaked, and for at least five decision points per episode.
pythonT = 8 * 30 # 240 frames for k in (100, 50, 40, 30, 16): print(k, round(k/T, 3), round(T/k, 1)) # 100 0.417 2.4 # 50 0.208 4.8 # 40 0.167 6.0 # 30 0.125 8.0 # 16 0.067 15.0 - 3Record a pilot of five episodes and read the metadata back
Do not record fifty before you check. Five is enough to see whether your real average matches your plan.
bashlerobot-record \ --robot.type=so100_follower --robot.port=/dev/tty.usbmodem58760431541 --robot.id=my_follower \ --teleop.type=so100_leader --teleop.port=/dev/tty.usbmodem58760431551 --teleop.id=my_leader \ --dataset.repo_id=${HF_USER}/pilot --dataset.single_task="Pick up the red cube" \ --dataset.num_episodes=5 --dataset.episode_time_s=15 --dataset.reset_time_s=10 lerobot-edit-dataset --repo_id ${HF_USER}/pilot --operation.type info - 4Throw away the episodes that ran long
An episode that hit the ceiling almost always means the attempt went wrong. Delete those rather than keeping them for volume. This writes a new dataset and leaves the original alone.
bashlerobot-edit-dataset \ --repo_id ${HF_USER}/pick-cube-short \ --new_repo_id ${HF_USER}/pick-cube-clean \ --operation.type delete_episodes \ --operation.episode_indices "[3, 11, 27]" - 5Set chunk_size when you train, not after
For ACT the chunk size is a policy config field, so it is fixed at training time. lerobot's own defaults are batch_size 8, steps 100000 and seed 1000, which match the ACT defaults this platform sends.
bashlerobot-train \ --dataset.repo_id=${HF_USER}/pick-cube-clean \ --policy.type=act \ --policy.chunk_size=40 \ --policy.n_action_steps=20 \ --batch_size=8 \ --steps=100000 \ --seed=1000 \ --output_dir=outputs/train/act_pick_cube
Two ways to get this right
Install lerobot with the recording extras, wire up the leader and follower, and drive the whole loop from your own terminal. You control every flag, including the two timers, and you can inspect the dataset metadata directly. You also own the GPU problem.
git clone https://github.com/huggingface/lerobot.git
cd lerobot
pip install -e ".[core_scripts]"
lerobot-find-port # identify the two USB serial ports
lerobot-calibrate --robot.type=so100_follower --robot.port=/dev/tty.usbmodem... --robot.id=my_follower
# then lerobot-record with your own episode_time_s, then lerobot-train- Every DatasetRecordConfig field is a CLI flag, so episode_time_s and reset_time_s are one keystroke each.
- chunk_size and n_action_steps are reachable for every policy, not just ACT.
- You need a 24 GB card locally for ACT or SmolVLA, and an A100 or H100 class card for GR00T or Pi0.5.
- Dataset format conversion is on you: a v3.0 dataset has to be converted down to v2.1 before GR00T will load it.
The desktop client from the download page records LeRobot-format datasets straight out of a teleop session, and the training form picks the model, the dataset and the hyperparameters. The backend rents a GPU on a spot market by required VRAM, runs the trainer and writes checkpoints to object storage.
- ACT exposes chunkSize and nActionSteps in the form, both defaulting to 100. Lower them if your episodes are short.
- Minimum episode counts are enforced per model: 50 for ACT, GR00T N1.7, GR00T N1.5 and Pi0.5, 30 for SmolVLA.
- A run on the RTX 4090 tier costs about 1 to 3 USD; the A100 or H100 tier is about 4 to 12 USD. See pricing.
- Public datasets in the directory can be inspected before you commit a GPU to them.
- Inference pods carry an idle watchdog and destroy themselves, so a forgotten pod does not bill silently.
There is no operation anywhere that cuts a 60 second episode into four 15 second ones. That is true of the platform and it is true of lerobot: lerobot-edit-dataset supports delete_episodes, split, merge, remove_feature, modify_tasks, convert_image_to_video, reencode_videos, recompute_stats and info. Splitting is by episode, not within one. Whole episodes in, whole episodes out. Get the length right at record time or re-record.
Where episode length stops being the problem
Two limits are worth stating plainly, because both get blamed on the data when they are not the data.
The first is inference latency. At 30 fps you need a new action every 33.3 ms. This platform lists ACT at 20 ms per action step, GR00T N1.7 at 152 ms, GR00T N1.5 at 165 ms, SmolVLA at 245 ms and Pi0.5 at 485 ms. Only ACT fits inside a 30 fps budget. Everything else has to run its chunk open loop while the next one computes, which is a large part of why chunking exists at all. No episode length fixes that, and putting the inference across a public internet hop makes it worse. Remote inference works for slow pick-and-place and not for fast reactive motion.
You record beautiful 8 second episodes, train ACT at the default chunk_size of 100, and the arm moves to roughly the right place and then stops. That looks like a broken checkpoint. It usually is not. With k/T at 0.42 the policy is committing to 3.33 seconds of a task that takes 8, from one frame, and 41 percent of your training frames had padded targets. Before you re-record anything, retrain with chunk_size=40 and n_action_steps=20 and compare. If it still stalls, then work through loss falls but the policy does nothing and policy freezes mid-motion.
The second is that episode length cannot buy you memory. Every policy here uses n_obs_steps=1. If your task genuinely requires knowing what happened ten seconds ago, a longer episode does not give the policy that information, it just gives it more ambiguous frames. That is an architecture question, and the VLA overview and the model arena are better places to start on it than a recording flag. For the hardware side of a first dataset, the SO-100 setup guide covers calibration and camera placement, which matter more than episode length does.

Record episodes at the length you meant to
The AY-Robots desktop client records LeRobot-format datasets straight from a teleoperation session, with the episode and reset timers in front of you instead of buried in a CLI flag.
Get the desktop clientA short checklist before you record fifty episodes
- Time the task by hand. Set episode_time_s to about 1.5x the median, not to 60.
- Set reset_time_s to what the reset actually takes. It is unrecorded time and it doubles your session length.
- Compute k/T for the policy you intend to train. Aim at or below 0.2. See the dataset docs for the format side.
- Record five, read the metadata back, then commit to fifty.
- Tap right arrow the moment the task is done. Dead frames at the end teach the arm to stop.
- Delete the episodes that hit the ceiling before training. The training docs cover what happens after that.
What is the default episode length in LeRobot?▾
episode_time_s defaults to 60 seconds and fps defaults to 30, so an episode caps at 1800 frames. reset_time_s is also 60 and num_episodes is 50. These are the defaults in src/lerobot/configs/dataset.py on the main branch as of 24 August 2026 (version 0.6.2 in development; 0.6.1 was the last PyPI release, 3 August 2026). Treat 60 seconds as a timeout rather than a target: real reference datasets average 8 to 13 seconds per episode.
How long should an SO-100 episode be?▾
Long enough to complete the task once plus a margin for attempts that go wrong. For a single pick and place that is usually 8 to 15 seconds at 30 fps, which is 240 to 450 frames. The LeRobot reference sets lerobot/svla_so101_pickplace and lerobot/svla_so100_pickplace average 8.0 and 13.1 seconds respectively. Published datasets cluster in the same band: BridgeData V2 at 7.6 seconds and DROID at about 16.6 seconds derived from 350 hours over 76,000 trajectories.
Does episode length change the chunk size I should use?▾
Yes, and this is the interaction that matters most. What predicts trouble is k/T, chunk size over episode length in frames. The ACT ablation peaked around k=100 on roughly 500 frame ALOHA episodes, which is k/T = 0.2, and fell off at k=200 and k=400. lerobot's default chunk_size of 100 on a 240 frame SO-100 episode is k/T = 0.42, past that peak. On short episodes, try 30 to 50 instead.
What happens when an action chunk runs past the end of an episode?▾
LeRobot clamps the query indices to the episode boundary, which repeats the final frame, and sets an action_is_pad mask for every repeated step. ACT then excludes those steps from the L1 loss and from its denominator, so they do not teach the policy to freeze. The cost is lost supervision rather than corrupted supervision: exactly k-1 frames per episode carry a partly padded target, and (k-1)/2T of all action steps are masked out.
Can I split a long episode into shorter ones after recording?▾
No, not with the shipped tooling. lerobot-edit-dataset supports delete_episodes, split, merge, remove_feature, modify_tasks, convert_image_to_video, reencode_videos, recompute_stats and info. The split operation divides a dataset into train and validation sets by episode, not within an episode. There is no trim or cut. Get the length right at recording time.
Are more short episodes better than fewer long ones?▾
For a single-stage task on this class of arm, yes, up to a point. More episodes means more independent starting configurations, and each one is cheap to discard when it goes wrong. The cost is padding: a short episode spends a larger share of its frames near the boundary where the action window is masked, and that share scales with your chunk size. If you must keep short episodes and cannot lower chunk_size, a policy with a 16 step horizon like GR00T loses far less to padding than ACT at 100.
Sources
- Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware (ACT / ALOHA), Zhao et al., 2023: chunk size ablation, 8 to 14 second episodes at 50 Hz
- lerobot DatasetRecordConfig: fps=30, episode_time_s=60, reset_time_s=60, num_episodes=50
- lerobot keyboard controls: right arrow ends an episode, left arrow re-records it, Esc stops recording
- lerobot DatasetReader._get_query_indices: index clamping and the action_is_pad mask
- lerobot ACTPolicy.forward: padded action steps masked out of the L1 loss
- lerobot ACTConfig: chunk_size=100, n_action_steps=100, n_obs_steps=1
- lerobot policy configs: SmolVLAConfig and PI05Config both default to chunk_size=50 and n_action_steps=50
- lerobot-edit-dataset: the full list of supported dataset operations
- LeRobotDataset v3.0: file-based storage, episode boundaries resolved through metadata
- lerobot/svla_so101_pickplace: 50 episodes, 11,939 frames, 30 fps
- lerobot/svla_so100_pickplace: 50 episodes, 19,631 frames, 30 fps
- Isaac-GR00T SO-100 modality config: 16 step action horizon, single observation frame
- BridgeData V2: A Dataset for Robot Learning at Scale, Walke et al., 2023: 60,096 trajectories, 38 timesteps average at 5 Hz
- DROID: A Large-Scale In-The-Wild Robot Manipulation Dataset, 2024: 76k trajectories, 350 hours
- SmolVLA, 2025: 481 community datasets, 22.9K episodes, 10.6M frames
Sources
- Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware (ACT / ALOHA), Zhao et al., 2023: chunk size ablation, 8 to 14 second episodes at 50 Hz
- lerobot DatasetRecordConfig: fps=30, episode_time_s=60, reset_time_s=60, num_episodes=50
- lerobot keyboard controls: right arrow ends an episode, left arrow re-records it, Esc stops recording
- lerobot DatasetReader._get_query_indices: index clamping and the action_is_pad mask
- lerobot ACTPolicy.forward: padded action steps masked out of the L1 loss
- lerobot ACTConfig: chunk_size=100, n_action_steps=100, n_obs_steps=1
- lerobot policy configs: SmolVLAConfig and PI05Config both default to chunk_size=50 and n_action_steps=50
- lerobot-edit-dataset: the full list of supported dataset operations
- LeRobotDataset v3.0: file-based storage, episode boundaries resolved through metadata
- lerobot/svla_so101_pickplace: 50 episodes, 11,939 frames, 30 fps
- lerobot/svla_so100_pickplace: 50 episodes, 19,631 frames, 30 fps
- Isaac-GR00T SO-100 modality config: 16 step action horizon, single observation frame
- BridgeData V2: A Dataset for Robot Learning at Scale, Walke et al., 2023: 60,096 trajectories, 38 timesteps average at 5 Hz
- DROID: A Large-Scale In-The-Wild Robot Manipulation Dataset, 2024: 76k trajectories, 350 hours
- SmolVLA, 2025: 481 community datasets, 22.9K episodes, 10.6M frames
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started