
Action chunking cuts compounding error by predicting a block of actions and executing part of it. What chunk_size and n_action_steps really do, and how to tune them.
What you need to know
- •A chunked policy predicts chunk_size future actions from one observation and executes only n_action_steps of them. Two numbers, two jobs.
- •In the ACT ablation, success went from 1 percent at chunk size 1 to 44 percent at 100, then tapered at 200 and 400.
- •lerobot ships ACT with chunk_size=100 and n_action_steps=100: open loop between queries, so new camera frames are ignored for the whole chunk.
- •Visible jitter is usually the seam between chunks, not a bad model: the twitch interval equals n_action_steps divided by your frame rate.
- •Temporal ensembling removes that seam by averaging overlapping chunks, but lerobot then forces n_action_steps=1: one forward pass per step.
- •Tuning order: set chunk_size to one motion primitive, lower n_action_steps until the arm reacts, then consider ensembling or real-time chunking.
Action chunking in one paragraph
A policy trained by imitation learning normally maps one observation to one action. At 30 frames per second over a twelve second episode that is 360 decisions in a row, each mistake feeding back into the next observation. Action chunking changes the output rather than the network: from one observation the model emits a block of consecutive actions covering the next second or three, and the controller plays part of it back before asking again.
The term comes from Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware by Zhao, Kumar, Levine and Finn, submitted to arXiv on 23 April 2023. It introduced Action Chunking with Transformers, which "learns a generative model over action sequences" and reports "80-90% success" on tasks such as slotting a battery "with only 10 minutes worth of demonstrations". At around 80 million parameters, ACT is the smallest of the five policies you can train here.
# lerobot/policies/act/configuration_act.py, main branch, read 2026-08-23
n_obs_steps: int = 1
chunk_size: int = 100
n_action_steps: int = 100
# Inference.
# Note: the value used in ACT when temporal ensembling is enabled is 0.01.
temporal_ensemble_coeff: float | None = NoneThe failure it fixes: compounding error
Behaviour cloning assumes training and test data come from the same distribution. A centimetre off the demonstrated trajectory, the arm sees a frame no human ever produced, so the next prediction is worse and the one after worse again. The ACT paper: "Small errors in the predicted action can incur large differences in the state, exacerbating the 'compounding error' problem of imitation learning".
Chunking attacks the number of decisions rather than the quality of each one. Committing to k steps at a time reduces the effective horizon of the task "by k-fold". A second benefit gets less attention: human teleoperation data is full of short pauses, which the paper calls temporally correlated confounders. A single-step model sees near-identical frames with different labels and averages them into a stall. A chunked model reproduces the pause as a pause, because it sits inside one chunk of the episode.
Averaged across 4 settings (2 simulated tasks, human or scripted data), success "improves drastically from 1% at k = 1 to 44% at k = 100, then slightly tapers down with higher k". The dip at k = 200 and 400 is attributed to "the lack of reactive behavior and the difficulty in modeling long action sequences". Note the shape: a huge gain at the low end, then a wide plateau.
chunk_size and n_action_steps are not the same knob
This is where people lose a day. chunk_size belongs to the trained network. It fixes the output shape and what the loss is computed against: ACTConfig exposes action_delta_indices as list(range(chunk_size)), so the dataloader slices that many future rows from the LeRobot dataset per sample. Change it and you retrain. n_action_steps belongs to the runtime loop only, and changes on an existing checkpoint without touching a weight.
The lerobot docstring spells the discard out: "the model predicts 100 steps worth of actions, runs 50 in the environment, and throws the other 50 out." Mechanically it is a queue: ACTPolicy.select_action holds a deque with maxlen=n_action_steps, refills it from predict_action_chunk() when it runs dry, and pops one action per control tick.
| chunk_size | n_action_steps | Replan interval at 30 fps | What the arm does |
|---|---|---|---|
| 100 | 100 | 3.33 s | lerobot default. Open loop for over three seconds. |
| 100 | 50 | 1.67 s | The docstring's example. Half of every prediction discarded. |
| 100 | 25 | 0.83 s | Sane starting point for tabletop pick and place. |
| 100 | 10 | 0.33 s | Near closed loop. Ten forward passes per second. |
| 100 | 1 | 0.033 s | Required for temporal ensembling. One forward pass per tick. |
| 20 | 20 | 0.67 s | Short chunk, less smoothing, smaller horizon reduction. |
# lerobot main. Both are plain draccus overrides on the policy config.
lerobot-train \
--dataset.repo_id=${HF_USER}/so101_dataset_test \
--policy.type=act \
--policy.chunk_size=100 \
--policy.n_action_steps=25 \
--policy.device=cuda \
--output_dir=outputs/train/act_chunk100_exec25 \
--job_name=act_chunk100_exec25 \
--steps=20000Validated at construction, so you find out at start-up, not two hours in. 1. n_action_steps greater than chunk_size: ValueError, "The chunk size is the upper bound for the number of action steps per model invocation." 2. temporal_ensemble_coeff set with n_action_steps > 1: NotImplementedError, "because the policy needs to be queried every step to compute the ensembled action". 3. n_obs_steps other than 1: ValueError, "Multiple observation steps not handled yet". ACT sees one frame per query.
What upstream actually ships
Every modern manipulation policy chunks. They disagree on how long the chunk is and how much of it they trust. Repository values below were read from the main branch on 23 August 2026, because these defaults move.
| Policy | Where the number lives | Chunk length | Executed per query | Detail |
|---|---|---|---|---|
| ACT (lerobot) | ACTConfig | 100 | 100 | temporal_ensemble_coeff is None by default |
| ACT (original repo) | tonyzhaozh/act | 100, at 50 Hz (DT = 0.02) | 1 with --temporal_agg | weight coefficient k = 0.01 |
| Diffusion Policy | Chi et al., Table 7, CNN variant | Tp = 16 | Ta = 8 | observation horizon To = 2 |
| SmolVLA and Pi0.5 (lerobot) | SmolVLAConfig, PI05Config | 50 | 50 | num_inference_steps = 10 denoising steps |
| GR00T N1 | GR00T N1 paper, 2025 | H = 16 | not stated | 63.9 ms per 16-action chunk on an L40 in bf16 |
| GR00T N1.7 | Isaac-GR00T README | action_horizon 40 | --execution-horizon, 8 in NVIDIA's example | expanded from 16 in N1.6 |
Diffusion Policy is the clearest published statement of the trade-off: the authors swept action horizons and "found the action horizon of 8 steps to be optimal for most tasks that we tested" out of a 16 step prediction. Executing half is far more conservative than lerobot's ACT default of executing all 100. NVIDIA went further: N1.7 expanded action_horizon from 16 to 40, and the README example executes 8 of those 40 per call.
Isaac-GR00T's rollout flag "was renamed from --action-horizon to --execution-horizon to clarify how many predicted actions are executed per policy call". Useful precedent, but it is a GR00T flag. Fine-tune Pi0.5 or SmolVLA through lerobot and the equivalent knob is n_action_steps, or execution_horizon once you switch on the real-time chunking backend below. One idea, three spellings.

