How to Validate URDF Files Generated by the URDF Skill: A Complete Guide

To validate URDF files generated by the URDF skill, use the read_urdf_source function in skills/urdf/scripts/urdf/source.py, which performs comprehensive structural, kinematic, and geometric checks before the robot description is loaded into simulation pipelines.

The earthtojake/text-to-cad repository provides a specialized URDF skill that converts natural language descriptions into robot definition files. Validating these generated URDF files is critical to ensure they conform to the XML specification, contain physically plausible inertial properties, and form valid kinematic trees suitable for downstream tools like MoveIt or Gazebo.

Core Validation Entry Point

The primary interface for URDF validation is the read_urdf_source function located in skills/urdf/scripts/urdf/source.py (lines 70-78). This function serves as the single entry point for parsing and verifying URDF files, returning a structured data object containing the robot name, root link, and validated kinematic chain.

When invoked, read_urdf_source executes a sequential validation pipeline that checks file integrity, XML structure, link definitions, joint constraints, and mesh references. Any violation raises a UrdfSourceError with a descriptive message pointing to the specific failure location.

Structural Validation Checks

Before processing robot components, the validator enforces basic file and XML constraints:

  • File Extension: The path must end with the .urdf suffix (defined as URDF_SUFFIX).
  • XML Parsing: The file content is loaded via ET.fromstring; malformed XML immediately raises UrdfSourceError.
  • Root Element: The document root must be a <robot> tag (lines 80-82).
  • Robot Name: The <robot> element must contain a non-empty name attribute.

These initial gates ensure the file is a well-formed URDF document before complex kinematic validation begins.

The validator collects all <link> elements and enforces naming uniqueness through _raise_on_duplicates (lines 94-95). Empty link names or duplicates trigger immediate errors.

For physical simulation accuracy, the _validate_link_inertials function (lines 20-48) checks every <inertial> block:

  • Mass: Must be a positive numeric value.
  • Inertia Matrix: Must satisfy the triangle inequality constraints required for physically valid rigid bodies.

Links without inertial definitions are permitted but flagged as incomplete for physics simulation.

Joint Kinematics and Constraints

Each <joint> element undergoes rigorous validation through multiple helper functions:

  • Uniqueness: Joint names must be unique across the document (_raise_on_duplicates at lines 74-78).
  • Type Validation: Must be one of the SUPPORTED_JOINT_TYPES (revolute, prismatic, fixed, etc.).
  • Connectivity: Both <parent> and <child> link attributes must reference existing links in the robot.
  • Origin: The <origin> element is validated for proper pose matrix format (_validate_origin, lines 65-84).
  • Axis Requirements: Non-fixed joints must provide a non-zero <axis> vector (_validate_joint_axis, lines 86-100).
  • Limits: Joint limits are parsed and validated in degrees (_joint_limits_deg, lines 102-122).

Geometry and Mesh Verification

For every <visual> and <collision> element, the _geometry_mesh_paths function (lines 99-110) validates geometry specifications:

  • Supported Types: The geometry tag must be one of box, cylinder, mesh, or sphere (SUPPORTED_GEOMETRY_TAGS).
  • Mesh URI Resolution: Mesh paths are classified via classify_mesh_uri (lines 28-57) and resolved through resolve_mesh_uri (lines 59-68).
  • File Existence: The _validated_mesh_path function (lines 84-99) confirms that referenced mesh files exist on disk.

Unresolved optional mesh URIs generate a UrdfSourceWarning via _warn_unresolved_mesh_uri (lines 71-78) rather than failing validation, allowing partial validation of robots with external dependencies.

Kinematic Tree Structure

The validator ensures the links and joints form a single rooted tree structure:

  • Root Detection: Exactly one link must not appear as a child of any joint (root_candidates at lines 175-179).
  • Cycle Detection: A recursive visit function (lines 185-195) traverses the kinematic chain to detect circular dependencies.
  • Connectivity: All links must be reachable from the root link, and the total joint count must equal the link count minus one.

This guarantees the URDF describes a valid, connected robot topology without floating sub-graphs.

Practical Validation Examples

Use the following patterns to integrate URDF validation into your workflow:

from pathlib import Path
from urdf.source import read_urdf_source, UrdfSourceError, UrdfSourceWarning

# Strict validation with error handling

urdf_path = Path("models/generated_robot.urdf")
try:
    urdf_info = read_urdf_source(urdf_path)
    print(f"✅ Valid: {urdf_info.robot_name}")
    print(f"   Root link: {urdf_info.root_link}")
except UrdfSourceError as e:
    print(f"❌ Validation failed: {e}")

To handle optional warnings such as unresolved mesh URIs while validating:

import warnings

with warnings.catch_warnings(record=True) as w:
    warnings.simplefilter("always", UrdfSourceWarning)
    try:
        urdf_info = read_urdf_source(
            urdf_path, 
            package_map={"my_pkg": Path("models/pkg")}
        )
    except UrdfSourceError as e:
        print(f"❌ Fatal error: {e}")
    else:
        for warning in w:
            print(f"⚠️  Warning: {warning.message}")

Command-Line Interface

For manual verification, the repository includes a CLI wrapper in skills/urdf/scripts/urdf/cli.py that invokes read_urdf_source and prints structured results. This tool is useful for CI/CD pipelines validating URDF artifacts generated by the skill.

Unit tests demonstrating expected validation behavior are available in tests/python/skills/urdf/test_source.py, serving as reference implementations for edge cases and error conditions.

Summary

  • Entry Point: Use read_urdf_source in skills/urdf/scripts/urdf/source.py to validate URDF files generated by the URDF skill.
  • Structural Checks: Ensures valid XML, .urdf extension, and proper <robot> root element with a name attribute.
  • Physical Validation: Verifies positive mass values and valid inertia matrices via _validate_link_inertials.
  • Geometric Verification: Confirms supported geometry types and resolves mesh file paths using classify_mesh_uri and resolve_mesh_uri.
  • Kinematic Integrity: Enforces single-rooted tree structure, unique joint names, and valid parent-child relationships.
  • Error Handling: Critical failures raise UrdfSourceError, while non-critical issues generate UrdfSourceWarning for optional mesh resolution problems.

Frequently Asked Questions

What file extension must URDF files have to pass validation?

The validator requires files to end with the .urdf extension (defined as URDF_SUFFIX in the source). Attempting to validate files with other extensions will raise a UrdfSourceError before XML parsing begins.

How does the validator handle missing mesh files?

Missing mesh files referenced in <geometry> tags trigger validation errors through _validated_mesh_path. However, unresolved optional mesh URIs generate UrdfSourceWarning warnings instead of fatal errors, allowing validation to continue for robots with external mesh dependencies that may be resolved at runtime.

Can I validate a URDF without loading it into a simulator?

Yes. The read_urdf_source function performs static analysis without requiring ROS, Gazebo, or other simulation environments. It validates XML structure, kinematic tree topology, and physical properties purely through code analysis in skills/urdf/scripts/urdf/source.py.

What constitutes a valid kinematic tree according to the validator?

A valid kinematic tree must have exactly one root link (not referenced as a child by any joint), no cycles in the joint-link graph, and exactly n-1 joints for n links. The root_candidates logic (lines 175-179) and recursive visit function (lines 185-195) enforce these constraints during validation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →