
The SO-100 gripper is one revolute joint with 110 degrees of travel and a torque cap written into the servo. What that means for grasping, compliance and what a policy can learn.
What you need to know
- •The SO-100 gripper is one revolute joint. The URDF limits are -0.174533 to 1.74533 radians, that is -10 to +100 degrees: 110 degrees of jaw swing against a fixed jaw.
- •It is not a parallel jaw. The contact normal rotates as the jaw opens, so a wide grasp and a narrow grasp are different mechanical events.
- •LeRobot writes a force ceiling into the servo on connect: Max_Torque_Limit 500, Protection_Current 250. No policy learns past a limit stored in the motor.
- •The observation is Present_Position only. No current, no torque, no touch, so the camera is the only reliable evidence a grasp worked.
- •In lerobot/svla_so101_pickplace (50 episodes, 11939 frames) the gripper action never exceeds 33.0 out of 100 and sits below 5 in 70.4 percent of frames.
- •gripper.pos is a percentage of whatever span you swept during calibration. Not millimetres, not degrees, not portable between arms.
The gripper is not an accessory, it is the task
Most people building an SO-100 give their attention to the five arm joints and treat the sixth as a switch. Those five move the end effector to a place. The gripper decides whether anything happens once it gets there. Plenty of failures that look like a vision or policy problem are contact problems, and contact is geometry plus stiffness plus force: a printed part and three numbers written into a servo.
Everything below comes from the SO-ARM100 design files, the LeRobot driver source, the Feetech datasheet and two public LeRobot datasets you can measure yourself. Where a number came out of a file, the command that produced it is here too.
Design files: TheRobotStudio/SO-ARM100, main branch on 23 August 2026, SO-101 revision of the parts. Driver: lerobot so_follower, same branch and date. Upstream moves; these numbers are pinned to that snapshot.
What the SO-100 gripper actually is
Open the kinematic model, not the product photo. In so101_new_calib.urdf there are five revolute arm joints plus one called gripper, and that one is revolute too. No prismatic joint, no second finger joint. One motor, one hinge, one moving jaw closing against a jaw moulded into the wrist roll body.
| Property | Value | Source |
|---|---|---|
| Joint type | revolute (hinge, not slide) | so101_new_calib.urdf |
| Limits | -0.174533 to 1.74533 rad, that is -10 to +100 deg | so101_new_calib.urdf |
| Total jaw travel | 110 degrees | upper minus lower |
| Arm freedoms | 5 revolute joints plus the gripper | joint count, same URDF |
| Servo | Feetech STS3215, 1/345 on the follower | LeRobot SO-101 guide |
| Stall torque | 19.5 kg.cm at 7.4 V | Feetech product page |
| Position resolution | 4096 steps per 360 deg, 0.088 deg | Feetech product page |
| Moving jaw part | 22.3 x 92.0 x 48.0 mm bounding box | Moving_Jaw_SO101.stl, measured |
| Normalisation | gripper RANGE_0_100, arm joints DEGREES by default (use_degrees) | so_follower.py |
Two rows do the damage. The first is revolute. A parallel jaw keeps both faces opposed however far it opens; a pivoting jaw does not. Near 100 degrees the moving face points almost sideways, the contact normals stop being opposed, and the grasp is no longer antipodal. Squeeze a cylinder in that pose and the jaw wedges it toward the hinge or squirts it past the tip. For a two-point grasp to resist anything at all the line joining the contacts has to lie inside the friction cone at both of them, and a pivoting jaw walks the contacts off that line as it opens. Roa and Suarez (Autonomous Robots, 2015) is the standard review of the grasp quality measures built on this, and the first family it surveys is exactly where the contact points sit on the object.
The second is five degrees of freedom plus the gripper, not six. Five joints cannot span pose. For any object position there is one family of approach azimuths, set by shoulder pan, plus roll about the tool axis. If the object's long axis lies badly relative to that plane the grasp is unavailable, and no training data changes it. Both arms in the SO-100 against SO-101 comparison share this layout.
Check the geometry yourself
curl -sL -o so101.urdf \
https://raw.githubusercontent.com/TheRobotStudio/SO-ARM100/main/Simulation/SO101/so101_new_calib.urdf
python3 - <<'PY'
import re, math
t = open('so101.urdf').read()
for m in re.finditer(r'<joint name="([^"]+)" type="([^"]+)">(.*?)</joint>', t, re.S):
name, typ, body = m.groups()
lim = re.search(r'lower="([-\d.]+)" upper="([-\d.]+)"', body)
if not lim:
print(f'{name:20s} {typ}')
continue
lo, hi = float(lim.group(1)), float(lim.group(2))
print(f'{name:20s} {typ:10s} {math.degrees(lo):7.1f} to {math.degrees(hi):7.1f} deg'
f' span {math.degrees(hi-lo):6.1f}')
PYThe gripper line prints -10.0 to 100.0 deg, span 110.0. That is the entire vocabulary your imitation learning run has for the word grasp.
The force ceiling LeRobot writes into your servo
The STS3215 takes a target angle, not a target force. Grip force is emergent: command the jaw past the object surface, the servo sees a standing position error and pushes with whatever the gains and torque limit allow. So grip force is not tuned in the policy. It is written into the motor, and LeRobot writes it on every connect.
for motor in self.bus.motors:
self.bus.write("Operating_Mode", motor, OperatingMode.POSITION.value)
self.bus.write("P_Coefficient", motor, self.config.position_p_coefficient) # 16
self.bus.write("I_Coefficient", motor, self.config.position_i_coefficient) # 0
self.bus.write("D_Coefficient", motor, self.config.position_d_coefficient) # 32
if motor == "gripper":
self.bus.write("Max_Torque_Limit", motor, 500) # 50% of max torque to avoid burnout
self.bus.write("Protection_Current", motor, 250) # 50% of max current to avoid burnout
self.bus.write("Overload_Torque", motor, 25) # 25% torque when overloadedRead the comments. The stock configuration gives the gripper half the available torque and half the current, dropping to a quarter once overload protection trips. That is sensible: the gripper spends its life stalled against something, and a stalled STS3215 cooks itself. It is also a firm bound on what your task can require, and better training does not negotiate with it.
| Contact distance from the jaw pivot | Clamping force at the stock torque cap | Note |
|---|---|---|
| 30 mm | about 32 N | strongest, but the faces diverge most here |
| 50 mm | about 19 N | mid jaw, the usual contact zone |
| 70 mm | about 14 N | weakest, best face alignment |
That is arithmetic on the published stall torque, not a measurement: 19.5 kg.cm is 1.91 N.m, half is 0.96 N.m, force is torque over lever arm. It is optimistic twice over, since stall torque is a peak not a continuous spec and Protection_Current usually trips first. Treat it as the number you never exceed.
The STS3215 in an SO-100 or SO-101 is the 7.4 V part. Feeding it 12 V destroys the servos, and it destroys the gripper servo first because that is the one that stalls. Koch v1.1 uses Dynamixel motors on 5 V and 12 V rails and LeKiwi runs a 7.4 V arm on a 12 V base, so a bench with several arms is where this goes wrong. Label your supplies. If an arm started twitching and sagging after a power change, read arm twitches then sags first.
The policy is blind to contact
This is the entire observation the driver assembles per control step:
obs_dict = self.bus.sync_read("Present_Position", num_retry=self.config.num_read_retries)
obs_dict = {f"{motor}.pos": val for motor, val in obs_dict.items()}Present_Position, nothing else. The STS3215 reports current, load, voltage and temperature over the same bus, and none of it reaches the observation vector. So a vision-language-action model has two ways to know a grasp worked: see the object, or notice commanded and reported gripper position disagreeing because a blocked jaw stops short.
That second channel is weak. Across the 11939 frames of lerobot/svla_so101_pickplace the mean gap between commanded and reported gripper position is 2.34 on the 0 to 100 scale, buried in a channel that also carries servo lag. Hence the wrist camera, and hence the people bolting sensors onto the jaw. LeFlexiTac (May 2026) swaps the SO-10x stock jaw for a tactile gripper and reports an ACT policy going from 7 out of 30 to 23 out of 30 on retrieving a pen from a cluttered bag, where the camera sees nothing at contact.
- A contact signal that survives occlusion, exactly when the jaw hides the object from the wrist camera
- Large gains where vision is blocked: 23/30 against 7/30 in the LeFlexiTac pen-in-bag result
- It changes the observation space, a real capability change rather than a hyperparameter
- The observation stops matching the stock
so100_followerfeature set, so existing datasets and checkpoints break - You now maintain a hardware fork, and every LeRobot upgrade becomes a merge
- Every dataset in the public directory assumes the stock six-value state, so warm-starting from other people's data stops working
- For pick and place on rigid objects it rarely pays for itself
Measure the gripper span in your own data before you train
Almost nobody does this, and it takes five minutes. Your episodes contain a gripper channel; look at its distribution, because a fine-tuning run reproduces whatever degeneracy is in there.
- 1Read the metadata
info.json gives the format version, the robot type, the frame count and the names of the six action dimensions.
bashcurl -sL -o info.json \ https://huggingface.co/datasets/lerobot/svla_so101_pickplace/resolve/main/meta/info.json python3 -c "import json;d=json.load(open('info.json'));\ print(d['codebase_version'], d['robot_type'], d['total_episodes'], d['total_frames']);\ print(d['features']['action']['names'])" - 2Read the summary statistics
stats.json holds min, max, mean and std per dimension. The gripper is the last of the six.
bashcurl -sL -o stats.json \ https://huggingface.co/datasets/lerobot/svla_so101_pickplace/resolve/main/meta/stats.json python3 -c "import json;s=json.load(open('stats.json'))['action'];\ print({k:[round(float(x),2) for x in s[k]] for k in ('min','max','mean','std')})" - 3Get the histogram, not just the extremes
Min and max hide the shape, and the shape is where the surprise lives. Download one parquet shard and bin the gripper channel.
bashcurl -sL -o f0.parquet \ https://huggingface.co/datasets/lerobot/svla_so101_pickplace/resolve/main/data/chunk-000/file-000.parquet python3 - <<'PY' import pandas as pd, numpy as np df = pd.read_parquet('f0.parquet') g = np.stack(df['action'].values)[:, 5] n = len(g) print(f'frames {n} episodes {df.episode_index.nunique()}') print(f'gripper min {g.min():.2f} max {g.max():.2f} mean {g.mean():.2f}') for lo, hi in [(0,5),(5,10),(10,20),(20,30),(30,40),(40,100)]: m = ((g >= lo) & (g < hi)).sum() print(f' [{lo:3d},{hi:3d}) {m:6d} {100*m/n:5.1f}%') PY - 4Cross-check against a second dataset
One dataset is an anecdote. Run the same query against lerobot/svla_so100_pickplace and see whether the pattern repeats.
bashcurl -sL https://huggingface.co/datasets/lerobot/svla_so100_pickplace/resolve/main/meta/stats.json \ | python3 -c "import json,sys;s=json.load(sys.stdin)['action'];\ print('min', round(float(s['min'][5]),2), 'max', round(float(s['max'][5]),2))"
Against lerobot/svla_so101_pickplace, 50 episodes of SO-100 follower pick and place at 30 fps, this is what comes back.
| Gripper action band (0 to 100 of calibrated range) | Frames | Share |
|---|---|---|
| 0 to 5 (effectively closed) | 8409 | 70.4 percent |
| 5 to 10 | 293 | 2.5 percent |
| 10 to 20 | 1153 | 9.7 percent |
| 20 to 30 | 1932 | 16.2 percent |
| 30 to 40 | 152 | 1.3 percent |
| 40 to 100 | 0 | 0.0 percent |
The maximum across the dataset is 33.0. Per episode the widest opening runs from 17.8 to 33.0, median 23.2. Two thirds of the jaw's travel never appears once. lerobot/svla_so100_pickplace is a separate 19631-frame recording and stops at 34.93. The pattern repeats, and a policy cannot output an action it never saw.

