NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
tgBulletCompressionSpring.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
30 #include "tgCast.h"
31 // The BulletPhysics library
32 #include "BulletDynamics/Dynamics/btRigidBody.h"
33 
34 #include <iostream>
35 #include <stdexcept>
36 
40 tgBulletCompressionSpring::tgBulletCompressionSpring( const std::vector<tgBulletSpringCableAnchor*>& anchors,
41  bool isFreeEndAttached,
42  double coefK,
43  double coefD,
44  double restLength) :
45 m_dampingForce(0.0),
46 m_velocity(0.0),
47 m_isFreeEndAttached(isFreeEndAttached),
48 m_coefK(coefK),
49 m_coefD(coefD),
50 m_restLength(restLength),
51 m_anchors(anchors),
52 anchor1(anchors.front()),
53 anchor2(anchors.back())
54 {
55  // There should be two anchors for a compression spring.
56  assert(m_anchors.size() == 2);
57 
58  // Constructor from tgSpringCable:
59  assert(coefK > 0.0);
60  assert(coefD >= 0.0);
61 
62  // the rest length of the spring has to be positive
63  if (m_restLength <= 0.0)
64  {
65  throw std::invalid_argument("Rest length for a compression spring must be postive.");
66  }
67 
68  // Debugging
69  #if (0)
70  btVector3 anchor1pos = anchor1->getWorldPosition();
71  btVector3 anchor2pos = anchor2->getWorldPosition();
72  std::cout << "Location of the starting and ending point of the two anchors:" << std::endl;
73  std::cout << "Anchor1: (" << anchor1pos.x() << ", ";
74  std::cout << anchor1pos.y() << ", ";
75  std::cout << anchor1pos.z() << ")" << std::endl;
76  std::cout << "Anchor2: (" << anchor2pos.x() << ", ";
77  std::cout << anchor2pos.y() << ", ";
78  std::cout << anchor2pos.z() << ")" << std::endl;
79  #endif
80 
82 
83  assert(invariant());
84 }
85 
86 // Destructor has to the responsibility of destroying the anchors also.
88 {
89  #if (0)
90  std::cout << "Destroying tgBulletCompressionSpring" << std::endl;
91  #endif
92 
93  std::size_t n = m_anchors.size();
94 
95  // Make absolutely sure these are deleted, in case we have a poorly timed reset
96  if (m_anchors[0] != anchor1)
97  {
98  delete anchor1;
99  }
100 
101  if (m_anchors[n-1] != anchor2)
102  {
103  delete anchor2;
104  }
105 
106  for (std::size_t i = 0; i < n; i++)
107  {
108  delete m_anchors[i];
109  }
110 
111 
112  m_anchors.clear();
113 }
114 
115 // The step function is what's called from other places in NTRT.
117 {
118  if (dt <= 0.0)
119  {
120  throw std::invalid_argument("dt is not positive!");
121  }
122 
124 
125  // If the spring distance has gone negative, crash the simulator on purpose.
126  // TO-DO: find a way to apply a hard stop here instead.
127  if( getCurrentSpringLength() <= 0.0)
128  {
129  throw std::runtime_error("Compression spring has negative length, simulation stopping. Increase your stiffness coefficient. TO-DO: implement a 'hard stop' inside the step method of tgBulletCompressionSpring instead of crashing the simulator.");
130  }
131 
132  assert(invariant());
133 }
134 
140 {
141  const btVector3 dist =
142  this->anchor2->getWorldPosition() - this->anchor1->getWorldPosition();
143  return dist.length();
144 }
145 
152 {
153  // initialize to the default value.
154  // If not attached, if the distance between the two anchors is larger
155  // than the rest length of the spring, it means (intuitively) that
156  // one end of the spring is not touching a rigid body.
157  double springLength = getRestLength();
158 
159  // store this variable so we don't have multiple calls to the same function.
160  double currAnchorDist = getCurrentAnchorDistance();
161 
162  if( isFreeEndAttached() )
163  {
164  // The spring length is always the distance between anchors.
165  springLength = currAnchorDist;
166  }
167  else if( currAnchorDist < getRestLength() )
168  {
169  // the spring is not attached at its free end, but is in compression,
170  // so there is a length change.
171  springLength = currAnchorDist;
172  }
173 
174  return springLength;
175 }
176 
177 
182 {
183  // Get the unit vector for the direction of the force, this is needed for
184  // applying the force to the rigid bodies.
185  const btVector3 dist =
187  // The unit vector of the direction of the force will be needed later
188  // In order to have a positive force move the two rigid bodies away
189  // from each other, this unit vector must be in the opposite direction
190  // of this calculation. Otherwise, a positive force brings them closer
191  // together. Needs a minus.
192  // note that dist.length is a scalar double.
193  const btVector3 unitVector = - dist / dist.length();
194  return unitVector;
195 }
196 
202 {
203  // The spring endpoint will always be the sum of the beginning point
204  // and the (spring length times the unit vector in the direction of the spring).
205  // Unit vector is in opposite direction here.
206  return anchor1->getWorldPosition() -
208 }
209 
218 {
219  // Since the getCurrentSpringLength function already includes the check
220  // against m_isFreeEndAttached:
221  double springForce = - getCoefK() * (getCurrentSpringLength() - getRestLength());
222 
223  // Debugging
224  #if (0)
225  std::cout << "getCoefK: " << getCoefK() << " getCurrentSpringLength(): "
226  << getCurrentSpringLength() << " getRestLength: "
227  << getRestLength() <<std::endl;
228  #endif
229 
230  // A negative delta_X should result in a positive force.
231  // note that if m_isFreeEndAttached == false, then springForce >= 0 always,
232  // since then the calculation above will have a (restlength - restLength) term.
233  // quick check to be sure of that:
234  if( !isFreeEndAttached())
235  {
236  assert(springForce >= 0.0);
237  }
238 
239  return springForce;
240 }
241 
248 {
249  // Create variables to hold the results of these computations
250  btVector3 force(0.0, 0.0, 0.0);
251  // the following ONLY includes forces due to K, not due to damping.
252  double magnitude = getSpringForce();
253 
254  // hold these variables so we don't have to call the accessor function twice.
255  const double currLength = getCurrentSpringLength();
256  const btVector3 unitVector = getAnchorDirectionUnitVector();
257 
258  // Calculate the damping force for this timestep.
259  // Take an approximated derivative to estimate the velocity of the
260  // tip of the compression spring:
261  // TO-DO: MAKE THIS A BETTER APPROXIMATION TO THE DERIVATIVE!!
262  const double changeInDeltaX = currLength - m_prevLength;
263  m_velocity = changeInDeltaX / dt;
264 
265  // The damping force for this timestep
266  // Like with spring force, a positive velocity should result in a
267  // force acting against the movement of the tip of the spring.
269 
270  // Debugging
271  #if (0)
272  std::cout << "Length: " << getCurrentSpringLength() << " rl: " << getRestLength() <<std::endl;
273  std::cout << "SpringForce: " << magnitude << " DampingForce: " << m_dampingForce <<std::endl;
274  #endif
275 
276  // Add the damping force to the force from the spring.
277  magnitude += m_dampingForce;
278 
279  // Project the force into the direction of the line between the two anchors
280  force = unitVector * magnitude;
281 
282  // Store the calculated length as the previous length
283  m_prevLength = currLength;
284 
285  //Now Apply it to the connected two bodies
286  btVector3 point1 = this->anchor1->getRelativePosition();
287  this->anchor1->attachedBody->activate();
288  this->anchor1->attachedBody->applyImpulse(force*dt,point1);
289 
290  btVector3 point2 = this->anchor2->getRelativePosition();
291  this->anchor2->attachedBody->activate();
292  this->anchor2->attachedBody->applyImpulse(-force*dt,point2);
293 }
294 
295 // returns the list of (two) anchors for this class.
296 const std::vector<const tgSpringCableAnchor*>tgBulletCompressionSpring::getAnchors() const
297 {
298  return tgCast::constFilter<tgBulletSpringCableAnchor, const tgSpringCableAnchor>(m_anchors);
299 }
300 
301 // The invariant, for checking that everything is OK.
302 bool tgBulletCompressionSpring::invariant(void) const
303 {
304  return (m_coefK > 0.0 &&
305  m_coefD >= 0.0 &&
306  m_prevLength >= 0.0 &&
307  m_restLength >= 0.0 &&
308  anchor1 != NULL &&
309  anchor2 != NULL &&
310  m_anchors.size() >= 2);
311 }
virtual const double getSpringForce() const
tgBulletSpringCableAnchor *const anchor1
virtual const bool isFreeEndAttached() const
Utility class for class casting and filtering collections by type.
tgBulletCompressionSpring(const std::vector< tgBulletSpringCableAnchor * > &anchors, bool isFreeEndAttached, double coefK, double coefD, double restLength)
virtual btVector3 getWorldPosition() const
virtual const btVector3 getSpringEndpoint() const
tgBulletSpringCableAnchor *const anchor2
Definitions of class tgBulletCompressionSpring.
std::vector< tgBulletSpringCableAnchor * > m_anchors
virtual const double getCoefK() const
Definitions of class tgBulletSpringCableAnchor, formerly muscleAnchor.
virtual const double getCurrentSpringLength() const
virtual const double getCoefD() const
virtual const std::vector< const tgSpringCableAnchor * > getAnchors() const
virtual void calculateAndApplyForce(double dt)
virtual const btVector3 getAnchorDirectionUnitVector() const
virtual const double getCurrentAnchorDistance() const
virtual const double getRestLength() const
virtual btVector3 getRelativePosition() const