Robot embodiment stats: the per-embodiment reference
Robot embodiment, in working robotics terms, is a body described by numbers. The numbers say how many joints the model commands, which cameras it sees through, what the commands mean, and how fast they play. This page is the reference for those numbers. It decodes the vocabulary, then documents the norm_stats.json artifact field by field. It tabulates the known bodies exactly as the open publishers print them. It states the stats contract of the platform's published action route.
Eight models are named on this page. All eight are written up on this platform's action route, and none is live today. The public model list carries none of them, and every name answers 404 today. No rate for this route renders anywhere. What follows are the publishers' reference facts, dated the day we read them.
Embodiment vocabulary, decoded
The search results for "robot embodiment meaning" define the word one way. A mind, given a body, that senses and acts in the real world. That is the dictionary half. The word does tighter work in VLA models. It names a set of numbers. Those numbers are what you need when you pick a model or read a stats file.
| Term | What it means in VLA work | Where you meet it |
|---|---|---|
| embodiment | One robot body as the model sees it: a fixed count of action numbers, a fixed set of camera views, one action space, one control rate. | Model pages, dataset cards, the norm_stats.json artifact. |
| cross-embodiment | One model trained on many bodies at once, so shared skills are learned once and the body-specific part is learned per body. | The Open X-Embodiment project, the pi0.5 training mix, the SmolVLA community mix. |
| embodiment gap | The physical differences between two bodies: joint counts, camera spots, link lengths, control rates. A policy trained on one body usually fails on the other because of them. | Forum threads where a fine-tune "works in training" and misbehaves on a different arm. |
| embodiment swap | Taking a model family to a different body, most often by a per-body fine-tune plus that body's own stats artifact. | The pi05 family rows (base, DROID, LIBERO), the MolmoAct2 embodiment tags. |
| norm stats | The per-dimension numbers that map between your robot's units and the small band the model was trained in. | meta/stats.json in a dataset, norm_stats.json beside a checkpoint, the normalization block in a served answer. |
The how-to layer for norm stats has its own guide. It covers computing your own and fixing bad ones: VLA normalization stats, from LeRobot to serving. This page stays on the reference side of that line. What things are, what the publishers publish, and what the route contract says.
What one embodiment is, in numbers
Four axes define a body for a VLA model. Every row in every table below is some mix of these.
Action dimensions. The count of numbers the model outputs per step. An SO-100 or SO-101 arm uses six: five arm joints plus the gripper. A single Franka-class arm uses seven or eight, seven joints plus a gripper. A dual-arm ALOHA setup uses fourteen, two arms of six joints plus a gripper each (ACT paper, 2023). The count is not always what it seems. Publishers pad. The pi model family pads every action to 32 numbers inside the model, with zeros in unused slots (openpi model config). The Open X-Embodiment pool uses one seven-number vector for every body, position or speed plus gripper. Unused dimensions are set to zero during training (Open X-Embodiment project). When you compare two models, check which count is real and which is padding.
Camera set. How many views, and where they sit. The same arm can carry one camera or four. ALOHA uses four: two on the wrists, one front, one top. The LIBERO simulation uses two, an agentview and a wrist view. The publisher's checkpoint decides the names, and the names are part of the contract. The MolmoAct2 port for SO-100 and SO-101 arms expects two views. Their names are cam0 and cam1, one primary and one secondary (LeRobot MolmoAct2 docs). Community datasets name cameras anything: laptop, phone, top. One model family had to map them all to standard views before training (SmolVLA paper, 2025).
Action space. What the numbers mean. Three choices dominate. Absolute joint pose: each number is a joint angle target. Delta joint: each number is a change from the current angle. End-effector: the numbers command the tool tip, as position and rotation changes plus a gripper. Units matter as much as mode. The MolmoAct2 stats for SO-100 arms are in degrees. The pi family uses radians for joints, and its grippers run 0 to 1, open to closed (openpi norm stats docs). The same body can appear under two action modes. The Franka in the DROID setup is joint speed at 15 Hz from one publisher, and absolute joint pose from another. The body is the embodiment. The action mode is the publisher's contract for it.
Control rate. How fast the loop plays the numbers. The same openpi document prints the rates. Franka and UR5e arms run at 20 Hz. ARX and ALOHA-class arms run at 50 Hz. The DROID setup runs at 15 Hz. The chunk the model returns only makes sense against this rate. Multiply the chunk length by the control period and you get the seconds of motion one chunk covers.
A fifth thing rides with all four: the stats. The observed range of each dimension over the training data. The next section covers the artifact that carries them.
The stats artifact, field by field
Publishers ship the per-body numbers as a small JSON file beside the weights. The clearest published example is the MolmoAct2 artifact, which its maker posts with the base checkpoint (the artifact itself, read October 5, 2026). Its shape:
| Field | What it holds |
|---|---|
| format | A version string for the artifact shape, molmoact2_norm_stats.v1. |
| norm_mode | The formula family. This artifact says q01_q99: actions are scaled using the 1st and 99th percentile. |
| metadata_by_tag | One named section per embodiment. Seven sections ship in the base artifact. |
Each section then carries the same fields:
| Per-tag field | What it holds |
|---|---|
| action_key, state_key | The dataset column names the stats describe. |
| camera_keys | The exact camera names the embodiment was trained with. |
| normalize_gripper | Whether the gripper dimension joins the percentile scaling or stays raw. |
| action_horizon, n_action_steps | How long a chunk the embodiment was trained to emit, and how many steps a serving loop plays from it. |
| setup_type | A plain sentence describing the body, fed to the model as prompt text. |
| control_mode | Absolute joint pose, or delta end-effector pose. |
| action_stats, state_stats | Per-dimension arrays: min, max, mean, std, count, five percentiles (q01, q10, q50, q90, q99), the dimension names, and a mask. |
Here is one section, trimmed. It is the Franka in the DROID setup, with its real percentile numbers. A percentile is a cutoff. q01 is the value that 99 percent of readings sit above. q99 is the value they sit below.
"franka_droid": {
"action_horizon": 15,
"control_mode": "absolute joint pose",
"setup_type": "single franka robotic arm in droid",
"camera_keys": ["observation.images.exterior_1_left",
"observation.images.exterior_2_left",
"observation.images.wrist_left"],
"action_stats": {
"names": ["joint_0","joint_1","joint_2","joint_3","joint_4","joint_5","joint_6","gripper"],
"q01": [ -0.3, -0.6, -0.3, -2.6, -0.5, 1.7, -0.5, 0.0 ],
"q99": [ 0.3, 0.7, 0.3, -1.5, 0.4, 2.8, 0.7, 0.9 ]
}
}
Read it as a shape, not as data. Eight action numbers, in radians. Three named cameras. Fifteen steps per chunk. One cutoff pair per dimension. Every section in the artifact reads this way.
Two sibling formats carry the same job elsewhere. A LeRobot dataset keeps its numbers in meta/stats.json, one entry per feature (compute stats source). Each entry holds min, max, mean, std, a frame count, and percentiles at the 1, 10, 50, 90, and 99 percent marks. The pi family keeps one named set per robot family in its checkpoint assets. Its document lists all nine published sets with their bodies and rates (openpi norm stats docs).
The known embodiments, as published
First, bodies the publishers command in joint space. Every number below is printed by the named source. Access dates October 5, 2026.
| Embodiment | Action numbers | Cameras | Control | Chunk | Source |
|---|---|---|---|---|---|
| SO-100 / SO-101 | 6: shoulder pan, shoulder lift, elbow flex, wrist flex, wrist roll, gripper. Degrees. | 2, named cam0 and cam1 (primary and secondary view) on the converted checkpoint | absolute joint pose | 30 in the artifact; the LeRobot port sets its own length, 10 in its LIBERO recipe | MolmoAct2 artifact, SO-101 docs |
| ALOHA | 14: two arms, six joints plus gripper each. Radians. | 4: two wrist, one front, one top | absolute joint positions at 50 Hz | 100 | ACT paper, openpi stats |
| Franka in DROID, joint pose variant | 8: joints 0 to 6 plus gripper. Radians. | 3: two exterior, one wrist | absolute joint pose | 15 | MolmoAct2 artifact |
| Franka in DROID, velocity variant | 8: joint speeds 0 to 6 plus gripper | 3, per the DROID camera keys above | joint speed at 15 Hz | 50 | openpi stats |
| Franka FR3 with Robotiq gripper | 7 joints plus gripper | per your setup | 20 Hz | 50 | openpi stats |
| UR5e with Robotiq gripper | 6 joints plus gripper | per your setup | 20 Hz | 50 | openpi stats |
| Bimanual YAM | 14: two arms, six joints plus gripper each | 3: top, left, right | absolute joint pose | 30 | MolmoAct2 artifact |
One note on the chunk column. The openpi rows carry the pi family's default length of 50 steps (openpi model config). The MolmoAct2 rows carry each section's own action_horizon from the artifact.
Second, bodies the publishers command in end-effector space, where the numbers move the tool tip instead of the joints.
| Embodiment | Action numbers | Cameras | Control mode | Chunk | Source |
|---|---|---|---|---|---|
| LIBERO, a simulated Franka | 7: x, y, z, roll, pitch, yaw, gripper | 2: agentview and wrist, simulated | delta end-effector pose | 10 | MolmoAct2-LIBERO artifact |
| WidowX in the Bridge data | 7: x, y, z, roll, pitch, yaw, gripper | 4: image_0 to image_3 | delta end-effector pose | 5 | MolmoAct2 artifact |
| Franka in the MolmoAct data | 7: x, y, z, rx, ry, rz, gripper | 2: primary and secondary | delta end-effector pose | 10 | MolmoAct2 artifact |
| Google robot in the Fractal data | 7: x, y, z, roll, pitch, yaw, gripper | 1 | delta end-effector pose | 3 | MolmoAct2 artifact |
| Google robot in the BC-Z data | 7: x, y, z, roll, pitch, yaw, gripper | 1 | delta end-effector pose | 10 | MolmoAct2 artifact |
| The Open X-Embodiment pool | one unified 7-number vector, position or speed plus gripper; unused dimensions zero | varies, 22 embodiments | per dataset | varies | Open X-Embodiment project |
Three rows deserve a second look.
The SO-100 and SO-101 row carries a published trap. The MolmoAct2 checkpoint for these arms was trained on a different joint calibration than current LeRobot. The fix is baked into the converted checkpoint as two small arrays. The signs are [1, -1, 1, 1, 1, 1]. They flip one joint's direction. The offsets are [0, 90, 90, 0, 0, 0] degrees. They shift two joints by 90 degrees. Working the transform out by hand is a documented way to make the arm move wrong (LeRobot MolmoAct2 docs).
The two Franka rows are the same robot. Same arm, same cameras, same data family. Two publishers, two action modes. When you compare models, the body is the embodiment and the action mode is the publisher's contract.
The DROID dataset behind two of those rows is itself a body spec worth naming: 76,000 demonstration trajectories, 350 hours, 564 scenes, 84 tasks, collected on a shared Franka platform (DROID paper, 2024).
Per-model stats modes: the reference twin
The pairing guide carries the how-to version of this table, with the failure signs and fix commands. This is the reference version. It says what each planned model wants, where its numbers live, and how a body is chosen. The modes match the guide cell for cell.
| Model (planned) | Stats mode | Where the stats live | How a body is chosen |
|---|---|---|---|
| pi05 | quantile, q01 and q99 | checkpoint assets, one named set per robot family, nine published | the row you call: base, or the DROID set, or the LIBERO set |
| pi05-droid | quantile, q01 and q99 | the DROID set from the same assets | fixed at the row: the DROID body |
| pi05-libero | quantile, q01 and q99 by default; the published LIBERO recipe trains in mean/std instead | the LIBERO set from the same assets | fixed at the row: the simulated Franka |
| smolvla | mean and std | your dataset's meta/stats.json | your dataset; community cameras map to standard views in training |
| act | mean and std, images included | your dataset's meta/stats.json | your dataset and camera set |
| openvla-oft | quantile bounds on its LIBERO and Bridge setups, plain bounds on ALOHA | per-dataset statistics shipped with the weights | an unnorm_key naming the dataset whose stats undo the output |
| molmoact2-so100-101 | quantile, q01 and q99 (the artifact's norm_mode) | norm_stats.json beside the weights, one section per tag | the tag: so100_so101_molmoact2 among seven in the base artifact |
| x-vla-0.9b | identity in its LeRobot config, no stats file | learned soft prompts carry the body instead | prompts learned per body, backbone frozen |
The quantile mode needs its plain definition, because two of these families will not train without it. Values are scaled into the band using the 1st and 99th percentile, not the raw minimum and maximum. One episode with a servo pressed past its limit cannot stretch the scale for the whole dataset. Datasets older than the percentile fields fail loudly on the first batch. The two fixes, recompute or switch modes, are the guide's territory (LeRobot pi05 docs, the guide).
The route returns the stats it applied
The action route's published contract makes the serving side of this subject a stated fact instead of a guess. Every answer from POST /v1/action carries three fields. The action chunk. A usage block that carries the bill. And a normalization block. The block holds the stats the model applied to produce that chunk, and it crosses unchanged, byte for byte. The machine reference for every field is the run-action reference page. The full route contract, request shapes and polling math, is the action route page.
The block is your check, not decoration. It should carry one number per action dimension of the body the model answered for. If it describes a different body than yours, the actions were shaped for that body. No amount of retry logic fixes that. This is the whole reason the block is contract.
Who owns what, in one small table:
| Side | Owns |
|---|---|
| The platform side, per call | Applying the model's own stats. Stating them in the response, every answer, unchanged. |
| Your side, per call | Sending state in the units your body's contract expects. Feeding the camera views the model trained on. The emergency stop and the joint limits. |
A robot with no state sensors sends the two characters [] as its state. That is the legal stateless embodiment on this route. And if you fine-tune your own policy, its stats are part of it and travel with it. The guide covers what any host then owes you (the guide).
Embodiment swaps and cross-embodiment models
The mechanisms differ by family, and the differences are worth knowing before you pick a row.
The pi05 family ships one model per body. The base is pre-trained on more than 10,000 hours across robots. Expert sets exist for the DROID Franka setup and for LIBERO (openpi README). The pi0.5 paper describes the method. It co-trains on mixed tasks, with data from many robots plus web data in one mix (pi0.5 paper, 2025). Its maker also says the plain part. The models were built for their own robots, which differ from the common platforms. Not every adaptation attempt will succeed. The DROID set, in their words, generalizes quite broadly in practice.
MolmoAct2 takes the tag route. One base checkpoint, and each body's fine-tune carries its own stats artifact, prompt sentence, image-key order, and chunk length, selected by name. The LeRobot port calls the selection a norm tag. Its document is blunt about the tempting shortcut. Do not feed rough percentile values from a benchmark dataset in place of the released file. The values differ (LeRobot MolmoAct2 docs).
SmolVLA takes the community route. It is pre-trained on 481 public datasets, 22.9 thousand episodes, 10.6 million frames, filtered by embodiment type. Every dataset's oddly named cameras were mapped to standard views (SmolVLA paper, 2025). X-VLA takes the learned route. Small prompt embeddings encode each body. A new body means learning new prompts, with the rest of the model frozen (LeRobot X-VLA docs).
One project named this vocabulary. Open X-Embodiment pooled more than one million trajectories from 22 robot bodies: single arms, dual arms, quadrupeds. Sixty datasets, 34 labs. It trained the RT-X models on the mix (Open X-Embodiment project). Every cross-embodiment claim today stands on that pool or its successors. The pool does not erase the gap. The stats artifact exists because bodies differ. No pool makes your joint conventions mine.
Frequently asked questions
What does robot embodiment mean?
In general use, a mind connected to a body that senses and acts. In VLA work, something tighter and more useful: one robot body as a set of numbers. Action dimensions, camera set, action space, control rate, plus the stats that map its units. Two robots with the same motors can be different embodiments if their calibration differs. The published SO-100 transform is the working example.
What is cross embodiment robot learning?
Training one policy on data from many bodies at once, so shared skills are learned once and only the body-specific part is relearned per robot. The Open X-Embodiment project is the reference pool: 22 bodies, more than a million trajectories. The pi0.5 model is a current example built with co-training across robots. Transfer is real, and it is strongest between close relatives. Community SO-100 data transfers best to SO-100-class arms.
How many joints does an SO-100 or SO-101 have?
Six motors in total. Five arm joints, then the gripper. That gives six action numbers per step, in degrees in the MolmoAct2 artifact. The two arms differ in gearing and rigidity, not in joint count.
What is norm_stats.json?
A small JSON file a publisher ships beside the weights. It holds the per-body numbers: the formula family (the MolmoAct2 artifact says q01_q99), one named section per body, and per-dimension arrays of min, max, mean, std, count, and five percentiles. Sibling formats are a dataset's meta/stats.json and the named sets inside pi-family checkpoint assets.
Which embodiment stats does the action route return?
The ones the model applied, in the normalization block of every answer, passed through unchanged. The contract is on the route, not on a docs page's goodwill. Read the block when the arm misbehaves. It tells you which body's numbers shaped the actions you just received.
Do I need my own norm stats to use the route?
Not for the planned published rows. The platform side applies each model's own stats and states them per answer. What stays yours is sending state in the units the body's contract expects, feeding the trained camera views, and the safety layer. If you fine-tune your own policy, you bring its stats with it. The normalization guide covers that path end to end.
What is the embodiment gap?
The physical differences between bodies: joint counts, camera spots, link lengths, control rates, calibration. It is why a policy trained on one arm degrades on another, why stats are per-body, and why cross-embodiment training is a research field rather than a checkbox.
The vocabulary is the entry point and the numbers are the substance. An embodiment is four numbers plus a stats file. The publishers print both, dated, in the artifacts and documents cited above. The stats contract on this platform's action route writes the serving half into every response. For computing and fixing your own stats, read the normalization guide. For the route's request and polling contract, read the action route page. The model class, and the family each model belongs to, live on the VLA page.
Last verified: 2026-10-05