Every ROS 2 developer who’s written a URDF has hit this: check_urdf passes your file, you launch Gazebo, and the robot collapses or explodes anyway. That’s because check_urdf is syntax-only — it cannot tell you whether your inertia tensors, mass values, or joint effort limits are physically plausible. A 2024 empirical study of 221 ROS bugs (ROBUST, Empirical Software Engineering) found that URDF semantic errors like this — bad mass, inertia, kinematic specs — are among the most common real-world failure modes across open-source robot packages. That gap is what got me building this.
urdf_validator is a pip-installable CLI that tries to close it. No ROS install required.
pip install urdf-validator
urdf_validate my_robot.urdf
What it checks beyond schema:
- Full-body COM, gravity torque per joint, motor effort margins (PASS/WARN/FAIL with plain-language summaries)
- Support polygon + COM stability margin, tipping angle
- Monte Carlo FK reach envelope, task-specific reachability (“can this arm reach a table at 0.75m?”)
- Payload-augmented statics — –payload-mass 5.0 recomputes torque margins with a carried load
- Optional MuJoCo cross-validation (–deep) for a simulated-confidence sanity check
The part I went back and forth on: robots outside the six reference types. Robot classification and contact-point detection are heuristic under the hood, and heuristics get things wrong — novel naming conventions, hexapod leg names, mecanum/tracked wheels, categories like aerial or marine platforms that don’t fit the original wheeled/legged/humanoid taxonomy at all. My first instinct was to keep tuning the heuristics. I think that’s the wrong fix — it doesn’t scale and it hides the uncertainty instead of surfacing it. So instead: you can declare what the tool can’t reliably infer (–robot-type, --contact-links, --arm-root/–arm-tip), the heuristic keeps running in the background as a cross-check, and if it disagrees with your declaration you get a warning naming the mismatch rather than a silent override either way. Same logic extends into a capability-profile model — a new robot category gets supported by composing existing flags (locomotion model, manipulator presence, force model) instead of a bespoke pipeline branch per category. One distinction I’m fairly opinionated about here: UNKNOWN (“couldn’t determine this”) and N/A (“doesn’t apply to this robot”) used to get conflated, and I think that was actively misleading — they’re different claims and the report says so now.
One thing I am confident about: this is built to be AI-agent-callable, deliberately. An LLM reasoning about robot geometry in natural language can’t reliably compute reach, torque margins, or stability — that’s a spatial/physics problem, not a language problem, and an LLM attempting it will produce confident, unverifiable numbers. So the design call here is that urdf_validator stays the deterministic, auditable oracle an agent calls into, full stop — there’s a structured task-query Python API (api/task_runner.py) that takes a task description and returns PASS/FAIL/N/A/UNKNOWN per sub-check with a geometric reason traceable to a specific link, joint, or distance. No ML or LLM anywhere in the physics pipeline, and I don’t have plans to add any — the moment you let a model guess a torque number, the whole point of the tool is gone.
Where it’s still rough, I will said upfront rather than waiting for someone to find it:
- Humanoid foot-contact stability is always UNKNOWN — supply –contact-links for a real margin
- Same for –robot-type unknown (no lowest-link fallback yet)
- Mimic joints are treated as fixed; their torques aren’t computed
- SDF isn’t supported, URDF/xacro only
- –pose home falls back silently to zero pose (no URDF standard for home config)
- Per-arm workspace breakdown is aggregated, not per-arm, in this release
- –deep runs a static MuJoCo cross-check only; the drop test isn’t implemented yet
Full output examples for TurtleBot3, PR2, ANYmal, Spot, Franka Panda, Fetch, plus two new capability-profile examples (a wheeled vehicle with no arm, an aerial drone) are in the README. MIT licensed, GitHub Actions workflow included.
GitHub: GitHub - Notlord69/urdf_validator · GitHub
If you’ve got a robot that doesn’t fit the assumptions above or any improvement applicable to the project, I’d genuinely like to hear about it — that’s exactly how the override-flag list grows, and right now it’s grown from exactly one perspective (mine).