Files
cad-Integration/text-to-cad-main/plugins/cad/skills/sdf/references/builder-helpers.md
T
2026-07-22 13:48:46 +08:00

137 lines
3.8 KiB
Markdown

# SDF builder helpers
Builder helpers are optional. They exist to reduce common LLM mistakes in XML construction, not to replace SDFormat or libsdformat.
## Why helpers exist
LLMs often make these mistakes when writing raw XML:
- wrong pose value length;
- hidden degree/radian conversion;
- missing `relative_to` or `expressed_in`;
- zero or non-finite joint axes;
- negative primitive dimensions;
- mesh scale applied inconsistently;
- inertial values copied from visuals;
- plugin filenames invented from plausible names.
Helpers should make the common path explicit, typed-ish, and auditable while still returning ordinary `xml.etree.ElementTree.Element` nodes.
## Design constraints
- Standard library only.
- No mandatory Gazebo, ROS, NumPy, lxml, CAD, or mesh dependency.
- Return ElementTree elements.
- Compose with raw ElementTree calls.
- Validate local numeric shape and finiteness.
- Do not attempt full SDFormat schema validation.
- Do not silently invent frames, axes, inertials, plugins, or sensor parameters.
## Recommended helper surface
Names may vary to match the current runtime package, but the helper surface should stay small.
```python
# XML basics
text(parent, tag, value, attrib=None)
fmt_float(value)
fmt_vector(values)
# Poses and axes
pose(parent, xyz=(0, 0, 0), rpy=(0, 0, 0), *, relative_to=None,
rotation_format="euler_rpy", degrees=False)
quat_pose(parent, xyz=(0, 0, 0), quat_xyzw=(0, 0, 0, 1), *, relative_to=None)
axis(parent, xyz=(0, 0, 1), *, expressed_in=None)
# Document structure
sdf_root(version="1.12")
world(parent, name)
model(parent, name, *, static=None, pose=None)
frame(parent, name, *, attached_to=None, pose=None)
link(parent, name, *, pose=None, inertial=None)
joint(parent, name, joint_type, parent_link, child_link, *, pose=None,
axis_xyz=None, axis_expressed_in=None, axis2_xyz=None, limits=None)
# Geometry
visual(parent, name, *, pose=None)
collision(parent, name, *, pose=None)
box(parent, size_xyz)
sphere(parent, radius)
cylinder(parent, radius, length)
capsule(parent, radius, length)
mesh(parent, uri, *, scale=None)
# Physics and metadata
inertial(parent, mass, inertia, *, pose=None)
sensor(parent, name, sensor_type, *, pose=None, topic=None, update_rate=None)
plugin(parent, name, filename, params=None)
include(parent, uri, *, name=None, pose=None)
```
## Numeric behavior
Helpers should reject:
- non-finite numbers;
- vectors with the wrong length;
- negative or zero primitive dimensions;
- zero joint axes;
- zero-mass inertials;
- zero-norm quaternions.
Helpers may warn, but should not silently fix:
- non-unit axes;
- non-normalized quaternions;
- use of degrees;
- missing `relative_to` on nontrivial poses.
## Example
```python
from sdf.builder import axis, box, collision, joint, link, model, sdf_root, visual
BASE_SIZE_M = (0.4, 0.3, 0.1)
LIFT_AXIS_Z = (0.0, 0.0, 1.0)
def gen_sdf():
sdf = sdf_root("1.12")
robot = model(sdf, "lift_fixture", static=False)
base = link(robot, "base_link")
v = visual(base, "base_visual")
box(v, BASE_SIZE_M)
c = collision(base, "base_collision")
box(c, BASE_SIZE_M)
carriage = link(robot, "carriage_link")
j = joint(
robot,
"lift_joint",
"prismatic",
parent_link="base_link",
child_link="carriage_link",
axis_xyz=LIFT_AXIS_Z,
axis_expressed_in="base_link",
)
return {
"xml": sdf,
"assumptions": [
{"code": "inertials_placeholder", "message": "Inertials omitted pending measured masses."}
],
}
```
## When not to use helpers
Raw ElementTree is acceptable when:
- a target simulator needs unusual extension XML;
- a plugin has arbitrary nested configuration;
- an existing generator already has a clear internal abstraction;
- the user asked for a minimal XML-only source.
Even then, keep named constants, ledger comments, and validation.