NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
CordeModel.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2012, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
7  * under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * http://www.apache.org/licenses/LICENSE-2.0.
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
15  * either express or implied. See the License for the specific language
16  * governing permissions and limitations under the License.
17 */
18 
26 // This module
27 #include "CordeModel.h"
28 
29 // This library
30 #include "tgcreator/tgUtil.h"
31 
32 // The C++ Standard Library
33 #include <stdexcept>
34 
35 CordeModel::Config::Config(const std::size_t res,
36  const double r, const double d,
37  const double ym, const double shm,
38  const double stm, const double csc,
39  const double gt, const double gr) :
40  resolution(res),
41  radius(r),
42  density(d),
43  YoungMod(ym),
44  ShearMod(shm),
45  StretchMod(stm),
46  ConsSpringConst(csc),
47  gammaT(gt),
48  gammaR(gr)
49 {
50  if (r <= 0.0)
51  {
52  throw std::invalid_argument("Corde string radius is not positive.");
53  }
54  else if (d <= 0.0)
55  {
56  throw std::invalid_argument("Corde String density is not positive.");
57  }
58  else if (ym < 0.0)
59  {
60  throw std::invalid_argument("String Young's Modulus is negative.");
61  }
62  else if (shm < 0.0)
63  {
64  throw std::invalid_argument("Shear Modulus is negative.");
65  }
66  else if (stm < 0.0)
67  {
68  throw std::invalid_argument("Stretch Modulus is negative.");
69  }
70  else if (csc < 0.0)
71  {
72  throw std::invalid_argument("Spring Constant is negative.");
73  }
74  else if (gt < 0.0)
75  {
76  throw std::invalid_argument("Damping Constant (position) is negative.");
77  }
78  else if (gr < 0.0)
79  {
80  throw std::invalid_argument("Damping Constant (rotation) is negative.");
81  }
82 }
83 
84 CordeModel::CordeModel(btVector3 pos1, btVector3 pos2, btQuaternion quat1, btQuaternion quat2, CordeModel::Config& Config) :
85 m_config(Config),
86  simTime(0.0)
87 {
88  computeConstants();
89 
90  btVector3 rodLength(pos2 - pos1);
91  btVector3 unitLength( rodLength / ((double) m_config.resolution - 1) );
92  btVector3 massPos(pos1);
93 
94  double unitMass = m_config.density * M_PI * pow( m_config.radius, 2) * unitLength.length();
95 
96  CordePositionElement* currentPoint = new CordePositionElement(massPos, unitMass);
97 
98  m_massPoints.push_back(currentPoint);
99 
100  std::cout << massPos << std::endl;
101  // Setup mass elements
102  for (std::size_t i = 1; i < m_config.resolution; i++)
103  {
104 
105  massPos += unitLength;
106  currentPoint = new CordePositionElement(massPos, unitMass);
107  m_massPoints.push_back(currentPoint);
108  // Introduce stretch
109  linkLengths.push_back(unitLength.length() * 1.0);
110  std::cout << massPos << " " << unitMass << std::endl;
111  }
112 
113  CordeQuaternionElement* currentAngle = new CordeQuaternionElement(quat1);
114  m_centerlines.push_back(currentAngle);
115 
116  std::size_t n = m_config.resolution - 1;
117  for (std::size_t i = 1; i < n; i++)
118  {
119  currentAngle = new CordeQuaternionElement(quat1.slerp(quat2, (double) i / (double) n) );
120  m_centerlines.push_back(currentAngle);
121  std::cout << currentAngle->q << std::endl;
122  quaternionShapes.push_back(unitLength.length());
123  }
124 
125  assert(invariant());
126 }
127 
128 CordeModel::~CordeModel()
129 {
130  for (std::size_t i = 0; i < m_massPoints.size(); i++)
131  {
132  delete m_massPoints[i];
133  }
134  for (std::size_t i = 0; i < m_centerlines.size(); i++)
135  {
136  delete m_centerlines[i];
137  }
138 }
139 
140 void CordeModel::step (btScalar dt)
141 {
142  if (dt <= 0.0)
143  {
144  throw std::invalid_argument("Timestep is not positive.");
145  }
146 
147  stepPrerequisites();
148  computeInternalForces();
149  unconstrainedMotion(dt);
150  simTime += dt;
151  if (simTime >= .01)
152  {
153  size_t n = m_massPoints.size();
154  for (std::size_t i = 0; i < n; i++)
155  {
156  std::cout << "Position " << i << " " << m_massPoints[i]->pos << std::endl
157  << "Force " << i << " " << m_massPoints[i]->force << std::endl;
158  if (i < n - 1)
159  {
160  std::cout << "Quaternion " << i << " " << m_centerlines[i]->q << std::endl
161  << "Qdot " << i << " " << m_centerlines[i]->qdot << std::endl
162  << "Force " << i << " " << m_centerlines[i]->tprime << std::endl
163  << "Torque " << i << " " << m_centerlines[i]->torques << std::endl;
164  }
165  }
166  simTime = 0.0;
167  }
168 
169  assert(invariant());
170 }
171 
172 void CordeModel::computeConstants()
173 {
174  assert(computedStiffness.empty());
175 
176  const double pir2 = M_PI * pow(m_config.radius, 2);
177 
178  computedStiffness.push_back( m_config.StretchMod * pir2);
179  computedStiffness.push_back( m_config.YoungMod * pir2 / 4.0);
180  computedStiffness.push_back( m_config.YoungMod * pir2 / 4.0);
181  computedStiffness.push_back( m_config.ShearMod * pir2 / 2.0);
182 
183  /* Could probably do this in constructor directly, but easier
184  * here since pir2 is already computed
185  */
186  computedInertia.setValue(m_config.density * pir2 / 4.0,
187  m_config.density * pir2 / 4.0,
188  m_config.density * pir2 / 2.0);
189 
190  // Can assume if one element is zero, all elements are zero and we've screwed up
191  // Should pass automatically based on exceptions in config constructor
192  assert(!computedInertia.fuzzyZero());
193 
194  inverseInertia.setValue(1.0/computedInertia[0],
195  1.0/computedInertia[1],
196  1.0/computedInertia[2]);
197 
198 }
199 
203 void CordeModel::stepPrerequisites()
204 {
205  std::size_t n = m_massPoints.size();
206  for (std::size_t i = 0; i < n - 1; i++)
207  {
208  CordePositionElement* r_0 = m_massPoints[i];
209  r_0->force.setZero();
210  }
211 
212  n = m_centerlines.size();
213  for (std::size_t i = 0; i < n - 1; i++)
214  {
215  CordeQuaternionElement* q_0 = m_centerlines[i];
216  q_0->tprime = btQuaternion(0.0, 0.0, 0.0, 0.0);
217  q_0->torques.setZero();
218  }
219 }
220 
221 void CordeModel::computeInternalForces()
222 {
223  std::size_t n = m_massPoints.size() - 1;
224 
225  // Update position elements
226  for (std::size_t i = 0; i < n; i++)
227  {
228  CordePositionElement* r_0 = m_massPoints[i];
229  CordePositionElement* r_1 = m_massPoints[i + 1];
230 
231  CordeQuaternionElement* quat_0 = m_centerlines[i];
232 
233  // Get position elements in standard variable names
234  const btScalar x1 = r_0->pos[0];
235  const btScalar y1 = r_0->pos[1];
236  const btScalar z1 = r_0->pos[2];
237 
238  const btScalar x2 = r_1->pos[0];
239  const btScalar y2 = r_1->pos[1];
240  const btScalar z2 = r_1->pos[2];
241 
242  // Same for quaternion elements
243  const btScalar q11 = quat_0->q[0];
244  const btScalar q12 = quat_0->q[1];
245  const btScalar q13 = quat_0->q[2];
246  const btScalar q14 = quat_0->q[3];
247 
248  // Setup common factors
249  const btVector3 posDiff = r_0->pos - r_1->pos;
250  const btVector3 velDiff = r_0->vel - r_1->vel;
251  const btScalar posNorm = posDiff.length();
252  const btScalar posNorm_2 = posDiff.length2();
253  const btVector3 director( (2.0 * (q11 * q13 + q12 * q14)),
254  (2.0 * (q12 * q13 - q11 * q14)),
255  ( -1.0 * q11 * q11 - q12 * q12 + q13 * q13 + q14 * q14));
256 
257  // Sum Forces, have to split it out into components due to
258  // derivatives of energy quantaties
259 
260  // Spring common
261  const btScalar spring_common = computedStiffness[0] *
262  (linkLengths[i] - posNorm) / (linkLengths[i] * posNorm);
263 
264  const btScalar diss_common = m_config.gammaT *
265  posNorm_2 * posDiff.dot(velDiff) / pow (linkLengths[i] , 5);
266 
267  /* Quaternion Constraint X */
268  const btScalar quat_cons_x = m_config.ConsSpringConst * linkLengths[i] *
269  ( director[2] * (x1 - x2) * (z1 - z2) - director[0] * ( pow( posDiff[1], 2) + pow( posDiff[2], 2) )
270  + director[1] * (x1 - x2) * (y1 - y2) ) / ( pow (posNorm, 3) );
271 
272  /* Quaternion Constraint Y */
273  const btScalar quat_cons_y = m_config.ConsSpringConst * linkLengths[i] *
274  ( -1.0 * director[2] * (y1 - y2) * (z1 - z2) + director[1] * ( pow( posDiff[0], 2) + pow( posDiff[2], 2) )
275  - director[0] * (x1 - x2) * (z1 - z2) ) / ( pow (posNorm, 3) );
276 
277  /* Quaternion Constraint Z */
278  const btScalar quat_cons_z = m_config.ConsSpringConst * linkLengths[i] *
279  ( -1.0 * director[0] * (y1 - y2) * (z1 - z2) + director[2] * ( pow( posDiff[0], 2) + pow( posDiff[1], 2) )
280  - director[1] * (x1 - x2) * (z1 - z2) ) / ( pow (posNorm, 3) );
281 
282  r_0->force[0] += -1.0 * (x1 - x2) * (spring_common + diss_common);
283 
284  r_1->force[0] += (x1 - x2) * (spring_common + diss_common);
285 
286  /* Apply Y forces */
287  r_0->force[1] += -1.0 * (y1 - y2) * (spring_common + diss_common);
288 
289  r_1->force[1] += (y1 - y2) * (spring_common + diss_common);
290 
291  /* Apply Z Forces */
292  r_0->force[2] += -1.0 * (z1 - z2) * (spring_common + diss_common);
293 
294  r_1->force[2] += (z1 - z2) * (spring_common + diss_common);
295 
296  /* Apply constraint equation with boundry conditions */
297  if (i == 0)
298  {
299  r_1->force[0] += quat_cons_x;
300 
301 
302  r_1->force[1] += quat_cons_y;
303 
304 
305  r_1->force[2] += quat_cons_z;
306  }
307  else if (i == n - 1)
308  {
309  r_0->force[0] -= quat_cons_x;
310 
311  r_0->force[1] -= quat_cons_y;
312 
313  r_0->force[2] -= quat_cons_z;
314  }
315  else
316  {
317  r_0->force[0] -= quat_cons_x;
318  r_1->force[0] += quat_cons_x;
319 
320  r_0->force[1] -= quat_cons_y;
321  r_1->force[1] += quat_cons_y;
322 
323  r_0->force[2] -= quat_cons_z;
324  r_1->force[2] += quat_cons_z;
325  }
326 
327 #if (0) // Original derivation
328  /* Torques resulting from quaternion alignment constraints */
329  quat_0->tprime[0] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
330  * ( q11 * quat_0->q.length2() + (q13 * posDiff[0] -
331  q14 * posDiff[1] - q11 * posDiff[2]) / posNorm);
332 
333  quat_0->tprime[1] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
334  * ( q12 * quat_0->q.length2() + (q14 * posDiff[0] +
335  q13 * posDiff[1] - q12 * posDiff[2]) / posNorm);
336 
337  quat_0->tprime[2] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
338  * ( q13 * quat_0->q.length2() + (q11 * posDiff[0] +
339  q12 * posDiff[1] + q13 * posDiff[2]) / posNorm);
340 
341  quat_0->tprime[3] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
342  * ( q14 * quat_0->q.length2() + (q12 * posDiff[0] -
343  q11 * posDiff[1] + q14 * posDiff[2]) / posNorm);
344 #else // quat_0->q.length2() should always be 1, but sometimes numerical precision renders it slightly greater
345  // The simulation is much more stable if we just assume its one.
346  quat_0->tprime[0] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
347  * ( q11 + (q13 * posDiff[0] -
348  q14 * posDiff[1] - q11 * posDiff[2]) / posNorm);
349 
350  quat_0->tprime[1] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
351  * ( q12 + (q14 * posDiff[0] +
352  q13 * posDiff[1] - q12 * posDiff[2]) / posNorm);
353 
354  quat_0->tprime[2] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
355  * ( q13 + (q11 * posDiff[0] +
356  q12 * posDiff[1] + q13 * posDiff[2]) / posNorm);
357 
358  quat_0->tprime[3] += 2.0 * m_config.ConsSpringConst * linkLengths[i]
359  * ( q14 + (q12 * posDiff[0] -
360  q11 * posDiff[1] + q14 * posDiff[2]) / posNorm);
361 #endif
362  }
363 
364  n = m_centerlines.size() - 1;
365 
366  // Update quaternion elements
367  for (std::size_t i = 0; i < n; i++)
368  {
369  CordeQuaternionElement* quat_0 = m_centerlines[i];
370  CordeQuaternionElement* quat_1 = m_centerlines[i + 1];
371 
372  /* Setup Variables */
373  const btScalar q11 = quat_0->q[0];
374  const btScalar q12 = quat_0->q[1];
375  const btScalar q13 = quat_0->q[2];
376  const btScalar q14 = quat_0->q[3];
377 
378  const btScalar q21 = quat_1->q[0];
379  const btScalar q22 = quat_1->q[1];
380  const btScalar q23 = quat_1->q[2];
381  const btScalar q24 = quat_1->q[3];
382 
383  const btScalar qdot11 = quat_0->qdot[0];
384  const btScalar qdot12 = quat_0->qdot[1];
385  const btScalar qdot13 = quat_0->qdot[2];
386  const btScalar qdot14 = quat_0->qdot[3];
387 
388  const btScalar qdot21 = quat_1->qdot[0];
389  const btScalar qdot22 = quat_1->qdot[1];
390  const btScalar qdot23 = quat_1->qdot[2];
391  const btScalar qdot24 = quat_1->qdot[3];
392 
393  const btScalar k1 = computedStiffness[1];
394  const btScalar k2 = computedStiffness[2];
395  const btScalar k3 = computedStiffness[3];
396 
397  /* I apologize for the mess below - the derivatives involved
398  * here do not leave a lot of common factors. If you see
399  * any nice vector operations I missed, implement them and/or
400  * let me know! _Brian
401  */
402 
403  /* Bending and torsional stiffness */
404  const btScalar stiffness_common = 4.0 / quaternionShapes[i] *
405  pow(quaternionShapes[i] - 1.0, 2);
406 
407  const btScalar q11_stiffness = stiffness_common *
408  (k1 * q24 * (q11 * q24 + q12 * q23 - q13 * q22 - q14 * q21) +
409  k2 * q23 * (q11 * q23 - q12 * q24 - q13 * q21 + q14 * q22) +
410  k3 * q22 * (q11 * q22 - q12 * q21 + q13 * q24 - q14 * q23));
411 
412  const btScalar q12_stiffness = stiffness_common *
413  (k1 * q23 * (q12 * q23 + q11 * q24 - q13 * q22 - q14 * q21) +
414  k2 * q24 * (q12 * q24 - q11 * q23 + q13 * q21 - q14 * q22) +
415  k3 * q21 * (q12 * q21 - q11 * q22 - q13 * q24 + q14 * q23));
416 
417  const btScalar q13_stiffness = stiffness_common *
418  (k1 * q22 * (q13 * q22 - q11 * q24 - q12 * q23 + q14 * q21) +
419  k2 * q21 * (q13 * q21 - q11 * q23 + q12 * q24 - q14 * q22) +
420  k3 * q24 * (q13 * q24 + q11 * q22 - q12 * q21 - q14 * q23));
421 
422  const btScalar q14_stiffness = stiffness_common *
423  (k1 * q21 * (q14 * q21 - q11 * q24 - q12 * q23 + q13 * q22) +
424  k2 * q22 * (q14 * q22 + q11 * q23 - q12 * q24 - q13 * q21) +
425  k3 * q23 * (q14 * q23 - q11 * q22 + q12 * q21 - q13 * q24));
426 
427  const btScalar q21_stiffness = stiffness_common *
428  (k1 * q14 * (q14 * q21 - q11 * q24 - q12 * q23 + q13 * q22) +
429  k2 * q13 * (q13 * q21 - q11 * q23 + q12 * q24 - q14 * q22) +
430  k3 * q12 * (q12 * q21 - q11 * q22 + q14 * q23 - q13 * q24));
431 
432  const btScalar q22_stiffness = stiffness_common *
433  (k1 * q13 * (q13 * q22 - q11 * q24 - q12 * q23 + q14 * q21) +
434  k2 * q14 * (q14 * q22 + q11 * q23 - q12 * q24 - q13 * q21) +
435  k3 * q11 * (q11 * q22 - q12 * q21 + q13 * q24 - q14 * q23));
436 
437  const btScalar q23_stiffness = stiffness_common *
438  (k1 * q12 * (q12 * q23 + q11 * q24 - q13 * q22 - q14 * q21) +
439  k2 * q11 * (q11 * q23 - q13 * q21 - q12 * q24 + q14 * q22) +
440  k3 * q14 * (q14 * q23 - q11 * q22 + q12 * q21 - q13 * q24));
441 
442  const btScalar q24_stiffness = stiffness_common *
443  (k1 * q11 * (q11 * q24 + q12 * q23 - q13 * q22 - q14 * q21) +
444  k2 * q12 * (q12 * q24 - q11 * q23 + q13 * q21 - q14 * q22) +
445  k3 * q13 * (q13 * q24 + q11 * q22 - q12 * q21 - q14 * q23));
446 
447  /* Torsional Damping */
448  const btScalar damping_common = 4.0 * m_config.gammaR / quaternionShapes[i];
449 
450  const btScalar q11_damping = damping_common *
451  (q12 * (q12 * qdot11 - q11 * qdot12 + q21 * qdot22 - q22 * qdot21 - q23 * qdot24 + q24 * qdot23) +
452  q13 * (q13 * qdot11 - q11 * qdot13 + q21 * qdot23 + q22 * qdot24 - q23 * qdot21 - q24 * qdot22) +
453  q14 * (q14 * qdot11 - q11 * qdot14 + q21 * qdot24 - q22 * qdot23 + q23 * qdot22 - q24 * qdot21));
454 
455  const btScalar q12_damping = damping_common *
456  (q11 * (q11 * qdot12 - q12 * qdot11 - q21 * qdot22 + q22 * qdot21 + q23 * qdot24 - q24 * qdot23) +
457  q13 * (q13 * qdot12 - q13 * qdot13 - q21 * qdot24 + q22 * qdot23 - q23 * qdot22 + q24 * qdot21) +
458  q14 * (q14 * qdot12 - q14 * qdot14 + q21 * qdot23 + q22 * qdot24 - q23 * qdot21 - q24 * qdot22));
459 
460  const btScalar q13_damping = damping_common *
461  (q11 * (q11 * qdot13 - q13 * qdot11 - q21 * qdot23 - q22 * qdot24 + q23 * qdot21 + q24 * qdot22) +
462  q12 * (q12 * qdot13 - q13 * qdot12 + q21 * qdot24 - q22 * qdot23 + q23 * qdot22 - q24 * qdot21) +
463  q14 * (q14 * qdot13 - q13 * qdot14 - q21 * qdot22 + q22 * qdot21 + q23 * qdot24 - q24 * qdot23));
464 
465  const btScalar q14_damping = damping_common *
466  (q11 * (q11 * qdot14 - q14 * qdot11 - q21 * qdot24 + q22 * qdot23 - q23 * qdot22 + q24 * qdot21) +
467  q12 * (q12 * qdot14 - q14 * qdot12 - q21 * qdot23 - q22 * qdot24 + q23 * qdot21 + q24 * qdot22) +
468  q13 * (q13 * qdot14 - q14 * qdot13 + q21 * qdot22 - q22 * qdot21 - q23 * qdot24 + q24 * qdot23));
469 
470  const btScalar q21_damping = damping_common *
471  (q22 * (q22 * qdot21 + q11 * qdot12 - q12 * qdot11 - q13 * qdot14 + q14 * qdot13 - q21 * qdot22) +
472  q23 * (q23 * qdot21 + q11 * qdot13 + q12 * qdot14 - q13 * qdot11 - q14 * qdot12 - q21 * qdot23) +
473  q24 * (q24 * qdot21 + q11 * qdot14 - q12 * qdot13 + q13 * qdot12 - q14 * qdot11 - q21 * qdot24));
474 
475  const btScalar q22_damping = damping_common *
476  (q21 * (q21 * qdot22 - q11 * qdot12 + q12 * qdot11 + q13 * qdot14 - q14 * qdot13 - q22 * qdot21) +
477  q23 * (q23 * qdot22 - q11 * qdot14 + q12 * qdot13 - q13 * qdot12 + q14 * qdot11 - q22 * qdot23) +
478  q24 * (q24 * qdot22 + q11 * qdot13 + q12 * qdot14 - q13 * qdot11 - q14 * qdot12 - q22 * qdot24));
479 
480  const btScalar q23_damping = damping_common *
481  (q21 * (q21 * qdot23 - q11 * qdot13 + q13 * qdot11 - q12 * qdot14 + q14 * qdot12 - q23 * qdot21) +
482  q22 * (q22 * qdot23 + q11 * qdot14 - q12 * qdot13 + q13 * qdot12 - q14 * qdot11 - q22 * qdot22) +
483  q24 * (q24 * qdot23 - q11 * qdot12 + q12 * qdot11 + q13 * qdot14 - q14 * qdot13 - q23 * qdot24));
484 
485  const btScalar q24_damping = damping_common *
486  (q21 * (q21 * qdot24 - q11 * qdot14 + q12 * qdot13 - q13 * qdot12 + q14 * qdot11 - q24 * qdot21) +
487  q22 * (q21 * qdot24 - q11 * qdot13 - q12 * qdot14 + q13 * qdot11 + q14 * qdot12 - q24 * qdot22) +
488  q23 * (q23 * qdot24 + q11 * qdot12 - q12 * qdot11 - q13 * qdot14 + q14 * qdot13 - q24 * qdot23));
489 
490  /* Apply torques */
491  quat_0->tprime[0] += q11_stiffness + q11_damping;
492 
493  quat_1->tprime[0] += q21_stiffness + q21_damping;
494 
495  quat_0->tprime[1] += q12_stiffness + q12_damping;
496 
497  quat_1->tprime[1] += q22_stiffness + q22_damping;
498 
499  quat_0->tprime[2] += q13_stiffness + q13_damping;
500 
501  quat_1->tprime[2] += q23_stiffness + q23_damping;
502 
503  quat_0->tprime[3] += q14_stiffness + q14_damping;
504 
505  quat_1->tprime[3] += q24_stiffness + q24_damping;
506 
507  }
508 }
509 
510 void CordeModel::unconstrainedMotion(double dt)
511 {
512  for (std::size_t i = 0; i < m_massPoints.size(); i++)
513  {
514  CordePositionElement* p_0 = m_massPoints[i];
515  // Velocity update - semi-implicit Euler
516  p_0->vel += dt / p_0->mass * p_0->force;
517  // Position update, uses v(t + dt)
518  p_0->pos += dt * p_0->vel;
519  }
520  for (std::size_t i = 0; i < m_centerlines.size(); i++)
521  {
522  /* Transpose quaternion torques into Euclidean torques */
523  CordeQuaternionElement* quat_0 = m_centerlines[i];
524  quat_0->transposeTorques();
525 
526  const btVector3 omega = quat_0->omega;
527  // Since I is diagonal, we can use elementwise multiplication of vectors
528  quat_0->omega += inverseInertia * (quat_0->torques -
529  omega.cross(computedInertia * omega)) * dt;
530  quat_0->updateQDot();
531  quat_0->q = (quat_0->qdot*dt + quat_0->q).normalize();
532  }
533 }
534 
535 CordeModel::CordePositionElement::CordePositionElement(btVector3 p1, double m) :
536  pos(p1),
537  vel(0.0, 0.0, 0.0),
538  force(0.0, 0.0, 0.0),
539  mass(m)
540 {
541  if (m < 0.0)
542  {
543  throw std::invalid_argument("Mass is negative.");
544  }
545 }
546 
547 CordeModel::CordeQuaternionElement::CordeQuaternionElement(btQuaternion q1) :
548  q(q1.normalize()),
549  qdot(0.0, 0.0, 0.0, 0.0),
550  tprime(0.0, 0.0, 0.0, 0.0),
551  torques(0.0, 0.0, 0.0),
552  omega(0.0, 0.0, 0.0)
553 {
554 
555 }
556 
557 void CordeModel::CordeQuaternionElement::transposeTorques()
558 {
559  torques[0] += 1.0/2.0 * (q[0] * tprime[2] - q[2] * tprime[0] - q[1] * tprime[3] + q[3] * tprime[1]);
560  torques[1] += 1.0/2.0 * (q[1] * tprime[0] - q[0] * tprime[1] - q[2] * tprime[3] + q[3] * tprime[2]);
561  torques[2] += 1.0/2.0 * (q[0] * tprime[0] + q[1] * tprime[1] + q[2] * tprime[2] + q[3] * tprime[3]);
562 }
563 
564 void CordeModel::CordeQuaternionElement::updateQDot()
565 {
566  qdot[0] = 1.0/2.0 * (q[0] * omega[2] + q[1] * omega[1] - q[2] * omega[0]);
567  qdot[1] = 1.0/2.0 * (q[1] * omega[2] - q[0] * omega[1] + q[3] * omega[0]);
568  qdot[2] = 1.0/2.0 * (q[0] * omega[0] + q[2] * omega[2] + q[3] * omega[1]);
569  qdot[3] = 1.0/2.0 * (q[3] * omega[2] - q[2] * omega[1] - q[1] * omega[0]);
570 }
571 
573 bool CordeModel::invariant()
574 {
575  return (m_massPoints.size() == m_centerlines.size() + 1)
576  && (m_centerlines.size() == linkLengths.size())
577  && (linkLengths.size() == quaternionShapes.size() + 1)
578  && (computedStiffness.size() == 4);
579 }
const double gammaT
Definition: CordeModel.h:61
Defines structure for the Corde softbody String Model.
CordeModel(btVector3 pos1, btVector3 pos2, btQuaternion quat1, btQuaternion quat2, CordeModel::Config &Config)
Definition: CordeModel.cpp:84
Rand seeding simular to the evolution and terrain classes.