home / skills / a5c-ai / babysitter / urdf-sdf-model

This skill generates and validates URDF and SDF robot models, computes inertial properties, and configures joints, sensors, and macros for modular design.

npx playbooks add skill a5c-ai/babysitter --skill urdf-sdf-model

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
12.7 KB
---
name: urdf-sdf-model
description: Expert skill for robot model creation and validation in URDF and SDF formats. Generate URDF files with proper link-joint hierarchy, create Xacro macros, calculate inertial properties, configure joint types, and validate models.
allowed-tools: Bash(*) Read Write Edit Glob Grep WebFetch
metadata:
  author: babysitter-sdk
  version: "1.0.0"
  category: robot-modeling
  backlog-id: SK-004
---

# urdf-sdf-model

You are **urdf-sdf-model** - a specialized skill for robot model creation and validation in URDF (Unified Robot Description Format) and SDF (Simulation Description Format).

## Overview

This skill enables AI-powered robot modeling including:
- Generating URDF files with proper link-joint hierarchy
- Creating Xacro macros for modular robot descriptions
- Converting between URDF and SDF formats
- Calculating and setting inertial properties (mass, inertia tensors)
- Importing and optimizing mesh files (visual and collision)
- Configuring joint types (revolute, prismatic, continuous, fixed, floating)
- Setting up transmission and actuator definitions
- Adding sensor plugins and attachments
- Validating models with urdfdom and check_urdf
- Visualizing and debugging in RViz

## Prerequisites

- ROS/ROS2 with urdf packages
- xacro for macro processing
- urdfdom for validation
- Gazebo for SDF validation
- Mesh tools (MeshLab, Blender) for mesh optimization

## Capabilities

### 1. URDF Generation

Generate URDF files with proper structure:

```xml
<?xml version="1.0"?>
<robot name="my_robot" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- Materials -->
  <material name="blue">
    <color rgba="0.0 0.0 0.8 1.0"/>
  </material>

  <!-- Base Link -->
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.5 0.3 0.1"/>
      </geometry>
      <material name="blue"/>
    </visual>
    <collision>
      <geometry>
        <box size="0.5 0.3 0.1"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="10.0"/>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <inertia ixx="0.0833" ixy="0" ixz="0"
               iyy="0.2167" iyz="0" izz="0.2833"/>
    </inertial>
  </link>

  <!-- Wheel Joint -->
  <joint name="wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="wheel_link"/>
    <origin xyz="0.2 0.15 -0.05" rpy="-1.5708 0 0"/>
    <axis xyz="0 0 1"/>
    <limit effort="10" velocity="10"/>
    <dynamics damping="0.1" friction="0.1"/>
  </joint>

  <!-- Wheel Link -->
  <link name="wheel_link">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.02"/>
      </geometry>
    </visual>
    <collision>
      <geometry>
        <cylinder radius="0.05" length="0.02"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="0.5"/>
      <inertia ixx="0.0003" ixy="0" ixz="0"
               iyy="0.0003" iyz="0" izz="0.0006"/>
    </inertial>
  </link>

</robot>
```

### 2. Xacro Macros

Create modular robot descriptions with Xacro:

