#[cfg(not(feature = "urdf"))]
fn main() {
eprintln!("This example requires the `urdf` feature.");
eprintln!("Run with: cargo run --example urdf_robot --features urdf");
}
#[cfg(feature = "urdf")]
fn main() {
use featherstone::prelude::*;
use featherstone::urdf_convert::articulated_body_from_urdf;
let urdf_xml = r#"
<robot name="two_link_arm">
<link name="base_link">
<inertial>
<mass value="5.0"/>
<inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
</inertial>
</link>
<link name="upper_arm">
<inertial>
<origin xyz="0.15 0 0"/>
<mass value="1.0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
</link>
<link name="forearm">
<inertial>
<origin xyz="0.1 0 0"/>
<mass value="0.5"/>
<inertia ixx="0.005" ixy="0" ixz="0" iyy="0.005" iyz="0" izz="0.005"/>
</inertial>
</link>
<joint name="shoulder" type="revolute">
<parent link="base_link"/>
<child link="upper_arm"/>
<origin xyz="0 0 0.1"/>
<axis xyz="0 0 1"/>
<limit lower="-1.57" upper="1.57" effort="100" velocity="5"/>
</joint>
<joint name="elbow" type="revolute">
<parent link="upper_arm"/>
<child link="forearm"/>
<origin xyz="0.3 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="50" velocity="10"/>
</joint>
</robot>
"#;
let robot: urdf_rs::Robot = urdf_rs::read_from_string(urdf_xml).expect("Failed to parse URDF");
let conversion = articulated_body_from_urdf(&robot).expect("Failed to convert URDF");
let mut body = conversion.body;
println!("Robot: {}", robot.name);
println!("Bodies: {}, DOF: {}", body.body_count(), body.dof_count());
for (i, name) in conversion.link_names.iter().enumerate() {
let mass = body.bodies[i].inertia.mass;
println!(" [{i}] {name} (mass={mass:.2} kg)");
}
println!();
body.set_joint_q(1, &[std::f32::consts::FRAC_PI_4]);
body.set_gravity(nalgebra::Vector3::new(0.0, -9.81, 0.0));
let dt = 0.001;
let config = IntegratorConfig {
method: IntegrationMethod::SemiImplicitEuler,
dt,
..Default::default()
};
let steps_per_print = 100;
let total_prints = 10;
println!(
"{:>8} {:>12} {:>12} {:>10} {:>10}",
"time(s)", "shoulder(deg)", "elbow(deg)", "qd1", "qd2"
);
println!("{}", "-".repeat(62));
print_state(0.0, &body);
for i in 1..=total_prints {
for _ in 0..steps_per_print {
step(&mut body, &config);
}
let t = i as f32 * steps_per_print as f32 * dt;
print_state(t, &body);
}
}
#[cfg(feature = "urdf")]
fn print_state(t: f32, body: &featherstone::body::ArticulatedBody) {
let q1_deg = body.q[body.bodies[1].q_index].to_degrees();
let q2_deg = body.q[body.bodies[2].q_index].to_degrees();
let qd1 = body.qd[body.bodies[1].v_index];
let qd2 = body.qd[body.bodies[2].v_index];
println!(
"{:>8.3} {:>12.3} {:>12.3} {:>10.4} {:>10.4}",
t, q1_deg, q2_deg, qd1, qd2
);
}