Metadata-Version: 2.4
Name: fieldpilot-urdf
Version: 0.1.0
Summary: Import any ROS robot from a URL and run FK/IK/collision/validation in pure Python — no ROS install, no build.
Project-URL: Homepage, https://github.com/DuQuatre/fieldpilot-urdf
Project-URL: FieldPilot SaaS, https://fieldpilot.example
Author: FieldPilot
License-Expression: AGPL-3.0-only
License-File: LICENSE
Keywords: collision,forward-kinematics,inverse-kinematics,kinematics,robotics,ros,urdf
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Requires-Dist: networkx>=3.4
Requires-Dist: numpy>=1.24
Requires-Dist: pydantic>=2.10
Requires-Dist: requests>=2.31
Requires-Dist: scipy>=1.11
Requires-Dist: xacro>=2.1
Provides-Extra: all
Requires-Dist: graphviz>=0.20; extra == 'all'
Requires-Dist: matplotlib>=3.8; extra == 'all'
Requires-Dist: trimesh>=4.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: graphviz>=0.20; extra == 'dev'
Requires-Dist: matplotlib>=3.8; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: trimesh>=4.0; extra == 'dev'
Provides-Extra: mesh
Requires-Dist: trimesh>=4.0; extra == 'mesh'
Provides-Extra: viz
Requires-Dist: graphviz>=0.20; extra == 'viz'
Requires-Dist: matplotlib>=3.8; extra == 'viz'
Description-Content-Type: text/markdown

# fieldpilot-urdf

