How to train GR00T N1.7 on an SO-101

The SO-101 trains exactly like an SO-100, and the interesting question is everything that happens before the trainer sees your data. This guide leads with the differences and then walks the run.

75 min · intermediate · Last updated 2026-08-09

Trainer key
groot1.7
GPU tier
A100 80 GB or H100 80 GB
Inference
about 152 ms per action step
Batch size
32, gradient accumulation 1
Learning rate
1e-4
Steps
20,000
Dataset format
LeRobot v2.1
Typical run
3 to 6 hours, about 4 to 12 USD
Servos
Feetech STS3215 bus servos
Servo voltage
7.4 V
Short answer

The SO-101 records the same six actuator values as an SO-100 into the same LeRobot v2.1 layout, so GR00T N1.7 fine-tunes on it with identical defaults: batch 32, learning rate 1e-4, 20 000 steps on an A100 80 GB. What differs is upstream: the revised wrist has its own mechanical limits, so the arm needs its own calibration and a copied calibration file will bias every value you record.

What is actually different about an SO-101

The honest answer first, because it saves you reading the rest twice: from the training backend’s point of view, nothing at all. An SO-101 episode contains the same six actuator columns as an SO-100 episode, in the same LeRobot v2.1 layout, and the fine-tune runs with the same defaults on the same GPU tier. There is no SO-101 switch in the training form and there does not need to be one.

What differs sits upstream of the dataset: the wrist, the cable routing, and therefore the calibration and the poses your demonstrations will contain. None of that changes the software path. All of it changes your data, and the data is the only thing the policy ever sees.

SO-100SO-101
ServosFeetech STS3215Feetech STS3215, same bus and same protocol
Supply7.4 V7.4 V, identical requirement
Recorded actuators5 joints plus gripper5 joints plus gripper, the same six columns
WristOriginal designRevised, with different mechanical limits and cleaner cable routing
Parts costroughly 110 to 150 euro per armroughly 130 to 170 euro per arm
Platform supportFull, and the arm every feature is tested on firstFull

Before you start

  • An assembled SO-101 with its own calibration, not one inherited from another arm
  • The 7.4 V supply for the STS3215 servos, verified against the label rather than the connector shape
  • One camera fixed in place at minimum, two if you have a wrist view
  • The client installed and paired, and the arm showing as online in your dashboard
  • A LeRobot v2.1 dataset of 50 or more reviewed episodes of a single task
The wrist changed, the electronics did not

The SO-101 revision is mechanical. Its servos are still 7.4 V STS3215 units and a 12 V brick still ends all six of them in seconds. The new hazard is owning both arms: two bricks on one bench look alike, and the SO-101 will not tell you it is being fed the wrong one until it is too late.

Calibration is the part that genuinely differs

Calibration was always per physical unit, and copying a calibration file between two arms was never valid. On an SO-101 it is worse than invalid. The revised wrist puts the flex and roll limits in different places than the older build, so a file borrowed from an SO-100 does not throw an error. It quietly offsets what every recorded joint value means, and you find out four hours into a fine-tune that the policy reaches consistently past the object.

bash
ay-robots calibrate

# SO-101 on /dev/cu.usbmodem58FA0821911
#  [1/6] shoulder_pan    range ok
#  [2/6] shoulder_lift   range ok
#  [3/6] elbow_flex      range ok
#  [4/6] wrist_flex      range ok
#  [5/6] wrist_roll      range ok
#  [6/6] gripper         range ok   full closure reached
# calibration stored for robot "so101-bench-left"
The sweep is where you find a wrist that cannot reach a pose, which is a joint your data will never teach.

Two things are worth watching during the sweep. First, that the gripper reaches full closure without the servo straining, because a gripper that stops a millimeter short turns every grasp in your dataset into a near miss. Second, that wrist roll travels the whole way in both directions without the cable loom catching. The improved routing makes that less likely than on the older arm, but a loom that has been re-run after a repair can still limit travel.

