# URDF Loading
featherstone can load robots from [URDF](http://wiki.ros.org/urdf) files, the standard robot description format.
## Enable the feature
URDF support is enabled by default. To disable:
```toml
[dependencies]
featherstone = { version = "0.1", default-features = false }
```
## Loading a URDF
```rust
use featherstone::urdf_convert::articulated_body_from_urdf;
let urdf_xml = std::fs::read_to_string("robot.urdf").unwrap();
let robot: urdf_rs::Robot = urdf_rs::read_from_string(&urdf_xml).unwrap();
let conversion = articulated_body_from_urdf(&robot)?;
let mut body = conversion.body; // ArticulatedBody ready for simulation
let limits = conversion.limits; // Joint limits per body index
let link_names = conversion.link_names; // Body index → URDF link name
let joint_names = conversion.joint_names; // Body index → URDF joint name
body.set_gravity(nalgebra::Vector3::new(0.0, -9.81, 0.0));
```
## What gets converted
| `<link>` | `BodyDef` in `ArticulatedBody` |
| `<joint type="revolute">` | `GenJoint::Revolute { axis }` |
| `<joint type="prismatic">` | `GenJoint::Prismatic { axis }` |
| `<joint type="fixed">` | `GenJoint::Fixed` |
| `<joint type="floating">` | `GenJoint::Floating` |
| `<joint type="planar">` | `GenJoint::Planar { normal }` |
| `<joint type="continuous">` | `GenJoint::Revolute { axis }` (no limits) |
| `<inertial>` | `SpatialInertia` (mass + COM + inertia tensor) |
| `<origin>` | `SpatialTransform` (joint frame) |
| `<limit>` | `JointLimits` (position, velocity, effort) |
| `<axis>` | Joint axis vector (normalized) |
## Inertia handling
URDF specifies inertia at the link's inertial frame (which may have a rotation offset from the link frame). featherstone correctly handles:
- COM offset from link frame origin
- Rotated inertia tensors (via RPY rotation in `<inertial><origin rpy="...">`)
- Zero-mass links (treated as massless)
## Error handling
```rust
match articulated_body_from_urdf(&robot) {
Ok(conversion) => { /* use conversion.body */ }
Err(featherstone::error::Error::EmptyUrdf) => { /* no links */ }
Err(featherstone::error::Error::MissingLink { joint, link }) => {
eprintln!("Joint '{joint}' references missing link '{link}'");
}
Err(e) => { eprintln!("URDF error: {e}"); }
}
```
## Applying joint limits
```rust
let config = IntegratorConfig {
dt: 0.001,
joint_limits: (0..body.body_count())
.map(|i| conversion.limits.get(&i).cloned())
.collect(),
..Default::default()
};
```