Jitter lives at the seam between chunks
The symptom is recognisable: the arm moves smoothly for about a second, twitches, moves smoothly again, twitches again, at a regular interval. Count that interval. If it matches n_action_steps divided by your frame rate, you have found it. The ACT paper names the mechanism, that "a new environment observation is incorporated abruptly every k steps and can result in jerky robot motion". Inside a chunk a decoder produced the trajectory as one sequence; across the boundary nothing enforces continuity.
Temporal ensembling removes the seam by never creating one. Query the policy every timestep and you hold several overlapping predictions for the same future timestep, each from a different observation, which you average. The paper writes the weights as w_i = exp(-m * i), "where w_0 is the weight for the oldest action" and "a smaller m means faster incorporation" of new observations. The reference implementation hard-codes k = 0.01.
# lerobot/policies/act/modeling_act.py -> ACTTemporalEnsembler
self.ensemble_weights = torch.exp(-temporal_ensemble_coeff * torch.arange(chunk_size))
self.ensemble_weights_cumsum = torch.cumsum(self.ensemble_weights, dim=0)
# from the class docstring:
# - Setting it to 0 uniformly weighs all actions.
# - Setting it positive gives more weight to older actions.
# - Setting it negative gives more weight to newer actions.
# and in ACTPolicy.select_action:
if self.config.temporal_ensemble_coeff is not None:
actions = self.predict_action_chunk(batch)
action = self.temporal_ensembler.update(actions)
return actionIn lerobot a positive temporal_ensemble_coeff weights older predictions more heavily, and 0.01 is the value "used by the original ACT work". The docstring warns against flipping it: experiments in pull request 319 "hint at why highly weighing new actions might be detrimental". That PR, merged 16 July 2024, also renamed the field from temporal_ensemble_momentum, so older configs need an edit to load.
What temporal ensembling costs
- Removes the periodic twitch: there is no boundary left to cross.
- Reacts to a new camera frame every step while still committing to a long-horizon plan.
- Free at training time: it "incurs no additional training cost, only extra inference-time computation".
- Works on a checkpoint you already have: a rollout setting, not a retrain.
- Worth a 3.3 percent gain for ACT in the paper's ablation, 4 percent for the BC-ConvMLP baseline.
- Forces n_action_steps=1: one forward pass per step instead of one per chunk.
- A latency question, not a quality one: if the loop budget is 33 ms and the model needs more, the option does not exist.
- Not a guaranteed win. In lerobot's 500-episode evaluation of act_aloha_sim_transfer_cube_human reported in PR 319, m = 0.01 scored 73.8 percent against 87.6 percent with no ensembling.
- Averaging blurs bimodal decisions: torn between grasping left and right, the mean grasps neither.
- Nothing tells you whether it helped: you need side by side rollouts.
A 30 Hz loop gives 33 ms per step, and lerobot's RolloutConfig defaults to fps = 30.0. Of the five policies here, the comparison page lists ACT at 20 ms per action step, SmolVLA at 245 ms, GR00T N1.7 at 152 ms, GR00T N1.5 at 165 ms and Pi0.5 at 485 ms. Only ACT fits inside 33 ms. For the other four, executing several steps per query is what lets the loop close, and that is why ACT is still the default choice on an SO-100.
Beyond ensembling: what lerobot ships today
Ensembling was the 2023 answer and is still the right first move for ACT. For slow vision-language-action models it is unavailable. Real-Time Execution of Action Chunking Flow Policies by Black, Galliker and Levine, at NeurIPS 2025, targets the boundary artefact directly. It names the "pauses or out-of-distribution jerky movements at chunk boundaries" and generates the next chunk while executing the current one, "freezing" the actions guaranteed to execute and "inpainting" the rest, "out of the box with no re-training".
On the main branch in August 2026 that is a flag, not a prototype. lerobot-rollout has a pluggable inference backend: --inference.type=sync is the default, "one policy call per control tick", and --inference.type=rtc is "Real-Time Chunking for slow VLA models". Its tunables are execution_horizon, where the docs give "typical values: 8-12 steps", and max_guidance_weight, where "for 10 steps flow matching (SmolVLA, Pi0, Pi0.5), a value of 10.0 is an optimal value". Even here the reactivity knob is the execution horizon.
# from the lerobot-rollout docstring, main branch, read 2026-08-23
# Base mode - RTC inference for slow VLAs (Pi0, Pi0.5, SmolVLA)
lerobot-rollout \
--strategy.type=base \
--policy.path=lerobot/pi0_base \
--inference.type=rtc \
--inference.rtc.execution_horizon=10 \
--inference.rtc.max_guidance_weight=10.0 \
--robot.type=so100_follower \
--robot.port=/dev/ttyACM0 \
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
--task="pick up cube" --duration=60RolloutConfig also carries interpolation_multiplier, default 1. From the source: "Values > 1 linearly interpolate between consecutive policy actions for smoother motion: commands go to the robot at fps x multiplier Hz while policy inference and dataset recording stay at fps Hz." It does not fix a chunk boundary, because it only interpolates between actions the policy already produced. The twitch stays, just smeared.
A tuning procedure that converges
Do not sweep both numbers at once. They are not independent and you will read the results wrong. This order changes one thing at a time, cheap steps before the expensive one.
- 1Read the dataset frame rate first
Chunk length is a duration, not a count, and the conversion factor is your recording rate. Read it off the dataset instead of assuming 30.
pythonfrom lerobot.datasets.lerobot_dataset import LeRobotDataset ds = LeRobotDataset("${HF_USER}/so101_dataset_test") print(ds.fps, ds.num_episodes, ds.num_frames) # chunk_size 100 at 30 fps = 3.33 s of committed motion # chunk_size 100 at 50 fps = 2.00 s, the ALOHA setting - 2Set chunk_size to about one motion primitive
Reach, grasp, lift, place. Time one in your recordings and multiply by the frame rate. Tabletop pick and place at 30 fps lands between 50 and 100, so the default of 100 is a reasonable first guess.
bashlerobot-train \ --dataset.repo_id=${HF_USER}/so101_dataset_test \ --policy.type=act \ --policy.chunk_size=100 \ --policy.n_action_steps=100 \ --policy.device=cuda \ --steps=20000 - 3Roll out at the default and time the twitches
A regular twitch every 3.3 seconds at 30 fps is the chunk boundary. An irregular tremor is a different problem, usually data or servos.
bashlerobot-rollout \ --strategy.type=base \ --policy.path=${HF_USER}/act_policy \ --robot.type=so101_follower \ --robot.port=/dev/ttyACM0 \ --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \ --task="put the red brick in a bowl" \ --duration=60 - 4Halve n_action_steps until the arm reacts
100, then 50, then 25, no retraining. You want the point where the arm corrects for an object you nudged mid-episode. Below roughly 10 you pay forward passes for no extra reactivity.
bash# same checkpoint, new runtime behaviour lerobot-rollout \ --strategy.type=base \ --policy.path=${HF_USER}/act_policy \ --robot.type=so101_follower \ --robot.port=/dev/ttyACM0 \ --duration=60 - 5Only then reach for ensembling or RTC
Enable ensembling if the loop still has budget at n_action_steps=1, starting at 0.01. If motion turns sluggish rather than smooth, stale predictions dominate the average: use a smaller coefficient. For a slow VLA, use the RTC backend instead.
bashlerobot-rollout \ --strategy.type=base \ --policy.path=${HF_USER}/pi0_policy \ --inference.type=rtc \ --inference.rtc.execution_horizon=10 \ --robot.type=so100_follower \ --robot.port=/dev/ttyACM0 \ --duration=60
chunk_size buys horizon reduction and is a training decision. n_action_steps buys reactivity and is a free rollout decision. Never tune chunk_size to fix jitter: tune n_action_steps first, because it costs a rollout, not a retrain.
Doing it yourself versus doing it here
All of it runs locally: a 24 GB card for ACT, Python 3.12 and, where TorchCodec is supported, ffmpeg. Install path from the lerobot installation guide, record and train commands from the cheat sheet.
conda create -y -n lerobot python=3.12
conda activate lerobot
conda install ffmpeg -c conda-forge
git clone https://github.com/huggingface/lerobot.git
cd lerobot
pip install -e ".[core_scripts,training,feetech]"
# 1. record
lerobot-record \
--robot.type=so101_follower --robot.port=/dev/ttyACM0 \
--robot.id=my_follower_arm \
--teleop.type=so101_leader --teleop.port=/dev/ttyACM1 \
--teleop.id=my_leader_arm \
--dataset.repo_id=${HF_USER}/so101_dataset_test \
--dataset.num_episodes=50 \
--dataset.single_task="put the red brick in a bowl"
# 2. train with explicit chunk settings
lerobot-train \
--dataset.repo_id=${HF_USER}/so101_dataset_test \
--policy.type=act --policy.chunk_size=100 --policy.n_action_steps=25 \
--policy.device=cuda --steps=20000 \
--output_dir=outputs/train/act_so101- Every flag is yours, including ones no hosted form exposes.
- Inference sits on the same machine as the servos, so the network adds nothing to the loop.
- Pin the step count down first: the cheat sheet trains ACT with
--steps=20000, the hosted trainer defaults to 100000 max steps. Hold it fixed while you sweep chunk settings, or you will read a step-count effect as a chunk-size effect. - You also own the driver problems and the ffmpeg build errors.
The ACT on SO-100 guide walks the same pipeline through a form. The ACT defaults it sends are batch size 8, learning rate 1e-5 and 100000 max steps, and the form exposes chunkSize and nActionSteps, both defaulting to 100: exactly the two knobs above. Seed and log frequency are there too. Gradient accumulation is listed but does not apply to ACT.
- 1Bring or record a dataset
Record with the desktop client, point at a Hugging Face repo id, or take one from the public dataset directory. ACT wants at least 50 episodes in LeRobot v3.0 format.
- 2Pick ACT and set the two numbers
Leave chunkSize at 100 for the first run. Set nActionSteps to 25 if the arm must react to a moving target, and leave it at 100 if the scene is static.
- 3Let the backend rent the GPU
ACT sits in the RTX 4090 / 24 GB tier: 2 to 5 hours at 0.30 to 0.60 USD per hour, about 1 to 3 USD per run. Checkpoints go to object storage; the pricing page has the full table.
- 4Serve the checkpoint and roll out
The inference endpoint auto-provisions a pod serving your policy, and the local robot client talks to it. Pods carry an idle watchdog and destroy themselves after an idle period. Same operations from the CLI.
Renting a GPU for inference puts the public internet between camera and servo. The control loop here is 20 to 485 ms per action step depending on the model, with round trips on top. Workable for slow pick and place, not for fast reactive motion. See inference latency.
Where chunking does not help
Chunking is a horizon trick. It adds no information, repairs no dataset and compensates for no camera that moved between recording and rollout. Being clear saves a week on the wrong number.
- A policy that never learned the task executes its confusion in smoother blocks. Smooth and wrong is still wrong.
- It does nothing about observation-side distribution shift. If the lighting changed, see policy only works in one setup.
- It cannot recover from an error inside the committed block: at n_action_steps=100 and 30 fps, an object that moves just after the query stays invisible for three seconds.
- Longer chunks reduce reactivity by construction. Diffusion Policy puts it plainly: an action horizon greater than 1 helps, "but too long a horizon reduces performance due to slow reaction time".
- It does not make a small dataset behave like a large one. Below ACT's 50 episode minimum no chunk setting rescues the run, and total compute is unchanged, only how often you spend it.