In so_follower.py the arm joints use MotorNormMode.DEGREES (the use_degrees default) and the gripper alone is hard-coded to MotorNormMode.RANGE_0_100. That 0 to 100 is a percentage of the span you swept during lerobot-calibrate, which asks you to move each joint through its full range of motion. Sweep lazily and 100 means a narrow opening; sweep hard and it means a wide one. Recalibrating after a dataset exists silently changes what every recorded action meant. If a policy works on the arm it was recorded on and nowhere else, start at policy only works in one setup and check calibration before touching the model.
Why a narrow distribution is worse than it looks
ACT and SmolVLA in LeRobot default to MEAN_STD normalisation on the action vector, so each dimension is divided by its own standard deviation before the loss. (Pi0.5 is the exception: configuration_pi05.py sets QUANTILES for state and action.) The gripper's std here is 9.0, the smallest of the six, but normalisation compensates for scale, so it is not underweighted. The problem is worse: the channel is nearly constant, so it is nearly free to predict. A useful diagnostic is the copycat baseline from Wen et al. (NeurIPS 2020), where an imitator echoes the current state instead of predicting the next action. Predict action equals state, then take the mean squared error per dimension in those normalised units:
import pandas as pd, numpy as np, json
df = pd.read_parquet('f0.parquet')
a = np.stack(df['action'].values)
s = np.stack(df['observation.state'].values)
std = np.array([float(x) for x in json.load(open('stats.json'))['action']['std']])
mse = ((a - s) ** 2).mean(0) / std ** 2 # copy-the-state error, MEAN_STD units
names = ['shoulder_pan','shoulder_lift','elbow_flex','wrist_flex','wrist_roll','gripper']
for n, v in zip(names, mse):
print(f'{n:16s} {v:.3f} {100*v/mse.sum():4.1f}% of total')| Action dimension | Copy-the-state error (mean squared, normalised) | Share of the total |
|---|---|---|
| shoulder_pan | 0.025 | 5.7 percent |
| shoulder_lift | 0.035 | 8.0 percent |
| elbow_flex | 0.037 | 8.4 percent |
| wrist_flex | 0.096 | 21.9 percent |
| wrist_roll | 0.028 | 6.5 percent |
| gripper | 0.217 | 49.5 percent |
Four of the six dimensions sit under nine percent of that error each, and the one that decides success carries half of it while contributing one sixth of the loss. That is how a training curve stays clean while the arm reaches the object, hovers and never closes. If that is your symptom, loss falls but the policy does nothing and gripper does not close are the two pages to read.
Compliance is the cheapest accuracy you will buy
A rigid jaw demands the policy place the end effector within a millimetre or two. A compliant jaw deforms around the object, turning positioning error into a harmless bend. Dollar and Howe's SDM Hand (IJRR, 2010) argued for underactuated elastomer-jointed fingers on exactly that ground, and the Fin Ray effect gripper of Crooks et al. (2016) showed how far a passive triangular structure with buckling crossbeams goes.
The SO-ARM100 repository ships this. Optional/Compliant_Gripper holds Compliant_Moving_Jaw_SO101.stl and Compliant_Wrist_Roll_Follower_SO101.stl, replacing both jaws. They are hollowed out with internal ribs, printed in TPU 95A at 20 percent, and the README states the external geometry is identical to the rigid parts apart from some removed holes and the added cavities and ribs, so the assembly does not change. It came out of the June 2025 Hugging Face LeRobot hackathon and credits the Fin Ray Effect.
- Tolerates positioning error, so fewer episodes cover the same envelope
- Lower contact force on fragile objects, which the official README targets
- Drop-in: the README states no change to the assembly or installation process
- Widens the set of shapes one grasp pose works for, which is the same as widening what a policy gets away with
- The jaw deflects under load, so reported position stops mapping to a fixed gap and your weak contact signal gets weaker
- Not every printer handles flexible filament; the README warns about print times and support removal
- Heavy or slippery objects slip where a rigid jaw would hold
- It changes what the gripper channel physically means, so rigid and compliant episodes should not be mixed
How much does jaw shape matter next to the algorithm on top of it? Georgadarellis et al. (17 March 2026, UMass Amherst) had eight participants open bandage packages across 15 bimanual trials in three conditions: bare hands, a modified UMI gripper spreading load across the whole finger face, and the same gripper with angled fingers concentrating load at the tips. The distributed version succeeded on 65.8 percent of trials; the concentrated version and bare hands on all of them. Hands were roughly 15 times faster than the distributed grippers and 4 times faster than the concentrated ones.
What varied was the angle of two printed fingers, and a third of the demonstrations stopped existing. Collect data through a gripper like that and you have a hardware problem wearing a policy problem's clothes. The UMI paper (Chi et al., 2024) makes the general case for handheld rigs; its own gripper is a 780 g printed parallel jaw with an 80 mm finger stroke, soft fingers, and a fiducial marker so finger width is logged continuously rather than as a flag.
What a policy can learn about your gripper, and what it cannot
Splitting this cleanly is the most useful thing to do before spending money on a run. One column is worth more data; the other is worth a different printed part.
| Behaviour | Fixable with data? | Why |
|---|---|---|
| When to close, given the wrist camera | Yes | Visual timing, what a VLA is good at |
| How far to open for an object class | Only inside the span your data used | 40 to 100 never appeared in the reference dataset |
| Landing the object mid-jaw, not at the hinge | Yes | A pose preference, teachable by consistent demonstrations |
| Recovering after a slip | Partly | Only if slips and recoveries are in the data; operators usually restart instead |
| Clamping harder than the stock torque cap | No | Max_Torque_Limit 500 reaches the servo before the policy sees anything |
| Regrasping without releasing | No | One actuator, one hinge, no in-hand freedom |
| Grasping wider than 110 degrees of jaw travel | No | Kinematic limit in the URDF |
| Approaching from an azimuth 5 DOF cannot reach | No | Five joints cannot span pose |
| Modulating force by feel | No | Present_Position is the only proprioceptive channel |
If the failure is when or where, more data usually helps. If it is how hard or from which side, more data almost never helps. Sort your failures into those buckets before renting a GPU. The failure mode index is organised along roughly the same split.

