RDF, ROS, and Sim-to-Real: Understanding Robot Description Files
2nd March 2026
When you start to work with robot simulation, you immediately meet a file called something.urdf. This is true whether you use Isaac Sim, Gazebo, or MoveIt. It’s one of those things that seems simple on the surface but connects to everything in the robotics stack. Here’s a clear breakdown of what URDF is, what it isn’t, and how it fits alongside ROS.
What is URDF?
URDF stands for Unified Robot Description Format. It’s an XML file that describes what a robot physically is:
- Links — rigid bodies (the physical segments of the arm)
- Joints — connections between links (how they move relative to each other)
- Mass & inertia — how heavy each part is and how it resists rotation
- Collision shapes — simplified geometry for physics engines
- Visual meshes — detailed 3D models for rendering
The critical distinction: URDF does NOT control the robot. It only describes what the robot is. Think of it as a blueprint, not a control system.
URDF Structure: The Kinematic Tree
A URDF file defines a tree of links connected by joints:
base_link
↓ (joint_1: revolute)
link_1
↓ (joint_2: revolute)
link_2
↓ (joint_3: revolute)
gripper
Each link includes:
| Property | What It Defines |
|---|---|
| Mass | Weight of the link (kg) |
| Inertia | Rotational inertia tensor (3x3 matrix) |
| Collision mesh | Simplified shape for physics calculations |
| Visual mesh | Detailed 3D model for rendering (STL/DAE files) |
Each joint includes:
| Property | What It Defines |
|---|---|
| Type | revolute, prismatic, fixed, continuous |
| Axis | Which axis the joint rotates/slides around |
| Limits | Min/max angle, max effort, max velocity |
| Parent link | The link “above” in the tree |
| Child link | The link “below” in the tree |
Example URDF Snippet
Here’s what a simplified SO-101 arm URDF looks like:
<link name="base_link">
<inertial>
<mass value="1.5"/>
<inertia ixx="0.01" ixy="0" ixz="0"
iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
<visual>
<geometry>
<mesh filename="meshes/base.stl"/>
</geometry>
</visual>
<collision>
<geometry>
<cylinder radius="0.05" length="0.1"/>
</geometry>
</collision>
</link>
<joint name="joint_1" type="revolute">
<parent link="base_link"/>
<child link="link_1"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57"
effort="10" velocity="2.0"/>
</joint>
This tells any simulator or visualization tool:
- what moves
- how it moves
- how heavy it is
- what shape it has
URDF in the Robotics Ecosystem
URDF is primarily associated with the ROS (Robot Operating System) ecosystem. It enables:
- RViz — 3D visualization of the robot model and sensor data
- MoveIt — motion planning and inverse kinematics
- Gazebo — physics simulation
- Isaac Sim — NVIDIA’s simulator imports URDF and converts it to USD internally
URDF is NOT Physics
This is an important distinction. URDF describes structure. Physics engines use URDF as input to build their internal representation:
URDF (structure blueprint)
→ Physics Engine (Isaac / Gazebo / MuJoCo)
→ Internal Physics Model (collisions, gravity, friction, contacts)
The actual physics behavior depends entirely on the simulator. This includes how objects collide, how friction works, and how gravity affects motion. If two simulators receive the same URDF, they can produce different physics behavior. The reason is that they use different solvers and contact models.
URDF vs Other Robot Description Formats
| Format | Used In | Purpose |
|---|---|---|
| URDF | ROS ecosystem | Robot structure (kinematic tree) |
| USD | Omniverse / Isaac Sim | Full 3D scene description |
| MJCF (XML) | MuJoCo | Physics + control definition |
| SDF | Gazebo | Advanced simulation (extends URDF) |
For an SO-101 arm, the GitHub repo typically includes both SO101.urdf (for ROS tools) and SO101.xml (MJCF format for MuJoCo). Isaac Sim cannot open URDF directly as a scene file. It imports the URDF and converts it to USD internally.
Now, What About ROS?
This is where confusion often starts. People see URDF files, launch files, rosbag files, and assume ROS is some kind of file-based system. It’s not.
ROS is middleware, a communication framework for robots. Think of it as a message bus:
Node A (camera driver)
publishes → /camera/image → 30 fps live stream
Node B (motor driver)
publishes → /joint_states → 50 Hz joint angles
subscribes ← /joint_commands ← target positions
Node C (VLA controller)
subscribes ← /camera/image
subscribes ← /joint_states
publishes → /joint_commands
Nodes send and receive messages via topics. This is live streaming data, not file I/O. ROS does not need any files to operate.
ROS: Streaming vs Files
Topics = Live Streams
/joint_states → publishing 50 times/sec → live data, no file
/camera/image → publishing 30 times/sec → live data, no file
This is a live data stream. It needs no file.
Files Are Optional (For Recording)
If you want to record demo data, debug later, or train ML models, you use:
ros2 bag record /joint_states /camera/image
That writes the live topic stream into a file on disk. But ROS itself does not need it to function.
Where URDF Fits With ROS
URDF is separate from ROS. ROS uses URDF so it knows the robot’s structure:
- What joints exist?
- What are their names?
- What are their limits?
Without URDF, ROS can still stream topics. But it won’t understand the robot’s structure. You lose visualization, motion planning, and collision checking.
| Thing | Required? | What It Does |
|---|---|---|
| ROS | Yes (if using ROS) | Communication layer between nodes |
| URDF | No (optional but common) | Robot structure blueprint |
| rosbag | No | Records topic data to disk |
| Launch file | No | Auto-starts multiple nodes |
For the SO-101: Why URDF Matters for Sim-to-Real
Sim-to-real transfer means you train a VLA in simulation and deploy it on the physical arm. If you own a real SO-101 and want to do this, URDF alignment is critical:
- Same joint names in sim and real — so commands map correctly
- Same joint limits — so the policy never commands impossible positions
- Same kinematic tree — so the model’s internal representation matches reality
Suppose your simulation URDF says joint_1 has a range of [-1.57, 1.57] radians. But your real motor only supports [-1.0, 1.0]. Then your trained policy will try to move past the physical limit. That misalignment is where sim-to-real fails.
URDF (shared blueprint)
├── Simulation (Isaac Sim / Gazebo)
│ → trains VLA policy
│ → uses URDF joint names + limits
│
└── Real Robot (SO-101 hardware)
→ executes VLA policy
→ same joint names + limits
→ policy transfers cleanly
Putting It All Together
Three separate concepts, three different roles:
URDF = Robot structure file (what the robot IS)
ROS = Communication layer (how nodes TALK)
rosbag = Recording file (saving streams to DISK)
URDF tells tools what your robot looks like. ROS lets your robot’s software components communicate in real time. Rosbag lets you record that communication for later analysis or training. They’re complementary but independent. When you understand where each one starts and stops, you will save hours of confusion as you build your robotics stack.
More recent articles
- pi-durable, from the ground up - 20th October 2026
- Hermes Agent: The Self-Improving Story - 12th June 2026
- Claude Code Dynamic Workflows: Inside Out - 29th May 2026