You change chunk_size, retrain, and the loss is worse in a way that makes no sense. chunk_size changes what the loss covers, because action_delta_indices is list(range(chunk_size)): a longer chunk grades predictions further out, which are harder, so loss rises even when nothing is broken. Two runs with different chunk_size are not comparable by loss value, only by rollout success. See loss falls, policy does nothing.
Symptom to setting
| What you see on the arm | Most likely cause | What to change first |
|---|---|---|
| Regular twitch at a fixed interval | Chunk boundary. Interval equals n_action_steps / fps. | Lower n_action_steps, or n_action_steps=1 with temporal_ensemble_coeff=0.01 |
| Smooth, but ignores an object you moved | Committed block too long | Lower n_action_steps. No retrain needed. |
| Trembles continuously, no rhythm | Not chunking. Noisy targets or servo tuning. | Check the data and the arm. |
| Freezes mid motion and never resumes | Queue starvation or a stalled inference call | Measure the endpoint round trip. |
| Sluggish after enabling ensembling | Average dominated by stale predictions | Lower temporal_ensemble_coeff below 0.01 |
| Stepped, staircase-looking motion | Policy rate below the servo command rate | Raise interpolation_multiplier above 1 |
Two of those rows are not tuning problems: policy freezes mid motion and arm twitches then sags have their own pages, indexed with the rest at the fix pages. No hardware yet? The live arm streams a physical SO-100 without signup.
Choosing a policy with chunking in mind
ACT has no base model: it exists only after you train it, so the settings are yours from the first run and the training steps are cheap enough to sweep. The VLAs arrive with a chunk length chosen on someone else's robot and a diffusion or flow matching action head. Fine-tune one and you inherit that length, so your reactivity budget comes entirely from the executed-steps flag.
For the numbers side by side, ACT versus SmolVLA and ACT versus GR00T N1.7 lay out the tiers, and the arena entry for ACT links each benchmark to its paper. Background: the VLA overview, the pi-zero flow matching article, the SO-100 complete guide and train your first policy.
What is the difference between chunk size and action horizon?▾
They usually mean the same thing: how many future actions the network predicts from one observation. The number people confuse it with is the executed horizon, how many are played back before the next query. lerobot calls them chunk_size and n_action_steps, Diffusion Policy Tp and Ta, Isaac-GR00T --execution-horizon.
Do I have to retrain to change how many actions get executed?▾
No. n_action_steps only controls the runtime queue, so you change it on an existing checkpoint and roll out again. chunk_size does require a retrain: it fixes the output shape and the slice of future actions the loss covers.
What is a good chunk size for an SO-100 pick and place?▾
Start at the lerobot default of 100 and treat it as a duration. At 30 fps that is 3.33 seconds, enough for a reach or a grasp. Then leave it alone and tune n_action_steps down to about 25. In the ACT ablation success peaked at k = 100 and tapered at 200 and 400, so there is no reward for going longer.
Should I turn on temporal ensembling?▾
Only if the loop has room for a forward pass every step, because lerobot requires n_action_steps=1 when temporal_ensemble_coeff is set. ACT is listed here at 20 ms per action step and the other four at 152 to 485 ms, so in practice it is an ACT option. Not a guaranteed win either: the ACT paper reports a 3.3 percent gain, while lerobot's PR 319 evaluation of a sim transfer-cube checkpoint scored worse with it.
Why does my training loss go up when I increase chunk size?▾
Because the loss covers more future steps, and steps further out are harder to predict. Expected. Two runs with different chunk_size cannot be compared by loss value, only by rollout success on the real arm.
Does action chunking help with a slow remote inference endpoint?▾
Partly, and less than you would like. More executed steps per query means fewer round trips, which hides latency, but the arm is open loop for that block. You trade reactivity for latency tolerance roughly one for one. For fast motion, inference has to sit next to the servos.
Five policies, compared with real numbers
Chunk defaults, parameter counts, GPU tier, latency per action step and the minimum episode count for each model you can train here.
Compare the policiesSources
- ACT: Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware, Zhao, Kumar, Levine, Finn, 23 Apr 2023
- tonyzhaozh/act: reference ACT implementation, k = 0.01 and DT = 0.02
- lerobot ACTConfig: chunk_size, n_action_steps, __post_init__ validation
- lerobot ACTPolicy.select_action and ACTTemporalEnsembler
- lerobot PR 319: Fix ACT temporal ensembling, merged 16 July 2024
- lerobot-rollout CLI: strategies and sync / rtc inference backends
- lerobot RolloutConfig: fps 30.0 and interpolation_multiplier
- lerobot PI05Config: chunk_size 50, n_action_steps 50, num_inference_steps 10
- NVIDIA Isaac-GR00T: action_horizon 40 in N1.7 and the --execution-horizon rename
- LeRobot docs: Real-Time Chunking (RTC) parameters
- LeRobot cheat sheet: record, train and rollout commands
- LeRobot installation guide: environment, ffmpeg, extras
- Diffusion Policy: Visuomotor Policy Learning via Action Diffusion, Chi et al.
- Real-Time Execution of Action Chunking Flow Policies, Black, Galliker, Levine, NeurIPS 2025
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots, NVIDIA
Sources
- ACT: Learning Fine-Grained Bimanual Manipulation with Low-Cost Hardware, Zhao, Kumar, Levine, Finn, 23 Apr 2023
- tonyzhaozh/act: reference ACT implementation, k = 0.01 and DT = 0.02
- lerobot ACTConfig: chunk_size, n_action_steps, __post_init__ validation
- lerobot ACTPolicy.select_action and ACTTemporalEnsembler
- lerobot PR 319: Fix ACT temporal ensembling, merged 16 July 2024
- lerobot-rollout CLI: strategies and sync / rtc inference backends
- lerobot RolloutConfig: fps 30.0 and interpolation_multiplier
- lerobot PI05Config: chunk_size 50, n_action_steps 50, num_inference_steps 10
- NVIDIA Isaac-GR00T: action_horizon 40 in N1.7 and the --execution-horizon rename
- LeRobot docs: Real-Time Chunking (RTC) parameters
- LeRobot cheat sheet: record, train and rollout commands
- LeRobot installation guide: environment, ffmpeg, extras
- Diffusion Policy: Visuomotor Policy Learning via Action Diffusion, Chi et al.
- Real-Time Execution of Action Chunking Flow Policies, Black, Galliker, Levine, NeurIPS 2025
- GR00T N1: An Open Foundation Model for Generalist Humanoid Robots, NVIDIA
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started