Getting a gripper-aware dataset onto a trained policy
Your machine, your arm. Know this path even if you never use it.
- 1Install LeRobot with the Feetech SDK
The feetech extra talks to the STS3215 bus. Without it the gripper motor is invisible.
bashgit clone https://github.com/huggingface/lerobot.git cd lerobot pip install -e ".[feetech]" - 2Calibrate deliberately and write down that you did
This step defines what gripper.pos means. Sweep the jaw fully closed to fully open every time; recalibrate later and old datasets stop meaning what they meant.
bashlerobot-calibrate \ --robot.type=so101_follower \ --robot.port=/dev/ttyACM0 \ --robot.id=my_follower - 3Record with the jaw span you intend to use
Decide before episode one whether the task needs a wide opening, then use it. A dataset topping out at 33 has decided your policy never opens wider.
bashlerobot-record \ --robot.type=so101_follower \ --robot.port=/dev/ttyACM0 \ --robot.id=my_follower \ --teleop.type=so101_leader \ --teleop.port=/dev/ttyACM1 \ --dataset.repo_id=${HF_USER}/gripper_span_test \ --dataset.num_episodes=50 \ --dataset.single_task="Pick up the block and drop it in the bin" - 4Audit the gripper channel before training
Run the histogram above against your own stats.json. If over 90 percent of frames sit in one bin, that dimension has nothing to teach.
bashpython3 -c "import json;s=json.load(open('meta/stats.json'))['action'];\ print('gripper min',round(float(s['min'][5]),2),'max',round(float(s['max'][5]),2),\ 'std',round(float(s['std'][5]),2))" - 5Train, and own the GPU problem
ACT and SmolVLA fit a 24 GB card. GR00T and Pi0.5 need an 80 GB A100 or H100 you rent and babysit.
bashlerobot-train \ --policy.type=act \ --dataset.repo_id=${HF_USER}/gripper_span_test \ --output_dir=outputs/train/act_gripper
The arm reaches perfectly and never closes, so you conclude the model is undertrained. Check three things first: does the gripper channel in meta/stats.json actually vary; was the arm recalibrated between recording and inference; is Max_Torque_Limit still 500. Five minutes each, and all three are likelier than the model.
Same goal, overhead handled. Nothing here removes the 110 degree jaw span or the torque cap.
- Feel the geometry first. /live streams a physical SO-100 to the browser, no signup, queue based. Open and close the gripper and watch the faces diverge.
- Record with the desktop client, which writes LeRobot-format datasets out of a teleoperation session. Walkthrough: record your first dataset.
- Check gripper spans in the public dataset directory before committing to a plan.
- Pick a model on evidence: the five trainable policies list parameters, GPU tier, latency and minimum episodes, and the arena holds 85 VLA models with 332 benchmark results.
- Train from a form: the backend rents a spot GPU sized to the model's VRAM and writes checkpoints to object storage. Start at ACT on SO-100 or SmolVLA on SO-100.
- Run it back on the arm:
/api/inference/podprovisions a pod serving the checkpoint, with an idle watchdog so nothing bills silently.
| Model | GPU tier | Min episodes | Per action step | Run cost |
|---|---|---|---|---|
| ACT | RTX 4090 or any 24 GB card | 50 | 20 ms | 1 to 3 USD |
| SmolVLA | RTX 4090 or any 24 GB card | 30 | 245 ms | 1 to 3 USD |
| GR00T N1.7 | A100 80 GB or H100 80 GB | 50 | 152 ms | 4 to 12 USD |
| GR00T N1.5 | A100 80 GB or H100 80 GB | 50 | 165 ms | 4 to 12 USD |
| Pi0.5 | A100 80 GB or H100 80 GB | 50 | 485 ms | 4 to 12 USD |
Those per-step numbers matter for grippers. Closing on an unstable object is the most timing-sensitive moment in a task, and inference latency is where remote inference hurts most. ACT at 20 ms has room for a network round trip; Pi0.5 at 485 ms does not. Remote inference works for slow pick and place, not fast reactive motion.
A gripper checklist before you record 50 episodes
| Check | How | If it fails |
|---|---|---|
| Object sits mid-jaw | Hold it in the jaws with torque off | Too small or too round for a pivoting jaw |
| Widest opening the task needs | Open the jaw there and read the value | Your data has to reach that value, so plan the demonstrations around it |
| Rigid or compliant, decided | Pick before episode one | Mixing them mid-dataset changes what the gripper channel means |
| Wrist camera sees the contact point | Watch the stream while closing | The jaw occludes the object when the decision happens and the policy has no evidence |
| Approach azimuth reachable | Rotate the object 90 degrees and retry | Five joints cannot get there; see joint stops early |
| Calibration date written down | Note it with the dataset | Recalibrating mid-dataset silently rewrites every recorded action |
The recording workflow sits in the SO-100 data collection guide and in how to collect high-quality VLA training data. Still assembling? Start at the complete SO-100 setup guide.
Where none of this helps
- No software layer changes the mechanics. AY-Robots can rent the GPU, size the run and serve the checkpoint; it can do nothing about a 110 degree jaw or a 50 percent torque cap. If the task needs a parallel jaw, a suction cup or three fingers, the answer is a different end effector.
- All five trainable policies consume the same six-value action vector, so bolting a tactile sensor onto the jaw takes you off the supported path. Legitimate research, not something a hosted form absorbs.
- Grasp planning is a separate discipline from behaviour cloning. If the real question is which grasp on a novel object is robust, that is what Dex-Net 2.0 answers: 6.7 million synthetic point clouds, 0.8 second planning, 93 percent success on eight known objects and 99 percent precision on 40 novel ones. A demonstration-trained SO-100 policy reproduces the grasps you showed it, nothing more.
- None of it removes the need for consistent human demonstrations, and gripper timing is what separates a usable dataset from an unusable one. The operator page is where that side starts.