[![CI](https://github.com/DuQuatre/fieldpilot-urdf/actions/workflows/ci.yml/badge.svg)](https://github.com/DuQuatre/fieldpilot-urdf/actions/workflows/ci.yml)
[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)

> Import any ROS robot from a URL and run **FK / IK / collision / validation /
> repair** in pure Python. No ROS install, no build.

`fieldpilot-urdf` is the **open core** of [FieldPilot](https://github.com/DuQuatre)'s
robotics toolkit — small, self-contained, pure-Python. Point it at a robot on
GitHub and get a working kinematic model in three lines.

> **Status: `0.1.0`, staged for first release.** 14 open modules + 144 passing
> tests; release tooling ready (see [`RELEASING.md`](RELEASING.md)). Until the
> tag is pushed and it lands on PyPI, install from source (`pip install -e .`).

## Install

```bash
pip install fieldpilot-urdf                # core (parse, FK, IK, validation)
pip install "fieldpilot-urdf[mesh]"        # + mesh-aware self-collision (trimesh)
pip install "fieldpilot-urdf[viz]"         # + kinematic-tree / 3D-pose renderers
pip install "fieldpilot-urdf[all]"         # everything
```

## Import any ROS robot in 3 lines

```python
from fieldpilot_urdf import import_urdf, run_all, summary

# Point at any ROS robot on GitHub — xacro, $(find), and <xacro:include> expand
robot, _ = import_urdf(
    "https://raw.githubusercontent.com/ros-industrial/universal_robot/melodic-devel/"
    "ur_description/urdf/ur5.urdf.xacro"
)

print(robot.name, len(robot.links), "links", len(robot.joints), "joints")
print(summary(run_all(robot)))   # validate: {'total': 0, 'error': 0, ...}
```

Then do something real:

```python
from fieldpilot_urdf import forward_kinematics, solve_ik, detect_self_collisions

poses = forward_kinematics(robot)                       # {link: 4x4 world transform}
ik = solve_ik(robot, "tool0", target_xyz=(0.4, 0.1, 0.5))
print(ik.converged, ik.position_error)                  # numerical IK, honours limits
print(detect_self_collisions(robot))                    # [(link_a, link_b), ...]
```

### Validate & auto-repair

```python
from fieldpilot_urdf import from_file, run_all, summary, repair

robot = from_file("maybe_broken.urdf")
findings = run_all(robot)                 # 8 lint rules (R001–R008)
print(summary(findings))                  # {'total': 3, 'error': 1, 'warning': 2, ...}

fixed, patches, unfixable = repair(robot)  # deterministic fixes for the repairable rules
print([p.code for p in patches])           # e.g. ['R003', 'R005']
print("left for a human:", unfixable)      # rule codes that can't be auto-fixed
print(summary(run_all(fixed)))             # fewer (often zero) findings
```

### Render (needs the `[viz]` extra)

```python
from fieldpilot_urdf.viz import render_kinematic_tree, render_pose_3d

open("tree.png", "wb").write(render_kinematic_tree(robot))      # graphviz
open("pose.png", "wb").write(render_pose_3d(robot, fmt="png"))  # matplotlib
```

### Symbolic fault diagnosis

```python
from fieldpilot_urdf import diagnose, Symptom, Hypothesis

# "tool can't reach this pose" — is a dead shoulder motor the cause?
report = diagnose(
    robot,
    Symptom(kind="cant_reach", target_link="tool0", target_xyz=(0.4, 0.1, 0.5)),
    [Hypothesis(suspect_joint="shoulder_pan_joint", fault_mode="motor_dead")],
)
print(report.verdict, "—", report.summary)   # CONFIRMED / REFUTED / INCONCLUSIVE
```

*(The natural-language front-end that generates hypotheses from a free-text
symptom via an LLM is part of [FieldPilot](https://github.com/DuQuatre) SaaS.)*

## What you can do

| Capability | API |
|---|---|
| Parse URDF ⇄ model | `from_xml`, `from_file`, `to_xml` |
| Import a robot from a URL (xacro/includes/meshes) | `import_urdf` |
| Forward kinematics | `forward_kinematics` |
| Inverse kinematics (numerical, limit-aware) | `solve_ik` |
| Self-collision (AABB + mesh) | `detect_self_collisions` |
| Workspace / trajectory sampling | `sample_workspace`, `check_trajectory` |
| 8 lint rules (R001–R008) | `run_all`, `summary` |
| Deterministic auto-repair | `repair` |
| Two-tier symbolic fault diagnosis | `diagnose` |
| Render kinematic tree / 3D pose | `render_kinematic_tree`, `render_pose_3d` |
| Local robot registry | `save_robot`, `load_robot`, `list_robots` |

## How this compares

The Python URDF ecosystem already has good *parsers*. `fieldpilot-urdf` is not
trying to replace them — it sits one layer up, as an **analysis** toolkit.

- **[`urchin`](https://github.com/fishbotics/urchin)** is the maintained fork of
  the classic `urdfpy` (unmaintained since 2020, won't install on Python 3.10+).
  Reach for it if you want the original `urdfpy` API and mesh-heavy
  visualization on a modern Python.
- **[`yourdfpy`](https://github.com/clemense/yourdfpy)** is the most robust
  *loader* of real-world URDFs and ships an excellent visualization CLI. Reach
  for it if your priority is parsing messy URDFs found in the wild.

Reach for **`fieldpilot-urdf`** when parsing is the *start*, not the goal — when
you also want to **solve IK** (numerical, joint-limit-aware), **import a robot
straight from a URL** (`$(find)` / `<xacro:include>` / xacro expansion, with
SSRF defenses), **lint** a URDF (8 rules, R001–R008) and **deterministically
auto-repair** the fixable ones, and run **symbolic fault diagnosis** ("is a dead
shoulder motor why the tool can't reach?"). The core install stays light —
`pydantic` + `numpy` + `scipy` + `networkx` — with mesh/viz as optional extras,
so you never pull `pyrender` or `pycollada` unless you ask for them.

> Need to *load* a difficult URDF more than analyze it? `yourdfpy` is probably
> the better fit — and `fieldpilot-urdf` happily consumes anything it can export.

## ⭐ Want more?

The open toolkit gives you the robotics. **[FieldPilot](https://github.com/DuQuatre)**
(the hosted SaaS) adds the parts you can't easily self-host:

- a **natural-language fault-diagnosis** front-end (describe a symptom → ranked hypotheses),
- a **13-tool LLM chat** over your robot,
- a **spare-parts BOM** with pricing, and
- **multi-tenant hosting**, Telegram bots, and the agro-food field-service pipeline.

→ **Star this repo** and check out FieldPilot SaaS.

## Security

`import_urdf` fetches a user-supplied URL, so it ships SSRF defences (HTTPS-only,
host allowlist, 5 MB cap, timeout, redirect re-validation). See
[`SECURITY.md`](SECURITY.md) for how to configure the allowlist and report issues.

## License

**AGPL-3.0-only.** Free to self-host, modify, and use; network use obliges source
disclosure. A **commercial license** is available for closed/embedded use — see
FieldPilot.