If both arms are paired to the same account, name them at pairing time. Cross-loading a calibration is a two-click mistake when both robots are called "my arm".

Recording: what carries over and what to reconsider

Everything from the SO-100 recording discipline carries over unchanged: fifty kept episodes as the floor, one task sentence used word for word, failures discarded rather than kept, cameras bolted down. The thing to reconsider is reach. The revised wrist makes some approach angles comfortable that were awkward before, and demonstrations tend to drift toward whatever is comfortable. If you record every episode with the new wrist angle and later want the dataset to serve an SO-100 as well, it will not, because half your poses are outside what that arm does gracefully.

The related question people ask is whether SO-100 and SO-101 episodes can share one dataset. They can, the columns line up exactly. Expect a small cost, because zero points differ between physical units and the model has to absorb that as noise. If you are going to mix, mix by adding to an existing fifty rather than by assembling fifty out of two piles of twenty five. A dataset that is half one arm and half another mostly teaches the model that the mapping is uncertain.

GR00T reads v2.1, and only v2.1

The trainer accepts LeRobot v2.1 datasets and rejects v3.0. Since the client records v2.1 by default, this normally bites people who imported a dataset from elsewhere, or who flipped the setting once for an experiment and never flipped it back before recording fifty episodes.

On the run page the rejection looks like an aborted takeoff. The status moves QUEUED, then RUNNING for under a minute, then FAILED, and there is no loss chart because the trainer never reached the first step. The message talks about the dataset metadata rather than announcing a version mismatch, so it reads like a platform fault. It is not, and re-uploading the same directory reproduces it exactly.

bash
# The one line that decides whether the run starts
grep codebase_version meta/info.json
#   "codebase_version": "v2.1",

# robot_type is bookkeeping for you, not a switch in the trainer
grep robot_type meta/info.json
#   "robot_type": "so101",

Run the fine-tune

  1. 1
    Select the SO-101 dataset in the Training page

    Datasets appear once processing has finished. Check the episode count on the card against what you think you recorded, since a partial upload is the quietest way to train on thirty episodes while believing you trained on sixty.

  2. 2
    Pick GR00T N1.7

    It is listed with the A100 80 GB tier it requests. N1.5 is kept only for reproducing older projects and is worse than N1.7 on every axis that matters, so pass it by unless reproduction is the goal.

  3. 3
    Read the pre-filled hyperparameters and leave them there

    Batch size 32, learning rate 1e-4, 20 000 steps, gradient accumulation 1, plus the save steps field that only GR00T shows. No seed field appears, because this entry point has none. Defaults are the correct first answer on an arm with a well recorded fifty episodes.

  4. 4
    Start the run and note the queue

    The pool buys an 80 GB card on the spot market and picks by VRAM rather than by name, so you may land on an A100 or an H100. Nothing is billed while the job waits in QUEUED.

  5. 5
    Check the loss shape early, then leave it alone

    A visible drop over the first few hundred steps means the data loaded. After that, staring at the curve tells you nothing you can act on, and the GPU telemetry panel is the more useful thing to glance at: a card at full utilization is a run progressing at the rate you are paying for.

  6. 6
    Take two checkpoints into the evaluation

    Pick one from the end of the run and one from the second half, and compare them on the arm rather than on the chart. Save steps decides how many candidates you have to choose between.

Defaults for this model

SettingDefaultChange this when
Batch size32The run reports a memory failure. Halve it and double gradient accumulation so the effective batch is unchanged.
Learning rate1e-4Loss spikes and does not recover, in which case halve it. A weak policy on a stable curve is a data signal, not a learning rate signal.
Max steps20 000Your dataset has grown well past a hundred episodes and loss is still descending at the end of the run.
Gradient accumulation1You reduced the batch size. On its own it only makes the run slower.
Save stepsGR00T-only field, shown in the formYou want more checkpoints to evaluate. On an arm you have just recalibrated, more candidates is cheap insurance.
Seednot available for GR00TNever. Choose Pi0.5 or a lerobot-family model instead if a run has to be repeatable.