```xml
<?xml version="1.0"?>
<robot name="my_robot" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- Properties -->
  <xacro:property name="wheel_radius" value="0.05"/>
  <xacro:property name="wheel_width" value="0.02"/>
  <xacro:property name="wheel_mass" value="0.5"/>

  <!-- Inertia Macros -->
  <xacro:macro name="cylinder_inertia" params="m r h">
    <inertia ixx="${m*(3*r*r+h*h)/12}" ixy="0" ixz="0"
             iyy="${m*(3*r*r+h*h)/12}" iyz="0" izz="${m*r*r/2}"/>
  </xacro:macro>

  <xacro:macro name="box_inertia" params="m x y z">
    <inertia ixx="${m*(y*y+z*z)/12}" ixy="0" ixz="0"
             iyy="${m*(x*x+z*z)/12}" iyz="0" izz="${m*(x*x+y*y)/12}"/>
  </xacro:macro>

  <!-- Wheel Macro -->
  <xacro:macro name="wheel" params="prefix parent x_offset y_offset">
    <joint name="${prefix}_wheel_joint" type="continuous">
      <parent link="${parent}"/>
      <child link="${prefix}_wheel_link"/>
      <origin xyz="${x_offset} ${y_offset} 0" rpy="-1.5708 0 0"/>
      <axis xyz="0 0 1"/>
      <limit effort="10" velocity="10"/>
      <dynamics damping="0.1" friction="0.1"/>
    </joint>

    <link name="${prefix}_wheel_link">
      <visual>
        <geometry>
          <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
        </geometry>
        <material name="black"/>
      </visual>
      <collision>
        <geometry>
          <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
        </geometry>
      </collision>
      <inertial>
        <mass value="${wheel_mass}"/>
        <xacro:cylinder_inertia m="${wheel_mass}" r="${wheel_radius}" h="${wheel_width}"/>
      </inertial>
    </link>

    <!-- Gazebo friction -->
    <gazebo reference="${prefix}_wheel_link">
      <mu1>1.0</mu1>
      <mu2>1.0</mu2>
      <kp>1e6</kp>
      <kd>1.0</kd>
    </gazebo>
  </xacro:macro>

  <!-- Instantiate wheels -->
  <xacro:wheel prefix="front_left" parent="base_link" x_offset="0.15" y_offset="0.12"/>
  <xacro:wheel prefix="front_right" parent="base_link" x_offset="0.15" y_offset="-0.12"/>
  <xacro:wheel prefix="rear_left" parent="base_link" x_offset="-0.15" y_offset="0.12"/>
  <xacro:wheel prefix="rear_right" parent="base_link" x_offset="-0.15" y_offset="-0.12"/>

</robot>
```

### 3. Inertia Calculations

Calculate inertia tensors for common geometries:

```python
import numpy as np

def box_inertia(mass, x, y, z):
    """Calculate inertia tensor for a box centered at origin."""
    ixx = mass * (y**2 + z**2) / 12
    iyy = mass * (x**2 + z**2) / 12
    izz = mass * (x**2 + y**2) / 12
    return {'ixx': ixx, 'iyy': iyy, 'izz': izz, 'ixy': 0, 'ixz': 0, 'iyz': 0}

def cylinder_inertia(mass, radius, height):
    """Calculate inertia tensor for a cylinder along z-axis."""
    ixx = mass * (3 * radius**2 + height**2) / 12
    iyy = mass * (3 * radius**2 + height**2) / 12
    izz = mass * radius**2 / 2
    return {'ixx': ixx, 'iyy': iyy, 'izz': izz, 'ixy': 0, 'ixz': 0, 'iyz': 0}

def sphere_inertia(mass, radius):
    """Calculate inertia tensor for a solid sphere."""
    i = 2 * mass * radius**2 / 5
    return {'ixx': i, 'iyy': i, 'izz': i, 'ixy': 0, 'ixz': 0, 'iyz': 0}

def mesh_inertia_from_stl(stl_file, mass, density=None):
    """Estimate inertia from STL mesh using convex hull approximation."""
    # Use trimesh or similar library for accurate calculation
    import trimesh
    mesh = trimesh.load(stl_file)
    mesh.density = density if density else mass / mesh.volume
    return mesh.moment_inertia
```

### 4. Joint Types Configuration

Configure different joint types:

```xml
<!-- Revolute Joint (limited rotation) -->
<joint name="arm_joint" type="revolute">
  <parent link="base"/>
  <child link="arm"/>
  <origin xyz="0 0 0.1" rpy="0 0 0"/>
  <axis xyz="0 1 0"/>
  <limit lower="-1.57" upper="1.57" effort="100" velocity="1.0"/>
  <dynamics damping="0.5" friction="0.1"/>
</joint>

<!-- Continuous Joint (unlimited rotation) -->
<joint name="wheel_joint" type="continuous">
  <parent link="base"/>
  <child link="wheel"/>
  <axis xyz="0 0 1"/>
  <limit effort="10" velocity="10"/>
</joint>

<!-- Prismatic Joint (linear motion) -->
<joint name="slider_joint" type="prismatic">
  <parent link="base"/>
  <child link="slider"/>
  <origin xyz="0 0 0"/>
  <axis xyz="0 0 1"/>
  <limit lower="0" upper="0.5" effort="50" velocity="0.5"/>
</joint>

<!-- Fixed Joint (no motion) -->
<joint name="sensor_mount" type="fixed">
  <parent link="base"/>
  <child link="sensor"/>
  <origin xyz="0.1 0 0.05" rpy="0 0 0"/>
</joint>
```

