SDF Simulator Model Generation with Physics, Sensors, and Lights: A Complete Guide
The text-to-CAD repository provides a three-layer pipeline—source parsing, model inspection, and CLI generation—to create validated SDFormat models for Gazebo and other physics simulators.
The SDF skill in earthtojake/text-to-cad enables automated creation of simulator-ready assets. This guide explains how the pipeline handles physics properties, sensor definitions, and lighting configurations while maintaining strict validation and single-source-of-truth principles.
Architecture of the SDF Simulator Generation Pipeline
The SDF skill is organized into three functional layers that transform Python generators or raw XML into validated simulator models.
Layer 1: Source Parsing with SdfSource
The entry point is the SdfSource dataclass defined in [skills/sdf/scripts/sdf/source.py](https://github.com/earthtojake/text-to-cad/blob/main/skills/sdf/scripts/sdf/source.py). This class:
- Parses SDF XML files into structured Python objects
- Validates structure via the
validationmodule - Extracts models, worlds, links, joints, and mesh references
from skills.sdf.scripts.sdf.source import SdfSource, read_sdf_source
# Parse and validate an existing SDF file
source = read_sdf_source("path/to/robot.sdf")
print(f"Found {len(source.models)} model(s), {len(source.worlds)} world(s)")
print(f"Mesh dependencies: {source.mesh_paths}")
The read_sdf_source() function orchestrates the workflow: it loads XML, calls validate_sdf_root() for schema compliance, then builds the SdfSource instance with all extracted metadata.
Layer 2: Model Inspection and Mesh Resolution
Helper functions in source.py perform deep inspection of simulator components:
| Function | Purpose |
|---|---|
_read_model() |
Extracts link names, joint definitions, and physics properties from a model element |
_geometry_mesh_paths() |
Locates all mesh URI references in geometry elements |
_resolve_local_mesh_uri() |
Converts relative mesh paths to absolute repository-relative paths |
_validate_link_reference() |
Ensures joint parent/child links exist and are properly named |
_raise_on_duplicates() |
Detects duplicate model, link, or joint identifiers |
All errors raise SdfSourceError with repository-relative paths computed by _relative_to_repo(). This makes debugging straightforward for both developers and automated agents.
# Example: Accessing parsed physics and sensor data
for model in source.models:
for link in model.links:
print(f"Link: {link.name}")
if link.inertial:
print(f" Mass: {link.inertial.mass}")
for sensor in link.sensors:
print(f" Sensor: {sensor.name} ({sensor.type})")
Layer 3: Command-Line Interface for Generation and Validation
The CLI wrapper in [skills/sdf/scripts/sdf/cli.py](https://github.com/earthtojake/text-to-cad/blob/main/skills/sdf/scripts/sdf/cli.py) provides three operational modes:
Mode 1: Default sibling output
python scripts/sdf path/to/my_model.py
# Creates my_model.sdf next to my_model.py
Mode 2: Custom output location
python scripts/sdf path/to/my_model.py -o models/robot.sdf
Mode 3: Batch generation
python scripts/sdf path/to/a.py=out/a.sdf path/to/b.py=out/b.sdf
Optional Gazebo validation
python scripts/sdf path/to/my_model.py --gz-check auto
When --gz-check is enabled and gz is installed, the CLI pipes output through gz sdf --check for additional simulator-specific validation.
Adding Physics, Sensors, and Lights Programmatically
For SDF simulator model generation with physics, sensors, and lights, use the builder API in [skills/sdf/scripts/sdf/builder.py](https://github.com/earthtojake/text-to-cad/blob/main/skills/sdf/scripts/sdf/builder.py):
from skills.sdf.scripts.sdf.builder import SdfBuilder, ModelBuilder
# Initialize SDF 1.12 format
builder = SdfBuilder(version="1.12")
# Create a model with physics properties
model = ModelBuilder(name="mobile_robot")
model.set_static(False)
model.set_self_collide(True)
# Add a base link with inertial physics
base = model.add_link("base_link")
base.set_inertial(
mass=5.0,
inertia=[0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1] # Ixx, Ixy, Ixz, Iyx, Iyy, Iyz, Izx, Izy, Izz
)
# Attach a LiDAR sensor
lidar = base.add_sensor("lidar_2d", type="gpu_lidar")
lidar.set_ray_properties(
samples=640,
resolution=1.0,
min_angle=-1.396263,
max_angle=1.396263
)
lidar.set_range_properties(min=0.08, max=10.0, resolution=0.01)
# Add illumination
light = model.add_light("headlamp", type="directional")
light.set_direction(x=0, y=0, z=-1)
light.set_diffuse(r=0.5, g=0.5, b=0.5, a=1.0)
builder.add_model(model.build())
sdf_xml = builder.build()
# Save and validate
with open("robot_with_physics.sdf", "w") as f:
f.write(sdf_xml)
The builder enforces schema compliance at construction time, preventing invalid combinations of physics, sensor, and light elements.
Validation and Error Handling
The validation system in [skills/sdf/scripts/sdf/validation.py](https://github.com/earthtojake/text-to-cad/blob/main/skills/sdf/scripts/sdf/validation.py) provides two key functions:
validate_sdf_root()— Checks XML structure against SDF schemaraise_for_validation_errors()— Converts validation failures to exceptions
This early validation architecture catches errors before any simulator execution, reducing downstream failures in Gazebo or other physics engines.
Error messages include repository-relative paths:
SdfSourceError: Duplicate link name 'wheel_left' in model 'mobile_robot'
File: models/robot.sdf (line 47)
Previous definition: line 23
Workflow Integration and CAD Viewer Hand-off
The SDF skill enforces single-source-of-truth per its core rules in [SKILL.md](https://github.com/earthtojake/text-to-cad/blob/main/skills/sdf/SKILL.md) (lines 18-20). The parser operates only on source files—never on generated XML—ensuring modifications flow back to the original Python generator.
The standard workflow proceeds through these stages:
- Define — Create Python generator using
SdfBuilderor raw XML - Generate — Run
python scripts/sdfto produce.sdfoutput - Validate — Automatic schema check plus optional
gz sdf --check - Inspect — Parse with
SdfSourceto extract mesh dependencies - Hand off — Transfer to CAD Viewer with validated asset bundle
Reference documentation in skills/sdf/references/ provides detailed guidance on frame semantics, guard-rails, and design ledger entries for complex simulator configurations.
Summary
SdfSourceinsource.pyprovides the core parser with mesh URI resolution and duplicate detectionread_sdf_source()orchestrates validation-first loading: XML → schema check → structured object- CLI in
cli.pysupports single-file, custom-output, and batch generation modes with optional Gazebo validation SdfBuilderinbuilder.pyenables programmatic construction of physics, sensor, and light elements- Single-source-of-truth enforcement ensures all edits propagate to original generators, never to derived XML
Frequently Asked Questions
How do I add physics properties like mass and inertia to an SDF model?
Use ModelBuilder and LinkBuilder methods as shown in [builder.py](https://github.com/earthtojake/text-to-cad/blob/main/skills/sdf/scripts/sdf/builder.py). Call link.set_inertial(mass=..., inertia=[...]) with a 9-element inertia matrix. The builder validates that mass is positive and the matrix is positive-definite before serialization.
Can the SDF skill validate models against Gazebo's specific requirements?
Yes. Pass --gz-check auto or --gz-check always to the CLI. When gz is available, the command pipes output through gz sdf --check for simulator-specific validation beyond basic XML schema compliance.
What sensor types are supported in programmatic SDF generation?
The builder.py API supports all SDFormat 1.12 sensor types including camera, depth_camera, gpu_lidar, imu, magnetometer, altimeter, and contact. Each sensor type has specialized configuration methods—consult the references/ directory for type-specific guard-rails and frame semantics.
How does the pipeline handle mesh file dependencies?
During parsing, _geometry_mesh_paths() extracts all URI references, _resolve_local_mesh_uri() converts them to absolute paths relative to the repository root, and SdfSource.mesh_paths stores the complete list. This enables automatic bundling of all required assets for simulator hand-off.
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 →