Cost and wall clock

This model runs on the A100 80 GB tier, which the pool rents at 1.20 to 2.00 USD per hour. A default 20 000 step run on a fifty to one hundred fifty episode SO-101 dataset takes 3 to 6 hours, so about 4 to 12 USD end to end. Spot prices move, so treat the wider end of the range as normal rather than as a warning sign.

Plan around the duration rather than the price. The useful cadence on an SO-101 is one run per dataset change: record a targeted block of episodes, start the fine-tune before you stop for the day, evaluate in the morning against the same protocol you used last time.

Back onto the arm

Select the checkpoint for the paired SO-101 and start inference from the client. Restore the recording conditions first: camera positions, lighting, reset procedure, and the task sentence exactly as it appears in the dataset. At about 152 ms per action step the arm will move in discrete increments, which is normal for this model and still the fastest of the ones this platform trains.

If the checkpoint was trained on SO-100 data and you are running it on an SO-101, it will load and it will move. Treat it as an untested policy rather than a working one. The differences show up at the grasp, where wrist limits and gripper closure differ most, and the twenty attempt protocol will tell you in ten minutes whether it transferred.

Physical success rate is the only metric that decides anything here. Twenty attempts with the object in twenty positions, written down while they happen. A run with a clean loss curve and four successes out of twenty is a four out of twenty policy, and the curve is not evidence to the contrary.

Clear the bench before the first attempt

The first attempt of a new policy is the least predictable one it will ever make. Move anything breakable out of reach, keep a hand near the power, and do not walk away from the arm until you have twenty attempts of evidence that it behaves.

When it does not work

SymptomFirst thing to check
Loss flattens early and the policy stays mediocreWhether the dataset actually contains the variation you want back. A plateau is the model telling you it has extracted what is there, and more steps will not create more.
The arm stops mid-motion and holds positionWhere exactly it stops. That observation is missing from the training set. Record a block of episodes that passes through that pose and retrain.
It succeeds in the afternoon and fails in the eveningThe light. Every episode you recorded shares one illumination, and the policy is matching pixels. Fix the lighting or record a second block under the other condition.
The gripper reaches the object and never closesCalibration first, on this arm specifically. If the sweep never reached full closure, no amount of extra data fixes it. If closure is fine, the wrist camera is probably occluded at the grasp.
The job fails a minute after it starts runningcodebase_version in meta/info.json. GR00T rejects v3.0, and this is what the rejection looks like from the outside.
Every joint is consistently offset from where it should beWhether this arm was calibrated in its own right. A calibration copied from an SO-100 produces exactly this and produces it silently.

Frequently asked questions

I have an SO-100 dataset and a new SO-101. Do I have to re-record?

No. Train on what you have, then evaluate on the SO-101 with the twenty attempt protocol and see where it lands. If the failures cluster at the grasp, add SO-101 episodes to the existing dataset rather than starting a new one from scratch.

Is the SO-101 a better arm for GR00T than the SO-100?

Not in any way the model can see, since it receives the same six columns either way. The practical argument for the SO-101 is cleaner cable routing and a wrist that binds less, which means fewer ruined episodes. That is a data quality benefit, not a model one.

Which robot_type should the dataset carry?

so101. The trainer does not branch on it, but you will want to know which arm produced which dataset when you have four of them and one of them transfers badly.

Can I record with an SO-100 leader and an SO-101 follower?

Yes, and it is common. What ends up in the dataset is the follower state and action, so the follower is the arm that must be calibrated correctly. Just keep the pairing consistent across a dataset rather than swapping halfway.

Do I need to recalibrate after taking the wrist apart?

Yes, and it is not optional. Reassembly moves the mechanical limits by a small amount, and everything you record afterwards inherits the offset. Recalibrating takes two minutes and re-recording fifty episodes does not.