diff options
| author | Sébastien Crozet <developer@crozet.re> | 2024-05-25 16:39:39 +0200 |
|---|---|---|
| committer | Sébastien Crozet <sebastien@crozet.re> | 2024-06-09 12:09:58 +0200 |
| commit | d6a76833d9ecf44607c37c8079600b3835e6962d (patch) | |
| tree | 3a00614634ab9094a136e0cb58e5b455ebde21d9 | |
| parent | d687fe97b10ec427a25e2b6579de0a271855fce5 (diff) | |
| download | rapier-d6a76833d9ecf44607c37c8079600b3835e6962d.tar.gz rapier-d6a76833d9ecf44607c37c8079600b3835e6962d.tar.bz2 rapier-d6a76833d9ecf44607c37c8079600b3835e6962d.zip | |
feat: start implementation of rapier_urdf
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | crates/rapier-urdf/Cargo.toml | 11 | ||||
| -rw-r--r-- | crates/rapier-urdf/src/lib.rs | 114 |
3 files changed, 126 insertions, 1 deletions
@@ -1,6 +1,6 @@ [workspace] members = ["crates/rapier2d", "crates/rapier2d-f64", "crates/rapier_testbed2d", "crates/rapier_testbed2d-f64", "examples2d", "benchmarks2d", - "crates/rapier3d", "crates/rapier3d-f64", "crates/rapier_testbed3d", "crates/rapier_testbed3d-f64", "examples3d", "examples3d-f64", "benchmarks3d"] + "crates/rapier3d", "crates/rapier3d-f64", "crates/rapier_testbed3d", "crates/rapier_testbed3d-f64", "examples3d", "examples3d-f64", "benchmarks3d", "crates/rapier-urdf"] resolver = "2" [patch.crates-io] diff --git a/crates/rapier-urdf/Cargo.toml b/crates/rapier-urdf/Cargo.toml new file mode 100644 index 0000000..a3d9d8e --- /dev/null +++ b/crates/rapier-urdf/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rapier-urdf" +version = "0.1.0" +edition = "2021" +description = "Load urdf files into rapier" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +urdf-rs = "0.8" +rapier3d = { version = "0.19", path = "../rapier3d" }
\ No newline at end of file diff --git a/crates/rapier-urdf/src/lib.rs b/crates/rapier-urdf/src/lib.rs new file mode 100644 index 0000000..fc5562f --- /dev/null +++ b/crates/rapier-urdf/src/lib.rs @@ -0,0 +1,114 @@ +use rapier3d::{ + dynamics::{GenericJoint, RigidBody}, + geometry::{Collider, ColliderBuilder, SharedShape}, + math::{Isometry, Point, Vector}, + na, +}; +use std::path::Path; +use urdf_rs::{Collision, Geometry, Inertial, Pose, Robot, UrdfError}; + +pub type LinkId = usize; + +/// An urdf link loaded as a rapier [`RigidBody`] and its [`Collider`]s. +#[derive(Clone)] +pub struct RapierLink { + pub body: RigidBody, + pub colliders: Vec<Collider>, +} + +/// An urdf joint loaded as a rapier [`GenericJoint`]. +#[derive(Clone)] +pub struct RapierJoint { + /// The rapier version for the corresponding urdf joint. + pub joint: GenericJoint, + /// Index of the rigid-body (from the [`RapierRobot`] array) at the first + /// endpoint of this joint. + pub link1: LinkId, + /// Index of the rigid-body (from the [`RapierRobot`] array) at the second + /// endpoint of this joint. + pub link2: LinkId, +} + +/// A robot represented as a set of rapier rigid-bodies, colliders, and joints. +#[derive(Clone)] +pub struct RapierRobot { + /// The bodies and colliders loaded from the urdf file. + /// + /// This vector matches the order of the loaded [`Robot::links`]. + pub links: Vec<RapierLink>, + /// The joints loaded from the urdf file. + /// + /// This vector matches the order of the loaded [`Robot::joints`]. + pub joints: Vec<RapierLink>, +} + +impl RapierRobot { + pub fn from_file(path: impl AsRef<Path>) -> urdf_rs::Result<(Self, Robot)> { + let robot = urdf_rs::read_from_string( + path.as_ref() + .to_str() + .ok_or_else(|| UrdfError::from("file path contains unsupported characters"))?, + )?; + Ok((Self::from_robot(&robot), robot)) + } + + pub fn from_str(str: &str) -> urdf_rs::Result<(Self, Robot)> { + let robot = urdf_rs::read_from_string(str)?; + Ok((Self::from_robot(&robot), robot)) + } + + pub fn from_robot(robot: &Robot) -> Self { + let links: Vec<_> = robot + .links + .iter() + .map(|link| { + let colliders: Vec<_> = link + .collision + .iter() + .map(|co| urdf_to_collider(co)) + .collect(); + let body = urdf_to_rigid_body(&link.inertial); + RapierLink { body, colliders } + }) + .collect(); + todo!() + } +} + +fn urdf_to_rigid_body(inertial: &Inertial) -> RigidBody { + RigidBodyBuilder::dynamic().mass_props(); +} + +fn urdf_to_collider(co: &Collision) -> Collider { + let mut builder = match &co.geometry { + Geometry::Box { size } => ColliderBuilder::cuboid( + size[0] as f32 / 2.0, + size[1] as f32 / 2.0, + size[2] as f32 / 2.0, + ), + Geometry::Cylinder { radius, length } => { + ColliderBuilder::cylinder(*length as f32 / 2.0, *radius as f32) + } + Geometry::Capsule { radius, length } => { + ColliderBuilder::capsule_y(*length as f32 / 2.0, *radius as f32) + } + Geometry::Sphere { radius } => ColliderBuilder::ball(*radius as f32), + Geometry::Mesh { filename, scale } => todo!(), + }; + + builder + .position(pose_to_isometry(&co.origin)) + .density(0.0) + .build() +} + +fn pose_to_isometry(pose: &Pose) -> Isometry<f32> { + Isometry::from_parts( + Point::new(pose.xyz[0] as f32, pose.xyz[1] as f32, pose.xyz[2] as f32).into(), + na::UnitQuaternion::from_euler_angles( + pose.rpy[0] as f32, + pose.rpy[1] as f32, + pose.rpy[2] as f32, + ), + ) +} |
