What is URDF? The robot description format explained
URDF (Unified Robot Description Format) is the XML format that defines a robot's links, joints, inertia, and geometry for ROS and most simulators — here's its structure, its strict limits, and the parser gotchas.
URDF (Unified Robot Description Format) is an XML format that describes a robot as a tree of rigid bodies. It originated in ROS and became the lingua franca of robot models: ROS, Gazebo, MoveIt, MuJoCo importers, Isaac Sim, PyBullet, and most web viewers all consume it — each with slightly different interpretations, which is where most of the pain lives.
The three building blocks
| Element | What it defines | Key children |
|---|---|---|
<link> | A rigid body | <inertial> (mass + inertia tensor), <visual> (what renders), <collision> (what physics uses) |
<joint> | How two links connect | <parent>, <child>, <origin> (the child frame's pose), <axis>, <limit> |
<robot> | The root container | All links and joints, plus <material> definitions |
A minimal valid robot — one arm on one base:
<robot name="two_link">
<link name="base">
<inertial>
<mass value="1.0"/>
<inertia ixx="0.1" iyy="0.1" izz="0.1" ixy="0" ixz="0" iyz="0"/>
</inertial>
</link>
<link name="arm"/>
<joint name="shoulder" type="revolute">
<parent link="base"/>
<child link="arm"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="10" velocity="2"/>
</joint>
</robot> Joint types
URDF supports exactly six: revolute (rotation with limits), continuous (unlimited rotation — wheels), prismatic (linear sliding), fixed (welded), floating (6-DOF free), and planar. Everything is single-axis: there is no ball joint, no universal joint. If your mechanism needs one, you approximate with stacked single-axis joints or switch formats — see the comparison.
The hard limits (by design)
- Tree structure only. Every link has exactly one parent; kinematic loops (four-bar linkages, parallel robots, closed grippers) cannot be represented. This is URDF's most fundamental constraint.
- No sensors, no world. URDF describes one robot's mechanics; cameras, lidars, physics settings, and environments live elsewhere (SDF, simulator config, or vendor extensions).
- All units are SI, all angles radians — metres, kilograms, kg·m² for inertia. A file authored in millimetres is wrong by a factor of 1000 and the parser will not warn you.
Parser divergence: the gotchas that eat afternoons
| Situation | What actually happens |
|---|---|
| Link with zero or missing mass, attached by a joint | RViz renders it fine; Gazebo's physics silently drops the link |
Joint without explicit <axis> | Defaults to (1,0,0) in some parsers, errors in others |
Revolute joint without <limit> | Required by spec; parsers disagree on the fallback |
Mesh path using package:// | Resolves only inside a ROS workspace — breaks in MuJoCo, web viewers, plain scripts |
| Inertia violating the triangle inequality | Physically impossible; some simulators go numerically unstable rather than erroring |
All of these are checked automatically by the free URDF validator — paste your file, get a structural report in seconds, no ROS install.
Need the full element/attribute syntax on one page instead of prose? See the URDF cheat sheet.
Where URDF files come from
Almost never written raw by hand. Real sources: xacro templates (the standard for maintainable robots), CAD exporters (SolidWorks/Fusion/Onshape plugins, or a STEP → URDF converter that computes inertia from geometry), and conversion from other formats (SDF → URDF).