NTRT Simulator
 All Classes Files Functions Variables Typedefs Friends Pages
tgRBString.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 
28 #include "tgRBString.h"
29 #include "core/tgLinearString.h"
30 
31 #include "core/tgCast.h"
32 
33 // The C++ Standard Library
34 #include <cmath>
35 #include <stdexcept>
36 
42 {
43  throw std::invalid_argument("Failed to provide arguments to tgRBString::Config");
44 }
45 
46 tgRBString::Config::Config( std::size_t segments,
47  const tgRod::Config& rodConf,
48  const tgLinearString::Config& stringConf,
49  double minTotalLength) :
50 m_segments(segments),
51 m_rodConfig(rodConf),
52 m_stringConfig(stringConf),
53 m_minTotalLength(minTotalLength)
54 {
55 }
56 
57 // @todo consider storing other confing info as a member variable
58 tgRBString::tgRBString(const tgTags& tags,
59  tgRBString::Config& config,
60  double restLength) :
61 tgBaseString(tags, config.m_stringConfig, restLength, restLength),
62 m_config(config)
63 {
64 }
65 
66 tgRBString::tgRBString(std::string space_separated_tags,
67  tgRBString::Config& config,
68  double restLength) :
69 tgBaseString(space_separated_tags,
70  config.m_stringConfig,
71  restLength,
72  restLength),
73 m_config(config)
74 {
75 }
76 
78 {
79  // These occur after the build process
80  allSegments = tgCast::filter<tgModel, tgRod> (getDescendants());
81 
82  assert(allSegments.size() == m_config.m_segments);
83 
84  allMuscles = this->find<tgLinearString> ("muscle");
85  // Should we assert something here?
86 
87  // Consider making this an assert since tensionMinLength also
88  // Depends on it
89  if (m_config.m_segments >= 2)
90  {
91  const double musclesPerSegment = (double) allMuscles.size() /
92  (double) (m_config.m_segments - 1);
93  /* True if all muscles are homogenous, which should be true
94  * given tgRBStringInfo's use of configs. Should this include
95  * RB segment mass?
96  */
97  m_effectiveStiffness = m_config.m_stringConfig.stiffness *
98  musclesPerSegment /
99  (double) (m_config.m_segments - 1);
100  }
101  else
102  {
103  // Infinite stiffness means its a single RB, which has no tension
104  m_effectiveStiffness = 0;
105  }
106  // All the heavy lifting is done by info
107  tgModel::setup(world);
108  logHistory(0.0);
109 
110 }
111 
113 {
115 }
116 
117 void tgRBString::step(double dt)
118 {
119  if (dt <= 0.0)
120  {
121  throw std::invalid_argument("dt is not positive.");
122  }
123  else
124  {
125 
126  logHistory(dt);
127  tgModel::step(dt); // Step any children
128 
129 #if (1)
130  std::cout << "Tension: " << getTension() <<
131  " Calculated Rest: " << getRestLength() <<
132  " Actual length: " << getCurrentLength() << std::endl;
133 #endif
134  }
135 
136 }
137 
138 //Does this make myModel an observer as well??
139 void tgRBString::changeMuscles (double lengthPercent, double dt)
140 {
141  if (dt <= 0.0)
142  {
143  throw std::invalid_argument("dt is not positive.");
144  }
145  else
146  {
147  assert(lengthPercent > 0.0);
148  for( int i = 0; i < allMuscles.size(); i++){
149  const double rl = allMuscles[i]->getRestLength();
150 
151  assert(rl > 0.0);
152  #if (0)
153  std::cout << "Indiv Muscle " << rl * lengthPercent << std::endl;
154  #endif
155 
156  allMuscles[i]->setRestLength(rl * lengthPercent, dt);
157  }
158  }
159 }
160 
161 void tgRBString::moveMotors(double dt)
162 {
163  // @todo add functions from muscle2P Bounded
164 
165  // Reverse the sign if restLength >= preferredLength
166  // Velocity limiter
167  double stepSize = m_config.m_stringConfig.targetVelocity * dt;
168  // Acceleration limiter
169  const double velChange = m_config.m_stringConfig.maxAcc * dt;
170  const double actualLength = getCurrentLength();
171  const double mostRecentVelocity = m_pHistory->lastVelocities.back();
172  m_restLength = getRestLength();
173 
174  double diff = m_preferredLength - m_restLength;
175  const double fabsDiff = std::abs(diff);
176 
177  // If below actual length, don't shorten any more
178  if ((actualLength > m_config.m_stringConfig.minActualLength) ||
179  (diff > 0))
180  {
181  if (abs(diff) > stepSize)
182  {
183  //Cap Velocity
184  if (std::abs((diff/fabsDiff) * m_config.m_stringConfig.targetVelocity -
185  mostRecentVelocity) >
186  velChange)
187  {
188  // Cap Acceleration
189  stepSize = velChange * dt;
190  }
191  m_restLength += (diff/fabsDiff)*stepSize;
192  }
193  else
194  {
195  if (std::abs(diff/dt - mostRecentVelocity) > velChange)
196  {
197  // Cap Acceleration
198  if (diff != 0)
199  {
200  diff = (diff/fabsDiff) * velChange * dt;
201  }
202  else
203  {
204  // If m_prevVelocity was zero, it would be smaller than
205  // velChange. Therefore preVelocity is valid for figuring
206  // out direction
207  diff = -(mostRecentVelocity / std::abs(mostRecentVelocity)) *
208  velChange * dt;
209  }
210  }
211  m_restLength += diff;
212  }
213  }
214 
215  // Ensure we aren't going below min rest length
216  if(m_restLength >= m_config.m_stringConfig.minRestLength)
217  {
218  changeMuscles(m_restLength / getRestLength(), dt);
219  }
220 
221 }
222 
223 void tgRBString::tensionMinLengthController(const double targetTension,
224  float dt)
225 {
226  const double stiffness = m_effectiveStiffness;
227  // @todo: write invariant that checks this;
228  assert(stiffness > 0.0);
229 
230  const double currentTension = getTension();
231  const double delta = targetTension - currentTension;
232  double diff = delta / stiffness;
233  m_restLength = getRestLength();
234 
235  const double newLength = m_restLength - diff;
236 
237  m_preferredLength =
238  (newLength > m_config.m_stringConfig.minRestLength) ?
239  newLength : m_config.m_stringConfig.minRestLength;
240 #if (0)
241  std::cout << "m_preferred: " << m_preferredLength << std::endl;
242 #endif
243  moveMotors(dt);
244 }
245 
246 const double tgRBString::getStartLength() const
247 {
248  return m_pHistory->lastLengths.front();
249 }
250 
251 const double tgRBString::getCurrentLength() const
252 {
253  double currLength = 0;
254 
255  // This doesn't consider anchors
256  std::size_t n = allSegments.size() - 1;
257  for (std::size_t i = 0; i < n; i++)
258  {
259  const btVector3 rodCenterOfMass1 = allSegments[i]->centerOfMass();
260  const btVector3 rodCenterOfMass2 = allSegments[i + 1]->centerOfMass();
261 
262  currLength += (rodCenterOfMass2 - rodCenterOfMass1).length();
263  }
264 
265  // Add the distance from the COM to the ends of the rods
266  currLength += allSegments[0]->length();
267 
268  return currLength;
269 }
270 
271 const double tgRBString::getTension() const
272 {
273  const double tension = (getCurrentLength() - getRestLength())
274  * m_effectiveStiffness;
275  return (tension < 0) ? 0.0 : tension;
276 }
277 
278 
279 // How does this relate to m_restLength?
280 const double tgRBString::getRestLength() const
281 {
282  double muscleRest = 0;
283  double rodRest = 0;
284 
285  std::size_t segSize = allSegments.size();
286  for (std::size_t i = 0; i < segSize; i++)
287  {
288  rodRest += allSegments[i]->length();
289  }
290 
291  std::size_t mSize = allMuscles.size();
292  for (std::size_t i = 0; i < mSize; i++)
293  {
294  muscleRest += allMuscles[i]->getRestLength();
295  }
296 
297  // This assumes all four muscles for a given segment have the
298  // same RL, or that averaging is appropreate
299  muscleRest /= ((double) mSize / (double) (segSize - 1));
300 
301  return rodRest + muscleRest;
302 }
303 
304 const double tgRBString::getVelocity() const
305 {
306  return m_pHistory->lastVelocities.back();
307 }
308 
309 const double tgRBString::computeVelocity(const double dt) const
310 {
311  // Check to make sure we're calling this at the start of or after
312  // a log history step
313  assert (m_pHistory->lastLengths.size() == m_pHistory->lastVelocities.size());
314  double vel;
315  if (dt > 0.0)
316  {
317  vel = (getCurrentLength() - m_pHistory->lastLengths.back()) / dt;
318  }
319  else if (dt == 0.0)
320  {
321  // For zero velocity at startup.
322  vel = 0.0;
323  }
324  else
325  {
326  throw std::invalid_argument("dt is negitive.");
327  }
328  return vel;
329 }
330 
331 // Private function, dt should have already been checked
332 void tgRBString::logHistory(const double dt)
333 {
334  const double currentVelocity = computeVelocity(dt);
335  // Needed for rendering, so not optional
336  m_pHistory->lastLengths.push_back(getCurrentLength());
337  // Needed for moveMotors
338  m_pHistory->lastVelocities.push_back(currentVelocity);
339  if (m_config.m_stringConfig.hist)
340  {
341  // Damping history is difficult to compute, so we're leaving it out
342  m_pHistory->restLengths.push_back(getRestLength());
343  m_pHistory->tensionHistory.push_back(getTension());
344  }
345 }
virtual void teardown()
Definition: tgModel.cpp:73
virtual void teardown()
Definition: tgRBString.cpp:112
virtual void setup(tgWorld &world)
Definition: tgModel.cpp:62
virtual void moveMotors(double dt)
Definition: tgRBString.cpp:161
double m_restLength
Definition: tgBaseString.h:233
virtual void step(double dt)
Definition: tgModel.cpp:86
Utility class for class casting and filtering collections by type.
std::deque< double > lastLengths
Definition: tgBaseString.h:153
std::deque< double > tensionHistory
Definition: tgBaseString.h:165
virtual void setup(tgWorld &world)
Definition: tgRBString.cpp:77
virtual void step(double dt)
Definition: tgRBString.cpp:117
Contains the definition of class tgLinearString.
Contains the definition of class tgRBString. A string with small rigid bodies to create contact dynam...
BaseStringHistory *const m_pHistory
Definition: tgBaseString.h:226
std::deque< double > lastVelocities
Definition: tgBaseString.h:162
std::deque< double > restLengths
Definition: tgBaseString.h:156
Definition: tgTags.h:43
std::vector< tgModel * > getDescendants() const
Definition: tgModel.cpp:174