### 5. Sensor Attachments

Add sensors to the robot model:

```xml
<!-- Camera Sensor -->
<link name="camera_link">
  <visual>
    <geometry>
      <box size="0.02 0.05 0.02"/>
    </geometry>
  </visual>
</link>

<joint name="camera_joint" type="fixed">
  <parent link="base_link"/>
  <child link="camera_link"/>
  <origin xyz="0.2 0 0.1" rpy="0 0 0"/>
</joint>

<gazebo reference="camera_link">
  <sensor type="camera" name="camera">
    <update_rate>30.0</update_rate>
    <camera>
      <horizontal_fov>1.3962634</horizontal_fov>
      <image>
        <width>640</width>
        <height>480</height>
        <format>R8G8B8</format>
      </image>
      <clip>
        <near>0.02</near>
        <far>100</far>
      </clip>
    </camera>
    <plugin name="camera_plugin" filename="libgazebo_ros_camera.so">
      <ros>
        <namespace>/robot</namespace>
        <remapping>image_raw:=camera/image_raw</remapping>
        <remapping>camera_info:=camera/camera_info</remapping>
      </ros>
      <frame_name>camera_link</frame_name>
    </plugin>
  </sensor>
</gazebo>

<!-- LiDAR Sensor -->
<link name="lidar_link">
  <visual>
    <geometry>
      <cylinder radius="0.03" length="0.04"/>
    </geometry>
  </visual>
</link>

<gazebo reference="lidar_link">
  <sensor type="ray" name="lidar">
    <pose>0 0 0 0 0 0</pose>
    <visualize>true</visualize>
    <update_rate>10</update_rate>
    <ray>
      <scan>
        <horizontal>
          <samples>360</samples>
          <resolution>1</resolution>
          <min_angle>-3.14159</min_angle>
          <max_angle>3.14159</max_angle>
        </horizontal>
      </scan>
      <range>
        <min>0.1</min>
        <max>10.0</max>
        <resolution>0.01</resolution>
      </range>
    </ray>
    <plugin name="lidar_plugin" filename="libgazebo_ros_ray_sensor.so">
      <ros>
        <namespace>/robot</namespace>
        <remapping>~/out:=scan</remapping>
      </ros>
      <output_type>sensor_msgs/LaserScan</output_type>
      <frame_name>lidar_link</frame_name>
    </plugin>
  </sensor>
</gazebo>
```

### 6. Model Validation

Validate URDF models:

```bash
# Check URDF syntax
check_urdf robot.urdf

# Process Xacro and check
xacro robot.urdf.xacro > robot.urdf && check_urdf robot.urdf

# Visualize URDF tree
urdf_to_graphviz robot.urdf

# View in RViz
ros2 launch urdf_tutorial display.launch.py model:=robot.urdf.xacro

# Convert URDF to SDF
gz sdf -p robot.urdf > robot.sdf
```

### 7. SDF Format

Generate SDF for Gazebo:

```xml
<?xml version='1.0'?>
<sdf version='1.7'>
  <model name='my_robot'>
    <link name='base_link'>
      <inertial>
        <mass>10.0</mass>
        <inertia>
          <ixx>0.0833</ixx>
          <iyy>0.2167</iyy>
          <izz>0.2833</izz>
        </inertia>
      </inertial>
      <collision name='base_collision'>
        <geometry>
          <box>
            <size>0.5 0.3 0.1</size>
          </box>
        </geometry>
        <surface>
          <friction>
            <ode>
              <mu>1.0</mu>
              <mu2>1.0</mu2>
            </ode>
          </friction>
        </surface>
      </collision>
      <visual name='base_visual'>
        <geometry>
          <box>
            <size>0.5 0.3 0.1</size>
          </box>
        </geometry>
        <material>
          <ambient>0.0 0.0 0.8 1</ambient>
        </material>
      </visual>
    </link>
  </model>
</sdf>
```

## MCP Server Integration

This skill can leverage the following MCP servers for enhanced capabilities:

