Skip to main content

dynamics_joint/
joint.rs

1//! Defines a generic joint model trait and a struct to wrap different joint types.
2//!
3//! This module provides both:
4//! * The `JointModel` trait, which defines the common interface for different joint types.
5//! * The `JointWrapper` struct, which encapsulates different joint model implementations and provides a
6//!   unified interface to interact with them.
7
8use crate::{
9    continuous::JointModelContinuous, fixed::JointModelFixed, joint_data::JointDataWrapper,
10    prismatic::JointModelPrismatic, revolute::JointModelRevolute,
11};
12use dynamics_spatial::{configuration::Configuration, force::SpatialForce, motion::SpatialMotion};
13use rand::rngs::ThreadRng;
14
15#[derive(Clone, Debug)]
16/// Enum encapsulating different joint model implementations.
17///
18/// It serves as the inner representation for the `JointWrapper` struct.
19/// As such, users should interact with joints through the `JointWrapper` interface,
20/// and avoid using this enum directly.
21enum JointModelImpl {
22    Continuous(JointModelContinuous),
23    Prismatic(JointModelPrismatic),
24    Revolute(JointModelRevolute),
25    Fixed(JointModelFixed),
26}
27
28#[derive(Clone, Debug)]
29/// Wrapper struct for different joint model implementations.
30///
31/// This struct provides a unified interface to interact with different joint types
32/// through the `JointModel` trait. It serves as the main entry point for users of
33/// the library to work with joints.
34pub struct JointWrapper {
35    inner: JointModelImpl,
36}
37
38impl JointWrapper {
39    /// Creates a new `JointWrapper` from a `JointModelContinuous`.
40    pub fn continuous(joint: JointModelContinuous) -> Self {
41        JointWrapper {
42            inner: JointModelImpl::Continuous(joint),
43        }
44    }
45
46    /// Creates a new `JointWrapper` from a `JointModelPrismatic`.
47    pub fn prismatic(joint: JointModelPrismatic) -> Self {
48        JointWrapper {
49            inner: JointModelImpl::Prismatic(joint),
50        }
51    }
52
53    /// Creates a new `JointWrapper` from a `JointModelRevolute`.
54    pub fn revolute(joint: JointModelRevolute) -> Self {
55        JointWrapper {
56            inner: JointModelImpl::Revolute(joint),
57        }
58    }
59
60    /// Creates a new `JointWrapper` from a `JointModelFixed`.
61    pub fn fixed(joint: JointModelFixed) -> Self {
62        JointWrapper {
63            inner: JointModelImpl::Fixed(joint),
64        }
65    }
66}
67
68// The following is boilerplate to forward JointModel trait methods to the inner joint model.
69impl JointModel for JointWrapper {
70    fn get_joint_type(&self) -> JointType {
71        match &self.inner {
72            JointModelImpl::Continuous(joint) => joint.get_joint_type(),
73            JointModelImpl::Prismatic(joint) => joint.get_joint_type(),
74            JointModelImpl::Revolute(joint) => joint.get_joint_type(),
75            JointModelImpl::Fixed(joint) => joint.get_joint_type(),
76        }
77    }
78
79    fn nq(&self) -> usize {
80        match &self.inner {
81            JointModelImpl::Continuous(joint) => joint.nq(),
82            JointModelImpl::Prismatic(joint) => joint.nq(),
83            JointModelImpl::Revolute(joint) => joint.nq(),
84            JointModelImpl::Fixed(joint) => joint.nq(),
85        }
86    }
87
88    fn nv(&self) -> usize {
89        match &self.inner {
90            JointModelImpl::Continuous(joint) => joint.nv(),
91            JointModelImpl::Prismatic(joint) => joint.nv(),
92            JointModelImpl::Revolute(joint) => joint.nv(),
93            JointModelImpl::Fixed(joint) => joint.nv(),
94        }
95    }
96
97    fn neutral(&self) -> Configuration {
98        match &self.inner {
99            JointModelImpl::Continuous(joint) => joint.neutral(),
100            JointModelImpl::Prismatic(joint) => joint.neutral(),
101            JointModelImpl::Revolute(joint) => joint.neutral(),
102            JointModelImpl::Fixed(joint) => joint.neutral(),
103        }
104    }
105
106    fn create_joint_data(&self) -> JointDataWrapper {
107        match &self.inner {
108            JointModelImpl::Continuous(joint) => joint.create_joint_data(),
109            JointModelImpl::Prismatic(joint) => joint.create_joint_data(),
110            JointModelImpl::Revolute(joint) => joint.create_joint_data(),
111            JointModelImpl::Fixed(joint) => joint.create_joint_data(),
112        }
113    }
114
115    fn random_configuration(&self, rng: &mut ThreadRng) -> Configuration {
116        match &self.inner {
117            JointModelImpl::Continuous(joint) => joint.random_configuration(rng),
118            JointModelImpl::Prismatic(joint) => joint.random_configuration(rng),
119            JointModelImpl::Revolute(joint) => joint.random_configuration(rng),
120            JointModelImpl::Fixed(joint) => joint.random_configuration(rng),
121        }
122    }
123
124    fn get_axis(&self) -> Vec<SpatialMotion> {
125        match &self.inner {
126            JointModelImpl::Continuous(joint) => joint.get_axis(),
127            JointModelImpl::Prismatic(joint) => joint.get_axis(),
128            JointModelImpl::Revolute(joint) => joint.get_axis(),
129            JointModelImpl::Fixed(joint) => joint.get_axis(),
130        }
131    }
132
133    fn subspace(&self, v: &Configuration) -> SpatialMotion {
134        match &self.inner {
135            JointModelImpl::Continuous(joint) => joint.subspace(v),
136            JointModelImpl::Prismatic(joint) => joint.subspace(v),
137            JointModelImpl::Revolute(joint) => joint.subspace(v),
138            JointModelImpl::Fixed(joint) => joint.subspace(v),
139        }
140    }
141
142    fn subspace_dual(&self, f: &SpatialForce) -> Configuration {
143        match &self.inner {
144            JointModelImpl::Continuous(joint) => joint.subspace_dual(f),
145            JointModelImpl::Prismatic(joint) => joint.subspace_dual(f),
146            JointModelImpl::Revolute(joint) => joint.subspace_dual(f),
147            JointModelImpl::Fixed(joint) => joint.subspace_dual(f),
148        }
149    }
150
151    fn bias(&self) -> SpatialMotion {
152        match &self.inner {
153            JointModelImpl::Continuous(joint) => joint.bias(),
154            JointModelImpl::Prismatic(joint) => joint.bias(),
155            JointModelImpl::Revolute(joint) => joint.bias(),
156            JointModelImpl::Fixed(joint) => joint.bias(),
157        }
158    }
159}
160
161/// Joint trait for defining joints in a robotic system.
162///
163/// This trait provides a common interface for different joint types,
164/// allowing for polymorphic behavior when working with various joint models.
165pub trait JointModel {
166    /// Returns the joint type.
167    fn get_joint_type(&self) -> JointType;
168
169    /// Returns the number of position variables.
170    fn nq(&self) -> usize;
171
172    /// Returns the number of velocity variables.
173    fn nv(&self) -> usize;
174
175    /// Returns the neutral configuration of the joint.
176    fn neutral(&self) -> Configuration;
177
178    /// Creates the joint data.
179    fn create_joint_data(&self) -> JointDataWrapper;
180
181    /// Returns the axis of the joint, if applicable.
182    fn get_axis(&self) -> Vec<SpatialMotion>; // TODO: modify signature
183
184    /// Returns a random configuration for the joint.
185    fn random_configuration(&self, rng: &mut ThreadRng) -> Configuration;
186
187    /// Applies the joint subspace constraint to obtain the motion associated with a given velocity configuration.
188    fn subspace(&self, v: &Configuration) -> SpatialMotion;
189
190    /// Applies the dual of the joint subspace constraint to obtain the force/torque associated with a given spatial force.
191    fn subspace_dual(&self, f: &SpatialForce) -> Configuration;
192
193    /// Returns the joint bias (Coriolis and centrifugal effects).
194    fn bias(&self) -> SpatialMotion;
195}
196
197/// Enum representing the type of joint.
198#[cfg_attr(feature = "python", pyo3::prelude::pyclass)]
199#[derive(Clone, Copy, Debug, PartialEq, Eq)]
200pub enum JointType {
201    Continuous,
202    Fixed,
203    Prismatic,
204    Revolute,
205}
206
207/// Type alias for joint bias, represented as a spatial motion.
208///
209/// A joint bias typically represents the Coriolis and centrifugal effects
210/// and are computed during the joint kinematics.
211pub type JointBias = SpatialMotion;