Physics-aware URDF validation for the ROS 2 community
Project description
urdf_validator
A physics-aware URDF validation tool for the ROS 2 community.
The problem
check_urdf, the only official ROS 2 validation tool, checks syntax only. A URDF that passes check_urdf can still silently fail in any physics-based simulator — collapsing robots, undersized motors, unstable configurations. urdf_validator catches this entire class of errors before you ever launch a simulation.
The tool is designed to work on any URDF, not just a curated set of reference robots. When the link-name heuristics cannot reliably classify your robot, you can declare what the tool cannot infer — robot type, ground-contact links, arm chain boundaries — and the heuristics continue running as a cross-check rather than the sole decision-maker.
What it checks
| Phase | What it analyses |
|---|---|
| Schema | Broken joint references, kinematic loops, duplicate names, zero/missing inertia, non-positive-definite inertia, inverted joint limits, missing effort/velocity limits, missing mesh files |
| Statics | Full-body centre of mass, gravity torque per actuated joint, motor effort margins (PASS / WARN / FAIL), weakest joint identification |
| Stability | Support polygon from wheel/caster contacts, COM-over-polygon containment, signed margin in mm, tip direction, COM height ratio, tipping angle |
| Workspace | Monte Carlo FK reach envelope (max / vertical / horizontal), task-specific reachability, COM stability during reach |
| User overrides | --robot-type, --contact-links, --arm-root/--arm-tip let you declare what heuristics cannot reliably infer; declared values are labeled exact and heuristics run as a cross-check |
| Deep (optional) | MuJoCo simulation cross-validation of gravity torques and COM; SIMULATED confidence badge |
Installation
pip install urdf-validator
Optional extras:
pip install "urdf-validator[xacro]" # adds xacro preprocessing
pip install "urdf-validator[mujoco]" # adds MuJoCo deep-validation mode
pip install "urdf-validator[full]" # adds both xacro and mujoco
No ROS installation required.
Quick start
urdf_validate my_robot.urdf
Writes my_robot_validation.json alongside the URDF. Exits non-zero on any WARN or FAIL finding — directly usable as a CI gate.
CLI reference
urdf_validate <urdf_file> [options]
| Flag | Values | Default | Description |
|---|---|---|---|
--pose |
zero | limits | custom | home |
zero |
Joint configuration for statics/stability/workspace. limits sets each joint to its declared upper limit (worst-case torques). custom requires --joint-angles. home warns and falls back to zero (no URDF standard for home configs). |
--joint-angles ANGLES |
"j1=0.5,j2=1.2" |
— | Joint angles for --pose custom in radians/metres. |
--task TASK |
pick_from_ground | pick_from_table | push_button | custom |
— | Task reachability check. Reports whether the arm can reach the target height and whether the COM remains stable during reach. |
--height M |
float | — | Target height in metres. Required with --task custom. |
--output-dir DIR |
path | alongside input | Directory for the JSON validation report. |
--deep |
flag | off | Run MuJoCo simulation pass to cross-validate gravity torques and COM. Auto-triggers when stability margin is negative. Requires pip install mujoco. |
--robot-type TYPE |
wheeled | ground_vehicle | legged | humanoid | arm_only | aerial | unknown |
— | Declare the robot category explicitly. The link-name heuristic still runs as a cross-check; a mismatch is reported as a warning but does not override this declaration. |
--contact-links LINKS |
"l1,l2,l3" |
— | Comma-separated list of ground-contact link names. Bypasses the geometry heuristic for stability polygon construction; useful for legged robots or non-standard wheel naming. |
--arm-root LINK |
link name | — | Root link of the arm chain. Bypasses the DOF-heuristic arm detection. Must be used together with --arm-tip. |
--arm-tip LINK |
link name | — | End-effector link of the arm chain. Bypasses the DOF-heuristic arm detection. Must be used together with --arm-root. |
Exit codes
| Code | Meaning |
|---|---|
0 |
PASS — all checks passed |
1 |
WARN — no failures, at least one warning |
2 |
FAIL or UNKNOWN — at least one check failed or a critical check could not run |
Output — reference robot examples
The acceptance standard is correct, non-crashing output on six well-known public robots plus two capability-profile examples added in v0.7. Output below is captured directly from the tool; ANSI colours are stripped.
TurtleBot3 — differential-drive mobile robot
╔════════════════════════════════════════════════════╗
║ urdf_validate — TurtleBot3.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ✓ PASS (6 infos)
[INFO] Joint 'wheel_left_joint' (continuous) has no effort or velocity limit declared
[INFO] Joint 'wheel_right_joint' (continuous) has no effort or velocity limit declared
[INFO] Link 'base_link': mesh 'package://turtlebot3_description/meshes/bases/burger_base.stl' not found — package:// resolution requires ROS workspace to be sourced
[INFO] Link 'wheel_left_link': mesh 'package://turtlebot3_description/meshes/wheels/left_tire.stl' not found — package:// resolution requires ROS workspace to be sourced
[INFO] Link 'wheel_right_link': mesh 'package://turtlebot3_description/meshes/wheels/right_tire.stl' not found — package:// resolution requires ROS workspace to be sourced
[INFO] Link 'base_scan': mesh 'package://turtlebot3_description/meshes/sensors/lds.stl' not found — package:// resolution requires ROS workspace to be sourced
[PHYSICS] 7 links — mass: 5 exact, 2 missing · inertia: 5 exact, 2 missing
[STATICS] COM [-0.004, 0.000, 0.031] m height 0.031 m total mass 1.002 kg (estimated)
Heaviest: base_link (82.4%)
[STATICS] joints: PASS
[STABILITY] ✓ STABLE margin 4.0 mm
COM height ratio 0.96 — stable tips at 27.4°
[WORKSPACE] UNKNOWN — No arm chain detected (robot may be wheeled or legged only)
[OVERALL] PASS confidence: MEDIUM
Full report: TurtleBot3_validation.json
Exit 0.
Fetch — wheeled mobile manipulator
╔════════════════════════════════════════════════════╗
║ urdf_validate — fetch.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ⚠ WARN — 42 issues
[WARN] Link 'r_gripper_finger_link' has non-positive-definite inertia tensor (min eigenvalue: 0.000000) — physically impossible
[WARN] Link 'l_gripper_finger_link' has non-positive-definite inertia tensor (min eigenvalue: 0.000000) — physically impossible
[INFO] (40 mesh resolution notices — package:// resolution requires ROS workspace)
[PHYSICS] 28 links — mass: 22 exact, 6 missing · inertia: 22 exact, 6 missing
[STATICS] COM [0.045, 0.001, 0.260] m height 0.260 m total mass 121.538 kg (estimated)
Heaviest: base_link (57.7%)
[STATICS] joints: PASS weakest: torso_lift_joint
[STABILITY] ✓ STABLE margin 43.7 mm
COM height ratio 0.69 — stable tips at 35.8°
[WORKSPACE] max reach 2.182 m vertical 2.158 m horizontal 1.165 m (estimated)
from base 2.182 m
[OVERALL] WARN confidence: MEDIUM
Full report: fetch_validation.json
Exit 1. The two gripper finger links have singular inertia tensors in the upstream URDF — a known issue with this file. All statics and stability checks proceed and pass.
PR2 — dual-arm wheeled robot (88 links)
╔════════════════════════════════════════════════════╗
║ urdf_validate — PR2.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ⚠ WARN — 88 issues
[WARN] Link 'r_gripper_l_finger_tip_frame' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'l_gripper_l_finger_tip_frame' has no inertial block (mass unknown) — will cause physics engine instability
[INFO] Joint 'torso_lift_motor_screw_joint' (continuous) has no effort or velocity limit declared
[INFO] Joint 'r_gripper_motor_screw_joint' (continuous) has no effort or velocity limit declared
[INFO] Joint 'l_gripper_motor_screw_joint' (continuous) has no effort or velocity limit declared
[INFO] Robot has 88 links (>50) — may be slow to simulate or validate
[INFO] (82 mesh resolution notices — package:// resolution requires ROS workspace)
[PHYSICS] 88 links — mass: 73 exact, 15 missing · inertia: 73 exact, 15 missing
[STATICS] COM [-0.016, 0.005, 0.477] m height 0.477 m total mass 265.732 kg (estimated)
Heaviest: base_link (43.7%)
[STATICS] joints: FAIL weakest: l_shoulder_lift_joint
[STABILITY] ✓ STABLE margin 208.5 mm
COM height ratio 1.06 — manageable tips at 25.2°
[WORKSPACE] max reach 1.887 m vertical 1.777 m horizontal 1.177 m (estimated)
from base 1.931 m
[OVERALL] FAIL confidence: MEDIUM
Full report: PR2_validation.json
Exit 2. The shoulder lift joints on both arms are undersized: the URDF declares 30 Nm but the gravity torque at zero pose requires ~49 Nm. The real PR2 compensates with passive counterbalance springs not modelled in the URDF.
ANYmal — legged quadruped
╔════════════════════════════════════════════════════╗
║ urdf_validate — ANYmal.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ✓ PASS (17 infos)
[INFO] (17 mesh resolution notices — package:// resolution requires ROS workspace)
[PHYSICS] 22 links — mass: 17 exact, 5 missing · inertia: 17 exact, 5 missing
[STATICS] COM [-0.001, -0.001, -0.034] m height -0.034 m total mass 30.421 kg (estimated)
Heaviest: base_inertia (55.2%)
[STATICS] joints: PASS weakest: RF_HAA
[STABILITY] UNKNOWN — robot type 'quadruped' — stability only computed for wheeled robots
[WORKSPACE] N/A — not applicable — robot type 'quadruped' has no manipulator
[OVERALL] PASS confidence: MEDIUM
Full report: ANYmal_validation.json
Exit 0. Stability is UNKNOWN for legged robots — support polygon computation requires declared foot contacts, which are not a standard URDF field. Use --contact-links to supply foot contact link names explicitly and get a real stability margin. Workspace is N/A — the capability profile for quadruped classifies this as a locomotion platform with no manipulator; v0.6 incorrectly reported leg reach as workspace reach.
Spot — legged quadruped (unofficial URDF, no masses)
╔════════════════════════════════════════════════════╗
║ urdf_validate — Spot.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ⚠ WARN — 37 issues
[WARN] Link 'fl.hip' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'fl.uleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'fl.lleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'fr.hip' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'fr.uleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'fr.lleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'hl.hip' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'hl.uleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'hl.lleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'hr.hip' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'hr.uleg' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'hr.lleg' has no inertial block (mass unknown) — will cause physics engine instability
[INFO] Link 'fl.hip' has visual geometry (mesh) but no collision geometry — will be invisible to physics engines
[INFO] (11 more visual-without-collision notices + 13 mesh resolution notices)
[PHYSICS] 13 links — mass: 0 exact, 13 missing · inertia: 0 exact, 13 missing
[STATICS] COM unknown (missing)
[STATICS] joints: PASS
[STABILITY] UNKNOWN — robot type 'quadruped' — stability only computed for wheeled robots
[WORKSPACE] N/A — not applicable — robot type 'quadruped' has no manipulator
[OVERALL] WARN confidence: LOW
Full report: Spot_validation.json
Exit 1. This unofficial URDF omits all link masses. The tool degrades gracefully: schema warns on every link, statics and stability correctly report missing data. Workspace is N/A — the capability profile for quadruped classifies this as a locomotion platform with no manipulator.
Franka Panda — fixed-base arm (no masses declared)
╔════════════════════════════════════════════════════╗
║ urdf_validate — Franka_Panda.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ⚠ WARN — 25 issues
[WARN] Link 'panda_base1' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_base_arm' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link1' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link2' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link3' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link4' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link5' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link6' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'panda_link7' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'frankie_leftfinger' has no inertial block (mass unknown) — will cause physics engine instability
[WARN] Link 'frankie_rightfinger' has no inertial block (mass unknown) — will cause physics engine instability
[INFO] (2 visual-without-collision notices + 12 mesh resolution notices)
[PHYSICS] 15 links — mass: 0 exact, 15 missing · inertia: 0 exact, 15 missing
[STATICS] COM unknown (missing)
[STATICS] joints: PASS
[STABILITY] UNKNOWN — robot type 'unknown' — stability only computed for wheeled robots
[WORKSPACE] max reach 1.255 m vertical 1.626 m horizontal 1.062 m (estimated)
from base 1.643 m
[OVERALL] WARN confidence: LOW
Full report: Franka_Panda_validation.json
Exit 1. No masses declared in this public URDF variant — a common issue with arm-only files intended for kinematic use only. Workspace is still computed from joint limits alone.
ground_vehicle — wheeled vehicle without manipulator
╔════════════════════════════════════════════════════╗
║ urdf_validate — ground_vehicle.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ✓ PASS
[PHYSICS] ✓ 5 links — all mass & inertia declared
[STATICS] COM [0.000, 0.000, -0.025] m height -0.025 m total mass 120.000 kg (estimated)
Heaviest: chassis (83.3%)
[STATICS] joints: PASS
j_wheel_fl req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
j_wheel_fr req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
j_wheel_rl req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
j_wheel_rr req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
[STABILITY] ✓ STABLE margin 300.0 mm
[WORKSPACE] N/A — not applicable — robot type 'ground_vehicle' has no manipulator
[WARN] User declared --robot-type=ground_vehicle, but link-name heuristic suggests wheeled
[OVERALL] PASS confidence: HIGH
Full report: ground_vehicle_validation.json
Exit 0. Stability runs the wheel-contact heuristic (ground_vehicle profile: locomotion_model="wheeled"). Workspace is N/A — this robot category has no manipulator. --robot-type ground_vehicle was supplied explicitly. The heuristic mismatch warning (ground_vehicle vs wheeled) is expected: both share the same wheel-contact algorithm but ground_vehicle disables workspace checks.
aerial_drone — airborne robot (4 fixed rotors)
╔════════════════════════════════════════════════════╗
║ urdf_validate — aerial_drone.urdf ║
╚════════════════════════════════════════════════════╝
[SCHEMA] ✓ PASS
[PHYSICS] ✓ 5 links — all mass & inertia declared
[STATICS] COM [0.000, 0.000, 0.000] m height 0.000 m total mass 1.900 kg (estimated)
Heaviest: body (78.9%)
[STABILITY] N/A — not applicable — robot type 'aerial' has no ground contact
[WORKSPACE] N/A — not applicable — robot type 'aerial' has no manipulator
[WARN] User declared --robot-type=aerial, but link-name heuristic suggests unknown
[OVERALL] PASS confidence: HIGH
Full report: aerial_drone_validation.json
Exit 0. Both stability (no ground contact) and workspace (no manipulator) are N/A. --robot-type aerial was supplied explicitly. Schema and statics still run.
User-declared robot info
When heuristics cannot reliably classify your robot — non-English link names, non-standard wheel geometry, hexapod naming conventions — you can declare the information directly:
# Legged robot with known foot contact links
urdf_validate my_hexapod.urdf \
--robot-type legged \
--contact-links foot_fl,foot_fr,foot_ml,foot_mr,foot_rl,foot_rr
# Robot with a non-obvious arm chain
urdf_validate my_robot.urdf \
--arm-root arm_base_link \
--arm-tip tool_flange
Declared values are used directly and labeled exact in the JSON output. The corresponding heuristic still runs in the background: if it disagrees, a warning is added to the report naming the mismatch. The declared value always wins — the disagreement is surfaced, never silently resolved.
If you omit these flags, heuristic output is used and labeled estimated to make clear it is an unverified inference, not a verified value.
Capability profiles
The tool uses a built-in profile table to decide which checks apply to each robot category. Consult this table when the default output shows N/A or UNKNOWN and you want to understand why:
| Robot type | Stability check | Workspace check |
|---|---|---|
wheeled |
Runs (wheel-contact heuristic) | Runs if arm chain detected |
ground_vehicle |
Runs (wheel-contact heuristic) | N/A — ground vehicles have no manipulator |
arm_only |
N/A — fixed-base arm has no ground contact | Runs |
legged / quadruped |
UNKNOWN — foot contacts must be declared via --contact-links |
N/A — legged robots have no manipulator |
humanoid |
UNKNOWN — foot-contact algorithm not yet implemented | Runs if arm chain detected |
aerial |
N/A — airborne robot has no ground contact | N/A — aerial vehicles have no manipulator |
unknown |
UNKNOWN — cannot determine contact geometry | Runs |
N/A means the check does not apply to this robot category and is excluded from the overall status derivation. UNKNOWN means the check was attempted but could not produce a result — either the required data is unavailable or the algorithm does not yet cover this case.
Use --robot-type to force the category. Without it, the link-name heuristic runs and the result is labeled estimated.
Payload-augmented statics
Pass --payload-mass <kg> to recompute gravity torques with a carried load included. The [STATICS] section shows the payload contribution and re-evaluates PASS/WARN/FAIL per joint:
urdf_validate fetch.urdf --payload-mass 5.0
urdf_validate fetch.urdf --payload-mass 5.0 --payload-link gripper_link
--payload-link sets which link the load is attached to. It defaults to the automatically-detected end-effector. payload_mass and payload_link are included in the JSON output.
Payload torque is computed as the cross-product of the moment arm (payload link world position relative to each joint) × gravity force. The same PASS/WARN/FAIL thresholds apply: PASS ≥ 1.5×, WARN 1.0–1.5×, FAIL < 1.0×.
CI integration
GitHub Actions
name: URDF validation
on:
push:
paths: ['**.urdf', '**.xacro']
pull_request:
paths: ['**.urdf', '**.xacro']
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install urdf-validator
run: pip install "urdf-validator[full]"
- name: Validate URDF
run: urdf_validate robot/my_robot.urdf --output-dir /tmp/reports
- name: Upload validation report
if: always()
uses: actions/upload-artifact@v4
with:
name: urdf-validation-report
path: /tmp/reports/*.json
The urdf_validate step exits non-zero on any WARN or FAIL finding, failing the CI job. Remove the paths: filter if you want to run on every push regardless of which files changed.
Validating multiple URDFs
- name: Validate all URDFs
run: |
find . -name '*.urdf' | while read f; do
echo "=== $f ==="
urdf_validate "$f" || exit 1
done
Allowing warnings but blocking failures
- name: Validate URDF (block on FAIL only)
run: |
urdf_validate robot/my_robot.urdf
code=$?
if [ $code -eq 2 ]; then exit 1; fi
Exit code 1 (WARN) passes; only exit code 2 (FAIL / UNKNOWN) fails the job.
Output sections
[SCHEMA]
Structural checks. Severities:
| Severity | Example |
|---|---|
CRITICAL |
Joint references a link that does not exist |
CRITICAL |
Kinematic loop detected |
WARN |
Non-positive-definite inertia tensor |
WARN |
Missing <inertial> block on a non-fixed link |
WARN |
Inverted joint limits (lower > upper) |
INFO |
Missing effort or velocity limit |
INFO |
Mesh file not found (package:// paths require a sourced ROS workspace) |
INFO |
Robot has more than 50 links |
[STATICS]
Computed at the declared --pose (default: zero pose).
- COM — full-body centre of mass
[x, y, z]in metres, total mass in kg. - Per joint — gravity torque required (
req), declared effort limit (declared), margin =declared / req.PASS≥ 1.5×,WARN1.0–1.5×,FAIL< 1.0×.
[STABILITY]
Available for wheeled robots by default. Contact point detection runs three passes in priority order:
- Links named
*wheel* - Cylindrical links with a wheel-like radius-to-length ratio (r/L > 0.3)
- Links named
*caster*with cylinder or sphere geometry
Use --contact-links to supply contact link names directly and bypass this heuristic entirely — required for legged robots and any configuration where link naming does not follow these conventions.
Reports signed margin in mm (positive = stable, negative = tipping), tip direction, COM height ratio, and tipping angle.
com_height_ratio_class |
Ratio | Meaning |
|---|---|---|
very_stable |
< 0.5 | Passive tip resistance |
stable |
0.5 – 1.0 | Normal for wheeled mobile robots |
manageable |
1.0 – 2.0 | Typical humanoid standing |
requires_active_balancing |
2.0 – 3.0 | Needs active balance control |
will_fall |
> 3.0 | Will fall without fast active control |
[WORKSPACE]
Monte Carlo FK sampling over joint limits. The arm chain is detected automatically via a BFS + DOF heuristic. Use --arm-root / --arm-tip to specify the chain boundary explicitly when auto-detection picks the wrong chain (e.g. a gripper chain instead of the full arm, or an arm on a non-standard robot).
Computes max_reach, vertical_reach, horizontal_reach, and reach_from_base. With --task, also reports whether the arm can reach the target height and whether the COM stays over the support polygon during full extension.
[OVERALL]
Worst status across all sections. Confidence level:
| Level | Condition |
|---|---|
HIGH |
All link masses and inertia tensors declared |
MEDIUM |
≥ 50% of link masses declared |
LOW |
Sparse physics data |
Confidence labels
Every physics estimate carries an explicit label:
| Label | Meaning |
|---|---|
exact |
Value read directly from a declared URDF field, or supplied via a user override flag |
estimated |
Derived from declared masses and geometry via analytical formula, or from a heuristic that ran without a user declaration to cross-check against |
guessed |
Heuristic estimate (e.g. mesh geometry — no explicit dims available) |
missing |
No data available |
simulated |
Cross-validated against MuJoCo simulation (--deep mode) |
The tool never presents an estimated value as ground truth.
JSON output
Every run writes <robot>_validation.json containing the full ValidationReport. The schema is stable across minor versions and documented in docs/json_schema.md.
{
"overall_status": "WARN",
"confidence_level": "MEDIUM",
"robot_type": "wheeled",
"robot_type_confidence": "exact",
"statics": {
"full_body_com": [0.045, 0.001, 0.260],
"total_mass": 121.538,
"com_height_above_ground": 0.260,
"weakest_joint_name": "torso_lift_joint",
"status": "PASS"
},
"stability": {
"stable": true,
"margin_mm": 43.7,
"com_height_ratio": 0.69,
"com_height_ratio_class": "stable",
"tipping_angle_deg": 35.8,
"contact_confidence": "estimated",
"status": "PASS"
}
}
robot_type_confidence and contact_confidence are "exact" when the value was supplied via --robot-type or --contact-links, and "estimated" when derived from the heuristic alone.
Task-query API
For AI agents and programmatic callers, urdf_validator exposes a structured Python interface. It runs the full physics pipeline and returns per-sub-check results without spawning a subprocess:
from urdf_validator_main.api.task_runner import run_pick_task, run_pick_sweep
from urdf_validator_main.api.task_schema import TaskQueryRequest
req = TaskQueryRequest(
urdf_path="fetch.urdf",
task_type="pick",
target_position=[0.5, 0.0, 0.8], # [x, y, z] metres, robot frame
target_orientation="top_down", # or "side", [r,p,y], [qw,qx,qy,qz]
object_mass_kg=0.5,
terrain_angle_deg=0.0,
)
resp = run_pick_task(req)
print(resp.overall_status) # "PASS" | "FAIL" | "UNKNOWN"
for check in resp.sub_checks:
print(check.name, check.status, check.reason)
Sub-checks returned per request:
| Sub-check | Passes when |
|---|---|
reach |
reach_from_base >= dist(target_position) |
reach_orientation |
≥ 5% of workspace samples satisfy target_orientation within tolerance |
payload_strength |
all joint effort margins ≥ 1.0× with object_mass_kg included |
stability_during_reach |
COM XY shift at maximum reach stays within the stability polygon margin |
self_collision |
≥ 95% of sampled arm poses are collision-free |
To sweep over a list of parameter variations (different heights, payloads, target positions):
responses = run_pick_sweep([req1, req2, req3])
# Returns List[TaskQueryResponse], order preserved, failures isolated
Full schema: urdf_validator_main/api/task_schema.py and urdf_validator_main/api/task_runner.py. Documented in docs/json_schema.md.
Status
| Version | Month | Status | Delivered |
|---|---|---|---|
| v0.1 | 1 | Complete | Parser, schema checks, physics confidence labels, no-crash on all 6 reference URDFs |
| v0.2 | 2 | Complete | Chain walker, full-body COM, gravity torques, MuJoCo ground-truth validation (0% error) |
| v0.3 | 3 | Complete | Robot type detection, support polygon, COM projection stability check |
| v0.4 | 4 | Complete | Workspace FK, task reachability, full report pipeline, JSON export |
| v0.5 | 5 | Complete | Pose flags, geometry contact detection, COM height ratio, --deep MuJoCo wiring, JSON schema docs, performance (PR2: 12.5s → 4.1s) |
| v0.6 | 6 | Complete | --robot-type, --contact-links, --arm-root/--arm-tip user override flags; heuristic cross-check and mismatch warnings; exact vs estimated confidence labeling |
| v0.7 | 7 | Complete | Capability profiles (N/A vs UNKNOWN); --payload-mass payload-augmented statics |
| v0.8 | 8 | Complete | Orientation-aware reachability (position + orientation, not position alone) |
| v0.9 | 9 | Complete | Real-pose COM stability during reach; self-collision/clearance checks |
| v0.10 | 10 | Complete | Structured task-query API for AI agents and programmatic callers |
| v0.11 | 11 | Complete | Hardening — full regression across all 6 reference robots + capability-profile URDFs |
| v1.0 | 12 | Complete | Public release — ROS Discourse announcement, pip package |
Dependencies
Core (pip install urdf-validator): urdf_parser_py, numpy, shapely, ikpy
Xacro (pip install "urdf-validator[xacro]"): adds xacro (.xacro / .xacro preprocessing)
MuJoCo (pip install "urdf-validator[mujoco]"): adds mujoco (--deep simulation mode)
Full (pip install "urdf-validator[full]"): both xacro and mujoco
No ROS installation required.
Known limitations
| Limitation | Status |
|---|---|
| Humanoid foot-contact stability | PENDING — stability is always UNKNOWN for humanoid robots. Supply foot positions with --contact-links to get a real margin. |
| Unknown-type contact fallback | PENDING — for --robot-type unknown, stability is UNKNOWN. Lowest-link fallback is not yet implemented. |
| Mimic joints | OPEN — mimic followers (common in parallel grippers) are treated as fixed. Joint angles and torques for mimic joints are not computed. |
| SDF format | DEFERRED — only URDF (.urdf, .xacro) is supported. |
--pose home |
Falls back silently to zero pose. URDF has no standard home-configuration field (that lives in SRDF, outside this tool's scope). |
| Per-arm workspace breakdown | Aggregated — max_reach is the maximum across all detected arm chains, not per-arm. A --detailed flag for per-arm envelopes is a planned future feature. |
| Payload capacity estimate | PENDING — payload_capacity_kg field exists in the report model but is not populated. |
--deep drop test |
PENDING — the 2-second MuJoCo drop test is not implemented. Only the static cross-validation pass runs under --deep. |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file urdf_validator-1.0.0.tar.gz.
File metadata
- Download URL: urdf_validator-1.0.0.tar.gz
- Upload date:
- Size: 119.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d070e3cef39b66464ac677d59f6c81ddf127ef23710090c364f36854671fe904
|
|
| MD5 |
9c0314892d904f86ec9c224562981c73
|
|
| BLAKE2b-256 |
1515944b4fa6c5628a9d87ce0a897a20d63c25711ae39510e2eb36a2feee5ab6
|
File details
Details for the file urdf_validator-1.0.0-py3-none-any.whl.
File metadata
- Download URL: urdf_validator-1.0.0-py3-none-any.whl
- Upload date:
- Size: 56.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3db07de61a1ef5f2aa19f86d7f8bf18046b934014c719cba4fd0cb6e08ea5bd
|
|
| MD5 |
c382a92389eddf726967bc008dd5d17c
|
|
| BLAKE2b-256 |
7d8374e9cb37fb3fc814a217c40f1d9e6c523f63a72f5188a0e81ca16a051c4f
|