first commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# URDF Design Ledger
|
||||
|
||||
Use this reference before creating or editing a URDF generator. The ledger is the written spatial model that prevents silent frame, axis, unit, and mesh-scale mistakes.
|
||||
|
||||
The ledger may live in the generator source comments, adjacent project documentation, a README, or a task note. It must be specific enough that another engineer can audit the generated URDF without reverse-engineering the XML.
|
||||
|
||||
## Required Sections
|
||||
|
||||
### Robot Metadata
|
||||
|
||||
Record:
|
||||
|
||||
- robot name
|
||||
- target consumers: RViz, robot_state_publisher, Gazebo/Ignition, MoveIt, real robot driver, or other
|
||||
- unit convention: meters, kilograms, seconds, radians unless the project explicitly states otherwise
|
||||
- frame convention: REP-103-style body convention when applicable, or a documented exception
|
||||
- mesh unit convention: meters, millimeters, inches, or other
|
||||
- source of dimensions: CAD, drawing, measured data, vendor documentation, existing URDF, or assumption
|
||||
|
||||
### Link Ledger
|
||||
|
||||
For every link, record:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| link name | Exact URDF `<link name="...">` value. |
|
||||
| role | Physical link, frame-only link, sensor frame, tool frame, base frame, or other. |
|
||||
| frame definition | Where the link frame is located and how its axes point. |
|
||||
| parent joint | Joint that creates this child link frame, or `none` for root. |
|
||||
| visual geometry | Primitive or mesh source, with origin relative to the link frame. |
|
||||
| collision geometry | Primitive or mesh source, with origin relative to the link frame. |
|
||||
| inertial source | CAD mass properties, vendor data, approximation, or intentionally omitted. |
|
||||
|
||||
Frame-only links such as `base_footprint`, optical frames, and `tool0` may omit inertial, visual, and collision blocks. Mark them explicitly as frame-only rather than leaving intent ambiguous.
|
||||
|
||||
### Joint Ledger
|
||||
|
||||
For every joint, record:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| joint name | Exact URDF `<joint name="...">` value. |
|
||||
| type | `fixed`, `revolute`, `continuous`, or `prismatic` for the current `scripts/urdf` validator; record `floating` or `planar` only if the project has a different supported validation path. |
|
||||
| parent link | Link whose frame expresses the joint origin. |
|
||||
| child link | Link whose frame is created at the joint frame. |
|
||||
| origin xyz/rpy | Parent-link-frame transform from parent link to joint frame. |
|
||||
| axis | Axis vector expressed in the joint frame, for movable joints. |
|
||||
| limits | Radians for revolute, meters for prismatic, no finite lower/upper limits for continuous. |
|
||||
| positive motion | What positive joint motion physically does. |
|
||||
| source | CAD, drawing, measured data, existing model, or documented assumption. |
|
||||
|
||||
Do not write a movable joint without an explicit positive-motion convention. The sign of the axis is part of the model, not a cosmetic detail.
|
||||
|
||||
### Geometry Ledger
|
||||
|
||||
For every visual or collision item, record:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| link | Owning link. |
|
||||
| kind | `visual` or `collision`. |
|
||||
| geometry type | `mesh`, `box`, `cylinder`, or `sphere`. |
|
||||
| source | CAD export, primitive approximation, vendor mesh, generated mesh, or temporary placeholder. |
|
||||
| origin xyz/rpy | Transform from link frame to geometry frame. |
|
||||
| scale | Mesh scale if applicable. |
|
||||
| units | Mesh source units and URDF scale needed to express meters. |
|
||||
|
||||
Visual geometry is for display. Collision geometry is for contact, planning, and physics. It may intentionally be simpler than the visual geometry.
|
||||
|
||||
### Inertial Ledger
|
||||
|
||||
For every physical link, record:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| mass | Kilograms. |
|
||||
| center of mass | Inertial origin xyz in the link frame. |
|
||||
| inertia tensor | Tensor values and frame. |
|
||||
| source | CAD mass properties, vendor data, calculation, approximation, or intentionally omitted. |
|
||||
| confidence | Exact, estimated, placeholder, or unknown. |
|
||||
|
||||
Do not silently copy visual origins into inertial origins. The visual frame, collision frame, link frame, and center of mass can all differ.
|
||||
|
||||
### Assumption Ledger
|
||||
|
||||
Record every inferred or guessed value, including:
|
||||
|
||||
- unknown dimensions
|
||||
- mesh units
|
||||
- sign conventions
|
||||
- joint axes
|
||||
- parent/child direction
|
||||
- visual or collision offsets
|
||||
- mass, COM, and inertia approximations
|
||||
- frame-only link intent
|
||||
- unverified package URI resolution
|
||||
|
||||
Use named constants in generator code for assumed values. Prefer names like `ASSUMED_BASE_TO_SHOULDER_Z_M` over unlabelled numeric literals.
|
||||
|
||||
## When Information Is Missing
|
||||
|
||||
If spatial information is missing, do not invent a precise-looking transform. Choose one of these outcomes:
|
||||
|
||||
1. preserve existing source data unchanged;
|
||||
2. create a frame-only or placeholder structure with explicit assumption comments;
|
||||
3. use a clearly named approximate constant;
|
||||
4. ask for dimensions or CAD data when the workflow allows interaction;
|
||||
5. report that the generated model is structurally valid but spatially provisional.
|
||||
|
||||
A provisional URDF is acceptable when clearly labelled. A plausible but undocumented URDF is not.
|
||||
@@ -0,0 +1,105 @@
|
||||
# URDF Frame Semantics
|
||||
|
||||
Use this reference whenever editing origins, axes, visual placement, collision placement, or inertials. Most URDF generation errors are frame errors.
|
||||
|
||||
## Core Semantics
|
||||
|
||||
URDF represents a robot as a tree of links connected by joints.
|
||||
|
||||
For a joint:
|
||||
|
||||
- `<parent link="...">` names the parent link.
|
||||
- `<child link="...">` names the child link.
|
||||
- `<origin xyz="..." rpy="...">` is the transform from the parent link frame to the joint frame.
|
||||
- The child link frame is coincident with the joint frame.
|
||||
- `<axis xyz="...">` for a movable joint is expressed in the joint frame, not automatically in the world frame and not in the visual mesh frame.
|
||||
|
||||
For link subelements:
|
||||
|
||||
- `<visual><origin ...>` is expressed in the link frame.
|
||||
- `<collision><origin ...>` is expressed in the link frame.
|
||||
- `<inertial><origin ...>` is the center-of-mass/inertial frame expressed in the link frame.
|
||||
|
||||
These origins are independent. A mesh can be offset from its link frame, and the center of mass can be offset differently.
|
||||
|
||||
## Units and Angles
|
||||
|
||||
Use:
|
||||
|
||||
- meters for length;
|
||||
- kilograms for mass;
|
||||
- radians for angles;
|
||||
- seconds for time;
|
||||
- right-handed coordinate frames unless the project documents an exception.
|
||||
|
||||
Do not store revolute limits in degrees in generated URDF. Convert degrees to radians before emission.
|
||||
|
||||
Do not use finite lower/upper limits for a `continuous` joint unless the project is intentionally not using URDF continuous-joint semantics.
|
||||
|
||||
## Joint Axis Checklist
|
||||
|
||||
For every non-fixed joint, confirm:
|
||||
|
||||
1. the axis is present;
|
||||
2. the axis vector has three finite numbers;
|
||||
3. the vector is nonzero;
|
||||
4. the vector is normalized or intentionally normalized by helper code;
|
||||
5. the vector is expressed in the joint frame;
|
||||
6. positive motion is documented.
|
||||
|
||||
Examples:
|
||||
|
||||
```xml
|
||||
<joint name="shoulder_pan_joint" type="revolute">
|
||||
<parent link="base_link" />
|
||||
<child link="shoulder_link" />
|
||||
<origin xyz="0 0 0.24" rpy="0 0 0" />
|
||||
<axis xyz="0 0 1" />
|
||||
<limit lower="-3.14159" upper="3.14159" effort="40" velocity="2" />
|
||||
</joint>
|
||||
```
|
||||
|
||||
This means the child link frame is at `z = 0.24` in `base_link`, and positive joint motion rotates about +Z of the joint/child frame.
|
||||
|
||||
## Visual and Collision Placement Checklist
|
||||
|
||||
For every visual or collision block, confirm:
|
||||
|
||||
1. the origin is relative to the owning link frame;
|
||||
2. mesh scale converts the mesh source units into meters;
|
||||
3. visual and collision geometry are intentionally the same or intentionally different;
|
||||
4. collision geometry is simple enough for the intended physics/planning consumer;
|
||||
5. mesh paths are stable from the generated URDF's location or use an intended package URI.
|
||||
|
||||
Example:
|
||||
|
||||
```xml
|
||||
<link name="forearm_link">
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="package://robot_description/meshes/forearm.stl" scale="0.001 0.001 0.001" />
|
||||
</geometry>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0.12 0 0" rpy="0 1.57079632679 0" />
|
||||
<geometry>
|
||||
<cylinder radius="0.035" length="0.24" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
```
|
||||
|
||||
This places the visual mesh at the link frame and uses a simplified collision cylinder offset in the same link frame.
|
||||
|
||||
## Inertial Placement Checklist
|
||||
|
||||
For every physical link with inertial data, confirm:
|
||||
|
||||
1. mass is positive and finite;
|
||||
2. inertial origin is the center of mass in the link frame;
|
||||
3. inertia tensor values are in SI units;
|
||||
4. tensor values correspond to the inertial frame being declared;
|
||||
5. approximations are documented.
|
||||
|
||||
Do not infer inertial origin from visual or collision origin unless the source data proves they coincide.
|
||||
@@ -0,0 +1,46 @@
|
||||
# URDF Generation
|
||||
|
||||
Regenerate explicit URDF outputs from Python sources with top-level `gen_urdf()` functions.
|
||||
|
||||
```bash
|
||||
python scripts/urdf path/to/assembly.py
|
||||
python scripts/urdf path/to/assembly.py -o path/to/robot.urdf
|
||||
python scripts/urdf path/to/a.py=out/a.urdf path/to/b.py=out/b.urdf
|
||||
```
|
||||
|
||||
Plain Python targets write a sibling `.urdf` beside the source. `-o`/`--output` is valid only with one plain target. Use `SOURCE.py=OUTPUT.urdf` pairs for custom multi-target destinations.
|
||||
|
||||
`gen_urdf()` must be a top-level zero-argument function returning the root `xml.etree.ElementTree.Element`, a complete URDF XML string, or an accepted envelope whose only field is `xml`. See `references/generator-contract.md`.
|
||||
|
||||
Relative source targets and CLI output paths resolve from the current working directory.
|
||||
|
||||
## Default Validation Behavior
|
||||
|
||||
The generation command validates the generated URDF before accepting the output. There is no separate validation-only command in this skill.
|
||||
|
||||
A generation failure should be treated as a model or source problem, not as a reason to hand-edit the generated `.urdf`. Fix the generator source, then regenerate the explicit target.
|
||||
|
||||
The generation-time validation is intended to catch compact robot-description issues such as:
|
||||
|
||||
- malformed XML or wrong root element;
|
||||
- missing or duplicate link and joint names;
|
||||
- invalid parent/child references;
|
||||
- multiple roots, disconnected graphs, or cycles;
|
||||
- suspicious joint limits, axes, origins, geometry, mesh references, or inertials when supported by the runtime.
|
||||
|
||||
## Boundaries
|
||||
|
||||
This tool runs only `gen_urdf()`. It does not regenerate CAD, mesh/export, GLB/topology, render, SDF, SRDF, MoveIt2, or simulator outputs.
|
||||
|
||||
If URDF visual/collision mesh references depend on updated CAD or mesh outputs, regenerate those explicit targets separately with the owning CAD or mesh workflow, then regenerate the affected URDF.
|
||||
|
||||
After creating or modifying generated `.urdf` files, hand explicit paths to `$cad-viewer` for live viewer links when available.
|
||||
|
||||
## Failure Handling
|
||||
|
||||
When generation-time validation fails:
|
||||
|
||||
1. inspect the reported links, joints, mesh references, or inertial fields;
|
||||
2. update the source generator, design ledger, or referenced assets;
|
||||
3. regenerate the same explicit URDF target;
|
||||
4. do not patch the generated `.urdf` directly unless the task is explicitly forensic and the patch will not be treated as source of truth.
|
||||
@@ -0,0 +1,105 @@
|
||||
# URDF Generator Contract
|
||||
|
||||
Use this reference when creating or editing Python sources that generate URDF files.
|
||||
|
||||
## Source of Truth
|
||||
|
||||
The Python source that defines `gen_urdf()` is source of truth. The configured `.urdf` file is generated and should not be hand-edited.
|
||||
|
||||
Keep the design ledger close to the source. At minimum, generator source should make units, frame conventions, parent/child choices, joint axes, mesh scale, and assumptions easy to audit.
|
||||
|
||||
## Contract
|
||||
|
||||
`gen_urdf()` must be a top-level zero-argument function that returns one of:
|
||||
|
||||
- the root `xml.etree.ElementTree.Element` for a complete URDF document;
|
||||
- a complete URDF XML string;
|
||||
- an envelope dict with exactly one field, `xml`, whose value is an `ElementTree.Element` or XML string.
|
||||
|
||||
Default generator shape:
|
||||
|
||||
```python
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
def gen_urdf():
|
||||
robot = ET.Element("robot", {"name": "sample"})
|
||||
ET.SubElement(robot, "link", {"name": "base_link"})
|
||||
return robot
|
||||
```
|
||||
|
||||
When an envelope is needed, set `xml` to the same root element or XML string:
|
||||
|
||||
```python
|
||||
def gen_urdf():
|
||||
robot = ET.Element("robot", {"name": "sample"})
|
||||
ET.SubElement(robot, "link", {"name": "base_link"})
|
||||
return {"xml": robot}
|
||||
```
|
||||
|
||||
Do not include output-path, validation, Explorer, pose-preset, or consumer metadata in the envelope. The current runtime rejects fields such as `urdf_output`, `validate`, and `explorer_metadata`; output paths are selected only by CLI arguments. Named robot poses belong in SRDF `<group_state>` elements, not URDF-side `explorer.json` or Explorer metadata artifacts.
|
||||
|
||||
The CLI serializes the returned payload, writes the configured `.urdf` output path, and validates that generated file before returning success.
|
||||
|
||||
The generated `.urdf` output path is selected by the CLI. A plain source target writes a sibling `.urdf`; `-o`/`--output` overrides one target; `SOURCE.py=OUTPUT.urdf` pairs override individual targets.
|
||||
|
||||
The host project may impose its own layout policy, but the URDF skill runtime does not hardcode a project directory.
|
||||
|
||||
## Authoring Expectations
|
||||
|
||||
Use explicit constants for physical dimensions, joint locations, joint limits, mesh scale, and inertial values. Avoid anonymous literals in joint origins and axes.
|
||||
|
||||
Prefer:
|
||||
|
||||
```python
|
||||
BASE_TO_SHOULDER_Z_M = 0.240
|
||||
SHOULDER_PAN_AXIS = (0.0, 0.0, 1.0)
|
||||
FOREARM_MESH_SCALE_FROM_MM = (0.001, 0.001, 0.001)
|
||||
```
|
||||
|
||||
Over:
|
||||
|
||||
```python
|
||||
origin="0 0 0.24"
|
||||
axis="0 0 1"
|
||||
scale="0.001 0.001 0.001"
|
||||
```
|
||||
|
||||
Document assumptions directly in comments near the constants or in `references/design-ledger.md` style project documentation.
|
||||
|
||||
## Frame and Unit Rules
|
||||
|
||||
Generators must emit URDF values in the project's URDF unit convention, normally meters, kilograms, seconds, and radians.
|
||||
|
||||
Before emitting a joint, confirm:
|
||||
|
||||
- the parent and child link names are correct;
|
||||
- the joint origin is expressed in the parent link frame;
|
||||
- the child link frame is intended to coincide with the joint frame;
|
||||
- the joint axis is expressed in the joint frame;
|
||||
- revolute limits are radians;
|
||||
- prismatic limits are meters;
|
||||
- continuous joints do not get fake finite lower/upper limits.
|
||||
|
||||
Before emitting visual, collision, or inertial data, confirm:
|
||||
|
||||
- its origin is expressed in the owning link frame;
|
||||
- mesh scale converts mesh source units into meters;
|
||||
- collision geometry is intentionally simplified or intentionally identical to visual geometry;
|
||||
- inertial origin represents the center of mass, not merely the visual origin.
|
||||
|
||||
The current `scripts/urdf` validation path accepts any non-empty mesh filename or URI, checks local file existence when the URI resolves locally, and leaves mesh-format loadability to the target URDF consumer. Visual and collision geometry may use `<mesh>`, `<box>`, `<cylinder>`, or `<sphere>`.
|
||||
|
||||
## Runtime Behavior
|
||||
|
||||
`scripts/urdf` runs only `gen_urdf()`. It does not regenerate external CAD, mesh/export, GLB/topology, render, SDF, or SRDF/MoveIt2 artifacts.
|
||||
|
||||
If URDF visual/collision mesh references depend on updated CAD or mesh outputs, regenerate those explicit targets separately with the owning CAD or mesh workflow.
|
||||
|
||||
Importing a generator module executes its top-level Python code. Keep top-level generator modules deterministic and side-effect-light. Place expensive or mutating work behind `gen_urdf()` only when the task explicitly requires it.
|
||||
|
||||
## Paths
|
||||
|
||||
Relative source targets and CLI output paths resolve from the current working directory.
|
||||
|
||||
Inside generator code, prefer paths derived from the generator file or package conventions over implicit shell working-directory assumptions. Mesh filenames emitted into URDF should be stable from the generated `.urdf` file's perspective or use a package URI understood by the consumer.
|
||||
@@ -0,0 +1,125 @@
|
||||
# URDF Workflow
|
||||
|
||||
Use this reference when editing robot-description structure, frame placement, mesh references, inertial data, or generated URDF output.
|
||||
|
||||
## Edit Loop
|
||||
|
||||
1. Find the Python source that defines `gen_urdf()`.
|
||||
2. Treat that Python source as source of truth and the `.urdf` file as generated.
|
||||
3. Identify target consumers and strictness requirements: visualization, TF tree, simulation, planning, or real robot integration.
|
||||
4. Create or update the design ledger before changing frames, origins, axes, limits, mesh scales, or inertials.
|
||||
5. Apply URDF frame semantics: joint origin in parent frame, child link frame at joint frame, joint axis in joint frame, visual/collision/inertial origins in link frame.
|
||||
6. Edit links, joints, limits, axes, origins, inertials, materials, visual/collision geometry, and mesh filenames deliberately in the generator source.
|
||||
7. Regenerate only the explicit URDF target with `scripts/urdf <source-file>`, `scripts/urdf <source-file> -o <output.urdf>`, or `scripts/urdf <source-file>=<output.urdf>`.
|
||||
8. Let generation-time validation catch structural and semantic problems. Fix the generator source instead of hand-editing generated XML.
|
||||
9. If mesh outputs changed, regenerate only the affected explicit outputs with the owning CAD or mesh workflow.
|
||||
10. Hand generated or modified `.urdf` files to `$cad-viewer` for live viewer links when available.
|
||||
11. When available, run a consumer smoke test and report what was not checked.
|
||||
|
||||
## Spatial-Reasoning Guardrails
|
||||
|
||||
LLMs are prone to plausible-looking spatial mistakes. Use these guardrails:
|
||||
|
||||
- Do not infer dimensions, handedness, axes, mesh units, or joint signs from vague descriptions.
|
||||
- Do not silently mirror left/right parts unless the mirror transform and sign changes are explicit.
|
||||
- Do not assume visual mesh origin equals link frame, collision frame, or center of mass.
|
||||
- Do not assume CAD mesh units are meters. STL files often carry no reliable unit metadata.
|
||||
- Do not encode a kinematic correction by offsetting only the visual mesh; correct the link and joint frames unless the visual mesh is genuinely offset.
|
||||
- Preserve existing proven transforms unless the task explicitly requires changing them.
|
||||
- Use named constants and comments for assumptions.
|
||||
|
||||
## Standard Link Tags
|
||||
|
||||
Use these tags for each link that represents physical robot geometry:
|
||||
|
||||
- `inertial`: mass, center of mass, and inertia tensor used by simulators.
|
||||
- `visual`: display geometry and optional material.
|
||||
- `collision`: contact geometry used by physics and planning.
|
||||
|
||||
Frame-only links, such as `base_footprint`, optical frames, or tool-center marker frames, may intentionally omit these tags when they represent no physical mass or geometry.
|
||||
|
||||
For movable physical links, avoid zero or missing mass unless the target simulator explicitly supports that modeling choice. If exact mass properties are unavailable, use a documented approximation and make the approximation easy to replace later.
|
||||
|
||||
## Joint Authoring
|
||||
|
||||
For every joint, confirm:
|
||||
|
||||
- parent and child direction are correct;
|
||||
- joint origin is expressed in the parent link frame;
|
||||
- child link frame is intended to coincide with the joint frame;
|
||||
- non-fixed joint axis is expressed in the joint frame;
|
||||
- positive motion is documented;
|
||||
- revolute limits are radians;
|
||||
- prismatic limits are meters;
|
||||
- continuous joints are not given artificial finite lower/upper limits;
|
||||
- fixed joints are used for frame relationships and rigid assemblies.
|
||||
|
||||
Supported joint types may vary by project runtime. If the validator/runtime supports only `fixed`, `continuous`, `revolute`, and `prismatic`, do not author `floating` or `planar` joints unless the consumer and validation path support them.
|
||||
|
||||
## Mesh References
|
||||
|
||||
URDF mesh filenames should be stable from the generated URDF file's perspective or use a package URI convention understood by the consumer.
|
||||
|
||||
The current `scripts/urdf` validation path accepts any non-empty mesh filename or URI. Local relative mesh paths are checked relative to the generated URDF file; `package://...` and remote references are left unresolved with warnings unless a package map is supplied through `read_urdf_source()`.
|
||||
|
||||
When using package URIs, confirm the consuming environment resolves the package root the same way as the generated URDF expects.
|
||||
|
||||
Do not use generated URDF XML as the source of truth for mesh placement. Prefer deriving visual mesh references from the same source data that owns the mesh instance placement.
|
||||
|
||||
When mesh references point to generated assets, keep the ownership clear:
|
||||
|
||||
- CAD or mesh workflows own mesh generation;
|
||||
- URDF generation owns references, scales, and placements;
|
||||
- SRDF/MoveIt workflows own semantic groups, named joint poses via `<group_state>`, and planning metadata.
|
||||
|
||||
## Collision Geometry
|
||||
|
||||
Add collision geometry under each `<link>` that should participate in physics, contact, or collision-aware planning. Do not encode collision behavior on joints.
|
||||
|
||||
Use one or more `<collision>` blocks per link. The `<origin>` is expressed in the link frame, just like `<visual>`, and mesh scales must match the units of the exported mesh:
|
||||
|
||||
The current `scripts/urdf` validator allows visual and collision geometry to use `<mesh>`, `<box>`, `<cylinder>`, or `<sphere>`.
|
||||
|
||||
```xml
|
||||
<link name="forearm_link">
|
||||
<visual>
|
||||
<origin xyz="0 0 0" rpy="0 0 0" />
|
||||
<geometry>
|
||||
<mesh filename="package://robot_description/meshes/forearm.stl" scale="0.001 0.001 0.001" />
|
||||
</geometry>
|
||||
</visual>
|
||||
<collision>
|
||||
<origin xyz="0.12 0 0" rpy="0 1.57079632679 0" />
|
||||
<geometry>
|
||||
<cylinder radius="0.035" length="0.24" />
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
```
|
||||
|
||||
Prefer simplified collision geometry over detailed visual meshes. Good options, from simplest to most specific:
|
||||
|
||||
- primitive `<box>`, `<cylinder>`, or `<sphere>` geometry when it approximates the part well;
|
||||
- a coarse, closed collision mesh exported from CAD;
|
||||
- the visual mesh as a temporary fallback for loading and smoke tests.
|
||||
|
||||
In generator sources, model collisions explicitly rather than hand-editing generated URDF. A common pattern is to add a `collisions` collection beside `visuals` in each link spec and emit it with the same origin and scale helper code used for visual meshes.
|
||||
|
||||
## Inertials
|
||||
|
||||
For each physical link, use an explicit `inertial` block when the target simulator or dynamics consumer needs mass properties.
|
||||
|
||||
The inertial origin is the center of mass in the link frame. It is not automatically the visual mesh origin, collision origin, or link origin.
|
||||
|
||||
When exact mass properties are unavailable, use a documented approximation and make it easy to replace. Mark approximate mass, COM, and inertia constants clearly.
|
||||
|
||||
## Smoke Tests
|
||||
|
||||
After generation-time validation, use the most relevant available smoke test:
|
||||
|
||||
- load in RViz or equivalent visualization to inspect visible placement;
|
||||
- run robot_state_publisher or equivalent to check the TF tree;
|
||||
- load in Gazebo/Ignition or another simulator for physics consumers;
|
||||
- load in MoveIt only after URDF structure is stable, then handle semantic data through the SRDF workflow.
|
||||
|
||||
Report the smoke tests run and any skipped checks that would materially affect confidence.
|
||||
@@ -0,0 +1,156 @@
|
||||
# URDF Generation-Time Validation
|
||||
|
||||
Use this reference to understand what generated URDFs should satisfy. The `scripts/urdf` generation path validates by default; there is no separate validation-only command in this skill.
|
||||
|
||||
Validation is a guardrail, not a substitute for a design ledger or visual/consumer smoke test. A URDF can pass structural checks while still having incorrect spatial assumptions.
|
||||
|
||||
Generated or modified `.urdf` files should be handed to `$cad-viewer` for live viewer links when available.
|
||||
|
||||
## Structural Checks
|
||||
|
||||
Validate that:
|
||||
|
||||
- the root element is `<robot>`;
|
||||
- the robot has a non-empty name;
|
||||
- every link has a unique non-empty name;
|
||||
- every joint has a unique non-empty name;
|
||||
- every joint has valid parent and child fields;
|
||||
- parent and child links exist;
|
||||
- each child link has at most one parent;
|
||||
- the graph has exactly one root link;
|
||||
- the graph is connected and acyclic;
|
||||
- the tree has exactly `links - 1` joints unless the design intentionally uses a different structure and the runtime supports it.
|
||||
|
||||
## Origin Checks
|
||||
|
||||
For each joint, visual, collision, and inertial origin, validate or review that:
|
||||
|
||||
- `xyz` has three finite numeric values when present;
|
||||
- `rpy` has three finite numeric values when present;
|
||||
- omitted values follow the URDF default only when that is intentional;
|
||||
- units are meters for `xyz` and radians for `rpy`;
|
||||
- the origin is expressed in the correct frame.
|
||||
|
||||
Frame correctness must be reviewed from the design ledger. XML validation alone cannot prove that an origin is spatially correct.
|
||||
|
||||
## Joint Checks
|
||||
|
||||
The current `scripts/urdf` source reader supports these joint types:
|
||||
|
||||
- `fixed`
|
||||
- `continuous`
|
||||
- `revolute`
|
||||
- `prismatic`
|
||||
|
||||
Some URDF consumers also support `floating` and `planar`; use them only when the project runtime and validation path support them. The current `scripts/urdf` reader rejects them.
|
||||
|
||||
For non-fixed joints, validate or review that:
|
||||
|
||||
- `<axis>` exists where required;
|
||||
- axis has exactly three finite numeric values;
|
||||
- axis is nonzero;
|
||||
- axis is normalized or intentionally normalized by generator code;
|
||||
- axis is expressed in the joint frame;
|
||||
- positive motion is documented in the design ledger.
|
||||
|
||||
For limits:
|
||||
|
||||
- `revolute` lower/upper limits are radians;
|
||||
- `prismatic` lower/upper limits are meters;
|
||||
- lower is not greater than upper;
|
||||
- effort and velocity are finite when present;
|
||||
- `continuous` joints do not use artificial finite lower/upper limits;
|
||||
- `fixed` joints do not need motion limits.
|
||||
|
||||
## Geometry Checks
|
||||
|
||||
General URDF visual and collision geometry may use:
|
||||
|
||||
- `<mesh>`
|
||||
- `<box>`
|
||||
- `<cylinder>`
|
||||
- `<sphere>`
|
||||
|
||||
The current `scripts/urdf` validation path allows these geometry types for both visual and collision geometry.
|
||||
|
||||
For geometry, validate or review that:
|
||||
|
||||
- each visual or collision block has a `<geometry>` element;
|
||||
- each geometry block has exactly one supported geometry child;
|
||||
- primitive dimensions are positive and finite;
|
||||
- mesh filenames are non-empty;
|
||||
- mesh scale, when present, has three positive finite values;
|
||||
- visual and collision origins are relative to the owning link frame;
|
||||
- collision geometry is appropriate for the target consumer.
|
||||
|
||||
## Mesh Reference Checks
|
||||
|
||||
For mesh references, distinguish syntax, local existence, and runtime package resolution.
|
||||
|
||||
Validate or review that:
|
||||
|
||||
- local relative and absolute paths are intentional;
|
||||
- local files exist when filesystem validation is available;
|
||||
- `package://...` URIs have valid syntax;
|
||||
- package URIs are not incorrectly assumed to resolve from the current working directory;
|
||||
- the consuming ROS or simulator environment can resolve package URIs;
|
||||
- mesh source units and emitted scale convert to meters.
|
||||
|
||||
The current source reader accepts any non-empty mesh filename or URI. It resolves local mesh paths from the generated URDF file's directory and verifies those files exist. It accepts unresolved `package://...` and remote references with warnings, because final mesh-format support is consumer-specific.
|
||||
|
||||
If mesh references changed, confirm the corresponding mesh outputs were regenerated separately by the owning CAD or mesh workflow.
|
||||
|
||||
## Inertial Checks
|
||||
|
||||
For each physical link with mass or geometry, prefer an explicit `inertial` block:
|
||||
|
||||
- `origin` is the center of mass in the link frame;
|
||||
- `mass` is positive and finite;
|
||||
- `inertia` defines `ixx`, `ixy`, `ixz`, `iyy`, `iyz`, and `izz`;
|
||||
- all inertia values are finite;
|
||||
- diagonal inertia values are positive;
|
||||
- the inertia matrix is physically plausible for the intended approximation;
|
||||
- approximations are documented.
|
||||
|
||||
Frame-only links may intentionally omit `inertial`. Physical links with omitted inertials should be called out when the target consumer uses simulation or dynamics.
|
||||
|
||||
## URDF Validity vs Project Policy
|
||||
|
||||
Separate general URDF validity from project-specific policy.
|
||||
|
||||
Examples of general URDF validity or sanity checks:
|
||||
|
||||
- unique links and joints;
|
||||
- valid tree structure;
|
||||
- valid joint parent/child references;
|
||||
- finite origins;
|
||||
- nonzero movable-joint axes;
|
||||
- positive primitive dimensions;
|
||||
- positive mass for physical inertial blocks.
|
||||
|
||||
Examples of project policy checks:
|
||||
|
||||
- visual mesh references must use a specific extension;
|
||||
- visual geometry must be mesh-only;
|
||||
- collision geometry must be primitive-only;
|
||||
- mesh files must live under a specific directory;
|
||||
- every physical link must have collision geometry;
|
||||
- every physical link must have inertial data;
|
||||
- package URIs must use a specific package prefix.
|
||||
|
||||
When a generated URDF fails because of project policy, report it as policy failure, not as universal URDF invalidity.
|
||||
|
||||
## Failure Handling
|
||||
|
||||
When generation-time validation fails:
|
||||
|
||||
1. fix the generator source, design ledger, or referenced assets;
|
||||
2. regenerate the explicit URDF target;
|
||||
3. do not hand-edit the generated `.urdf` as a permanent fix;
|
||||
4. record any remaining assumptions or unchecked spatial claims.
|
||||
|
||||
## Tooling
|
||||
|
||||
Use `scripts/urdf/source.py` through the `urdf.source.read_urdf_source()` helper for compact robot/link/joint checks when writing tests or focused checks.
|
||||
|
||||
The URDF source reader is a lightweight standard-library validator. It checks the generated subset used by this skill; consumer-specific parser and mesh-loading compatibility should still be smoke-tested in the target runtime when confidence matters.
|
||||
Reference in New Issue
Block a user