Record the span before you train on it
The desktop client records LeRobot-format datasets straight out of a teleoperation session, so you can set the jaw span you actually need and check it in meta/stats.json before renting a GPU.
Get the desktop clientIs the SO-100 gripper a parallel jaw?▾
No. In so101_new_calib.urdf the gripper is a revolute joint limited to -0.174533 and 1.74533 radians, that is -10 to +100 degrees. One jaw swings on a hinge against a fixed jaw moulded into the wrist roll follower body. The faces are only near parallel at the closed end of that 110 degree travel, which is why narrow grasps beat wide ones here.
Why does my policy reach the object but never close the gripper?▾
Check the gripper channel first. In lerobot/svla_so101_pickplace, 70.4 percent of frames sit below 5 on the 0 to 100 scale, so a model can drive that dimension's loss down while learning almost nothing about when to close. Then check the arm has not been recalibrated since recording, and that Max_Torque_Limit is still 500.
What does gripper.pos = 30 mean in millimetres?▾
Nothing fixed. LeRobot declares the gripper with MotorNormMode.RANGE_0_100 while the arm joints use DEGREES, so the value is a percentage of the span you swept during lerobot-calibrate. Two arms with different sweeps report different numbers for the same gap. For millimetres, measure with calipers at a few known values on your own arm.
Should I print the compliant TPU gripper?▾
Worth it for fragile, irregular or hard-to-align objects, which is what the official Optional/Compliant_Gripper README targets. It costs grip strength on heavy or slippery objects and weakens your one contact signal, since a deflecting jaw no longer maps position to a fixed gap. Decide before recording: mixing rigid and compliant episodes changes what the channel means partway through.
How many episodes do I need if I change the gripper?▾
Treat a jaw change as a new robot. Platform minimums are 30 episodes for SmolVLA and 50 for ACT, GR00T N1.5, GR00T N1.7 and Pi0.5, and those assume the data matches the hardware. A dataset recorded with rigid jaws does not describe a compliant one: the same commanded position gives a different gap and a different force.
Sources
- SO-ARM100: Compliant Gripper Guide for the SO-101 Arm (TPU 95A, Fin Ray inspired)
- so101_new_calib.urdf: joint types and limits for the SO-101, including the gripper
- LeRobot so_follower.py: motor normalisation modes, PID gains and gripper torque limits
- LeRobot documentation: SO-101 assembly, motor setup and calibration
- Feetech STS3215 serial bus servo: 19.5 kg.cm at 7.4 V, 4096 step encoder, 1:345 gearing
- lerobot/svla_so101_pickplace: 50 episodes, 11939 frames of SO-100 follower pick and place
- lerobot/svla_so100_pickplace: second public SO-100 dataset used as a cross-check
- Georgadarellis et al., Influence of Gripper Design on Human Demonstration Quality for Robot Learning (2026)
- Chi et al., Universal Manipulation Interface: In-The-Wild Robot Teaching Without In-The-Wild Robots (2024)
- Roa and Suarez, Grasp quality measures: review and performance, Autonomous Robots 38(1):65-88, 2015
- Dollar and Howe, The Highly Adaptive SDM Hand: Design and Performance Evaluation, IJRR 29(5), 2010
- Crooks et al., Fin Ray Effect Inspired Soft Robotic Gripper: From the RoboSoft Grand Challenge toward Optimization, Frontiers in Robotics and AI 3, 2016
- Wen et al., Fighting Copycat Agents in Behavioral Cloning from Observation Histories, NeurIPS 2020
- Mahler et al., Dex-Net 2.0: Deep Learning to Plan Robust Grasps with Synthetic Point Clouds and Analytic Grasp Metrics (2017)
- LeFlexiTac: adding FlexiTac tactile sensing to the SO-10x gripper (Tao et al., Columbia University, project page, May 2026)
Sources
- SO-ARM100: Compliant Gripper Guide for the SO-101 Arm (TPU 95A, Fin Ray inspired)
- so101_new_calib.urdf: joint types and limits for the SO-101, including the gripper
- LeRobot so_follower.py: motor normalisation modes, PID gains and gripper torque limits
- LeRobot documentation: SO-101 assembly, motor setup and calibration
- Feetech STS3215 serial bus servo: 19.5 kg.cm at 7.4 V, 4096 step encoder, 1:345 gearing
- lerobot/svla_so101_pickplace: 50 episodes, 11939 frames of SO-100 follower pick and place
- lerobot/svla_so100_pickplace: second public SO-100 dataset used as a cross-check
- Georgadarellis et al., Influence of Gripper Design on Human Demonstration Quality for Robot Learning (2026)
- Chi et al., Universal Manipulation Interface: In-The-Wild Robot Teaching Without In-The-Wild Robots (2024)
- Roa and Suarez, Grasp quality measures: review and performance, Autonomous Robots 38(1):65-88, 2015
- Dollar and Howe, The Highly Adaptive SDM Hand: Design and Performance Evaluation, IJRR 29(5), 2010
- Crooks et al., Fin Ray Effect Inspired Soft Robotic Gripper: From the RoboSoft Grand Challenge toward Optimization, Frontiers in Robotics and AI 3, 2016
- Wen et al., Fighting Copycat Agents in Behavioral Cloning from Observation Histories, NeurIPS 2020
- Mahler et al., Dex-Net 2.0: Deep Learning to Plan Robust Grasps with Synthetic Point Clouds and Analytic Grasp Metrics (2017)
- LeFlexiTac: adding FlexiTac tactile sensing to the SO-10x gripper (Tao et al., Columbia University, project page, May 2026)
Ready for high-quality robotics data?
AY-Robots connects your robots to skilled operators worldwide.
Get Started