rapier2d/dynamics/joint/multibody_joint/
unit_multibody_joint.rs1#![allow(missing_docs)] use crate::dynamics::integration_parameters::SpringCoefficients;
4use crate::dynamics::joint::MultibodyLink;
5use crate::dynamics::solver::{GenericJointConstraint, WritebackId};
6use crate::dynamics::{IntegrationParameters, JointMotor, Multibody};
7use crate::math::{DVector, Real};
8
9pub fn unit_joint_limit_constraint(
12 params: &IntegrationParameters,
13 multibody: &Multibody,
14 link: &MultibodyLink,
15 limits: [Real; 2],
16 curr_pos: Real,
17 dof_id: usize,
18 j_id: &mut usize,
19 jacobians: &mut DVector,
20 constraints: &mut [GenericJointConstraint],
21 insert_at: &mut usize,
22 softness: SpringCoefficients<Real>,
23) {
24 let ndofs = multibody.ndofs();
25 let min_enabled = curr_pos < limits[0];
26 let max_enabled = limits[1] < curr_pos;
27
28 let erp_inv_dt = softness.erp_inv_dt(params.dt);
30 let cfm_coeff = softness.cfm_coeff(params.dt);
31
32 let rhs_bias = ((curr_pos - limits[1]).max(0.0) - (limits[0] - curr_pos).max(0.0)) * erp_inv_dt;
33 let rhs_wo_bias = 0.0;
34
35 let dof_j_id = *j_id + dof_id + link.assembly_id;
36 jacobians.rows_mut(*j_id, ndofs * 2).fill(0.0);
37 jacobians[dof_j_id] = 1.0;
38 jacobians[dof_j_id + ndofs] = 1.0;
39 multibody
40 .inv_augmented_mass()
41 .solve_mut(&mut jacobians.rows_mut(*j_id + ndofs, ndofs));
42
43 let lhs = jacobians[dof_j_id + ndofs]; let impulse_bounds = [
45 min_enabled as u32 as Real * -Real::MAX,
46 max_enabled as u32 as Real * Real::MAX,
47 ];
48 let cfm_gain = lhs * cfm_coeff;
49
50 let constraint = GenericJointConstraint {
51 is_rigid_body1: false,
52 solver_vel1: u32::MAX,
53 ndofs1: 0,
54 j_id1: 0,
55
56 is_rigid_body2: false,
57 solver_vel2: multibody.solver_id,
58 ndofs2: ndofs,
59 j_id2: *j_id,
60 joint_id: usize::MAX, impulse: 0.0,
62 impulse_bounds,
63 inv_lhs: crate::utils::inv(lhs + cfm_gain),
64 rhs: rhs_wo_bias + rhs_bias,
65 rhs_wo_bias,
66 cfm_coeff,
67 cfm_gain,
68 writeback_id: WritebackId::Limit(dof_id),
69 };
70
71 constraints[*insert_at] = constraint;
72 *insert_at += 1;
73
74 *j_id += 2 * ndofs;
75}
76
77#[allow(clippy::too_many_arguments)]
83pub fn unit_joint_friction_constraint(
84 params: &IntegrationParameters,
85 multibody: &Multibody,
86 link: &MultibodyLink,
87 friction: Real,
88 dof_id: usize,
89 j_id: &mut usize,
90 jacobians: &mut DVector,
91 constraints: &mut [GenericJointConstraint],
92 insert_at: &mut usize,
93 softness: SpringCoefficients<Real>,
94) {
95 let ndofs = multibody.ndofs();
96 let cfm_coeff = softness.cfm_coeff(params.dt);
97
98 let dof_j_id = *j_id + dof_id + link.assembly_id;
99 jacobians.rows_mut(*j_id, ndofs * 2).fill(0.0);
100 jacobians[dof_j_id] = 1.0;
101 jacobians[dof_j_id + ndofs] = 1.0;
102 multibody
103 .inv_augmented_mass()
104 .solve_mut(&mut jacobians.rows_mut(*j_id + ndofs, ndofs));
105
106 let lhs = jacobians[dof_j_id + ndofs]; let max_impulse = friction * params.dt;
108 let cfm_gain = lhs * cfm_coeff;
109
110 let constraint = GenericJointConstraint {
111 is_rigid_body1: false,
112 solver_vel1: u32::MAX,
113 ndofs1: 0,
114 j_id1: 0,
115 is_rigid_body2: false,
116 solver_vel2: multibody.solver_id,
117 ndofs2: ndofs,
118 j_id2: *j_id,
119 joint_id: usize::MAX, impulse: 0.0,
121 impulse_bounds: [-max_impulse, max_impulse],
122 inv_lhs: crate::utils::inv(lhs + cfm_gain),
123 rhs: 0.0,
124 rhs_wo_bias: 0.0,
125 cfm_coeff,
126 cfm_gain,
127 writeback_id: WritebackId::Friction(dof_id),
128 };
129
130 constraints[*insert_at] = constraint;
131 *insert_at += 1;
132
133 *j_id += 2 * ndofs;
134}
135
136pub fn unit_joint_motor_constraint(
139 params: &IntegrationParameters,
140 multibody: &Multibody,
141 link: &MultibodyLink,
142 motor: &JointMotor,
143 curr_pos: Real,
144 limits: Option<[Real; 2]>,
145 dof_id: usize,
146 j_id: &mut usize,
147 jacobians: &mut DVector,
148 constraints: &mut [GenericJointConstraint],
149 insert_at: &mut usize,
150) {
151 let inv_dt = params.inv_dt();
152 let ndofs = multibody.ndofs();
153 let motor_params = motor.motor_params(params.dt);
154
155 let dof_j_id = *j_id + dof_id + link.assembly_id;
156 jacobians.rows_mut(*j_id, ndofs * 2).fill(0.0);
157 jacobians[dof_j_id] = 1.0;
158 jacobians[dof_j_id + ndofs] = 1.0;
159 multibody
160 .inv_augmented_mass()
161 .solve_mut(&mut jacobians.rows_mut(*j_id + ndofs, ndofs));
162
163 let lhs = jacobians[dof_j_id + ndofs]; let impulse_bounds = [-motor_params.max_impulse, motor_params.max_impulse];
165 let cfm_gain = lhs * motor_params.cfm_coeff + motor_params.cfm_gain;
166
167 let mut rhs_wo_bias = 0.0;
168 if motor_params.erp_inv_dt != 0.0 {
169 rhs_wo_bias += (curr_pos - motor_params.target_pos) * motor_params.erp_inv_dt;
170 }
171
172 let mut target_vel = motor_params.target_vel;
173 if let Some(limits) = limits {
174 target_vel = target_vel.clamp(
175 (limits[0] - curr_pos) * inv_dt,
176 (limits[1] - curr_pos) * inv_dt,
177 );
178 };
179
180 rhs_wo_bias += -target_vel;
181
182 let constraint = GenericJointConstraint {
183 is_rigid_body1: false,
184 solver_vel1: u32::MAX,
185 ndofs1: 0,
186 j_id1: 0,
187
188 is_rigid_body2: false,
189 solver_vel2: multibody.solver_id,
190 ndofs2: ndofs,
191 j_id2: *j_id,
192 joint_id: usize::MAX, impulse: 0.0,
194 impulse_bounds,
195 cfm_coeff: motor_params.cfm_coeff,
196 cfm_gain,
197 inv_lhs: crate::utils::inv(lhs + cfm_gain),
198 rhs: rhs_wo_bias,
199 rhs_wo_bias,
200 writeback_id: WritebackId::Limit(dof_id),
201 };
202
203 constraints[*insert_at] = constraint;
204 *insert_at += 1;
205
206 *j_id += 2 * ndofs;
207}