rapier2d/dynamics/joint/multibody_joint/
multibody_joint.rs1use crate::dynamics::solver::GenericJointConstraint;
2use crate::dynamics::{
3 FixedJointBuilder, GenericJoint, IntegrationParameters, Multibody, MultibodyLink,
4 RigidBodyVelocity, joint,
5};
6use crate::math::{
7 ANG_DIM, DIM, DVector, JacobianViewMut, Pose, Real, Rotation, SPATIAL_DIM, SpatialVector,
8 Vector,
9};
10use parry::math::VectorExt;
11
12#[cfg(feature = "dim2")]
13use crate::math::rotation_from_angle;
14#[cfg(feature = "dim3")]
15use crate::utils::RotationOps;
16use crate::utils::vect_to_na;
17use na::DVectorViewMut;
18
19#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
20#[derive(Copy, Clone, Debug)]
21pub struct MultibodyJoint {
23 pub data: GenericJoint,
25 pub kinematic: bool,
30 pub(crate) coords: SpatialVector,
31 pub(crate) joint_rot: Rotation,
32}
33
34impl MultibodyJoint {
35 pub fn new(data: GenericJoint, kinematic: bool) -> Self {
37 Self {
38 data,
39 kinematic,
40 coords: Default::default(),
41 joint_rot: Rotation::IDENTITY,
42 }
43 }
44
45 pub(crate) fn free(pos: Pose) -> Self {
46 let mut result = Self::new(GenericJoint::default(), false);
47 result.set_free_pos(pos);
48 result
49 }
50
51 pub(crate) fn fixed(pos: Pose) -> Self {
52 Self::new(
53 FixedJointBuilder::new().local_frame1(pos).build().into(),
54 false,
55 )
56 }
57
58 pub(crate) fn set_free_pos(&mut self, pos: Pose) {
59 #[cfg(feature = "dim2")]
60 {
61 self.coords.x = pos.translation.x;
62 self.coords.y = pos.translation.y;
63 }
64 #[cfg(feature = "dim3")]
65 {
66 self.coords[0] = pos.translation.x;
67 self.coords[1] = pos.translation.y;
68 self.coords[2] = pos.translation.z;
69 }
70 self.joint_rot = pos.rotation;
71 }
72
73 fn num_free_lin_dofs(&self) -> usize {
78 let locked_bits = self.data.locked_axes.bits();
79 DIM - (locked_bits & ((1 << DIM) - 1)).count_ones() as usize
80 }
81
82 pub fn ndofs(&self) -> usize {
84 SPATIAL_DIM - self.data.locked_axes.bits().count_ones() as usize
85 }
86
87 pub fn body_to_parent(&self) -> Pose {
89 let locked_bits = self.data.locked_axes.bits();
90 let mut transform = Pose::from_rotation(self.joint_rot) * self.data.local_frame2.inverse();
91
92 for i in 0..DIM {
93 if (locked_bits & (1 << i)) == 0 {
94 let translation = Vector::ith(i, self.coords[i]);
96 transform = Pose::from_translation(translation) * transform;
97 }
98 }
99
100 self.data.local_frame1 * transform
101 }
102
103 #[profiling::function]
105 pub fn integrate(&mut self, dt: Real, vels: &[Real]) {
106 let locked_bits = self.data.locked_axes.bits();
107 let mut curr_free_dof = 0;
108
109 for i in 0..DIM {
110 if (locked_bits & (1 << i)) == 0 {
111 self.coords[i] += vels[curr_free_dof] * dt;
112 curr_free_dof += 1;
113 }
114 }
115
116 let locked_ang_bits = locked_bits >> DIM;
117 let num_free_ang_dofs = ANG_DIM - locked_ang_bits.count_ones() as usize;
118 match num_free_ang_dofs {
119 0 => { }
120 1 => {
121 let dof_id = (!locked_ang_bits).trailing_zeros() as usize;
122 self.coords[DIM + dof_id] += vels[curr_free_dof] * dt;
123 #[cfg(feature = "dim2")]
124 {
125 self.joint_rot = rotation_from_angle(self.coords[DIM + dof_id]);
126 }
127 #[cfg(feature = "dim3")]
128 {
129 self.joint_rot = Rotation::from_axis_angle(
130 Vector::ith(dof_id, 1.0),
131 self.coords[DIM + dof_id],
132 );
133 }
134 }
135 2 => {
136 todo!()
137 }
138 #[cfg(feature = "dim3")]
139 3 => {
140 let angvel = Vector::from_slice(&vels[curr_free_dof..curr_free_dof + 3]);
141 let disp = Rotation::from_scaled_axis(angvel * dt);
142 self.joint_rot = disp * self.joint_rot;
143 self.coords[3] += angvel[0] * dt;
144 self.coords[4] += angvel[1] * dt;
145 self.coords[5] += angvel[2] * dt;
146 }
147 _ => unreachable!(),
148 }
149 }
150
151 pub fn apply_displacement(&mut self, disp: &[Real]) {
153 self.integrate(1.0, disp);
154 }
155
156 pub fn jacobian(&self, transform: &Rotation, out: &mut JacobianViewMut<Real>) {
158 let locked_bits = self.data.locked_axes.bits();
159 let mut curr_free_dof = 0;
160
161 for i in 0..DIM {
162 if (locked_bits & (1 << i)) == 0 {
163 let transformed_axis = (*transform) * Vector::ith(i, 1.0);
164 out.fixed_view_mut::<DIM, 1>(0, curr_free_dof)
165 .copy_from(&vect_to_na(transformed_axis));
166 curr_free_dof += 1;
167 }
168 }
169
170 let locked_ang_bits = locked_bits >> DIM;
171 let num_free_ang_dofs = ANG_DIM - locked_ang_bits.count_ones() as usize;
172 match num_free_ang_dofs {
173 0 => { }
174 1 => {
175 #[cfg(feature = "dim2")]
176 {
177 out[(DIM, curr_free_dof)] = 1.0;
178 }
179
180 #[cfg(feature = "dim3")]
181 {
182 let dof_id = (!locked_ang_bits).trailing_zeros() as usize;
183 let rotmat = transform.to_mat();
184 out.fixed_view_mut::<ANG_DIM, 1>(DIM, curr_free_dof)
185 .copy_from_slice(rotmat.col(dof_id).as_ref());
186 }
187 }
188 2 => {
189 todo!()
190 }
191 #[cfg(feature = "dim3")]
192 3 => {
193 let rotmat = transform.to_mat();
194 out.fixed_view_mut::<3, 3>(3, curr_free_dof)
195 .copy_from_slice(rotmat.as_ref());
196 }
197 _ => unreachable!(),
198 }
199 }
200
201 pub fn jacobian_mul_coordinates(&self, acc: &[Real]) -> RigidBodyVelocity<Real> {
204 let locked_bits = self.data.locked_axes.bits();
205 let mut result = RigidBodyVelocity::zero();
206 let mut curr_free_dof = 0;
207
208 for i in 0..DIM {
209 if (locked_bits & (1 << i)) == 0 {
210 result.linvel += Vector::ith(i, acc[curr_free_dof]);
211 curr_free_dof += 1;
212 }
213 }
214
215 let locked_ang_bits = locked_bits >> DIM;
216 let num_free_ang_dofs = ANG_DIM - locked_ang_bits.count_ones() as usize;
217 match num_free_ang_dofs {
218 0 => { }
219 1 => {
220 #[cfg(feature = "dim2")]
221 {
222 result.angvel += acc[curr_free_dof];
223 }
224 #[cfg(feature = "dim3")]
225 {
226 let dof_id = (!locked_ang_bits).trailing_zeros() as usize;
227 result.angvel[dof_id] += acc[curr_free_dof];
228 }
229 }
230 2 => {
231 todo!()
232 }
233 #[cfg(feature = "dim3")]
234 3 => {
235 let angvel = Vector::from_slice(&acc[curr_free_dof..curr_free_dof + 3]);
236 result.angvel += angvel;
237 }
238 _ => unreachable!(),
239 }
240 result
241 }
242
243 pub fn default_damping(&self, out: &mut DVectorViewMut<Real>) {
245 let locked_bits = self.data.locked_axes.bits();
246 let mut curr_free_dof = self.num_free_lin_dofs();
247
248 for i in DIM..SPATIAL_DIM {
250 if locked_bits & (1 << i) == 0 {
251 out[curr_free_dof] = 0.1;
253 curr_free_dof += 1;
254 }
255 }
256 }
257
258 pub fn num_velocity_constraints(&self) -> usize {
260 let locked_bits = self.data.locked_axes.bits();
261 let limit_bits = self.data.limit_axes.bits();
262 let motor_bits = self.data.motor_axes.bits();
263 let mut num_constraints = 0;
264
265 for i in 0..SPATIAL_DIM {
266 if (locked_bits & (1 << i)) == 0 {
267 if (limit_bits & (1 << i)) != 0 {
268 num_constraints += 1;
269 }
270 if (motor_bits & (1 << i)) != 0 {
271 num_constraints += 1;
272 }
273 }
274 }
275
276 num_constraints
277 }
278
279 pub fn velocity_constraints(
281 &self,
282 params: &IntegrationParameters,
283 multibody: &Multibody,
284 link: &MultibodyLink,
285 mut j_id: usize,
286 jacobians: &mut DVector,
287 constraints: &mut [GenericJointConstraint],
288 ) -> usize {
289 let j_id = &mut j_id;
290 let locked_bits = self.data.locked_axes.bits();
291 let limit_bits = self.data.limit_axes.bits();
292 let motor_bits = self.data.motor_axes.bits();
293 let mut num_constraints = 0;
294 let mut curr_free_dof = 0;
295
296 for i in 0..DIM {
297 if (locked_bits & (1 << i)) == 0 {
298 let limits = if (limit_bits & (1 << i)) != 0 {
299 Some([self.data.limits[i].min, self.data.limits[i].max])
300 } else {
301 None
302 };
303
304 if (motor_bits & (1 << i)) != 0 {
305 joint::unit_joint_motor_constraint(
306 params,
307 multibody,
308 link,
309 &self.data.motors[i],
310 self.coords[i],
311 limits,
312 curr_free_dof,
313 j_id,
314 jacobians,
315 constraints,
316 &mut num_constraints,
317 );
318 }
319
320 if (limit_bits & (1 << i)) != 0 {
321 joint::unit_joint_limit_constraint(
322 params,
323 multibody,
324 link,
325 [self.data.limits[i].min, self.data.limits[i].max],
326 self.coords[i],
327 curr_free_dof,
328 j_id,
329 jacobians,
330 constraints,
331 &mut num_constraints,
332 self.data.softness,
333 );
334 }
335 curr_free_dof += 1;
336 }
337 }
338
339 for i in DIM..SPATIAL_DIM {
354 if (locked_bits & (1 << i)) == 0 {
355 let limits = if (limit_bits & (1 << i)) != 0 {
356 let limits = [self.data.limits[i].min, self.data.limits[i].max];
357 joint::unit_joint_limit_constraint(
358 params,
359 multibody,
360 link,
361 limits,
362 self.coords[i],
363 curr_free_dof,
364 j_id,
365 jacobians,
366 constraints,
367 &mut num_constraints,
368 self.data.softness,
369 );
370 Some(limits)
371 } else {
372 None
373 };
374
375 if (motor_bits & (1 << i)) != 0 {
376 joint::unit_joint_motor_constraint(
377 params,
378 multibody,
379 link,
380 &self.data.motors[i],
381 self.coords[i],
382 limits,
383 curr_free_dof,
384 j_id,
385 jacobians,
386 constraints,
387 &mut num_constraints,
388 );
389 }
390 curr_free_dof += 1;
391 }
392 }
393
394 num_constraints
395 }
396}