rapier3d/dynamics/joint/multibody_joint/
multibody_joint.rs1use crate::dynamics::solver::JointGenericOneBodyConstraint;
2use crate::dynamics::{
3 FixedJointBuilder, GenericJoint, IntegrationParameters, Multibody, MultibodyLink,
4 RigidBodyVelocity, joint,
5};
6use crate::math::{
7 ANG_DIM, DIM, Isometry, JacobianViewMut, Real, Rotation, SPATIAL_DIM, SpacialVector,
8 Translation, Vector,
9};
10use na::{DVector, DVectorViewMut};
11#[cfg(feature = "dim3")]
12use na::{UnitQuaternion, Vector3};
13
14#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
15#[derive(Copy, Clone, Debug)]
16pub struct MultibodyJoint {
18 pub data: GenericJoint,
20 pub kinematic: bool,
25 pub(crate) coords: SpacialVector<Real>,
26 pub(crate) joint_rot: Rotation<Real>,
27}
28
29impl MultibodyJoint {
30 pub fn new(data: GenericJoint, kinematic: bool) -> Self {
32 Self {
33 data,
34 kinematic,
35 coords: na::zero(),
36 joint_rot: Rotation::identity(),
37 }
38 }
39
40 pub(crate) fn free(pos: Isometry<Real>) -> Self {
41 let mut result = Self::new(GenericJoint::default(), false);
42 result.set_free_pos(pos);
43 result
44 }
45
46 pub(crate) fn fixed(pos: Isometry<Real>) -> Self {
47 Self::new(
48 FixedJointBuilder::new().local_frame1(pos).build().into(),
49 false,
50 )
51 }
52
53 pub(crate) fn set_free_pos(&mut self, pos: Isometry<Real>) {
54 self.coords
55 .fixed_rows_mut::<DIM>(0)
56 .copy_from(&pos.translation.vector);
57 self.joint_rot = pos.rotation;
58 }
59
60 fn num_free_lin_dofs(&self) -> usize {
65 let locked_bits = self.data.locked_axes.bits();
66 DIM - (locked_bits & ((1 << DIM) - 1)).count_ones() as usize
67 }
68
69 pub fn ndofs(&self) -> usize {
71 SPATIAL_DIM - self.data.locked_axes.bits().count_ones() as usize
72 }
73
74 pub fn body_to_parent(&self) -> Isometry<Real> {
76 let locked_bits = self.data.locked_axes.bits();
77 let mut transform = self.joint_rot * self.data.local_frame2.inverse();
78
79 for i in 0..DIM {
80 if (locked_bits & (1 << i)) == 0 {
81 transform = Translation::from(Vector::ith(i, self.coords[i])) * transform;
82 }
83 }
84
85 self.data.local_frame1 * transform
86 }
87
88 #[profiling::function]
90 pub fn integrate(&mut self, dt: Real, vels: &[Real]) {
91 let locked_bits = self.data.locked_axes.bits();
92 let mut curr_free_dof = 0;
93
94 for i in 0..DIM {
95 if (locked_bits & (1 << i)) == 0 {
96 self.coords[i] += vels[curr_free_dof] * dt;
97 curr_free_dof += 1;
98 }
99 }
100
101 let locked_ang_bits = locked_bits >> DIM;
102 let num_free_ang_dofs = ANG_DIM - locked_ang_bits.count_ones() as usize;
103 match num_free_ang_dofs {
104 0 => { }
105 1 => {
106 let dof_id = (!locked_ang_bits).trailing_zeros() as usize;
107 self.coords[DIM + dof_id] += vels[curr_free_dof] * dt;
108 #[cfg(feature = "dim2")]
109 {
110 self.joint_rot = Rotation::new(self.coords[DIM + dof_id]);
111 }
112 #[cfg(feature = "dim3")]
113 {
114 self.joint_rot = Rotation::from_axis_angle(
115 &Vector::ith_axis(dof_id),
116 self.coords[DIM + dof_id],
117 );
118 }
119 }
120 2 => {
121 todo!()
122 }
123 #[cfg(feature = "dim3")]
124 3 => {
125 let angvel = Vector3::from_row_slice(&vels[curr_free_dof..curr_free_dof + 3]);
126 let disp = UnitQuaternion::new_eps(angvel * dt, 0.0);
127 self.joint_rot = disp * self.joint_rot;
128 self.coords[3] += angvel[0] * dt;
129 self.coords[4] += angvel[1] * dt;
130 self.coords[5] += angvel[2] * dt;
131 }
132 _ => unreachable!(),
133 }
134 }
135
136 pub fn apply_displacement(&mut self, disp: &[Real]) {
138 self.integrate(1.0, disp);
139 }
140
141 pub fn jacobian(&self, transform: &Rotation<Real>, out: &mut JacobianViewMut<Real>) {
143 let locked_bits = self.data.locked_axes.bits();
144 let mut curr_free_dof = 0;
145
146 for i in 0..DIM {
147 if (locked_bits & (1 << i)) == 0 {
148 let transformed_axis = transform * Vector::ith(i, 1.0);
149 out.fixed_view_mut::<DIM, 1>(0, curr_free_dof)
150 .copy_from(&transformed_axis);
151 curr_free_dof += 1;
152 }
153 }
154
155 let locked_ang_bits = locked_bits >> DIM;
156 let num_free_ang_dofs = ANG_DIM - locked_ang_bits.count_ones() as usize;
157 match num_free_ang_dofs {
158 0 => { }
159 1 => {
160 #[cfg(feature = "dim2")]
161 {
162 out[(DIM, curr_free_dof)] = 1.0;
163 }
164
165 #[cfg(feature = "dim3")]
166 {
167 let dof_id = (!locked_ang_bits).trailing_zeros() as usize;
168 let rotmat = transform.to_rotation_matrix().into_inner();
169 out.fixed_view_mut::<ANG_DIM, 1>(DIM, curr_free_dof)
170 .copy_from(&rotmat.column(dof_id));
171 }
172 }
173 2 => {
174 todo!()
175 }
176 #[cfg(feature = "dim3")]
177 3 => {
178 let rotmat = transform.to_rotation_matrix();
179 out.fixed_view_mut::<3, 3>(3, curr_free_dof)
180 .copy_from(rotmat.matrix());
181 }
182 _ => unreachable!(),
183 }
184 }
185
186 pub fn jacobian_mul_coordinates(&self, acc: &[Real]) -> RigidBodyVelocity {
189 let locked_bits = self.data.locked_axes.bits();
190 let mut result = RigidBodyVelocity::zero();
191 let mut curr_free_dof = 0;
192
193 for i in 0..DIM {
194 if (locked_bits & (1 << i)) == 0 {
195 result.linvel += Vector::ith(i, acc[curr_free_dof]);
196 curr_free_dof += 1;
197 }
198 }
199
200 let locked_ang_bits = locked_bits >> DIM;
201 let num_free_ang_dofs = ANG_DIM - locked_ang_bits.count_ones() as usize;
202 match num_free_ang_dofs {
203 0 => { }
204 1 => {
205 #[cfg(feature = "dim2")]
206 {
207 result.angvel += acc[curr_free_dof];
208 }
209 #[cfg(feature = "dim3")]
210 {
211 let dof_id = (!locked_ang_bits).trailing_zeros() as usize;
212 result.angvel[dof_id] += acc[curr_free_dof];
213 }
214 }
215 2 => {
216 todo!()
217 }
218 #[cfg(feature = "dim3")]
219 3 => {
220 let angvel = Vector3::from_row_slice(&acc[curr_free_dof..curr_free_dof + 3]);
221 result.angvel += angvel;
222 }
223 _ => unreachable!(),
224 }
225 result
226 }
227
228 pub fn default_damping(&self, out: &mut DVectorViewMut<Real>) {
230 let locked_bits = self.data.locked_axes.bits();
231 let mut curr_free_dof = self.num_free_lin_dofs();
232
233 for i in DIM..SPATIAL_DIM {
235 if locked_bits & (1 << i) == 0 {
236 out[curr_free_dof] = 0.1;
238 curr_free_dof += 1;
239 }
240 }
241 }
242
243 pub fn num_velocity_constraints(&self) -> usize {
245 let locked_bits = self.data.locked_axes.bits();
246 let limit_bits = self.data.limit_axes.bits();
247 let motor_bits = self.data.motor_axes.bits();
248 let mut num_constraints = 0;
249
250 for i in 0..SPATIAL_DIM {
251 if (locked_bits & (1 << i)) == 0 {
252 if (limit_bits & (1 << i)) != 0 {
253 num_constraints += 1;
254 }
255 if (motor_bits & (1 << i)) != 0 {
256 num_constraints += 1;
257 }
258 }
259 }
260
261 num_constraints
262 }
263
264 pub fn velocity_constraints(
266 &self,
267 params: &IntegrationParameters,
268 multibody: &Multibody,
269 link: &MultibodyLink,
270 mut j_id: usize,
271 jacobians: &mut DVector<Real>,
272 constraints: &mut [JointGenericOneBodyConstraint],
273 ) -> usize {
274 let j_id = &mut j_id;
275 let locked_bits = self.data.locked_axes.bits();
276 let limit_bits = self.data.limit_axes.bits();
277 let motor_bits = self.data.motor_axes.bits();
278 let mut num_constraints = 0;
279 let mut curr_free_dof = 0;
280
281 for i in 0..DIM {
282 if (locked_bits & (1 << i)) == 0 {
283 let limits = if (limit_bits & (1 << i)) != 0 {
284 Some([self.data.limits[i].min, self.data.limits[i].max])
285 } else {
286 None
287 };
288
289 if (motor_bits & (1 << i)) != 0 {
290 joint::unit_joint_motor_constraint(
291 params,
292 multibody,
293 link,
294 &self.data.motors[i],
295 self.coords[i],
296 limits,
297 curr_free_dof,
298 j_id,
299 jacobians,
300 constraints,
301 &mut num_constraints,
302 );
303 }
304
305 if (limit_bits & (1 << i)) != 0 {
306 joint::unit_joint_limit_constraint(
307 params,
308 multibody,
309 link,
310 [self.data.limits[i].min, self.data.limits[i].max],
311 self.coords[i],
312 curr_free_dof,
313 j_id,
314 jacobians,
315 constraints,
316 &mut num_constraints,
317 );
318 }
319 curr_free_dof += 1;
320 }
321 }
322
323 for i in DIM..SPATIAL_DIM {
338 if (locked_bits & (1 << i)) == 0 {
339 let limits = if (limit_bits & (1 << i)) != 0 {
340 let limits = [self.data.limits[i].min, self.data.limits[i].max];
341 joint::unit_joint_limit_constraint(
342 params,
343 multibody,
344 link,
345 limits,
346 self.coords[i],
347 curr_free_dof,
348 j_id,
349 jacobians,
350 constraints,
351 &mut num_constraints,
352 );
353 Some(limits)
354 } else {
355 None
356 };
357
358 if (motor_bits & (1 << i)) != 0 {
359 joint::unit_joint_motor_constraint(
360 params,
361 multibody,
362 link,
363 &self.data.motors[i],
364 self.coords[i],
365 limits,
366 curr_free_dof,
367 j_id,
368 jacobians,
369 constraints,
370 &mut num_constraints,
371 );
372 }
373 curr_free_dof += 1;
374 }
375 }
376
377 num_constraints
378 }
379}