Rigid Body Dynamics Library
Constraint_Loop.cc
Go to the documentation of this file.
1/*
2 * RBDL - Rigid Body Dynamics Library
3 * Copyright (c) 2019 Matthew Millard <millard.matthew@gmail.com>
4 *
5 * Licensed under the zlib license. See LICENSE for more details.
6 */
7
8#include <iostream>
9#include <sstream>
10#include <limits>
11#include <assert.h>
12
13#include "rbdl/rbdl_mathutils.h"
14#include "rbdl/Logging.h"
15
16#include "rbdl/Model.h"
18#include "rbdl/Kinematics.h"
19
20using namespace RigidBodyDynamics;
21using namespace Math;
22
23
24
25//==============================================================================
26LoopConstraint::LoopConstraint():
27 Constraint("",ConstraintTypeLoop,unsigned(int(0)),
28 std::numeric_limits<unsigned int>::max()){}
29
30//==============================================================================
32 //const unsigned int rowInSystem,
33 const unsigned int bodyIdPredecessor,
34 const unsigned int bodyIdSuccessor,
35 const Math::SpatialTransform &bodyFramePredecessor,
36 const Math::SpatialTransform &bodyFrameSuccessor,
37 const Math::SpatialVector &constraintAxis,
38 bool enableBaumgarteStabilization,
39 double stabilizationTimeConstant,
40 const char *loopConstraintName,
41 unsigned int userDefinedIdNumber,
42 bool positionLevelConstraint,
43 bool velocityLevelConstraint):
44 Constraint(loopConstraintName,
46 unsigned(int(1)),
47 userDefinedIdNumber)
48{
49
50 T.push_back(constraintAxis);
51 dblA = std::numeric_limits<double>::epsilon()*10.;
52#ifndef RBDL_USE_CASADI_MATH
53 assert(std::fabs(T[0].norm()-1.0)<= dblA);
54#endif
55
56 positionConstraint[0]=positionLevelConstraint;
57 velocityConstraint[0]=velocityLevelConstraint;
58
59 bodyIds.push_back(bodyIdPredecessor);
60 bodyIds.push_back(bodyIdSuccessor);
61
62 bodyFrames.push_back(bodyFramePredecessor);
63 bodyFrames.push_back(bodyFrameSuccessor);
64
65 setEnableBaumgarteStabilization(enableBaumgarteStabilization);
66 setBaumgarteTimeConstant(stabilizationTimeConstant);
67
68}
69
70
71//==============================================================================
72
73void LoopConstraint::bind(const Model &model)
74{
75 //There are no dynamically-sized local matrices or vectors that
76 //need to be adjusted for this Constraint - the dynamic members in
77 //the ConstraintCache are enough.
78}
79
80
81//==============================================================================
82
84 const double time,
85 const Math::VectorNd &Q,
86 const Math::VectorNd &QDot,
87 Math::MatrixNd &GSysUpd,
88 ConstraintCache &cache,
89 bool updateKinematics)
90{
91 //Please refer to Ch. 8 of Featherstone's Rigid Body Dynamics for details
92
93 //Compute the spatial Jacobians of the predecessor point Gp and the
94 //successor point Gs and evaluate Gs-Gp
95 cache.mat6NA.setZero();
96 cache.mat6NB.setZero();
97 CalcPointJacobian6D(model,Q,bodyIds[0],bodyFrames[0].r,cache.mat6NA,
98 updateKinematics);
99 CalcPointJacobian6D(model,Q,bodyIds[1],bodyFrames[1].r,cache.mat6NB,
100 updateKinematics);
101 cache.mat6NA = cache.mat6NB-cache.mat6NA;
102
103 //Evaluate the transform from the world frame into the constraint frame
104 //that is attached to the precessor body
105 cache.stA.r = CalcBodyToBaseCoordinates(model,Q,bodyIds[0],bodyFrames[0].r,
106 updateKinematics);
107 cache.stA.E = CalcBodyWorldOrientation(model,Q,bodyIds[0],updateKinematics
108 ).transpose()*bodyFrames[0].E;
109
110 for(unsigned int i=0; i<sizeOfConstraint;++i){
111 //Resolve each constraint axis into the global frame
112 cache.svecA =cache.stA.apply(T[i]);
113 //Take the dot product of the constraint axis with Gs-Gp
114 GSysUpd.block(rowInSystem+i,0,1,GSysUpd.cols())
115 = cache.svecA.transpose()*cache.mat6NA;
116 }
117
118}
119
120//==============================================================================
121
122void LoopConstraint::calcGamma( Model &model,
123 const double time,
124 const Math::VectorNd &Q,
125 const Math::VectorNd &QDot,
126 const Math::MatrixNd &GSys,
127 Math::VectorNd &gammaSysUpd,
128 ConstraintCache &cache,
129 bool updateKinematics)
130{
131 //Please refer to Ch. 8 of Featherstone's Rigid Body Dynamics text for details
132
133 // Express the constraint axis in the base frame.
134 cache.stA.r = CalcBodyToBaseCoordinates(model,Q,bodyIds[0],bodyFrames[0].r,
135 updateKinematics);
136 cache.stA.E = CalcBodyWorldOrientation(model,Q,bodyIds[0],updateKinematics
137 ).transpose()*bodyFrames[0].E;
138
139 // Compute the spatial velocities of the two constrained bodies.
140 //vel_p
141 cache.svecA = CalcPointVelocity6D(model,Q,QDot,bodyIds[0],bodyFrames[0].r,
142 updateKinematics);
143
144 //vel_s
145 cache.svecB = CalcPointVelocity6D(model,Q,QDot,bodyIds[1],bodyFrames[1].r,
146 updateKinematics);
147
148 // Compute the velocity product accelerations. These correspond to the
149 // accelerations that the bodies would have if q ddot were 0. If this
150 // confuses you please see Sec. 8.2 of Featherstone's Rigid Body Dynamics text
151
152 //acc_p
153 cache.svecC = CalcPointAcceleration6D(model,Q,QDot,cache.vecNZeros,
154 bodyIds[0],bodyFrames[0].r,updateKinematics);
155 //acc_s
156 cache.svecD = CalcPointAcceleration6D(model,Q,QDot,cache.vecNZeros,
157 bodyIds[1],bodyFrames[1].r,updateKinematics);
158
159 for(unsigned int i=0; i<sizeOfConstraint;++i){
160
161 cache.svecE = cache.stA.apply(T[i]);
162
163 cache.svecF = crossm(cache.svecA, cache.svecE);
164
165 gammaSysUpd[rowInSystem+i] =
166 -cache.svecE.dot(cache.svecD-cache.svecC)
167 -cache.svecF.dot(cache.svecB-cache.svecA);
168 }
169
170}
171
172
173//==============================================================================
174
175
177 const double time,
178 const Math::VectorNd &Q,
179 Math::VectorNd &errSysUpd,
180 ConstraintCache &cache,
181 bool updateKinematics)
182{
183
184 // Constraints computed in the predecessor body frame.
185
186
187 // Compute the position of the two contact points.
188
189 //Kp: predecessor frame
190 cache.stA.r = CalcBodyToBaseCoordinates(model,Q,bodyIds[0],bodyFrames[0].r,
191 updateKinematics);
192 cache.stA.E = CalcBodyWorldOrientation(model,Q,bodyIds[0],updateKinematics
193 ).transpose()*bodyFrames[0].E;
194
195 //Ks: successor frame
196 cache.stB.r = CalcBodyToBaseCoordinates(model,Q,bodyIds[1],bodyFrames[1].r,
197 updateKinematics);
198 cache.stB.E = CalcBodyWorldOrientation(model,Q,bodyIds[1],updateKinematics
199 ).transpose()*bodyFrames[1].E;
200
201
202 // Compute the orientation from the predecessor to the successor frame.
203
204 cache.mat3A = cache.stA.E.transpose()*cache.stB.E;
205
206 // The first three elements represent the rotation error.
207 // This formulation is equivalent to u * sin(theta), where u and theta are
208 // the angle-axis of rotation from the predecessor to the successor frame.
209 // These quantities are expressed in the predecessor frame. This is also
210 // similar to the rotation error calculation that appears in Table 8.1 of
211 // Featherstone.
212 cache.svecA[0] = -0.5*(cache.mat3A(1,2)-cache.mat3A(2,1));
213 cache.svecA[1] = -0.5*(cache.mat3A(2,0)-cache.mat3A(0,2));
214 cache.svecA[2] = -0.5*(cache.mat3A(0,1)-cache.mat3A(1,0));
215
216 // The last three elements represent the position error.
217 // It is equivalent to the difference in the position of the two
218 // constraint points. The distance is projected on the predecessor frame
219 // to be consistent with the rotation.
220
221 //Qn: Should this be multiplied by -0.5 to be consistent with table 8.1?
222 //For now I'm leaving this as is: this is equivalent to the functioning
223 //original loop constraint code.
224 cache.svecA.block(3,0,3,1)=cache.stA.E.transpose()*(cache.stB.r-cache.stA.r);
225
226 for(unsigned int i=0; i<sizeOfConstraint;++i){
227 if(positionConstraint[i]){
228 errSysUpd[rowInSystem+i] = T[i].transpose()*cache.svecA;
229 }else{
230 errSysUpd[rowInSystem+i] = 0.;
231 }
232 }
233
234}
235
236//==============================================================================
237
239 const double time,
240 const Math::VectorNd &Q,
241 const Math::VectorNd &QDot,
242 const Math::MatrixNd &GSys,
243 Math::VectorNd &derrSysUpd,
244 ConstraintCache &cache,
245 bool updateKinematics)
246{
247 //SimpleMath cannot handle multiplying a block matrix by a vector
248 //Using a for loop here to maintain backwards compatibility.
249 //Rant: all of this ugliness for a dot product! Does anyone even use
250 // SimpleMath?
251
252 //derrSysUpd.block(rowInSystem,0,sizeOfConstraint,1) =
253 // GSys.block(rowInSystem,0,sizeOfConstraint,GSys.cols())*QDot;
254
255 for(unsigned int i=0; i<sizeOfConstraint;++i){
256 derrSysUpd[rowInSystem+i] = 0;
257 if(velocityConstraint[i]){
258 for(unsigned int j=0; j<GSys.cols();++j){
259 derrSysUpd[rowInSystem+i] +=
260 GSys(rowInSystem+i,j)*QDot[j];
261 }
262 }
263 }
264
265}
266
267//==============================================================================
268
270 Model &model,
271 const double time,
272 const Math::VectorNd &Q,
273 const Math::VectorNd &QDot,
274 const Math::MatrixNd &GSys,
275 const Math::VectorNd &LagMultSys,
276 std::vector< unsigned int > &constraintBodiesUpd,
277 std::vector< Math::SpatialTransform > &constraintBodyFramesUpd,
278 std::vector< Math::SpatialVector > &constraintForcesUpd,
279 ConstraintCache &cache,
280 bool resolveAllInRootFrame,
281 bool updateKinematics)
282{
283 constraintBodiesUpd.resize(2);
284 constraintBodyFramesUpd.resize(2);
285
286 cache.stA.r = CalcBodyToBaseCoordinates(model,Q,bodyIds[0],bodyFrames[0].r,
287 updateKinematics);
288 cache.stA.E = CalcBodyWorldOrientation(model,Q,bodyIds[0],updateKinematics
289 ).transpose()*bodyFrames[0].E;
290 cache.stB.r = CalcBodyToBaseCoordinates(model,Q,bodyIds[1],bodyFrames[1].r,
291 updateKinematics);
292 cache.stB.E = CalcBodyWorldOrientation(model,Q,bodyIds[1],updateKinematics
293 ).transpose()*bodyFrames[1].E;
294
295 constraintForcesUpd.resize(2);
296 constraintForcesUpd[0].setZero();
297 constraintForcesUpd[1].setZero();
298
299
300 //Using Eqn. 8.30 of Featherstone. Note that this force is resolved in the
301 //root frame.
302 cache.svecB.setZero();
303 for(unsigned int i=0; i<sizeOfConstraint;++i){
304 cache.svecA = cache.stA.apply(T[i]);
305 cache.svecB += cache.svecA*LagMultSys[rowInSystem+i];
306 }
307
308 constraintBodiesUpd.resize(2);
309 constraintBodyFramesUpd.resize(2);
310
311 if(resolveAllInRootFrame){
312 constraintBodiesUpd[0] = 0;
313 constraintBodiesUpd[1] = 0;
314
315 //These forces are returned in the coordinates of the
316 //root frame but w.r.t. the respective points of the constaint
317 constraintBodyFramesUpd[0].r = cache.stA.r;
318 constraintBodyFramesUpd[0].E.Identity();
319
320 constraintBodyFramesUpd[1].r = cache.stB.r;
321 constraintBodyFramesUpd[1].E.Identity();
322
323 //The forces applied to the successor body are equal and opposite
324 constraintForcesUpd[0] = -cache.svecB;
325 constraintForcesUpd[1] = cache.svecB;
326
327 }else{
328
329 constraintBodiesUpd = bodyIds;
330 constraintBodyFramesUpd = bodyFrames;
331
332 constraintForcesUpd[0].block(0,0,3,1) = -cache.stA.E.transpose()
333 *cache.svecB.block(0,0,3,1);
334 constraintForcesUpd[0].block(3,0,3,1) = -cache.stA.E.transpose()
335 *cache.svecB.block(3,0,3,1);
336
337
338 constraintForcesUpd[1].block(0,0,3,1) = cache.stB.E.transpose()
339 *cache.svecB.block(0,0,3,1);
340 constraintForcesUpd[1].block(3,0,3,1) = cache.stB.E.transpose()
341 *cache.svecB.block(3,0,3,1);
342
343
344
345 }
346
347
348
349}
350//==============================================================================
352 appendConstraintAxis( const Math::SpatialVector &constraintAxis,
353 bool positionLevelConstraint,
354 bool velocityLevelConstraint)
355{
356
357 dblA = 10.0*std::numeric_limits<double>::epsilon();
358
359 //Make sure the normal is valid
360#ifndef RBDL_USE_CASADI_MATH
361 assert( std::fabs(constraintAxis.norm()-1.) < dblA);
362 for(unsigned int i=0; i<sizeOfConstraint;++i){
363 assert(std::fabs(T[i].dot(constraintAxis)) <= dblA);
364 }
365#endif
366
367 T.push_back(constraintAxis);
368 positionConstraint.push_back(positionLevelConstraint);
369 velocityConstraint.push_back(velocityLevelConstraint);
371
372 assert(sizeOfConstraint <= 6 && sizeOfConstraint > 0);
373}
374
unsigned int cols() const
Definition: MX_Xd_dynamic.h:99
void resize(unsigned int newI, unsigned int newJ=1)
Definition: MX_Xd_dynamic.h:91
MX_Xd_SubMatrix block(unsigned int row_start, unsigned int col_start)
Interface to define general-purpose constraints.
Definition: Constraint.h:139
void setEnableBaumgarteStabilization(bool flagEnableBaumgarteStabilization)
Definition: Constraint.h:566
void setBaumgarteTimeConstant(double tStab)
Calculates and sets the Baumgarte stabilization coefficients as a function of tStab,...
Definition: Constraint.h:555
std::vector< Math::SpatialTransform > bodyFrames
Transform from the frame of the predecessor body to the constraint frame.
Definition: Constraint.h:726
unsigned int rowInSystem
The first row in G that corresponds to this constraint.
Definition: Constraint.h:720
std::vector< bool > positionConstraint
Definition: Constraint.h:740
unsigned int sizeOfConstraint
The number of rows that this constraint adds to G.
Definition: Constraint.h:717
std::vector< unsigned int > bodyIds
The index of the predecessor body in the vector of bodies in Model.
Definition: Constraint.h:723
std::vector< bool > velocityConstraint
Definition: Constraint.h:741
void calcPositionError(Model &model, const double time, const Math::VectorNd &Q, Math::VectorNd &errSysUpd, ConstraintCache &cache, bool updateKinematics=false) override
In this function the sub vector of this constraint is inserted into the position error vector of the...
double dblA
A local working double.
void bind(const Model &model) override
Any local memory that has a dimension of N, where N is the length of QDot, is resized in this functio...
void calcGamma(Model &model, const double time, const Math::VectorNd &Q, const Math::VectorNd &QDot, const Math::MatrixNd &GSys, Math::VectorNd &gammaSysUpd, ConstraintCache &cache, bool updateKinematics=false) override
In this function the vector of this constraint is inserted into the right-hand-side vector of the s...
std::vector< Math::SpatialVector > T
Vector of constraint axis resolved in the predecessor frame.
void calcConstraintForces(Model &model, const double time, const Math::VectorNd &Q, const Math::VectorNd &QDot, const Math::MatrixNd &GSys, const Math::VectorNd &lagrangeMultipliersSys, std::vector< unsigned int > &constraintBodiesUpd, std::vector< Math::SpatialTransform > &constraintBodyFramesUpd, std::vector< Math::SpatialVector > &constraintForcesUpd, ConstraintCache &cache, bool resolveAllInRootFrame=false, bool updateKinematics=false) override
This function resolves the generalized forces this constraint applies to the system into the wrenches...
void calcConstraintJacobian(Model &model, const double time, const Math::VectorNd &Q, const Math::VectorNd &QDot, Math::MatrixNd &GSysUpd, ConstraintCache &cache, bool updateKinematics=false) override
In this function the matrix of this contraint is inserted into the system constraint Jacobian (GSys...
void calcVelocityError(Model &model, const double time, const Math::VectorNd &Q, const Math::VectorNd &QDot, const Math::MatrixNd &GSys, Math::VectorNd &derrSysUpd, ConstraintCache &cache, bool updateKinematics=false) override
In this function the sub vector of this constraint is inserted into the position error vector of the...
void appendConstraintAxis(const Math::SpatialVector &constraintAxis, bool positionLevelConstraint=true, bool velocityLevelConstraint=true)
RBDL_DLLAPI Matrix3d CalcBodyWorldOrientation(Model &model, const VectorNd &Q, const unsigned int body_id, bool update_kinematics)
Returns the orientation of a given body as 3x3 matrix.
Definition: Kinematics.cc:222
RBDL_DLLAPI void CalcPointJacobian6D(Model &model, const VectorNd &Q, unsigned int body_id, const Vector3d &point_position, MatrixNd &G, bool update_kinematics)
Computes a 6-D Jacobian for a point on a body.
Definition: Kinematics.cc:308
RBDL_DLLAPI Vector3d CalcBodyToBaseCoordinates(Model &model, const VectorNd &Q, unsigned int body_id, const Vector3d &point_body_coordinates, bool update_kinematics)
Returns the base coordinates of a point given in body coordinates.
Definition: Kinematics.cc:157
RBDL_DLLAPI SpatialVector CalcPointAcceleration6D(Model &model, const VectorNd &Q, const VectorNd &QDot, const VectorNd &QDDot, unsigned int body_id, const Vector3d &point_position, bool update_kinematics)
Computes linear and angular acceleration of a point on a body.
Definition: Kinematics.cc:562
RBDL_DLLAPI Math::SpatialVector CalcPointVelocity6D(Model &model, const Math::VectorNd &Q, const Math::VectorNd &QDot, unsigned int body_id, const Math::Vector3d &point_position, bool update_kinematics)
Computes angular and linear velocity of a point that is fixed on a body.
Definition: Kinematics.cc:478
SpatialMatrix crossm(const SpatialVector &v)
STL namespace.
MX_Xd_dynamic fabs(const MX_Xd_dynamic &m)
Definition: MX_Xd_utils.h:371
Math::SpatialVector svecA
Working SpatialVectors.
Definition: Constraint.h:57
Math::SpatialTransform stB
Definition: Constraint.h:60
Math::SpatialTransform stA
Working SpatialTransforms.
Definition: Constraint.h:60
Math::VectorNd vecNZeros
Here N is taken to mean the number of elements in QDot.
Definition: Constraint.h:37
Math::Matrix3d mat3A
Working Matrix3d entries.
Definition: Constraint.h:46
Compact representation of spatial transformations.
SpatialVector apply(const SpatialVector &v_sp)