How to Regenerate URDF Files from Python Source in text-to-cad
To regenerate URDF files from Python source in the earthtojake/text-to-cad repository, implement a zero-argument gen_urdf() function that returns an XML Element, string, or dict, then run the CLI module at skills/urdf/scripts/urdf/cli.py to automatically generate, annotate with CAD metadata, and validate the output.
The earthtojake/text-to-cad repository provides a streamlined pipeline to regenerate URDF files from Python source code, enabling programmatic robot description generation with built-in validation. This workflow allows you to define robot kinematics and geometry using pure Python, then convert those definitions into validated, metadata-enriched URDF files ready for ROS and MoveIt.
The URDF Regeneration Pipeline
The regeneration system is implemented in the skills/urdf package and follows a strict sequence of module loading, execution, normalization, and validation before producing the final file.
CLI Entry Point and Target Resolution
The process begins in skills/urdf/scripts/urdf/cli.py at the generate_urdf_targets function (line 38). This CLI resolves the input Python script path and determines the output .urdf file location. It uses _load_generator_module (line 58) to import your script into an isolated namespace via importlib.util, ensuring no side effects from existing code contaminate the generation process.
The gen_urdf Contract
Your Python script must expose a zero-argument function named gen_urdf. According to the source implementation, this function may return one of three formats:
- An
xml.etree.ElementTree.Elementrepresenting the root<robot>node - A raw XML string containing the URDF content
- A dictionary with a single key
{"xml": ...}containing the XML string
Payload Normalization and Metadata Injection
The helper _normalize_urdf_payload (line 86) standardizes these varied return types into a consistent format. The CLI then calls _write_urdf_payload to write the XML to the destination path using output_path.write_text. During this write operation, the CAD-metadata wrapper from packages/cadpy_metadata/src/cadpy_metadata/generator.py—specifically xml_with_text_to_cad_metadata—injects provenance data including the source file hash and generation timestamp.
Strict Validation with read_urdf_source
Immediately after writing, the pipeline validates the URDF using read_urdf_source from skills/urdf/scripts/urdf/source.py (line 70). This function enforces a strict schema matching the ROS URDF specification: it verifies unique link and joint names, confirms a single-root tree structure, checks joint limits, validates positive inertia values, and ensures mesh references exist. It utilizes classify_mesh_uri (line 28) for URI handling and raises UrdfSourceError on any validation failure.
Creating a Python URDF Generator
To regenerate URDF files from Python source, create a script that implements the required gen_urdf interface.
Minimal ElementTree Example
The most common approach builds the URDF using Python's xml.etree.ElementTree:
# my_robot.py
import xml.etree.ElementTree as ET
def gen_urdf():
root = ET.Element("robot", {"name": "my_robot"})
link = ET.SubElement(root, "link", {"name": "base_link"})
visual = ET.SubElement(link, "visual")
geometry = ET.SubElement(visual, "geometry")
mesh = ET.SubElement(geometry, "mesh", {"filename": "meshes/base.stl"})
joint = ET.SubElement(root, "joint", {"name": "joint1", "type": "fixed"})
ET.SubElement(joint, "parent", {"link": "base_link"})
ET.SubElement(joint, "child", {"link": "link1"})
return root
Returning Raw XML Strings
Alternatively, return a raw XML string directly:
def gen_urdf():
return """<?xml version="1.0"?>
<robot name="my_robot">
<link name="base_link"/>
</robot>"""
Using the Envelope Dict Format
For future-proofing or additional metadata wrapping, return a dictionary:
def gen_urdf():
return {"xml": "<robot name='my_robot'><link name='base_link'/></robot>"}
Running the Regeneration CLI
Execute the regeneration using the Python module execution syntax.
Basic Usage
Run the CLI against your generator script to create the URDF beside the source file:
python -m skills.urdf.scripts.urdf.cli my_robot.py
Output:
Wrote URDF: my_robot.urdf
Specifying Custom Output Paths
Use the -o flag to define a specific output location:
python -m skills.urdf.scripts.urdf.cli my_robot.py -o /tmp/my_robot_generated.urdf
Understanding the Validation Layer
The read_urdf_source function in skills/urdf/scripts/urdf/source.py performs comprehensive validation immediately after generation. It parses the XML and checks link/joint consistency, confirms mesh references exist via resolve_mesh_uri (line 59), and validates the package_map for package:// URIs. This ensures the generated URDF is immediately importable by ROS components without manual inspection.
Summary
- The regeneration pipeline lives in
skills/urdf/scripts/urdf/cli.pyand is driven by thegenerate_urdf_targetsfunction. - Your Python script must expose a zero-argument
gen_urdf()function returning an Element, string, or dict. - The CLI normalizes output via
_normalize_urdf_payloadand injects metadata usingxml_with_text_to_cad_metadatafrom thecadpy_metadatapackage. - Automatic validation occurs through
read_urdf_sourceinskills/urdf/scripts/urdf/source.py, enforcing ROS URDF specification compliance including unique names and valid mesh references. - Mesh URI resolution handles both relative paths and
package://references throughclassify_mesh_uriandresolve_mesh_uri.
Frequently Asked Questions
What happens if my gen_urdf function accepts arguments?
The CLI strictly expects a zero-argument function signature. If your generator requires parameters, you must wrap it in a zero-argument function or use closure variables and module-level constants to pass configuration data before the CLI imports the module.
How does the pipeline handle package:// mesh URIs?
The validation layer uses resolve_mesh_uri with a package_map argument to resolve package:// references into absolute filesystem paths. You can provide this mapping via environment variables or the CADPY_METADATA tracking system during CLI execution, which the read_urdf_source function picks up automatically.
Why does the CLI re-read the file immediately after generation?
The read_urdf_source validation step guarantees that the produced URDF conforms to the strict ROS specification, checking for unique link/joint names, valid joint limits, positive inertia values, and existing mesh references before marking the generation as successful. This prevents generating broken URDFs that would fail when loaded into ROS or MoveIt.
Where is the provenance metadata stored in the output URDF?
The xml_with_text_to_cad_metadata function from packages/cadpy_metadata/src/cadpy_metadata/generator.py injects generation metadata—including source file hashes and timestamps—directly into the XML structure during the _write_urdf_payload operation, ensuring traceability from generated artifact back to source code.
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 →