How to Generate URDF Robot Descriptions from Python with `gen_urdf()`

Use the genurdf() function in skills/urdf/scripts/urdf/source.py to parse, validate, and inspect URDF files, returning a typed UrdfSource object with full programmatic access to links, joints, and mesh resources.

Generating URDF robot descriptions from Python is essential for robotics workflows that require automated validation, inspection, or transformation of robot models. The text-to-CAD repository provides a purpose-built URDF skill that exposes genurdf()—a robust parser that handles XML validation, mesh URI resolution, and kinematic tree verification in a single call.

What genurdf() Does

The genurdf() function serves as the primary entry point for the URDF skill. It wraps read_urdf_source to provide a complete analysis pipeline:

  • Parses XML structure using ET.fromstring, requiring a root <robot> element with a name attribute
  • Validates link definitions, checking for duplicate names and consistent inertial properties via _validate_link_inertials
  • Processes geometry elements, classifying and resolving mesh URIs through classify_mesh_uri and resolve_mesh_uri
  • Verifies joint integrity, ensuring supported types (fixed, continuous, revolute, prismatic), valid parent/child references, and proper axis/limit specifications
  • Confirms tree connectivity, enforcing a single root link and acyclic structure through depth-first traversal

All errors raise UrdfSourceError; warnings emit UrdfSourceWarning for non-critical issues.

Function Signature and Parameters

def genurdf(
    path: Path,
    package_map: dict[str, Path] | None = None
) -> UrdfSource
Parameter Type Description
path Path Absolute or relative path to the .urdf file
package_map dict[str, Path] | None Optional mapping of ROS package names to local directories for resolving package:// mesh URIs

The function returns a frozen UrdfSource dataclass containing:

  • file_ref, source_path, robot_name, root_link
  • links: tuple[str, …] — all link names in declaration order
  • joints: tuple[UrdfJoint, …] — validated joint objects with limit information
  • mesh_paths, visual_mesh_paths, collision_mesh_paths — resolved filesystem paths

Complete Python Example

from pathlib import Path
from skills.urdf.scripts.urdf.source import read_urdf_source as genurdf

# Load a URDF file (absolute or relative to repo root)

urdf_path = Path("models/my_robot.urdf")

# Optional: map ROS package names to local directories

package_map = {"my_robot_description": Path("models/my_robot_description")}

# Parse & validate

robot = genurdf(urdf_path, package_map=package_map)

# Inspect the robot description

print(f"Robot name: {robot.robot_name}")
print(f"Root link:   {robot.root_link}")

print("\nLinks:")
for link in robot.links:
    print(f" - {link}")

print("\nJoints:")
for joint in robot.joints:
    print(
        f" - {joint.name} ({joint.joint_type}) "
        f"parent={joint.parent_link} child={joint.child_link} "
        f"limits=[{joint.min_value_deg}, {joint.max_value_deg}]"
    )

print("\nVisual meshes:")
for mesh in robot.visual_mesh_paths:
    print(f" • {mesh}")

print("\nCollision meshes:")
for mesh in robot.collision_mesh_paths:
    print(f" • {mesh}")

Source File Architecture

The URDF skill maintains clean separation between core logic and interfaces:

File Purpose Key Components
skills/urdf/scripts/urdf/source.py Parser and validator implementation genurdf(), read_urdf_source(), UrdfSource dataclass, _validate_link_inertials(), _joint_limits_deg()
skills/urdf/scripts/urdf/cli.py Command-line frontend Thin wrapper exposing text-to-cad urdf ... commands

Functions in source.py follow a strict validation hierarchy: XML parsing → link collection → geometry extraction → joint processing → tree validation. This ordering ensures that structural errors surface early with precise UrdfSourceError messages.

Mesh URI Resolution

The genurdf() function handles three mesh URI types through classify_mesh_uri:

  1. package:// — Resolved against package_map entries
  2. file:// — Converted to absolute filesystem paths
  3. Relative paths — Interpreted relative to source_path

Unsupported geometry tags trigger immediate UrdfSourceError exceptions, preventing downstream processing of invalid robot descriptions.

Integration with text-to-CAD

The URDF skill adheres to repository-wide isolation principles:

  • No cross-skill imports — All dependencies live within skills/urdf/ or shared utilities in packages/cadpy_metadata
  • Reusable geometry utilities — resolve_mesh_uri and classify_mesh_uri leverage packages/cadpy_metadata for consistent mesh handling across skills
  • Test coverage — Unit tests in tests/python/skills/urdf/test_source.py and test_cli.py verify parser behavior against malformed inputs

Extending genurdf() for Custom Workflows

To adapt genurdf() for specialized requirements:

  • Custom package resolution — Pass an expanded package_map with additional URI scheme handlers
  • Serialization pipelines — The frozen UrdfSource dataclass supports direct JSON conversion for MoveIt! SRDF generation or Gazebo SDF export
  • Validation overrides — Subclass UrdfSourceError to capture specific failure modes in automated CI/CD pipelines

Summary

  • genurdf() in skills/urdf/scripts/urdf/source.py provides complete URDF parsing, validation, and inspection from Python
  • Returns an immutable UrdfSource dataclass with full access to kinematic structure and resolved mesh paths
  • Handles ROS package URI resolution through the optional package_map parameter
  • Enforces strict validation—duplicate links, cyclic joints, and unsupported geometry types raise UrdfSourceError
  • Integrates cleanly with the text-to-CAD ecosystem while maintaining skill isolation

Frequently Asked Questions

What Python version does genurdf() require?

The text-to-CAD repository uses Python 3.10+ features including union type syntax (dict[str, Path] | None) and the match statement in related skills. Ensure your environment matches the repository's pyproject.toml specifications.

How do I resolve package:// URIs without ROS installed?

Provide a package_map dictionary mapping package names to local directories. The genurdf() function intercepts these URIs before any ROS infrastructure is invoked, making pure-Python URDF processing possible without a full ROS installation.

Can genurdf() export modified URDF files?

The current implementation focuses on ingestion and validation. To generate modified URDF XML, access the UrdfSource fields programmatically and reconstruct the XML using xml.etree.ElementTree or template engines. The dataclass structure provides all necessary data for faithful reconstruction.

What's the difference between genurdf() and read_urdf_source()?

They are aliases for the same function—genurdf() is the preferred public name, while read_urdf_source appears in internal import statements. Both reside in skills/urdf/scripts/urdf/source.py and exhibit identical behavior.

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 →