How to Model Inertial, Visual, and Collision Properties for URDFs

To model inertial, visual, and collision properties for URDFs, define an <inertial> block with positive mass and a physically valid inertia tensor, optional <visual> elements for display meshes, and optional <collision> elements for physics geometry, ensuring all origins are expressed in the link frame and mesh URIs resolve correctly.

The earthtojake/text-to-cad repository includes a dedicated URDF skill that parses robot description XML and validates these three critical property types. Understanding the validation logic in skills/urdf/scripts/urdf/source.py helps you author URDFs that pass strict physical plausibility checks and mesh resolution requirements.

Every rigid body in a URDF is defined within a <link> element. The text-to-cad validator enforces distinct rules for inertial, visual, and collision sub-elements.

The <inertial> block defines the link's mass distribution and is mandatory for any link that participates in dynamics. According to _validate_link_inertials() in source.py:226-230, the validator performs three critical checks:

  • <mass> must contain a positive floating-point value (source.py:31-44). Zero or negative values trigger validation errors.
  • <inertia> must contain the six tensor components (ixx, ixy, ixz, iyy, iyz, izz). The diagonal terms must be positive, and the matrix must satisfy the triangle inequalities (ixx + iyy > izz, etc.) to ensure physical plausibility (source.py:46-42).
  • <origin> specifies the center-of-mass (CoM) pose expressed in the link frame, not the joint frame. This is validated separately from joint origins (source.py:226-230).

Visual Geometry (Optional)

The <visual> element defines the mesh used for rendering. The _geometry_mesh_paths() function (source.py:100-115) extracts geometry references and:

  • Validates the <origin> sub-element if present.
  • Requires a <geometry> child containing a <mesh> element (other geometry types are not processed by this skill).
  • Resolves the filename via classify_mesh_uri() and resolve_mesh_uri(), supporting local relative paths, absolute paths, ROS package URIs, and remote URLs. Missing files raise errors; unresolved URIs emit warnings.

Collision Geometry (Optional)

The <collision> element uses an identical structure to <visual> but defines the geometry used for physics engines and collision checking. The same mesh resolution logic applies (source.py:100-115). While optional, defining simplified collision meshes (separate from high-fidelity visual meshes) significantly improves simulation performance.

The Validation Pipeline

The read_urdf_source() function (source.py:70-95) orchestrates the validation flow:

  1. Root Parsing – Ensures the root element is <robot> and extracts the robot name.
  2. Link Collection – Builds a list of all link names for cross-referencing.
  3. Inertial Validation – Walks each <link> to validate inertial blocks as described above.
  4. Geometry Extraction – Processes <visual> and <collision> sections to resolve mesh paths.
  5. Joint Validation – Validates <joint> origins separately (source.py:133-138). This distinction is crucial because joint origins define the kinematic tree, while inertial origins define mass properties.
  6. Tree Consistency – Verifies the kinematic structure forms a single rooted tree with no cycles (source.py:175-190). Inertial and collision data are only meaningful if the topology is valid.

Complete URDF Example

Below is a minimal, valid URDF that demonstrates proper structuring of all three property types according to the text-to-cad validator requirements:

<robot name="example_robot">
  <!-- Base link with full property definitions -->
  <link name="base_link">
    <!-- Inertial: Required for dynamics -->
    <inertial>
      <!-- CoM expressed in base_link frame -->
      <origin xyz="0 0 0.02" rpy="0 0 0"/>
      <mass value="5.0"/>
      <inertia ixx="0.1" ixy="0.0" ixz="0.0"
               iyy="0.2" iyz="0.0" izz="0.3"/>
    </inertial>

    <!-- Visual: Optional display geometry -->
    <visual>
      <origin xyz="0 0 0.0" rpy="0 0 0"/>
      <geometry>
        <mesh filename="meshes/base_visual.stl"/>
      </geometry>
    </visual>

    <!-- Collision: Optional physics geometry -->
    <collision>
      <origin xyz="0 0 0.0" rpy="0 0 0"/>
      <geometry>
        <mesh filename="meshes/base_collision.stl"/>
      </geometry>
    </collision>
  </link>

  <!-- Connecting joint -->
  <joint name="base_to_arm" type="fixed">
    <parent link="base_link"/>
    <child link="arm_link"/>
    <origin xyz="0 0 0.1" rpy="0 0 0"/>
  </joint>

  <!-- Frame-only link (no inertial or geometry) -->
  <link name="arm_link"/>
</robot>

Key implementation details from the source:

  • The mass value 5.0 satisfies the positive-mass constraint enforced at source.py:31-44.
  • The inertia values satisfy ixx > 0, iyy > 0, izz > 0, and the triangle inequalities checked at source.py:46-42.
  • Mesh filenames are relative to the URDF file location. If meshes/base_visual.stl is missing, the validator raises an error at source.py:95-99.

Summary

  • Inertial properties require positive mass, positive diagonal inertia terms, and satisfaction of triangle inequalities to represent physically valid rigid bodies.
  • Visual and collision properties rely on mesh file resolution through classify_mesh_uri() and resolve_mesh_uri(), supporting local and remote paths.
  • Frame semantics are strict: inertial origins are expressed in the link frame, while joint origins define the kinematic structure.
  • Tree validation ensures the URDF describes a single rooted kinematic tree without cycles before processing geometric properties.

Frequently Asked Questions

What validation rules apply to URDF inertia tensors?

The validator requires the inertia matrix to have positive diagonal components (ixx, iyy, izz) and satisfy the triangle inequalities (ixx + iyy > izz, ixx + izz > iyy, iyy + izz > ixx). These checks, implemented in source.py:46-42, ensure the matrix is positive-definite and physically realizable.

How does text-to-cad resolve mesh file paths in visual and collision elements?

The _geometry_mesh_paths() function (source.py:100-115) calls classify_mesh_uri() to identify whether the path is local, absolute, a ROS package URI, or remote, then uses resolve_mesh_uri() to locate the file. Missing files raise validation errors, while unresolvable URIs trigger warnings but allow parsing to continue.

According to the frame semantics validation in source.py:226-230, the <inertial> origin defines the center-of-mass relative to the link's own coordinate system. This is distinct from <joint> origins (source.py:133-138), which define the spatial relationship between parent and child links. Keeping these frames separate allows the inertia to remain constant regardless of how the link is connected to the kinematic tree.

What happens if a URDF fails the tree consistency check?

If the validator detects cycles or disconnected subgraphs during the tree consistency verification (source.py:175-190), it rejects the URDF before processing inertial or collision data. This ensures that physical properties are only calculated for valid kinematic structures that simulation engines can actually simulate.

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 →