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
.urdfsuffix (defined asURDF_SUFFIX). - XML Parsing: The file content is loaded via
ET.fromstring; malformed XML immediately raisesUrdfSourceError. - Root Element: The document root must be a
<robot>tag (lines 80-82). - Robot Name: The
<robot>element must contain a non-emptynameattribute.
These initial gates ensure the file is a well-formed URDF document before complex kinematic validation begins.
Link and Inertial Validation
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_duplicatesat 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 throughresolve_mesh_uri(lines 59-68). - File Existence: The
_validated_mesh_pathfunction (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_candidatesat lines 175-179). - Cycle Detection: A recursive
visitfunction (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_sourceinskills/urdf/scripts/urdf/source.pyto validate URDF files generated by the URDF skill. - Structural Checks: Ensures valid XML,
.urdfextension, 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_uriandresolve_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 generateUrdfSourceWarningfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →