NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
tgBulletUnidirComprSpr.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 
27 // This module
28 #include "tgBulletUnidirComprSpr.h"
30 #include "tgCast.h"
31 // The BulletPhysics library
32 #include "BulletDynamics/Dynamics/btRigidBody.h"
33 // The C++ standard library
34 #include <iostream>
35 #include <stdexcept>
36 
44  const std::vector<tgBulletSpringCableAnchor*>& anchors,
45  bool isFreeEndAttached,
46  double coefK,
47  double coefD,
48  double restLength,
49  btVector3 * direction) :
50 tgBulletCompressionSpring(anchors, isFreeEndAttached, coefK, coefD, restLength),
51 m_direction(direction)
52 {
53  // Since tgBulletCompressionSpring takes care of everything else,
54  // just need to check that direction is valid, and then check the invariant.
55 
56  assert(invariant());
57 
58  #if (0)
59  std::cout << "tgBulletUnidirComprSpr constructor, ";
60  std::cout << "direction is: ";
61  std::cout << "(" << m_direction->x() << ",";
62  std::cout << m_direction->y() << ",";
63  std::cout << m_direction->z() << ")" << std::endl;
64  #endif
65 
66  // Check that m_direction is indeed a unit vector.
67  // A dot product with (1,1,1) should always return the scalar 1 if
68  // the vector is indeed a unit vector.
69  // @TODO: make this work with arbitrary unit vectors. Those dot products
70  // are probably not exactly 1.0, but 1.0somethingsmall.
71  double dotproduct = m_direction->dot( btVector3(1,1,1) );
72  // @TODO: Note that this should also check if the length at start is negative:
73  // this would indicate that the dotproduct must be negative.
74  if( fabs(dotproduct) != 1.0 ){
75  std::cout << "Error: m_direction is not a unit vector. Its dot product" <<
76  " with (1,1,1) is " << dotproduct << std::endl;
77  throw std::invalid_argument("Direction must be a unit vector.");
78  }
79 }
80 
81 // Destructor has to the responsibility of destroying the anchors also,
82 // as well as the btVector3 direction.
84 {
85  #if (0)
86  std::cout << "Destroying tgBulletUnidirComprSpr..." << std::endl;
87  #endif
88 }
89 
90 // The step function is what's called from other places in NTRT.
92 {
93  if (dt <= 0.0)
94  {
95  throw std::invalid_argument("dt is not positive!");
96  }
97 
99 
100  // If the spring distance has gone negative, output a scary warning.
101  // TO-DO: find a way to apply a hard stop here instead.
102  if( getCurrentSpringLength() < 0.0)
103  {
104  std::cout << "WARNING! UNIDIRECTIONAL COMPRESSION SPRING IS "
105  << "LESS THAN ZERO LENGTH. YOUR SIMULATION MAY BE INACCURATE FOR "
106  << "ANY TIMESTEPS WHEN THIS MESSAGE APPEARS. " << std::endl;
107  std::cout << "Current spring length is " << getCurrentSpringLength()
108  << std::endl << std::endl;
109 
110  /* If we wanted the simulator to completely quit instead:
111  std::cout << "Error, unidirectional compression spring length "
112  << "is negative. Length is: " << getCurrentSpringLength()
113  << std::endl;
114  throw std::runtime_error("Unidirectional compression spring has negative length, simulation stopping. Increase your stiffness coefficient.");
115  */
116  }
117 
118  assert(invariant());
119 }
120 
125 {
126  // btVector3 between the two anchors
127  const btVector3 dist =
129 
130  // Dot it with the direction of this spring, should return a double.
131  // m_direction is a pointer, so dereference first.
132  double currAnchDistAlongDir = dist.dot( (*getDirection()) );
133  return currAnchDistAlongDir;
134 }
135 
143 {
144  // initialize to the default value.
145  // if the distance between the two anchors is larger
146  // than the rest length of the spring, it means (intuitively) that
147  // one end of the spring is not touching a rigid body.
148  double springLength = getRestLength();
149 
150  // store this variable so we don't have multiple calls to the same function.
151  //double currAnchorDist = getCurrentAnchorDistance();
152  double currAnchorDistAlongDir = getCurrentAnchorDistanceAlongDirection();
153 
154  if( isFreeEndAttached() )
155  {
156  // The spring length is always the distance between anchors, projected along
157  // the direction vector.
158  springLength = currAnchorDistAlongDir;
159  }
160  else if( currAnchorDistAlongDir < getRestLength() )
161  {
162  // the spring is not attached at its free end, but is in compression,
163  // so there is a length change.
164  springLength = currAnchorDistAlongDir;
165  }
166 
167  return springLength;
168 }
169 
175 {
176  // The spring endpoint will always be the sum of the beginning point
177  // and the (spring length times the vector in the direction of the spring).
178  // Note that, by this point, it should have been checked that m_direction,
179  // which is what's returned by getDirection, is indeed a unit vector.
180  // Direction is a pointer, so it must be dereferenced first.
181  // Direction has the opposite magnitude of what unitVector woudld be in the parent
182  // class, so this is a "+" instead of a "-".
183  return anchor1->getWorldPosition() +
185 }
186 
195 {
196  // Since the getCurrentSpringLength function already includes the check
197  // against m_isFreeEndAttached, as well as a projection along m_direction,
198  double springForce = - getCoefK() * (getCurrentSpringLength() - getRestLength());
199 
200  //DEBUGGING
201  #if (0)
202  std::cout << "getCoefK: " << getCoefK() << " getCurrentSpringLength(): "
203  << getCurrentSpringLength() << " getRestLength: "
204  << getRestLength() <<std::endl;
205  #endif
206 
207  //DEBUGGING
208  if (0) {
209  std::cout << "Called getSpringForce "
210  << "inside tgBulletUnidirComprSpr" << std::endl;
211  }
212 
213  // A negative delta_X should result in a positive force.
214  // note that if m_isFreeEndAttached == false, then springForce >= 0 always,
215  // since then the calculation above will have a (restlength - restLength) term.
216  // quick check to be sure of that:
217  if( !isFreeEndAttached())
218  {
219  assert(springForce >= 0.0);
220  }
221  return springForce;
222 }
223 
230 {
231 
232  // Create variables to hold the results of these computations
233  btVector3 force(0.0, 0.0, 0.0);
234  // the following ONLY includes forces due to K, not due to damping.
235  double magnitude = getSpringForce();
236 
237  // hold this variable so we don't have to call the accessor function twice.
238  const double currLength = getCurrentSpringLength();
239 
240  // Get the unit vector for the direction of the force.
241  // This spring applies a force only along m_direction.
242  // again, it should have been checked that m_direction is a unit vector by now.
243  // Direction is a pointer, so must be dereferenced first.
244  // TO-DO: justify the "-" here. This works, not sure exactly why, but probably
245  // has to do with choice of which anchor to subtract from the other.
246  const btVector3 unitVector = - (*getDirection());
247 
248  // Calculate the damping force for this timestep.
249  // Take an approximated derivative to estimate the velocity of the
250  // tip of the compression spring:
251  const double changeInDeltaX = currLength - m_prevLength;
252  m_velocity = changeInDeltaX / dt;
253 
254  // The damping force for this timestep
255  // Like with spring force, a positive velocity should result in a
256  // force acting against the movement of the tip of the spring.
258 
259  // Debugging
260  #if (0)
261  std::cout << "tgBulletUnidirComprSpr::calculateAndApplyForce " << std::endl;
262  std::cout << "Length: " << getCurrentSpringLength() << " rl: " << getRestLength() <<std::endl;
263  std::cout << "SpringForce: " << magnitude << " DampingForce: " << m_dampingForce <<std::endl;
264  #endif
265 
266  // Add the damping force to the force from the spring.
267  magnitude += m_dampingForce;
268 
269  // Project the force into the direction of the line between the two anchors
270  force = unitVector * magnitude;
271 
272  // Store the calculated length as the previous length
273  m_prevLength = currLength;
274 
275  //Now Apply it to the connected two bodies.
276  //Note that the point of applied force on the second body is NOT the same
277  // as the location specified by getSpringEndpoint. The anchor is the point
278  // to apply the force, and getSpringEndpoint is only used for rendering
279  // purposes: it makes more sense to have the spring free end "floating in space"
280  // in the rendering.
281  btVector3 point1 = this->anchor1->getRelativePosition();
282  this->anchor1->attachedBody->activate();
283  this->anchor1->attachedBody->applyImpulse(force*dt,point1);
284 
285  btVector3 point2 = this->anchor2->getRelativePosition();
286  this->anchor2->attachedBody->activate();
287  this->anchor2->attachedBody->applyImpulse(-force*dt,point2);
288 }
289 
290 bool tgBulletUnidirComprSpr::invariant(void) const
291 {
292  // Instead of checking for less than zero length, just output a warning.
293  // @TODO: find some way of dealing with Bullet's less-than-zero-length between
294  // rigid bodies that are colliding.
295  if( (m_prevLength < 0) ) {
296  std::cout << "WARNING! UNIDIRECTIONAL COMPRESSION SPRING IS "
297  << "LESS THAN ZERO LENGTH. YOUR SIMULATION MAY BE INACCURATE FOR "
298  << "ANY TIMESTEPS WHEN THIS MESSAGE APPEARS. " << std::endl;
299  }
300  // Used to have m_prevLength >= 0.0 &&
301  return (m_coefK > 0.0 &&
302  m_coefD >= 0.0 &&
303  m_restLength >= 0.0 &&
304  anchor1 != NULL &&
305  anchor2 != NULL &&
306  m_direction != NULL &&
307  m_anchors.size() >= 2);
308 }
Definitions of class tgBulletUnidirComprSpr, a version of tgBulletCompressionSpring that only applies...
virtual const btVector3 getSpringEndpoint() const
virtual void calculateAndApplyForce(double dt)
tgBulletSpringCableAnchor *const anchor1
virtual const bool isFreeEndAttached() const
Utility class for class casting and filtering collections by type.
virtual const double getCurrentAnchorDistanceAlongDirection() const
virtual btVector3 getWorldPosition() const
tgBulletUnidirComprSpr(const std::vector< tgBulletSpringCableAnchor * > &anchors, bool isFreeEndAttached, double coefK, double coefD, double restLength, btVector3 *direction)
tgBulletSpringCableAnchor *const anchor2
virtual const double getCurrentSpringLength() const
virtual const double getSpringForce() const
std::vector< tgBulletSpringCableAnchor * > m_anchors
virtual const double getCoefK() const
Definitions of class tgBulletSpringCableAnchor, formerly muscleAnchor.
virtual const double getCoefD() const
virtual void step(double dt)
virtual const btVector3 * getDirection() const
virtual const double getRestLength() const
virtual btVector3 getRelativePosition() const