URDF Tutorial: Complete Guide to Robot Description Files
URDF (Unified Robot Description Format) is the standard way to describe a robot's physical structure in ROS and ROS2. This tutorial covers everything you need to know, from basic concepts to production-ready robot descriptions.
In this article
What is URDF?
URDF stands for Unified Robot Description Format. It is an XML-based file format used across the ROS ecosystem to describe a robot's mechanical structure, including its rigid bodies (links), the connections between them (joints), how the robot looks (visual geometry), how it interacts with the physical world (collision geometry), and its mass properties (inertial parameters).
Every ROS2 tool, from Gazebo simulation to MoveIt motion planning to RViz visualization, reads URDF files to understand your robot. Getting your URDF right is the foundation of everything else in the ROS2 ecosystem. A minimal URDF file looks like this:
<?xml version="1.0"?>
<robot name="my_robot">
<link name="base_link">
<visual>
<geometry>
<box size="0.3 0.3 0.1"/>
</geometry>
</visual>
</link>
</robot>This defines a robot with a single rectangular link. Real robots are far more complex, but every URDF follows the same structure: a collection of links connected by joints, forming a tree (not a graph, which is an important limitation to understand).
Links: The Building Blocks
A link represents a single rigid body in your robot. Each link can have up to three sub-elements: visual (how it looks), collision (its physical shape for contact detection), and inertial (mass and rotational inertia). Here is a complete link definition:
<link name="upper_arm">
<visual>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.04" length="0.3"/>
</geometry>
<material name="blue">
<color rgba="0.2 0.4 0.8 1.0"/>
</material>
</visual>
<collision>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<geometry>
<cylinder radius="0.05" length="0.32"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<mass value="2.5"/>
<inertia ixx="0.02" ixy="0" ixz="0"
iyy="0.02" iyz="0" izz="0.003"/>
</inertial>
</link>URDF supports four primitive geometry types: box, cylinder, sphere, and mesh. Meshes let you use detailed 3D models (STL or DAE files) for realistic visualization while keeping simpler primitives for collision detection.
The origin element on each sub-element defines its position and orientation relative to the link's reference frame. The rpy attribute specifies roll, pitch, and yaw in radians.
Joints: Connecting Links Together
Joints define the kinematic relationships between links. Each joint connects a parent link to a child link and specifies how they can move relative to each other. URDF supports six joint types:
- revolute - Rotates around an axis with upper and lower limits (most common for robot arms)
- continuous - Like revolute but with no limits (wheels, for example)
- prismatic - Translates along an axis (linear actuators)
- fixed - No motion, rigidly attaches two links
- floating - Allows motion in all 6 degrees of freedom
- planar - Allows motion in a plane perpendicular to the axis
<joint name="shoulder_pan_joint" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14"
effort="50.0" velocity="1.0"/>
<dynamics damping="0.5" friction="0.1"/>
</joint>The axis element defines which axis the joint rotates or translates along. The limit element is required for revolute and prismatic joints and specifies position limits (in radians or meters), maximum effort (torque or force), and maximum velocity. The dynamics element adds damping and friction for more realistic simulation behavior.
Visual vs Collision Geometry
A common source of confusion for URDF beginners is the difference between visual and collision geometry. Visual geometry is what you see in RViz or your 3D viewer: it can use high-polygon meshes, colors, and textures for a detailed appearance. Collision geometry is what the physics engine uses for contact detection: it should be as simple as possible for computational efficiency.
Best practice is to use detailed meshes (STL/DAE) for visual geometry and simplified convex hulls or primitive shapes for collision geometry. A robotic gripper finger might have a 10,000-triangle mesh for visualization but use a simple box for collision. This keeps simulation fast without sacrificing visual fidelity.
<link name="gripper_finger">
<!-- Detailed mesh for visualization -->
<visual>
<geometry>
<mesh filename="package://my_robot/meshes/finger.dae"
scale="0.001 0.001 0.001"/>
</geometry>
</visual>
<!-- Simple box for fast collision checking -->
<collision>
<geometry>
<box size="0.02 0.08 0.01"/>
</geometry>
</collision>
</link>If you omit collision geometry, your robot will pass through objects in simulation. If you omit visual geometry, your robot will be invisible in viewers but still physically present. Both should be defined for every link that interacts with the environment.
Inertial Properties for Physics Simulation
Inertial properties, including mass, center of mass, and the inertia tensor, are essential for accurate physics simulation. Without them, simulators like Gazebo and MuJoCo cannot compute realistic dynamics. The inertia tensor is a 3x3 symmetric matrix that describes how mass is distributed within the link.
<inertial>
<!-- Center of mass position -->
<origin xyz="0 0 0.1" rpy="0 0 0"/>
<!-- Mass in kilograms -->
<mass value="1.5"/>
<!-- Inertia tensor (kg*m^2) -->
<inertia ixx="0.01" ixy="0.0" ixz="0.0"
iyy="0.01" iyz="0.0"
izz="0.005"/>
</inertial>Calculating inertia tensors manually is tedious and error-prone. For primitive shapes, you can use standard formulas (a solid cylinder of mass m, radius r, and height h has ixx = iyy = m(3r² + h²)/12 and izz = mr²/2). For complex meshes, you typically need CAD software like SolidWorks or Fusion 360 to compute the values.
Incorrect inertial values cause simulation instability, jittering, and unrealistic behavior. A common mistake is setting mass to zero or using an identity inertia matrix. Kindly IDE's physics linter automatically calculates correct inertial properties from your geometry, flagging any link that has missing or physically implausible values.
Common URDF Pitfalls and How to Avoid Them
After working with hundreds of URDF files, these are the most frequent mistakes we see:
Kinematic loops
URDF only supports tree structures. If your robot has a closed kinematic chain (like a parallel gripper or a four-bar linkage), you need to break the loop with a virtual joint and use a plugin or mimic joint to enforce the constraint.
Missing inertial elements
Every link that is not a leaf in the tree should have inertial properties. Missing them causes simulation crashes or the link being treated as massless, leading to numerical instabilities.
Joint name mismatches
Joint names in URDF must exactly match the names used in ros2_control config, MoveIt config, and controller YAML files. A typo here causes silent failures that are hard to track down.
Wrong units
URDF uses SI units: meters for length, radians for angles, kilograms for mass. Importing meshes from CAD software that uses millimeters without scaling is a classic mistake that produces robots 1000x too large.
Incorrect origin frames
The joint origin defines the transform from the parent link frame to the child link frame. Getting this wrong produces robots with links stacked on top of each other or oriented incorrectly. Always visualize your URDF in RViz or a 3D editor before using it.
Generating URDF Automatically with Kindly IDE
Writing URDF by hand is a rite of passage in robotics, but it does not have to be. Kindly IDE provides two ways to create URDF files without manual XML editing:
AI generation: Describe your robot in natural language, such as "a 6-DOF robot arm with a parallel gripper, 80cm reach, and 5kg payload," and Kindly IDE generates a structurally valid URDF with correct kinematics, inertial properties, and collision geometry. The AI robot design system uses structured output validation to ensure every generated URDF passes the physics linter.
Visual editor: Build your robot interactively in the 3D viewport. Add links, connect them with joints, adjust geometry and transforms visually, and see the URDF update in real time in the integrated code editor. This is particularly useful for learning URDF because you can see the relationship between the XML and the 3D visualization.
Both approaches produce URDF files that are ready for ROS2 integration, with correct naming conventions, complete inertial properties, and properly defined joint limits. Export to SDF (for Gazebo) and MJCF (for MuJoCo) is also built in.
Continue Learning
Start building robots with AI
Stop writing URDF by hand. Kindly IDE generates valid robot descriptions from natural language or visual editing, complete with physics validation. Free and open source.
Download Kindly IDE