| Server | Description | Installation |
|--------|-------------|--------------|
| CAD-Query MCP | Parametric 3D modeling | [mcpservers.org](https://mcpservers.org/servers/rishigundakaram/cadquery-mcp-server) |
| FreeCAD MCP | FreeCAD integration | [GitHub](https://github.com/bonninr/freecad_mcp) |
| Blender MCP | Mesh creation and editing | [blender-mcp.com](https://blender-mcp.com/) |
| OpenSCAD MCP | Parametric modeling | [playbooks.com](https://playbooks.com/mcp/jhacksman-openscad) |

## Best Practices

1. **Consistent units** - Use SI units (meters, kilograms, radians)
2. **Origin placement** - Place link origins at center of mass when possible
3. **Collision geometry** - Use simplified collision meshes for performance
4. **Inertia accuracy** - Calculate accurate inertia for stable simulation
5. **Mesh optimization** - Reduce polygon count for collision meshes
6. **Modular design** - Use Xacro macros for reusable components

## Process Integration

This skill integrates with the following processes:
- `robot-urdf-sdf-model.js` - Primary model creation process
- `robot-system-design.js` - System architecture with models
- `moveit-manipulation-planning.js` - MoveIt configuration
- `gazebo-simulation-setup.js` - Simulation model setup

## Output Format

When executing operations, provide structured output:

```json
{
  "operation": "create-urdf",
  "robotName": "my_robot",
  "status": "success",
  "validation": {
    "syntaxValid": true,
    "inertiasValid": true,
    "jointsValid": true
  },
  "artifacts": [
    "urdf/my_robot.urdf.xacro",
    "meshes/base_link.stl",
    "meshes/wheel.stl"
  ],
  "statistics": {
    "links": 5,
    "joints": 4,
    "sensors": 2
  }
}
```

## Constraints

- Verify coordinate frame conventions (REP-103)
- Ensure consistent units throughout model
- Validate inertia tensors are physically plausible
- Check for self-collision in collision geometry
- Respect Gazebo SDF version compatibility

Overview

This skill is an expert tool for creating, converting, and validating robot models in URDF and SDF formats. It generates clean link–joint hierarchies, Xacro macros, calculates inertial properties, configures joints and sensors, and validates models for simulation and visualization. The skill focuses on correctness, performance, and compatibility with ROS/Gazebo tooling.

How this skill works

It generates URDF/Xacro files with proper link, joint, inertial, visual, and collision elements; produces Xacro macros for modular components; and can convert URDF to SDF for Gazebo. It computes inertia tensors for standard primitives or estimates inertia from meshes using libraries like trimesh, inserts actuator/transmission and sensor plugin entries, and runs validation steps (check_urdf, urdfdom, urdf_to_graphviz, gz sdf). Output is a structured JSON report describing artifacts and validation results.

When to use it

  • Creating a new robot description for simulation or control.
  • Converting URDF models to SDF for Gazebo compatibility.
  • Adding or validating inertial properties to improve simulation stability.
  • Modularizing repetitive components with Xacro macros.
  • Preparing optimized collision meshes and sensor mounts for performance.

Best practices

  • Use SI units consistently (meters, kilograms, radians) and document unit assumptions.
  • Place link origin near the center of mass where possible to simplify inertial entries.
  • Use simplified collision meshes for physics and detailed visual meshes separately.
  • Compute inertia analytically for primitives and verify mesh-derived inertia against mass/volume.
  • Validate the assembled model with check_urdf and inspect the kinematic tree before simulation.

Example use cases

  • Generate a wheeled robot URDF with Xacro wheel macros and validated inertias for fast simulation setup.
  • Convert a legacy URDF robot into SDF and add Gazebo sensor plugins for camera and LiDAR testing.
  • Estimate inertia for a custom manipulator using mesh-based moment calculations and insert transmission elements for controllers.
  • Create modular robot subcomponents (grippers, wheel assemblies) as reusable Xacro macros for multiple platforms.

FAQ

Can this skill compute inertia from STL meshes?

Yes — it can estimate inertia using mesh libraries (e.g., trimesh) by computing volume and moment of inertia; verify density or supply mass for accurate results.

Does it check for unit or frame convention mismatches?

Yes — the skill enforces SI units and checks coordinate frame conventions (REP-103) and flags inconsistent origins or axis definitions during validation.