Cheetah Software  1.0
test_dynamics.cpp
Go to the documentation of this file.
1 
7 #include "Dynamics/Cheetah3.h"
10 #include "Dynamics/Quadruped.h"
11 #include "Utilities/utilities.h"
12 
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 
16 using namespace spatial;
17 
18 #include <stdio.h>
19 using namespace std;
20 
26 TEST(Dynamics, cheetah3model) {
27  FloatingBaseModel<double> cheetah = buildCheetah3<double>().buildModel();
28  cheetah.check();
29 
30  // check total mass
31  EXPECT_TRUE(fpEqual(41.0737, cheetah.totalNonRotorMass(), .0001));
32  EXPECT_TRUE(fpEqual(6.3215, cheetah.totalRotorMass(), .0001));
33 
34  // check tree structure
35  std::vector<int> parentRef{0, 0, 0, 0, 0, 0, 5, 6, 7,
36  5, 9, 10, 5, 12, 13, 5, 15, 16};
37  EXPECT_TRUE(vectorEqual(parentRef, cheetah.getParentVector()));
38 
39  // this is kind of stupid, but a reasonable sanity check for inertias
40  Mat6<double> inertiaSumRef;
41  inertiaSumRef << 0.4352, -0.0000, -0.0044, 0, 0.6230, -0.0000, -0.0000,
42  1.0730, 0.0000, -0.6230, 0, -0.0822, -0.0044, 0.0000, 1.0071, 0.0000,
43  0.0822, 0, 0, -0.6230, 0.0000, 42.6540, 0, 0, 0.6230, 0, 0.0822, 0,
44  42.6540, 0, -0.0000, -0.0822, 0, 0, 0, 42.6540;
45 
46  Mat6<double> inertiaSum = Mat6<double>::Zero();
47 
48  for (size_t i = 0; i < 18; i++) {
49  inertiaSum += cheetah.getBodyInertiaVector()[i].getMatrix() +
50  cheetah.getRotorInertiaVector()[i].getMatrix() * 0.25;
51  }
52  EXPECT_TRUE(almostEqual(inertiaSum, inertiaSumRef, .0001));
53 }
54 
58 TEST(Dynamics, cheetah3ModelTransforms) {
59  FloatingBaseModel<double> cheetah = buildCheetah3<double>().buildModel();
62  for (size_t i = 0; i < 18; i++) {
63  XTotal = XTotal + cheetah._Xtree[i];
64  XRotTotal = XRotTotal + cheetah._Xrot[i];
65  }
66  Mat6<double> Xtr, Xrtr;
67  Xtr << 11.0000, 0.0000, 0, 0, 0, 0, -0.0000, 11.0000, 0, 0, 0, 0, 0, 0,
68  19.0000, 0, 0, 0, 0, -1.3680, 0, 11.0000, 0.0000, 0, 1.3680, 0, 0.0000,
69  -0.0000, 11.0000, 0, 0.0000, 0, 0, 0, 0, 19.0000;
70  Xrtr << 11.0000, 0.0000, 0, 0, 0, 0, -0.0000, 11.0000, 0, 0, 0, 0, 0, 0,
71  19.0000, 0, 0, 0, 0, 0, 0.0000, 11.0000, 0.0000, 0, 0, 0, 0, -0.0000,
72  11.0000, 0, 0, 0, 0, 0, 0, 19.0000;
73 
74  EXPECT_TRUE(almostEqual(Xtr, XTotal, .0005));
75  EXPECT_TRUE(almostEqual(Xrtr, XRotTotal, .0005));
76 }
77 
83 TEST(Dynamics, simulatorDynamicsABANoExternalForceCheetah3) {
84  FloatingBaseModel<double> cheetahModel = buildCheetah3<double>().buildModel();
85  DynamicsSimulator<double> sim(cheetahModel, true);
86 
87  RotMat<double> rBody = coordinateRotation(CoordinateAxis::X, .123) *
88  coordinateRotation(CoordinateAxis::Z, .232) *
89  coordinateRotation(CoordinateAxis::Y, .111);
90 
91  SVec<double> bodyVel;
92  bodyVel << 1, 2, 3, 4, 5, 6;
94  DVec<double> q(12);
95  DVec<double> dq(12);
96  DVec<double> tau(12);
97  for (size_t i = 0; i < 12; i++) {
98  q[i] = i + 1;
99  dq[i] = (i + 1) * 2;
100  tau[i] = (i + 1) * -30.;
101  }
102 
103  // set state
104  x.bodyOrientation = rotationMatrixToQuaternion(rBody.transpose());
105  x.bodyVelocity = bodyVel;
106  x.bodyPosition = Vec3<double>(6, 7, 8);
107  x.q = q;
108  x.qd = dq;
109 
110  // do aba
111  sim.setState(x);
112  sim.forwardKinematics();
113  sim.runABA(tau);
114 
115  // check:
116  Vec3<double> pdRef(4.3717, 4.8598, 5.8541);
117  SVec<double> vbdRef;
118  vbdRef << 455.5224, 62.1684, -70.56, -11.4505, 10.2354, -15.2394;
119 
120  DVec<double> qddRef(12);
121  qddRef << -0.7924, -0.2205, -0.9163, -1.6136, -0.4328, -1.6911, -2.9878,
122  -0.9358, -2.6194, -3.3773, -1.3235, -3.1598;
123  qddRef *= 1000;
124 
125  EXPECT_TRUE(almostEqual(pdRef, sim.getDState().dBodyPosition, .001));
126  EXPECT_TRUE(almostEqual(vbdRef, sim.getDState().dBodyVelocity, .001));
127 
128  for (size_t i = 0; i < 12; i++) {
129  // the qdd's are large - see qddRef, so we're only accurate to within ~1.
130  EXPECT_TRUE(fpEqual(sim.getDState().qdd[i], qddRef[i], 3.));
131  }
132 
133  // check the integrator for the body (orientation, position, and spatial
134  // velocity). we use a huge timestep here so that any error in the integrator
135  // isn't multiplied by something small
136  sim.integrate(2.);
137 
138  Quat<double> quat2Ref(-0.8962, -0.0994, -0.2610, -0.3446);
139  Vec3<double> x2Ref(14.7433, 16.7196, 19.7083);
140  SVec<double> v2Ref;
141  v2Ref << 912.0449, 126.3367, -138.1201, -18.9011, 25.4709, -24.4788;
142 
143  EXPECT_TRUE(almostEqual(quat2Ref, sim.getState().bodyOrientation, .0002));
144  EXPECT_TRUE(almostEqual(x2Ref, sim.getState().bodyPosition, .0002));
145  EXPECT_TRUE(almostEqual(v2Ref, sim.getState().bodyVelocity, .0002));
146 }
147 
153 TEST(Dynamics, inverseDynamicsNoContacts) {
154  FloatingBaseModel<double> cheetahModel = buildCheetah3<double>().buildModel();
155 
156  RotMat<double> rBody = coordinateRotation(CoordinateAxis::X, .123) *
157  coordinateRotation(CoordinateAxis::Z, .232) *
158  coordinateRotation(CoordinateAxis::Y, .111);
159  SVec<double> bodyVel;
160  bodyVel << 1, 2, 3, 4, 5, 6;
162  DVec<double> q(12);
163  DVec<double> dq(12);
164  DVec<double> tauref(12);
165  for (size_t i = 0; i < 12; i++) {
166  q[i] = i + 1;
167  dq[i] = (i + 1) * 2;
168  tauref[i] = (i + 1) * -30.;
169  }
170 
171  // set state
172  x.bodyOrientation = rotationMatrixToQuaternion(rBody.transpose());
173  x.bodyVelocity = bodyVel;
174  x.bodyPosition = Vec3<double>(6, 7, 8);
175  x.q = q;
176  x.qd = dq;
177  cheetahModel.setState(x);
178 
179  // Construct state derivative
180  SVec<double> vbd;
181  vbd << 455.5224, 62.1684, -70.56, -11.4505, 10.2354, -15.2394;
182 
183  DVec<double> qdd(12);
184  qdd << -0.7924, -0.2205, -0.9163, -1.6136, -0.4328, -1.6911, -2.9878, -0.9358,
185  -2.6194, -3.3773, -1.3235, -3.1598;
186  qdd *= 1000;
187 
189  dx.dBodyVelocity = vbd;
190  dx.qdd = qdd;
191 
192  // Vector form of state derivative
193  DVec<double> nu_dot(18);
194  nu_dot.head(6) = dx.dBodyVelocity;
195  nu_dot.tail(12) = qdd;
196 
197  // Components of the equations
198  DMat<double> H = cheetahModel.massMatrix();
199  DVec<double> Cqd = cheetahModel.generalizedCoriolisForce();
200  DVec<double> G = cheetahModel.generalizedGravityForce();
201 
202  // Compute ID two different ways
203  DVec<double> genForce = cheetahModel.inverseDynamics(dx);
204  DVec<double> component_ID_result = H * nu_dot + Cqd + G;
205 
206  SVec<double> zero6x1 = SVec<double>::Zero();
207  DVec<double> tauReturn = genForce.tail(12);
208  SVec<double> fReturn = genForce.head(6);
209 
210  EXPECT_TRUE(almostEqual(zero6x1, fReturn, .03));
211  EXPECT_TRUE(almostEqual(tauref, tauReturn, .01));
212  EXPECT_TRUE(almostEqual(component_ID_result, genForce, 1e-6));
213 }
214 
220 TEST(Dynamics, contactJacobians) {
221  FloatingBaseModel<double> cheetahModel = buildCheetah3<double>().buildModel();
222 
223  RotMat<double> rBody = coordinateRotation(CoordinateAxis::X, .123) *
224  coordinateRotation(CoordinateAxis::Z, .232) *
225  coordinateRotation(CoordinateAxis::Y, .111);
226  SVec<double> bodyVel;
227  bodyVel << 1, 2, 3, 4, 5, 6;
229  DVec<double> q(12);
230  DVec<double> dq(12);
231  DVec<double> tauref(12);
232  for (size_t i = 0; i < 12; i++) {
233  q[i] = i + 1;
234  dq[i] = (i + 1) * 2;
235  tauref[i] = (i + 1) * -30.;
236  }
237 
238  // set state
239  x.bodyOrientation = rotationMatrixToQuaternion(rBody.transpose());
240  x.bodyVelocity = bodyVel;
241  x.bodyPosition = Vec3<double>(6, 7, 8);
242  x.q = q;
243  x.qd = dq;
244  cheetahModel.setState(x);
245 
246  // Construct state derivative
247  SVec<double> vbd;
248  vbd << 45.5224, 62.1684, -70.56, -11.4505, 10.2354, -15.2394;
249 
250  DVec<double> qdd(12);
251  qdd << -0.7924, -0.2205, -0.9163, -1.6136, -0.4328, -1.6911, -2.9878, -0.9358,
252  -2.6194, -3.3773, -1.3235, -3.1598;
253  qdd *= 400;
254 
256  dx.dBodyVelocity = vbd;
257  dx.qdd = qdd;
258 
259  // Vector form of state derivative
260  DVec<double> nu(18), nu_dot(18);
261  nu.head(6) = x.bodyVelocity;
262  nu.tail(12) = x.qd;
263 
264  nu_dot.head(6) = dx.dBodyVelocity;
265  nu_dot.tail(12) = qdd;
266 
267  cheetahModel.contactJacobians();
268 
269  // Compute Positions
270  Vec3<double> pos0, posf, vel0, vel0_fromJ, velf, acc0, J0dqd;
271  pos0 = cheetahModel._pGC[15];
272  vel0 = cheetahModel._vGC[15];
273  D3Mat<double> J0 = cheetahModel._Jc[15];
274  vel0_fromJ = J0 * nu;
275  acc0 = J0 * nu_dot + cheetahModel._Jcdqd[15];
276 
277  double dt = 1e-9;
278 
279  // Integrate the state
281  dx.dBodyPosition = Rup.transpose() * x.bodyVelocity.tail(3);
282 
283  Vec3<double> omega0 = Rup.transpose() * x.bodyVelocity.head(3);
284  Vec3<double> axis;
285  double ang = omega0.norm();
286  axis = omega0 / ang;
287 
288  ang *= dt;
289  Vec3<double> ee = std::sin(ang / 2) * axis;
290  Quat<double> quatD(std::cos(ang / 2), ee[0], ee[1], ee[2]);
291  Quat<double> quatNew = quatProduct(quatD, x.bodyOrientation);
292  quatNew = quatNew / quatNew.norm();
293 
294  // actual integration
295  x.q += x.qd * dt;
296  x.qd += dx.qdd * dt;
297  x.bodyVelocity += dx.dBodyVelocity * dt;
298  x.bodyPosition += dx.dBodyPosition * dt;
299  x.bodyOrientation = quatNew;
300 
301  cheetahModel.setState(x);
302  cheetahModel.contactJacobians();
303 
304  // Final
305  posf = cheetahModel._pGC[15];
306  velf = cheetahModel._vGC[15];
307 
308  // Finite Difference
309  Vec3<double> vel_fd, acc_fd;
310  vel_fd = (posf - pos0) / dt;
311  acc_fd = (velf - vel0) / dt;
312 
313  EXPECT_TRUE(almostEqual(vel0, vel0_fromJ, 1e-6));
314  EXPECT_TRUE(almostEqual(vel_fd, vel0, 1e-5));
315  EXPECT_TRUE(almostEqual(acc_fd, acc0, 1e-3));
316 }
317 
324 TEST(Dynamics, simulatorDynamicsWithExternalForceCheetah3) {
325  FloatingBaseModel<double> cheetahModel = buildCheetah3<double>().buildModel();
326  DynamicsSimulator<double> sim(cheetahModel, true);
327 
328  RotMat<double> rBody = coordinateRotation(CoordinateAxis::X, .123) *
329  coordinateRotation(CoordinateAxis::Z, .232) *
330  coordinateRotation(CoordinateAxis::Y, .111);
331  SVec<double> bodyVel;
332  bodyVel << 1, 2, 3, 4, 5, 6;
334  DVec<double> q(12);
335  DVec<double> dq(12);
336  DVec<double> tau(12);
337  for (size_t i = 0; i < 12; i++) {
338  q[i] = i + 1;
339  dq[i] = (i + 1) * 2;
340  tau[i] = (i + 1) * -30.;
341  }
342 
343  // set state
344  x.bodyOrientation = rotationMatrixToQuaternion(rBody.transpose());
345  x.bodyVelocity = bodyVel;
346  x.bodyPosition = Vec3<double>(6, 7, 8);
347  x.q = q;
348  x.qd = dq;
349 
350  // generate external forces
351  vectorAligned<SVec<double>> forces(18);
352  for (size_t i = 0; i < 18; i++) {
353  for (size_t j = 0; j < 6; j++) {
354  forces[i][j] = i + j + 1;
355  }
356  }
357 
358  // do aba
359  sim.setState(x);
360  sim.setAllExternalForces(forces);
361  sim.step(0.0, tau, 5e5, 5e3);
362 
363  // check:
364  Vec3<double> pdRef(4.3717, 4.8598, 5.8541);
365  SVec<double> vbdRef;
366  vbdRef << 806.6664, 44.1266, 33.8287, -10.1360, 2.1066, 12.1677;
367 
368  DVec<double> qddRef(12);
369  qddRef << -0.5630, -0.1559, -1.0182, -0.9012, -0.3585, -1.6170, -2.0995,
370  -0.8959, -2.7325, -2.0808, -1.3134, -3.1206;
371  qddRef *= 1000;
372 
373  EXPECT_TRUE(almostEqual(pdRef, sim.getDState().dBodyPosition, .001));
374  EXPECT_TRUE(almostEqual(vbdRef, sim.getDState().dBodyVelocity, .001));
375 
376  for (size_t i = 0; i < 12; i++) {
377  // the qdd's are large - see qddRef, so we're only accurate to within ~1.
378  EXPECT_TRUE(fpEqual(sim.getDState().qdd[i], qddRef[i], 3.));
379  }
380 }
381 
387 TEST(Dynamics, simulatorFootPosVelCheetah3) {
388  FloatingBaseModel<double> cheetahModel = buildCheetah3<double>().buildModel();
389  DynamicsSimulator<double> sim(cheetahModel);
390 
391  RotMat<double> rBody = coordinateRotation(CoordinateAxis::X, .123) *
392  coordinateRotation(CoordinateAxis::Z, .232) *
393  coordinateRotation(CoordinateAxis::Y, .111);
394  SVec<double> bodyVel;
395  bodyVel << 1, 2, 3, 4, 5, 6;
397  DVec<double> q(12);
398  DVec<double> dq(12);
399  DVec<double> tau(12);
400  for (size_t i = 0; i < 12; i++) {
401  q[i] = i + 1;
402  dq[i] = (i + 1) * 2;
403  tau[i] = (i + 1) * -30.;
404  }
405 
406  // set state
407  x.bodyOrientation = rotationMatrixToQuaternion(rBody.transpose());
408  x.bodyVelocity = bodyVel;
409  x.bodyPosition = Vec3<double>(6, 7, 8);
410  x.q = q;
411  x.qd = dq;
412 
413  // generate external forces
414  vectorAligned<SVec<double>> forces(18);
415  for (size_t i = 0; i < 18; i++) {
416  for (size_t j = 0; j < 6; j++) {
417  forces[i][j] = i + j + 1;
418  }
419  }
420 
421  // fwd kin is included in this
422  sim.setState(x);
423  sim.setAllExternalForces(forces);
424  sim.step(0.0, tau, 5e5, 5e3);
425 
426  // Vec3<double> bodypRef1ML(6.25, 6.8271, 8.155);
427  Vec3<double> bodypRef1ML(6.260735, 6.812413, 8.056675);
428  Vec3<double> footpRefML(5.1594, 7.3559, 7.674);
429  // Vec3<double> bodyvRef1ML(5.1989, 5.4008, 5.1234);
430  Vec3<double> bodyvRef1ML(5.028498, 5.540016, 5.083884);
431  Vec3<double> footvRefML(-9.3258, -0.1926, 26.3323);
432 
433  // I add the body points in a different order, so comparing them is kind of
434  // annoying. this just tests one body point and one foot point.
435  EXPECT_TRUE(almostEqual(bodypRef1ML, sim.getModel()._pGC.at(2), .0005));
436  EXPECT_TRUE(almostEqual(footpRefML, sim.getModel()._pGC.at(15), .0005));
437  EXPECT_TRUE(almostEqual(bodyvRef1ML, sim.getModel()._vGC.at(2), .0005));
438  EXPECT_TRUE(almostEqual(footvRefML, sim.getModel()._vGC.at(15), .0005));
439 }
Vec3< T > bodyPosition
vector< Mat6< T >, Eigen::aligned_allocator< Mat6< T > > > _Xrot
DVec< T > inverseDynamics(const FBModelStateDerivative< T > &dState)
bool fpEqual(T a, T b, T tol)
Definition: utilities.h:15
void forwardKinematics()
Do forward kinematics for feet.
SVec< T > bodyVelocity
Mat3< T > coordinateRotation(CoordinateAxis axis, T theta)
typename Eigen::Matrix< T, 6, 6 > Mat6
Definition: cppTypes.h:70
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Vec3< T > dBodyPosition
typename Eigen::Matrix< T, 3, 3 > Mat3
Definition: cppTypes.h:54
DVec< T > generalizedCoriolisForce()
Data structure containing parameters for quadruped robot.
typename Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > DMat
Definition: cppTypes.h:106
const std::vector< int > & getParentVector()
Utility function to build a Cheetah 3 Quadruped object.
typename Eigen::Matrix< T, 4, 1 > Quat
Definition: cppTypes.h:58
vectorAligned< Vec3< T > > _Jcdqd
vector< Mat6< T >, Eigen::aligned_allocator< Mat6< T > > > _Xtree
typename Eigen::Matrix< T, 3, 1 > Vec3
Definition: cppTypes.h:26
void integrate(T dt)
Integrate to find new _state.
const std::vector< SpatialInertia< T >, Eigen::aligned_allocator< SpatialInertia< T > > > & getBodyInertiaVector()
vector< Vec3< T > > _vGC
void setState(const FBModelState< T > &state)
TEST(Dynamics, cheetah3model)
typename Eigen::Matrix< T, 3, Eigen::Dynamic > D3Mat
Definition: cppTypes.h:114
typename Eigen::Matrix< T, 6, 1 > SVec
Definition: cppTypes.h:62
const std::vector< SpatialInertia< T >, Eigen::aligned_allocator< SpatialInertia< T > > > & getRotorInertiaVector()
void setAllExternalForces(const vectorAligned< SVec< T >> &forces)
Quat< typename T::Scalar > rotationMatrixToQuaternion(const Eigen::MatrixBase< T > &r1)
Quat< typename T::Scalar > quatProduct(const Eigen::MatrixBase< T > &q1, const Eigen::MatrixBase< T > &q2)
bool almostEqual(const Eigen::MatrixBase< T > &a, const Eigen::MatrixBase< T > &b, T2 tol)
Definition: MathUtilities.h:23
void step(T dt, const DVec< T > &tau, T kp, T kd)
Initialize simulator with given model.
void runABA(const DVec< T > &tau)
Simulate forward one step.
bool vectorEqual(const std::vector< T > &a, const std::vector< T > &b)
Definition: utilities.h:23
const FBModelState< T > & getState() const
void setState(const FBModelState< T > &state)
typename std::vector< T, Eigen::aligned_allocator< T >> vectorAligned
Definition: cppTypes.h:118
vector< Vec3< T > > _pGC
const FBModelStateDerivative< T > & getDState() const
typename Eigen::Matrix< T, Eigen::Dynamic, 1 > DVec
Definition: cppTypes.h:102
vectorAligned< D3Mat< T > > _Jc
Rigid Body Dynamics Simulator with Collisions.
Mat3< typename T::Scalar > quaternionToRotationMatrix(const Eigen::MatrixBase< T > &q)
const FloatingBaseModel< T > & getModel()
DVec< T > generalizedGravityForce()
typename Eigen::Matrix< T, 3, 3 > RotMat
Definition: cppTypes.h:18
Implementation of Rigid Body Floating Base model data structure.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Quat< T > bodyOrientation