ROS 2 URDF Tutorial: Build and Validate a Robot Model
May 21, 2026By URDF Hub editorial teamUpdated August 18, 20264 min read

ROS 2 URDF Tutorial: Build and Validate a Robot Model

A ROS 2 URDF describes the robot model; it does not by itself make the robot move. Build the link-and-joint tree first, validate it in RViz with robot_state_publisher, and then add the controller or simulator integration required by your ROS distribution and hardware.

1. Create the smallest valid robot model

URDF is XML. A robot is a tree of rigid link elements connected by joint elements. Start with geometry and the kinematic relationship, then add collision and inertial data before relying on physics simulation.

<?xml version="1.0"?>
<robot name="two_link_robot">
  <link name="base_link" />
  <link name="arm_link" />

  <joint name="arm_joint" type="revolute">
    <parent link="base_link" />
    <child link="arm_link" />
    <origin xyz="0 0 0.3" rpy="0 0 0" />
    <axis xyz="0 0 1" />
    <limit lower="-1.57" upper="1.57" effort="20" velocity="1" />
  </joint>
</robot>

Keep link and joint names unique. Confirm that mesh paths resolve from the installed ROS package, joint axes match the physical mechanism, and limits use the units expected by URDF. Do not invent mass, inertia, effort, or velocity values for a real robot.

2. Use Xacro only when repetition justifies it

Xacro generates URDF from macros, properties, and expressions. It is useful for repeated structures and robot variants, but the generated robot description must still be valid. Keep a simple model as plain URDF until the link tree is correct; then introduce macros without changing the resulting semantics.

3. Load the model into robot_state_publisher

Pass the generated XML as the robot_description parameter. robot_state_publisher combines that model with joint states to publish the transform tree. Fixed transforms are published separately from transforms that depend on moving joints.

robot_state_publisher = Node(
    package="robot_state_publisher",
    executable="robot_state_publisher",
    parameters=[{"robot_description": robot_description}],
    output="screen",
)

The official urdf_launch package also provides reusable launch files for loading a URDF or Xacro model and displaying it with RViz and a joint-state publisher. Use the package version shipped for your ROS distribution.

4. Validate the model in RViz before adding physics

  1. Confirm that every expected frame appears in the TF tree.
  2. Move non-fixed joints through their permitted range.
  3. Check axes, origins, rotations, and mesh scale from multiple viewpoints.
  4. Resolve missing-package and missing-mesh errors before proceeding.
  5. Verify that link and joint names match downstream configuration files.

A joint-state publisher is useful for visualization tests. Publishing a desired joint position there does not command physical hardware and does not replace a controller.

5. Add ros2_control for commanded motion

The ros2_control framework describes hardware components and their command and state interfaces with a <ros2_control> block in the robot description. The Controller Manager loads the hardware component and gives active controllers access to compatible interfaces.

<ros2_control name="ExampleSystem" type="system">
  <hardware>
    <plugin>your_package/YourHardwarePlugin</plugin>
  </hardware>
  <joint name="arm_joint">
    <command_interface name="position" />
    <state_interface name="position" />
    <state_interface name="velocity" />
  </joint>
</ros2_control>

Every joint referenced in the ros2_control block must also exist in the URDF. Choose the hardware plugin, interfaces, controller configuration, and safety limits from the documentation for the actual device. A simulated plugin and a real hardware driver are not interchangeable.

6. Integrate with current Gazebo deliberately

For current Gazebo releases, follow the gz_ros2_control documentation that matches your ROS distribution. Its simulation system plugin connects Gazebo joints to ros2_control command and state interfaces. Simulator-specific sensors, plugins, and physics settings require additional configuration beyond the base URDF tree.

Do not copy a gazebo_ros or gazebo_ros2_control snippet from a Gazebo Classic tutorial into a current Gazebo project. Package names, launch paths, and plugin configuration differ.

Debug in dependency order

  1. Can the URDF or Xacro be parsed without unresolved resources?
  2. Does robot_state_publisher receive the intended description?
  3. Are TF frames and joint states complete and named consistently?
  4. Does the Controller Manager load the expected hardware interfaces?
  5. Are the required controllers configured, loaded, and active?
  6. Does the simulator use the plugin for your ROS/Gazebo combination?

This order separates model errors from controller and simulator errors. A visually correct RViz model proves the description and transforms are coherent; it does not prove collision behavior, controller tuning, or hardware safety.

Official references

Browse URDF Hub's upstream model sources after you understand the pipeline, then verify each repository's license, ROS branch, and hardware assumptions before reuse.

Sources checked August 18, 2026. Commands and package names can vary by ROS distribution.