#![allow(non_snake_case)]
pub mod aba;
pub mod system;
use gizmo_math::spatial::{SpatialInertia, SpatialMatrix, SpatialVector};
use gizmo_math::{Mat3, Quat, Vec3};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug)]
pub struct SpatialTransform {
pub rotation: Mat3,
pub translation: Vec3,
}
impl SpatialTransform {
pub const IDENTITY: Self = Self {
rotation: Mat3::IDENTITY,
translation: Vec3::ZERO,
};
pub fn new(rotation: Quat, translation: Vec3) -> Self {
Self {
rotation: Mat3::from_quat(rotation),
translation,
}
}
pub fn transform_motion(self, v: SpatialVector) -> SpatialVector {
let rw = self.rotation.mul_vec3(v.w);
let rv = self.rotation.mul_vec3(v.v);
SpatialVector::new(rw, self.translation.cross(rw) + rv)
}
pub fn inverse_transform_motion(self, v: SpatialVector) -> SpatialVector {
let rw = self.rotation.transpose().mul_vec3(v.w);
let r_trans_cross = self.translation.cross(v.w);
let rv = self.rotation.transpose().mul_vec3(v.v - r_trans_cross);
SpatialVector::new(rw, rv)
}
pub fn transform_force(self, f: SpatialVector) -> SpatialVector {
let rw = self.rotation.mul_vec3(f.w);
let rv = self.rotation.mul_vec3(f.v);
SpatialVector::new(rw + self.translation.cross(rv), rv)
}
pub fn inverse_transform_force(self, f: SpatialVector) -> SpatialVector {
let r_trans_cross = self.translation.cross(f.v);
let rw = self.rotation.transpose().mul_vec3(f.w - r_trans_cross);
let rv = self.rotation.transpose().mul_vec3(f.v);
SpatialVector::new(rw, rv)
}
pub fn transform_inertia(self, i: SpatialInertia) -> SpatialInertia {
SpatialInertia {
mass: i.mass,
com: self.translation + self.rotation.mul_vec3(i.com),
rot: self.rotation * i.rot * self.rotation.transpose(),
}
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum JointType {
Fixed,
Revolute(Vec3), Prismatic(Vec3), }
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArticulatedLink {
pub parent_index: usize, pub joint_type: JointType,
pub transform_to_parent: Vec3,
pub rotation_to_parent: Quat,
pub inertia: SpatialInertia,
pub q: f32, pub q_dot: f32, pub q_ddot: f32,
pub joint_force: f32,
#[serde(skip)] pub v: SpatialVector, #[serde(skip)] pub a: SpatialVector, #[serde(skip)] pub c: SpatialVector, #[serde(skip)] pub i_a: SpatialMatrix, #[serde(skip)] pub p_a: SpatialVector, #[serde(skip)] pub S: SpatialVector, #[serde(skip)] pub u: f32, #[serde(skip)] pub d_val: f32, #[serde(skip)] pub u_vec: SpatialVector, }
impl ArticulatedLink {
pub fn compute_spatial_transform(&self) -> SpatialTransform {
let (local_rot, local_trans) = match self.joint_type {
JointType::Fixed => (Quat::IDENTITY, Vec3::ZERO),
JointType::Revolute(axis) => (Quat::from_axis_angle(axis, self.q), Vec3::ZERO),
JointType::Prismatic(axis) => (Quat::IDENTITY, axis * self.q),
};
let total_rot = self.rotation_to_parent * local_rot;
let total_trans = self.transform_to_parent + self.rotation_to_parent.mul_vec3(local_trans);
SpatialTransform::new(total_rot, total_trans)
}
pub fn compute_motion_subspace(&self) -> SpatialVector {
match self.joint_type {
JointType::Fixed => SpatialVector::ZERO,
JointType::Revolute(axis) => SpatialVector::new(axis, Vec3::ZERO),
JointType::Prismatic(axis) => SpatialVector::new(Vec3::ZERO, axis),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArticulatedTree {
pub links: Vec<ArticulatedLink>,
pub base_position: Vec3,
pub base_rotation: Quat,
pub base_velocity: SpatialVector, pub base_acceleration: SpatialVector, pub is_fixed_base: bool,
}
impl Default for ArticulatedTree {
fn default() -> Self {
Self {
links: Vec::new(),
base_position: Vec3::ZERO,
base_rotation: Quat::IDENTITY,
base_velocity: SpatialVector::ZERO,
base_acceleration: SpatialVector::ZERO,
is_fixed_base: true,
}
}
}