Skip to main content

dynamics_joint/
prismatic.rs

1//! Prismatic joint, constraining two objects to translate along a given axis.
2
3use dynamics_spatial::{
4    configuration::Configuration,
5    motion::{SpatialMotion, SpatialRotation},
6    se3::SE3,
7    vector3d::Vector3D,
8};
9use rand::rngs::ThreadRng;
10
11use crate::{
12    joint::{JointModel, JointType, JointWrapper},
13    joint_data::{JointData, JointDataWrapper, JointError},
14    limits::JointLimits,
15};
16
17/// Model of a prismatic joint.
18///
19/// This joint constraints two objects to translate along a given axis.
20#[derive(Clone, Debug)]
21pub struct JointModelPrismatic {
22    /// The axis of translation expressed in the local frame of the joint.
23    pub axis: Vector3D,
24    /// The joint limits.
25    pub limits: JointLimits,
26}
27
28impl JointModelPrismatic {
29    /// Creates a new `JointModelPrismatic` with the given axis of translation and unbounded limits.
30    ///
31    /// # Arguments
32    ///
33    /// * `axis` - The axis of translation expressed in the local frame of the joint.
34    ///
35    /// # Returns
36    /// A new `JointModelPrismatic` object.
37    #[must_use]
38    pub fn new(axis: Vector3D) -> Self {
39        JointModelPrismatic {
40            axis,
41            limits: JointLimits::new_unbounded(1),
42        }
43    }
44
45    /// Creates a new prismatic joint model with `x` as axis of translation.
46    ///
47    /// # Returns
48    /// A new `JointModelPrismatic` object.
49    #[must_use]
50    pub fn new_px() -> Self {
51        Self::new(Vector3D::x())
52    }
53
54    /// Creates a new prismatic joint model with `y` as axis of translation.
55    ///
56    /// # Returns
57    /// A new `JointModelPrismatic` object.
58    #[must_use]
59    pub fn new_py() -> Self {
60        Self::new(Vector3D::y())
61    }
62
63    /// Creates a new prismatic joint model with `z` as axis of translation.
64    ///
65    /// # Returns
66    /// A new `JointModelPrismatic` object.
67    #[must_use]
68    pub fn new_pz() -> Self {
69        Self::new(Vector3D::z())
70    }
71}
72
73impl JointModel for JointModelPrismatic {
74    fn get_joint_type(&self) -> JointType {
75        JointType::Prismatic
76    }
77
78    fn nq(&self) -> usize {
79        1
80    }
81
82    fn nv(&self) -> usize {
83        1
84    }
85
86    fn neutral(&self) -> Configuration {
87        Configuration::from_row_slice(&[0.0])
88    }
89
90    fn create_joint_data(&self) -> JointDataWrapper {
91        JointDataWrapper::prismatic(JointDataPrismatic::new(self))
92    }
93
94    fn get_axis(&self) -> Vec<SpatialMotion> {
95        vec![SpatialMotion::from_translational_axis(&self.axis)]
96    }
97
98    fn random_configuration(&self, rng: &mut ThreadRng) -> Configuration {
99        Configuration::random(
100            1,
101            rng,
102            &self.limits.min_configuration,
103            &self.limits.max_configuration,
104        )
105    }
106
107    fn subspace(&self, v: &Configuration) -> SpatialMotion {
108        assert_eq!(
109            v.len(),
110            1,
111            "Prismatic joint model expects a single velocity value."
112        );
113        v[0] * SpatialMotion::from_translational_axis(&self.axis)
114    }
115
116    fn subspace_dual(&self, f: &dynamics_spatial::force::SpatialForce) -> Configuration {
117        Configuration::from_row_slice(&[f.translation().dot(&self.axis)])
118    }
119
120    fn bias(&self) -> SpatialMotion {
121        SpatialMotion::zero()
122    }
123}
124
125/// Data associated to a prismatic joint.
126#[derive(Clone, Debug)]
127pub struct JointDataPrismatic {
128    /// The joint configuration value (translation along the axis).
129    pub joint_q: Configuration,
130    /// The joint velocity value (velocity along the axis).
131    pub joint_v: Configuration,
132    /// The placement of the joint in the local frame.
133    pub placement: SE3,
134    /// The joint velocity as a spatial motion.
135    pub joint_velocity: SpatialMotion,
136}
137
138impl JointDataPrismatic {
139    /// Creates a new `JointDataPrismatic` associated to the given joint model.
140    ///
141    /// # Arguments
142    ///
143    /// * `model` - The prismatic joint model.
144    ///
145    /// # Returns
146    /// A new `JointDataPrismatic` object.
147    #[must_use]
148    pub fn new(_model: &JointModelPrismatic) -> Self {
149        JointDataPrismatic {
150            joint_q: Configuration::zeros(1),
151            joint_v: Configuration::zeros(1),
152            placement: SE3::identity(),
153            joint_velocity: SpatialMotion::zero(),
154        }
155    }
156}
157
158impl JointData for JointDataPrismatic {
159    fn get_joint_placement(&self) -> SE3 {
160        self.placement
161    }
162
163    fn get_joint_q(&self) -> &Configuration {
164        &self.joint_q
165    }
166
167    fn get_joint_v(&self) -> &Configuration {
168        &self.joint_v
169    }
170
171    fn update(
172        &mut self,
173        joint_model: &JointWrapper,
174        joint_q: &Configuration,
175        joint_v: Option<&Configuration>,
176    ) -> Result<(), JointError> {
177        assert_eq!(
178            joint_q.len(),
179            1,
180            "Prismatic joint data update expects a single position value."
181        );
182        if let Some(joint_v) = joint_v {
183            assert_eq!(
184                joint_v.len(),
185                1,
186                "Prismatic joint model expects a single velocity value."
187            );
188        }
189
190        let axis = match joint_model.get_axis().len() {
191            1 => &joint_model.get_axis()[0],
192            _ => return Err(JointError::MissingAttributeError("axis".to_string())),
193        };
194
195        // store q and v
196        self.joint_q = joint_q.clone();
197        if let Some(joint_v) = joint_v {
198            self.joint_v = joint_v.clone();
199            self.joint_velocity = self.joint_v[0] * joint_model.get_axis()[0].clone();
200        }
201
202        self.placement =
203            SE3::from_parts(axis.translation() * joint_q[0], SpatialRotation::identity());
204        Ok(())
205    }
206
207    fn get_joint_velocity(&self) -> &SpatialMotion {
208        &self.joint_velocity
209    }
210}