urdf-validator 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- urdf_validator-1.0.0/LICENSE +21 -0
- urdf_validator-1.0.0/PKG-INFO +649 -0
- urdf_validator-1.0.0/README.md +614 -0
- urdf_validator-1.0.0/pyproject.toml +44 -0
- urdf_validator-1.0.0/setup.cfg +4 -0
- urdf_validator-1.0.0/tests/test_arm_chain.py +268 -0
- urdf_validator-1.0.0/tests/test_capability_profile_reference.py +204 -0
- urdf_validator-1.0.0/tests/test_capability_wiring.py +245 -0
- urdf_validator-1.0.0/tests/test_chain_walker.py +230 -0
- urdf_validator-1.0.0/tests/test_cli.py +978 -0
- urdf_validator-1.0.0/tests/test_formatter.py +297 -0
- urdf_validator-1.0.0/tests/test_geometry_physics.py +139 -0
- urdf_validator-1.0.0/tests/test_imports.py +77 -0
- urdf_validator-1.0.0/tests/test_install.py +19 -0
- urdf_validator-1.0.0/tests/test_models.py +134 -0
- urdf_validator-1.0.0/tests/test_mujoco_validation.py +146 -0
- urdf_validator-1.0.0/tests/test_orientation.py +129 -0
- urdf_validator-1.0.0/tests/test_pending_degradation.py +196 -0
- urdf_validator-1.0.0/tests/test_report_derivation.py +167 -0
- urdf_validator-1.0.0/tests/test_robot_classifier.py +179 -0
- urdf_validator-1.0.0/tests/test_schema_checks.py +375 -0
- urdf_validator-1.0.0/tests/test_schema_mesh_check.py +266 -0
- urdf_validator-1.0.0/tests/test_schema_new_checks.py +237 -0
- urdf_validator-1.0.0/tests/test_self_collision.py +342 -0
- urdf_validator-1.0.0/tests/test_stability.py +483 -0
- urdf_validator-1.0.0/tests/test_statics.py +684 -0
- urdf_validator-1.0.0/tests/test_support_polygon.py +224 -0
- urdf_validator-1.0.0/tests/test_task_runner.py +193 -0
- urdf_validator-1.0.0/tests/test_task_runner_reference.py +409 -0
- urdf_validator-1.0.0/tests/test_task_runner_sweep.py +122 -0
- urdf_validator-1.0.0/tests/test_task_runner_toy.py +345 -0
- urdf_validator-1.0.0/tests/test_task_schema.py +83 -0
- urdf_validator-1.0.0/tests/test_urdf_adapter.py +331 -0
- urdf_validator-1.0.0/tests/test_workspace.py +708 -0
- urdf_validator-1.0.0/tests/test_xacro_handler.py +81 -0
- urdf_validator-1.0.0/urdf_validator.egg-info/PKG-INFO +649 -0
- urdf_validator-1.0.0/urdf_validator.egg-info/SOURCES.txt +67 -0
- urdf_validator-1.0.0/urdf_validator.egg-info/dependency_links.txt +1 -0
- urdf_validator-1.0.0/urdf_validator.egg-info/entry_points.txt +2 -0
- urdf_validator-1.0.0/urdf_validator.egg-info/requires.txt +17 -0
- urdf_validator-1.0.0/urdf_validator.egg-info/top_level.txt +1 -0
- urdf_validator-1.0.0/urdf_validator_main/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/api/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/api/task_runner.py +248 -0
- urdf_validator-1.0.0/urdf_validator_main/api/task_schema.py +34 -0
- urdf_validator-1.0.0/urdf_validator_main/checks/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/checks/schema.py +347 -0
- urdf_validator-1.0.0/urdf_validator_main/checks/stability.py +174 -0
- urdf_validator-1.0.0/urdf_validator_main/checks/statics.py +272 -0
- urdf_validator-1.0.0/urdf_validator_main/checks/workspace.py +332 -0
- urdf_validator-1.0.0/urdf_validator_main/cli.py +396 -0
- urdf_validator-1.0.0/urdf_validator_main/integrations/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/integrations/mujoco_wrapper.py +182 -0
- urdf_validator-1.0.0/urdf_validator_main/parser/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/parser/urdf_adapter.py +293 -0
- urdf_validator-1.0.0/urdf_validator_main/parser/xacro_handler.py +48 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/arm_chain.py +179 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/capability_profiles.py +76 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/chain_walker.py +130 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/geometry_physics.py +45 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/orientation.py +80 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/robot_classifier.py +28 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/self_collision.py +166 -0
- urdf_validator-1.0.0/urdf_validator_main/physics/support_polygon.py +178 -0
- urdf_validator-1.0.0/urdf_validator_main/report/__init__.py +0 -0
- urdf_validator-1.0.0/urdf_validator_main/report/formatter.py +284 -0
- urdf_validator-1.0.0/urdf_validator_main/report/json_export.py +22 -0
- urdf_validator-1.0.0/urdf_validator_main/report/models.py +122 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Notlord69
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: urdf-validator
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Physics-aware URDF validation for the ROS 2 community
|
|
5
|
+
License: MIT
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Requires-Python: >=3.8
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: urdf_parser_py
|
|
22
|
+
Requires-Dist: numpy
|
|
23
|
+
Requires-Dist: shapely
|
|
24
|
+
Requires-Dist: ikpy
|
|
25
|
+
Provides-Extra: xacro
|
|
26
|
+
Requires-Dist: xacro; extra == "xacro"
|
|
27
|
+
Provides-Extra: mujoco
|
|
28
|
+
Requires-Dist: mujoco; extra == "mujoco"
|
|
29
|
+
Provides-Extra: full
|
|
30
|
+
Requires-Dist: xacro; extra == "full"
|
|
31
|
+
Requires-Dist: mujoco; extra == "full"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# urdf_validator
|
|
37
|
+
|
|
38
|
+
A physics-aware URDF validation tool for the ROS 2 community.
|
|
39
|
+
|
|
40
|
+
## The problem
|
|
41
|
+
|
|
42
|
+
`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.
|
|
43
|
+
|
|
44
|
+
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.
|
|
45
|
+
|
|
46
|
+
## What it checks
|
|
47
|
+
|
|
48
|
+
| Phase | What it analyses |
|
|
49
|
+
|---|---|
|
|
50
|
+
| **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 |
|
|
51
|
+
| **Statics** | Full-body centre of mass, gravity torque per actuated joint, motor effort margins (PASS / WARN / FAIL), weakest joint identification |
|
|
52
|
+
| **Stability** | Support polygon from wheel/caster contacts, COM-over-polygon containment, signed margin in mm, tip direction, COM height ratio, tipping angle |
|
|
53
|
+
| **Workspace** | Monte Carlo FK reach envelope (max / vertical / horizontal), task-specific reachability, COM stability during reach |
|
|
54
|
+
| **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 |
|
|
55
|
+
| **Deep (optional)** | MuJoCo simulation cross-validation of gravity torques and COM; `SIMULATED` confidence badge |
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install urdf-validator
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Optional extras:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install "urdf-validator[xacro]" # adds xacro preprocessing
|
|
67
|
+
pip install "urdf-validator[mujoco]" # adds MuJoCo deep-validation mode
|
|
68
|
+
pip install "urdf-validator[full]" # adds both xacro and mujoco
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
No ROS installation required.
|
|
72
|
+
|
|
73
|
+
## Quick start
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
urdf_validate my_robot.urdf
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Writes `my_robot_validation.json` alongside the URDF. Exits non-zero on any WARN or FAIL finding — directly usable as a CI gate.
|
|
80
|
+
|
|
81
|
+
## CLI reference
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
urdf_validate <urdf_file> [options]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Flag | Values | Default | Description |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| `--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). |
|
|
90
|
+
| `--joint-angles ANGLES` | `"j1=0.5,j2=1.2"` | — | Joint angles for `--pose custom` in radians/metres. |
|
|
91
|
+
| `--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. |
|
|
92
|
+
| `--height M` | float | — | Target height in metres. Required with `--task custom`. |
|
|
93
|
+
| `--output-dir DIR` | path | alongside input | Directory for the JSON validation report. |
|
|
94
|
+
| `--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`. |
|
|
95
|
+
| `--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. |
|
|
96
|
+
| `--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. |
|
|
97
|
+
| `--arm-root LINK` | link name | — | Root link of the arm chain. Bypasses the DOF-heuristic arm detection. Must be used together with `--arm-tip`. |
|
|
98
|
+
| `--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`. |
|
|
99
|
+
|
|
100
|
+
### Exit codes
|
|
101
|
+
|
|
102
|
+
| Code | Meaning |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `0` | PASS — all checks passed |
|
|
105
|
+
| `1` | WARN — no failures, at least one warning |
|
|
106
|
+
| `2` | FAIL or UNKNOWN — at least one check failed or a critical check could not run |
|
|
107
|
+
|
|
108
|
+
## Output — reference robot examples
|
|
109
|
+
|
|
110
|
+
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.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### TurtleBot3 — differential-drive mobile robot
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
╔════════════════════════════════════════════════════╗
|
|
118
|
+
║ urdf_validate — TurtleBot3.urdf ║
|
|
119
|
+
╚════════════════════════════════════════════════════╝
|
|
120
|
+
[SCHEMA] ✓ PASS (6 infos)
|
|
121
|
+
[INFO] Joint 'wheel_left_joint' (continuous) has no effort or velocity limit declared
|
|
122
|
+
[INFO] Joint 'wheel_right_joint' (continuous) has no effort or velocity limit declared
|
|
123
|
+
[INFO] Link 'base_link': mesh 'package://turtlebot3_description/meshes/bases/burger_base.stl' not found — package:// resolution requires ROS workspace to be sourced
|
|
124
|
+
[INFO] Link 'wheel_left_link': mesh 'package://turtlebot3_description/meshes/wheels/left_tire.stl' not found — package:// resolution requires ROS workspace to be sourced
|
|
125
|
+
[INFO] Link 'wheel_right_link': mesh 'package://turtlebot3_description/meshes/wheels/right_tire.stl' not found — package:// resolution requires ROS workspace to be sourced
|
|
126
|
+
[INFO] Link 'base_scan': mesh 'package://turtlebot3_description/meshes/sensors/lds.stl' not found — package:// resolution requires ROS workspace to be sourced
|
|
127
|
+
[PHYSICS] 7 links — mass: 5 exact, 2 missing · inertia: 5 exact, 2 missing
|
|
128
|
+
[STATICS] COM [-0.004, 0.000, 0.031] m height 0.031 m total mass 1.002 kg (estimated)
|
|
129
|
+
Heaviest: base_link (82.4%)
|
|
130
|
+
[STATICS] joints: PASS
|
|
131
|
+
[STABILITY] ✓ STABLE margin 4.0 mm
|
|
132
|
+
COM height ratio 0.96 — stable tips at 27.4°
|
|
133
|
+
[WORKSPACE] UNKNOWN — No arm chain detected (robot may be wheeled or legged only)
|
|
134
|
+
[OVERALL] PASS confidence: MEDIUM
|
|
135
|
+
Full report: TurtleBot3_validation.json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Exit 0.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Fetch — wheeled mobile manipulator
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
╔════════════════════════════════════════════════════╗
|
|
146
|
+
║ urdf_validate — fetch.urdf ║
|
|
147
|
+
╚════════════════════════════════════════════════════╝
|
|
148
|
+
[SCHEMA] ⚠ WARN — 42 issues
|
|
149
|
+
[WARN] Link 'r_gripper_finger_link' has non-positive-definite inertia tensor (min eigenvalue: 0.000000) — physically impossible
|
|
150
|
+
[WARN] Link 'l_gripper_finger_link' has non-positive-definite inertia tensor (min eigenvalue: 0.000000) — physically impossible
|
|
151
|
+
[INFO] (40 mesh resolution notices — package:// resolution requires ROS workspace)
|
|
152
|
+
[PHYSICS] 28 links — mass: 22 exact, 6 missing · inertia: 22 exact, 6 missing
|
|
153
|
+
[STATICS] COM [0.045, 0.001, 0.260] m height 0.260 m total mass 121.538 kg (estimated)
|
|
154
|
+
Heaviest: base_link (57.7%)
|
|
155
|
+
[STATICS] joints: PASS weakest: torso_lift_joint
|
|
156
|
+
[STABILITY] ✓ STABLE margin 43.7 mm
|
|
157
|
+
COM height ratio 0.69 — stable tips at 35.8°
|
|
158
|
+
[WORKSPACE] max reach 2.182 m vertical 2.158 m horizontal 1.165 m (estimated)
|
|
159
|
+
from base 2.182 m
|
|
160
|
+
[OVERALL] WARN confidence: MEDIUM
|
|
161
|
+
Full report: fetch_validation.json
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
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.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### PR2 — dual-arm wheeled robot (88 links)
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
╔════════════════════════════════════════════════════╗
|
|
172
|
+
║ urdf_validate — PR2.urdf ║
|
|
173
|
+
╚════════════════════════════════════════════════════╝
|
|
174
|
+
[SCHEMA] ⚠ WARN — 88 issues
|
|
175
|
+
[WARN] Link 'r_gripper_l_finger_tip_frame' has no inertial block (mass unknown) — will cause physics engine instability
|
|
176
|
+
[WARN] Link 'l_gripper_l_finger_tip_frame' has no inertial block (mass unknown) — will cause physics engine instability
|
|
177
|
+
[INFO] Joint 'torso_lift_motor_screw_joint' (continuous) has no effort or velocity limit declared
|
|
178
|
+
[INFO] Joint 'r_gripper_motor_screw_joint' (continuous) has no effort or velocity limit declared
|
|
179
|
+
[INFO] Joint 'l_gripper_motor_screw_joint' (continuous) has no effort or velocity limit declared
|
|
180
|
+
[INFO] Robot has 88 links (>50) — may be slow to simulate or validate
|
|
181
|
+
[INFO] (82 mesh resolution notices — package:// resolution requires ROS workspace)
|
|
182
|
+
[PHYSICS] 88 links — mass: 73 exact, 15 missing · inertia: 73 exact, 15 missing
|
|
183
|
+
[STATICS] COM [-0.016, 0.005, 0.477] m height 0.477 m total mass 265.732 kg (estimated)
|
|
184
|
+
Heaviest: base_link (43.7%)
|
|
185
|
+
[STATICS] joints: FAIL weakest: l_shoulder_lift_joint
|
|
186
|
+
[STABILITY] ✓ STABLE margin 208.5 mm
|
|
187
|
+
COM height ratio 1.06 — manageable tips at 25.2°
|
|
188
|
+
[WORKSPACE] max reach 1.887 m vertical 1.777 m horizontal 1.177 m (estimated)
|
|
189
|
+
from base 1.931 m
|
|
190
|
+
[OVERALL] FAIL confidence: MEDIUM
|
|
191
|
+
Full report: PR2_validation.json
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
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.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### ANYmal — legged quadruped
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
╔════════════════════════════════════════════════════╗
|
|
202
|
+
║ urdf_validate — ANYmal.urdf ║
|
|
203
|
+
╚════════════════════════════════════════════════════╝
|
|
204
|
+
[SCHEMA] ✓ PASS (17 infos)
|
|
205
|
+
[INFO] (17 mesh resolution notices — package:// resolution requires ROS workspace)
|
|
206
|
+
[PHYSICS] 22 links — mass: 17 exact, 5 missing · inertia: 17 exact, 5 missing
|
|
207
|
+
[STATICS] COM [-0.001, -0.001, -0.034] m height -0.034 m total mass 30.421 kg (estimated)
|
|
208
|
+
Heaviest: base_inertia (55.2%)
|
|
209
|
+
[STATICS] joints: PASS weakest: RF_HAA
|
|
210
|
+
[STABILITY] UNKNOWN — robot type 'quadruped' — stability only computed for wheeled robots
|
|
211
|
+
[WORKSPACE] N/A — not applicable — robot type 'quadruped' has no manipulator
|
|
212
|
+
[OVERALL] PASS confidence: MEDIUM
|
|
213
|
+
Full report: ANYmal_validation.json
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
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.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
### Spot — legged quadruped (unofficial URDF, no masses)
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
╔════════════════════════════════════════════════════╗
|
|
224
|
+
║ urdf_validate — Spot.urdf ║
|
|
225
|
+
╚════════════════════════════════════════════════════╝
|
|
226
|
+
[SCHEMA] ⚠ WARN — 37 issues
|
|
227
|
+
[WARN] Link 'fl.hip' has no inertial block (mass unknown) — will cause physics engine instability
|
|
228
|
+
[WARN] Link 'fl.uleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
229
|
+
[WARN] Link 'fl.lleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
230
|
+
[WARN] Link 'fr.hip' has no inertial block (mass unknown) — will cause physics engine instability
|
|
231
|
+
[WARN] Link 'fr.uleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
232
|
+
[WARN] Link 'fr.lleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
233
|
+
[WARN] Link 'hl.hip' has no inertial block (mass unknown) — will cause physics engine instability
|
|
234
|
+
[WARN] Link 'hl.uleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
235
|
+
[WARN] Link 'hl.lleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
236
|
+
[WARN] Link 'hr.hip' has no inertial block (mass unknown) — will cause physics engine instability
|
|
237
|
+
[WARN] Link 'hr.uleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
238
|
+
[WARN] Link 'hr.lleg' has no inertial block (mass unknown) — will cause physics engine instability
|
|
239
|
+
[INFO] Link 'fl.hip' has visual geometry (mesh) but no collision geometry — will be invisible to physics engines
|
|
240
|
+
[INFO] (11 more visual-without-collision notices + 13 mesh resolution notices)
|
|
241
|
+
[PHYSICS] 13 links — mass: 0 exact, 13 missing · inertia: 0 exact, 13 missing
|
|
242
|
+
[STATICS] COM unknown (missing)
|
|
243
|
+
[STATICS] joints: PASS
|
|
244
|
+
[STABILITY] UNKNOWN — robot type 'quadruped' — stability only computed for wheeled robots
|
|
245
|
+
[WORKSPACE] N/A — not applicable — robot type 'quadruped' has no manipulator
|
|
246
|
+
[OVERALL] WARN confidence: LOW
|
|
247
|
+
Full report: Spot_validation.json
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
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.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### Franka Panda — fixed-base arm (no masses declared)
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
╔════════════════════════════════════════════════════╗
|
|
258
|
+
║ urdf_validate — Franka_Panda.urdf ║
|
|
259
|
+
╚════════════════════════════════════════════════════╝
|
|
260
|
+
[SCHEMA] ⚠ WARN — 25 issues
|
|
261
|
+
[WARN] Link 'panda_base1' has no inertial block (mass unknown) — will cause physics engine instability
|
|
262
|
+
[WARN] Link 'panda_base_arm' has no inertial block (mass unknown) — will cause physics engine instability
|
|
263
|
+
[WARN] Link 'panda_link1' has no inertial block (mass unknown) — will cause physics engine instability
|
|
264
|
+
[WARN] Link 'panda_link2' has no inertial block (mass unknown) — will cause physics engine instability
|
|
265
|
+
[WARN] Link 'panda_link3' has no inertial block (mass unknown) — will cause physics engine instability
|
|
266
|
+
[WARN] Link 'panda_link4' has no inertial block (mass unknown) — will cause physics engine instability
|
|
267
|
+
[WARN] Link 'panda_link5' has no inertial block (mass unknown) — will cause physics engine instability
|
|
268
|
+
[WARN] Link 'panda_link6' has no inertial block (mass unknown) — will cause physics engine instability
|
|
269
|
+
[WARN] Link 'panda_link7' has no inertial block (mass unknown) — will cause physics engine instability
|
|
270
|
+
[WARN] Link 'frankie_leftfinger' has no inertial block (mass unknown) — will cause physics engine instability
|
|
271
|
+
[WARN] Link 'frankie_rightfinger' has no inertial block (mass unknown) — will cause physics engine instability
|
|
272
|
+
[INFO] (2 visual-without-collision notices + 12 mesh resolution notices)
|
|
273
|
+
[PHYSICS] 15 links — mass: 0 exact, 15 missing · inertia: 0 exact, 15 missing
|
|
274
|
+
[STATICS] COM unknown (missing)
|
|
275
|
+
[STATICS] joints: PASS
|
|
276
|
+
[STABILITY] UNKNOWN — robot type 'unknown' — stability only computed for wheeled robots
|
|
277
|
+
[WORKSPACE] max reach 1.255 m vertical 1.626 m horizontal 1.062 m (estimated)
|
|
278
|
+
from base 1.643 m
|
|
279
|
+
[OVERALL] WARN confidence: LOW
|
|
280
|
+
Full report: Franka_Panda_validation.json
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
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.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### ground_vehicle — wheeled vehicle without manipulator
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
╔════════════════════════════════════════════════════╗
|
|
291
|
+
║ urdf_validate — ground_vehicle.urdf ║
|
|
292
|
+
╚════════════════════════════════════════════════════╝
|
|
293
|
+
[SCHEMA] ✓ PASS
|
|
294
|
+
[PHYSICS] ✓ 5 links — all mass & inertia declared
|
|
295
|
+
[STATICS] COM [0.000, 0.000, -0.025] m height -0.025 m total mass 120.000 kg (estimated)
|
|
296
|
+
Heaviest: chassis (83.3%)
|
|
297
|
+
[STATICS] joints: PASS
|
|
298
|
+
j_wheel_fl req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
|
|
299
|
+
j_wheel_fr req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
|
|
300
|
+
j_wheel_rl req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
|
|
301
|
+
j_wheel_rr req 0.0 Nm declared 50.0 Nm no margin PASS — OK — torque negligible
|
|
302
|
+
[STABILITY] ✓ STABLE margin 300.0 mm
|
|
303
|
+
[WORKSPACE] N/A — not applicable — robot type 'ground_vehicle' has no manipulator
|
|
304
|
+
[WARN] User declared --robot-type=ground_vehicle, but link-name heuristic suggests wheeled
|
|
305
|
+
[OVERALL] PASS confidence: HIGH
|
|
306
|
+
Full report: ground_vehicle_validation.json
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
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.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
### aerial_drone — airborne robot (4 fixed rotors)
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
╔════════════════════════════════════════════════════╗
|
|
317
|
+
║ urdf_validate — aerial_drone.urdf ║
|
|
318
|
+
╚════════════════════════════════════════════════════╝
|
|
319
|
+
[SCHEMA] ✓ PASS
|
|
320
|
+
[PHYSICS] ✓ 5 links — all mass & inertia declared
|
|
321
|
+
[STATICS] COM [0.000, 0.000, 0.000] m height 0.000 m total mass 1.900 kg (estimated)
|
|
322
|
+
Heaviest: body (78.9%)
|
|
323
|
+
[STABILITY] N/A — not applicable — robot type 'aerial' has no ground contact
|
|
324
|
+
[WORKSPACE] N/A — not applicable — robot type 'aerial' has no manipulator
|
|
325
|
+
[WARN] User declared --robot-type=aerial, but link-name heuristic suggests unknown
|
|
326
|
+
[OVERALL] PASS confidence: HIGH
|
|
327
|
+
Full report: aerial_drone_validation.json
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
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.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## User-declared robot info
|
|
335
|
+
|
|
336
|
+
When heuristics cannot reliably classify your robot — non-English link names, non-standard wheel geometry, hexapod naming conventions — you can declare the information directly:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Legged robot with known foot contact links
|
|
340
|
+
urdf_validate my_hexapod.urdf \
|
|
341
|
+
--robot-type legged \
|
|
342
|
+
--contact-links foot_fl,foot_fr,foot_ml,foot_mr,foot_rl,foot_rr
|
|
343
|
+
|
|
344
|
+
# Robot with a non-obvious arm chain
|
|
345
|
+
urdf_validate my_robot.urdf \
|
|
346
|
+
--arm-root arm_base_link \
|
|
347
|
+
--arm-tip tool_flange
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
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.
|
|
351
|
+
|
|
352
|
+
If you omit these flags, heuristic output is used and labeled `estimated` to make clear it is an unverified inference, not a verified value.
|
|
353
|
+
|
|
354
|
+
## Capability profiles
|
|
355
|
+
|
|
356
|
+
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:
|
|
357
|
+
|
|
358
|
+
| Robot type | Stability check | Workspace check |
|
|
359
|
+
|---|---|---|
|
|
360
|
+
| `wheeled` | Runs (wheel-contact heuristic) | Runs if arm chain detected |
|
|
361
|
+
| `ground_vehicle` | Runs (wheel-contact heuristic) | N/A — ground vehicles have no manipulator |
|
|
362
|
+
| `arm_only` | N/A — fixed-base arm has no ground contact | Runs |
|
|
363
|
+
| `legged` / `quadruped` | UNKNOWN — foot contacts must be declared via `--contact-links` | N/A — legged robots have no manipulator |
|
|
364
|
+
| `humanoid` | UNKNOWN — foot-contact algorithm not yet implemented | Runs if arm chain detected |
|
|
365
|
+
| `aerial` | N/A — airborne robot has no ground contact | N/A — aerial vehicles have no manipulator |
|
|
366
|
+
| `unknown` | UNKNOWN — cannot determine contact geometry | Runs |
|
|
367
|
+
|
|
368
|
+
**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.
|
|
369
|
+
|
|
370
|
+
Use `--robot-type` to force the category. Without it, the link-name heuristic runs and the result is labeled `estimated`.
|
|
371
|
+
|
|
372
|
+
## Payload-augmented statics
|
|
373
|
+
|
|
374
|
+
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:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
urdf_validate fetch.urdf --payload-mass 5.0
|
|
378
|
+
urdf_validate fetch.urdf --payload-mass 5.0 --payload-link gripper_link
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
`--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.
|
|
382
|
+
|
|
383
|
+
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×.
|
|
384
|
+
|
|
385
|
+
## CI integration
|
|
386
|
+
|
|
387
|
+
### GitHub Actions
|
|
388
|
+
|
|
389
|
+
```yaml
|
|
390
|
+
name: URDF validation
|
|
391
|
+
|
|
392
|
+
on:
|
|
393
|
+
push:
|
|
394
|
+
paths: ['**.urdf', '**.xacro']
|
|
395
|
+
pull_request:
|
|
396
|
+
paths: ['**.urdf', '**.xacro']
|
|
397
|
+
|
|
398
|
+
jobs:
|
|
399
|
+
validate:
|
|
400
|
+
runs-on: ubuntu-latest
|
|
401
|
+
steps:
|
|
402
|
+
- uses: actions/checkout@v4
|
|
403
|
+
|
|
404
|
+
- uses: actions/setup-python@v5
|
|
405
|
+
with:
|
|
406
|
+
python-version: '3.11'
|
|
407
|
+
|
|
408
|
+
- name: Install urdf-validator
|
|
409
|
+
run: pip install "urdf-validator[full]"
|
|
410
|
+
|
|
411
|
+
- name: Validate URDF
|
|
412
|
+
run: urdf_validate robot/my_robot.urdf --output-dir /tmp/reports
|
|
413
|
+
|
|
414
|
+
- name: Upload validation report
|
|
415
|
+
if: always()
|
|
416
|
+
uses: actions/upload-artifact@v4
|
|
417
|
+
with:
|
|
418
|
+
name: urdf-validation-report
|
|
419
|
+
path: /tmp/reports/*.json
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
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.
|
|
423
|
+
|
|
424
|
+
### Validating multiple URDFs
|
|
425
|
+
|
|
426
|
+
```yaml
|
|
427
|
+
- name: Validate all URDFs
|
|
428
|
+
run: |
|
|
429
|
+
find . -name '*.urdf' | while read f; do
|
|
430
|
+
echo "=== $f ==="
|
|
431
|
+
urdf_validate "$f" || exit 1
|
|
432
|
+
done
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Allowing warnings but blocking failures
|
|
436
|
+
|
|
437
|
+
```yaml
|
|
438
|
+
- name: Validate URDF (block on FAIL only)
|
|
439
|
+
run: |
|
|
440
|
+
urdf_validate robot/my_robot.urdf
|
|
441
|
+
code=$?
|
|
442
|
+
if [ $code -eq 2 ]; then exit 1; fi
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Exit code 1 (WARN) passes; only exit code 2 (FAIL / UNKNOWN) fails the job.
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Output sections
|
|
450
|
+
|
|
451
|
+
### `[SCHEMA]`
|
|
452
|
+
|
|
453
|
+
Structural checks. Severities:
|
|
454
|
+
|
|
455
|
+
| Severity | Example |
|
|
456
|
+
|---|---|
|
|
457
|
+
| `CRITICAL` | Joint references a link that does not exist |
|
|
458
|
+
| `CRITICAL` | Kinematic loop detected |
|
|
459
|
+
| `WARN` | Non-positive-definite inertia tensor |
|
|
460
|
+
| `WARN` | Missing `<inertial>` block on a non-fixed link |
|
|
461
|
+
| `WARN` | Inverted joint limits (lower > upper) |
|
|
462
|
+
| `INFO` | Missing effort or velocity limit |
|
|
463
|
+
| `INFO` | Mesh file not found (`package://` paths require a sourced ROS workspace) |
|
|
464
|
+
| `INFO` | Robot has more than 50 links |
|
|
465
|
+
|
|
466
|
+
### `[STATICS]`
|
|
467
|
+
|
|
468
|
+
Computed at the declared `--pose` (default: zero pose).
|
|
469
|
+
|
|
470
|
+
- **COM** — full-body centre of mass `[x, y, z]` in metres, total mass in kg.
|
|
471
|
+
- **Per joint** — gravity torque required (`req`), declared effort limit (`declared`), margin = `declared / req`. `PASS` ≥ 1.5×, `WARN` 1.0–1.5×, `FAIL` < 1.0×.
|
|
472
|
+
|
|
473
|
+
### `[STABILITY]`
|
|
474
|
+
|
|
475
|
+
Available for wheeled robots by default. Contact point detection runs three passes in priority order:
|
|
476
|
+
|
|
477
|
+
1. Links named `*wheel*`
|
|
478
|
+
2. Cylindrical links with a wheel-like radius-to-length ratio (r/L > 0.3)
|
|
479
|
+
3. Links named `*caster*` with cylinder or sphere geometry
|
|
480
|
+
|
|
481
|
+
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.
|
|
482
|
+
|
|
483
|
+
Reports signed margin in mm (positive = stable, negative = tipping), tip direction, COM height ratio, and tipping angle.
|
|
484
|
+
|
|
485
|
+
| `com_height_ratio_class` | Ratio | Meaning |
|
|
486
|
+
|---|---|---|
|
|
487
|
+
| `very_stable` | < 0.5 | Passive tip resistance |
|
|
488
|
+
| `stable` | 0.5 – 1.0 | Normal for wheeled mobile robots |
|
|
489
|
+
| `manageable` | 1.0 – 2.0 | Typical humanoid standing |
|
|
490
|
+
| `requires_active_balancing` | 2.0 – 3.0 | Needs active balance control |
|
|
491
|
+
| `will_fall` | > 3.0 | Will fall without fast active control |
|
|
492
|
+
|
|
493
|
+
### `[WORKSPACE]`
|
|
494
|
+
|
|
495
|
+
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).
|
|
496
|
+
|
|
497
|
+
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.
|
|
498
|
+
|
|
499
|
+
### `[OVERALL]`
|
|
500
|
+
|
|
501
|
+
Worst status across all sections. Confidence level:
|
|
502
|
+
|
|
503
|
+
| Level | Condition |
|
|
504
|
+
|---|---|
|
|
505
|
+
| `HIGH` | All link masses and inertia tensors declared |
|
|
506
|
+
| `MEDIUM` | ≥ 50% of link masses declared |
|
|
507
|
+
| `LOW` | Sparse physics data |
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Confidence labels
|
|
512
|
+
|
|
513
|
+
Every physics estimate carries an explicit label:
|
|
514
|
+
|
|
515
|
+
| Label | Meaning |
|
|
516
|
+
|---|---|
|
|
517
|
+
| `exact` | Value read directly from a declared URDF field, or supplied via a user override flag |
|
|
518
|
+
| `estimated` | Derived from declared masses and geometry via analytical formula, or from a heuristic that ran without a user declaration to cross-check against |
|
|
519
|
+
| `guessed` | Heuristic estimate (e.g. mesh geometry — no explicit dims available) |
|
|
520
|
+
| `missing` | No data available |
|
|
521
|
+
| `simulated` | Cross-validated against MuJoCo simulation (`--deep` mode) |
|
|
522
|
+
|
|
523
|
+
The tool never presents an estimated value as ground truth.
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## JSON output
|
|
528
|
+
|
|
529
|
+
Every run writes `<robot>_validation.json` containing the full `ValidationReport`. The schema is stable across minor versions and documented in [`docs/json_schema.md`](docs/json_schema.md).
|
|
530
|
+
|
|
531
|
+
```json
|
|
532
|
+
{
|
|
533
|
+
"overall_status": "WARN",
|
|
534
|
+
"confidence_level": "MEDIUM",
|
|
535
|
+
"robot_type": "wheeled",
|
|
536
|
+
"robot_type_confidence": "exact",
|
|
537
|
+
"statics": {
|
|
538
|
+
"full_body_com": [0.045, 0.001, 0.260],
|
|
539
|
+
"total_mass": 121.538,
|
|
540
|
+
"com_height_above_ground": 0.260,
|
|
541
|
+
"weakest_joint_name": "torso_lift_joint",
|
|
542
|
+
"status": "PASS"
|
|
543
|
+
},
|
|
544
|
+
"stability": {
|
|
545
|
+
"stable": true,
|
|
546
|
+
"margin_mm": 43.7,
|
|
547
|
+
"com_height_ratio": 0.69,
|
|
548
|
+
"com_height_ratio_class": "stable",
|
|
549
|
+
"tipping_angle_deg": 35.8,
|
|
550
|
+
"contact_confidence": "estimated",
|
|
551
|
+
"status": "PASS"
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
`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.
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Task-query API
|
|
561
|
+
|
|
562
|
+
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:
|
|
563
|
+
|
|
564
|
+
```python
|
|
565
|
+
from urdf_validator_main.api.task_runner import run_pick_task, run_pick_sweep
|
|
566
|
+
from urdf_validator_main.api.task_schema import TaskQueryRequest
|
|
567
|
+
|
|
568
|
+
req = TaskQueryRequest(
|
|
569
|
+
urdf_path="fetch.urdf",
|
|
570
|
+
task_type="pick",
|
|
571
|
+
target_position=[0.5, 0.0, 0.8], # [x, y, z] metres, robot frame
|
|
572
|
+
target_orientation="top_down", # or "side", [r,p,y], [qw,qx,qy,qz]
|
|
573
|
+
object_mass_kg=0.5,
|
|
574
|
+
terrain_angle_deg=0.0,
|
|
575
|
+
)
|
|
576
|
+
resp = run_pick_task(req)
|
|
577
|
+
print(resp.overall_status) # "PASS" | "FAIL" | "UNKNOWN"
|
|
578
|
+
for check in resp.sub_checks:
|
|
579
|
+
print(check.name, check.status, check.reason)
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Sub-checks returned per request:
|
|
583
|
+
|
|
584
|
+
| Sub-check | Passes when |
|
|
585
|
+
|---|---|
|
|
586
|
+
| `reach` | `reach_from_base >= dist(target_position)` |
|
|
587
|
+
| `reach_orientation` | ≥ 5% of workspace samples satisfy `target_orientation` within tolerance |
|
|
588
|
+
| `payload_strength` | all joint effort margins ≥ 1.0× with `object_mass_kg` included |
|
|
589
|
+
| `stability_during_reach` | COM XY shift at maximum reach stays within the stability polygon margin |
|
|
590
|
+
| `self_collision` | ≥ 95% of sampled arm poses are collision-free |
|
|
591
|
+
|
|
592
|
+
To sweep over a list of parameter variations (different heights, payloads, target positions):
|
|
593
|
+
|
|
594
|
+
```python
|
|
595
|
+
responses = run_pick_sweep([req1, req2, req3])
|
|
596
|
+
# Returns List[TaskQueryResponse], order preserved, failures isolated
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Full schema: [`urdf_validator_main/api/task_schema.py`](urdf_validator_main/api/task_schema.py) and [`urdf_validator_main/api/task_runner.py`](urdf_validator_main/api/task_runner.py). Documented in [`docs/json_schema.md`](docs/json_schema.md).
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## Status
|
|
604
|
+
|
|
605
|
+
| Version | Month | Status | Delivered |
|
|
606
|
+
|---|---|---|---|
|
|
607
|
+
| v0.1 | 1 | **Complete** | Parser, schema checks, physics confidence labels, no-crash on all 6 reference URDFs |
|
|
608
|
+
| v0.2 | 2 | **Complete** | Chain walker, full-body COM, gravity torques, MuJoCo ground-truth validation (0% error) |
|
|
609
|
+
| v0.3 | 3 | **Complete** | Robot type detection, support polygon, COM projection stability check |
|
|
610
|
+
| v0.4 | 4 | **Complete** | Workspace FK, task reachability, full report pipeline, JSON export |
|
|
611
|
+
| v0.5 | 5 | **Complete** | Pose flags, geometry contact detection, COM height ratio, `--deep` MuJoCo wiring, JSON schema docs, performance (PR2: 12.5s → 4.1s) |
|
|
612
|
+
| 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 |
|
|
613
|
+
| v0.7 | 7 | **Complete** | Capability profiles (N/A vs UNKNOWN); `--payload-mass` payload-augmented statics |
|
|
614
|
+
| v0.8 | 8 | **Complete** | Orientation-aware reachability (position + orientation, not position alone) |
|
|
615
|
+
| v0.9 | 9 | **Complete** | Real-pose COM stability during reach; self-collision/clearance checks |
|
|
616
|
+
| v0.10 | 10 | **Complete** | Structured task-query API for AI agents and programmatic callers |
|
|
617
|
+
| v0.11 | 11 | **Complete** | Hardening — full regression across all 6 reference robots + capability-profile URDFs |
|
|
618
|
+
| v1.0 | 12 | **Complete** | Public release — ROS Discourse announcement, pip package |
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
## Dependencies
|
|
623
|
+
|
|
624
|
+
**Core** (`pip install urdf-validator`): `urdf_parser_py`, `numpy`, `shapely`, `ikpy`
|
|
625
|
+
|
|
626
|
+
**Xacro** (`pip install "urdf-validator[xacro]"`): adds `xacro` (`.xacro` / `.xacro` preprocessing)
|
|
627
|
+
|
|
628
|
+
**MuJoCo** (`pip install "urdf-validator[mujoco]"`): adds `mujoco` (`--deep` simulation mode)
|
|
629
|
+
|
|
630
|
+
**Full** (`pip install "urdf-validator[full]"`): both `xacro` and `mujoco`
|
|
631
|
+
|
|
632
|
+
No ROS installation required.
|
|
633
|
+
|
|
634
|
+
## Known limitations
|
|
635
|
+
|
|
636
|
+
| Limitation | Status |
|
|
637
|
+
|---|---|
|
|
638
|
+
| Humanoid foot-contact stability | `PENDING` — stability is always `UNKNOWN` for `humanoid` robots. Supply foot positions with `--contact-links` to get a real margin. |
|
|
639
|
+
| Unknown-type contact fallback | `PENDING` — for `--robot-type unknown`, stability is `UNKNOWN`. Lowest-link fallback is not yet implemented. |
|
|
640
|
+
| Mimic joints | `OPEN` — mimic followers (common in parallel grippers) are treated as fixed. Joint angles and torques for mimic joints are not computed. |
|
|
641
|
+
| SDF format | `DEFERRED` — only URDF (`.urdf`, `.xacro`) is supported. |
|
|
642
|
+
| `--pose home` | Falls back silently to zero pose. URDF has no standard home-configuration field (that lives in SRDF, outside this tool's scope). |
|
|
643
|
+
| 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. |
|
|
644
|
+
| Payload capacity estimate | `PENDING` — `payload_capacity_kg` field exists in the report model but is not populated. |
|
|
645
|
+
| `--deep` drop test | `PENDING` — the 2-second MuJoCo drop test is not implemented. Only the static cross-validation pass runs under `--deep`. |
|
|
646
|
+
|
|
647
|
+
## License
|
|
648
|
+
|
|
649
|
+
MIT
|