use nalgebra::{Isometry3, Matrix3, Translation3, Unit, UnitQuaternion, Vector3};
use crate::{Error, Frame, Result, Wrench};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum JointType {
Revolute,
Prismatic,
Fixed,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Link {
name: String,
mass: f64,
center_of_mass: Vector3<f64>,
inertia: Matrix3<f64>,
}
impl Link {
pub(crate) fn new(
name: impl Into<String>,
mass: f64,
center_of_mass: Vector3<f64>,
inertia: Matrix3<f64>,
) -> Self {
Self {
name: name.into(),
mass,
center_of_mass,
inertia,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub const fn mass(&self) -> f64 {
self.mass
}
pub const fn center_of_mass(&self) -> &Vector3<f64> {
&self.center_of_mass
}
pub const fn inertia(&self) -> &Matrix3<f64> {
&self.inertia
}
}
#[derive(Clone, Debug)]
pub struct Joint {
name: String,
joint_type: JointType,
origin: Frame,
axis: Unit<Vector3<f64>>,
lower_limit: f64,
upper_limit: f64,
velocity_limit: f64,
position: f64,
velocity: f64,
acceleration: f64,
home_offset: f64,
}
impl Joint {
#[allow(clippy::too_many_arguments)]
pub fn new(
name: impl Into<String>,
joint_type: JointType,
origin: Frame,
axis: Vector3<f64>,
lower_limit: f64,
upper_limit: f64,
velocity_limit: f64,
) -> Result<Self> {
Self::new_named(
name.into(),
joint_type,
origin,
axis,
lower_limit,
upper_limit,
velocity_limit,
)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn new_named(
name: String,
joint_type: JointType,
origin: Frame,
axis: Vector3<f64>,
lower_limit: f64,
upper_limit: f64,
velocity_limit: f64,
) -> Result<Self> {
let axis = match joint_type {
JointType::Revolute | JointType::Prismatic => {
Unit::try_new(axis, 1.0e-12).ok_or_else(|| Error::InvalidJointAxis {
joint: name.clone(),
})?
}
JointType::Fixed => Vector3::x_axis(),
};
Ok(Self {
name,
joint_type,
origin,
axis,
lower_limit,
upper_limit,
velocity_limit,
position: 0.0,
velocity: 0.0,
acceleration: 0.0,
home_offset: 0.0,
})
}
pub fn name(&self) -> &str {
&self.name
}
pub const fn joint_type(&self) -> JointType {
self.joint_type
}
pub const fn lower_limit(&self) -> f64 {
self.lower_limit
}
pub const fn upper_limit(&self) -> f64 {
self.upper_limit
}
pub const fn velocity_limit(&self) -> f64 {
self.velocity_limit
}
pub const fn origin(&self) -> &Frame {
&self.origin
}
pub const fn axis(&self) -> &Unit<Vector3<f64>> {
&self.axis
}
pub fn frame(&self, q: f64) -> Frame {
match self.joint_type {
JointType::Revolute => {
self.origin
* Isometry3::from_parts(
Translation3::identity(),
UnitQuaternion::from_axis_angle(&self.axis, q),
)
}
JointType::Prismatic => self.origin * Translation3::from(self.axis.as_ref() * q),
JointType::Fixed => self.origin,
}
}
pub fn active_force(&self, load: Wrench) -> f64 {
match self.joint_type {
JointType::Revolute => load.torque.dot(self.axis.as_ref()),
JointType::Prismatic => load.force.dot(self.axis.as_ref()),
JointType::Fixed => 0.0,
}
}
pub fn is_over_limit(&self, q: f64) -> bool {
q > self.upper_limit + 1.0e-12 || q < self.lower_limit - 1.0e-12
}
pub const fn position(&self) -> f64 {
self.position
}
pub fn set_position(&mut self, position: f64) -> f64 {
self.position = position.clamp(self.lower_limit, self.upper_limit);
self.position
}
pub const fn velocity(&self) -> f64 {
self.velocity
}
pub fn set_velocity(&mut self, velocity: f64) -> f64 {
self.velocity = velocity.clamp(-self.velocity_limit, self.velocity_limit);
self.velocity
}
pub const fn acceleration(&self) -> f64 {
self.acceleration
}
pub fn set_acceleration(&mut self, acceleration: f64) -> f64 {
self.acceleration = acceleration;
acceleration
}
pub const fn home_offset(&self) -> f64 {
self.home_offset
}
pub fn set_home_offset(&mut self, offset: f64) -> f64 {
self.home_offset = offset;
offset
}
}