NTRT Simulator
 All Classes Files Functions Variables Typedefs Friends Pages
tgLinearString.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 "Muscle2P.h"
28 #include "tgLinearString.h"
29 #include "tgModelVisitor.h"
30 #include "tgWorld.h"
31 // The C++ Standard Library
32 #include <cmath>
33 #include <deque> // For history
34 #include <iostream>
35 #include <stdexcept>
36 
37 using namespace std;
38 
39 void tgLinearString::constructorAux()
40 {
41  // Precondition
42  assert(m_pHistory != NULL);
43  prevVel = 0.0;
44  if (m_muscle == NULL)
45  {
46  throw std::invalid_argument("Pointer to Muscle2P is NULL.");
47  }
48  else if (m_config.targetVelocity < 0.0)
49  {
50  throw std::invalid_argument("Target velocity is negative.");
51  }
52  else if (m_config.maxAcc < 0.0)
53  {
54  throw std::invalid_argument("Maximum acceleration is negative.");
55  }
56  else if (m_config.minActualLength < 0.0)
57  {
58  throw std::invalid_argument("Minimum length is negative.");
59  }
60  else
61  {
62  logHistory();
63  }
64 }
66  const tgTags& tags,
67  tgBaseString::Config& config) :
68  m_muscle(muscle),
69  tgBaseString(tags, config, muscle->getRestLength(), muscle->getActualLength())
70 {
71  constructorAux();
72 
73  // Postcondition
74  assert(invariant());
75  assert(m_muscle == muscle);
76  assert(m_preferredLength == m_restLength);
77 }
78 
80  std::string space_separated_tags,
81  tgBaseString::Config& config) :
82  m_muscle(muscle),
83  tgBaseString(space_separated_tags,
84  config,
85  muscle->getRestLength(),
86  muscle->getActualLength())
87 {
88  constructorAux();
89 
90  // Postcondition
91  assert(invariant());
92  assert(m_muscle == muscle);
93  assert(m_preferredLength == m_restLength);
94 }
95 
97 {
98  //std::cout << "deleting linear string" << std::endl;
99  // Should have already torn down.
100  delete m_muscle;
101 }
102 
104 {
105  notifySetup();
106  tgModel::setup(world);
107 }
108 
110 {
111  // Do not notify teardown. The controller has already been deleted.
113 }
114 
115 void tgLinearString::step(double dt)
116 {
117  if (dt <= 0.0)
118  {
119  throw std::invalid_argument("dt is not positive.");
120  }
121  else
122  {
123  // Want to update any controls before applying forces
124  notifyStep(dt);
125  m_muscle->calculateAndApplyForce(dt);
126  logHistory();
127  tgModel::step(dt);
128  }
129 }
130 
132 {
133  r.render(*this);
134 }
135 
136 void tgLinearString::logHistory()
137 {
138  m_prevVelocity = m_muscle->getVelocity();
139 
140  if (m_config.hist)
141  {
142  m_pHistory->lastLengths.push_back(m_muscle->getActualLength());
143  m_pHistory->lastVelocities.push_back(m_muscle->getVelocity());
144  m_pHistory->dampingHistory.push_back(m_muscle->getDamping());
145  m_pHistory->restLengths.push_back(m_muscle->getRestLength());
146  m_pHistory->tensionHistory.push_back(m_muscle->getTension());
147  }
148 }
149 
150 const double tgLinearString::getStartLength() const
151 {
152  return m_startLength;
153 }
154 
155 const double tgLinearString::getCurrentLength() const
156 {
157  return m_muscle->getActualLength();
158 }
159 
160 const double tgLinearString::getTension() const
161 {
162  return m_muscle->getTension();
163 }
164 
165 const double tgLinearString::getRestLength() const
166 {
167  return m_muscle->getRestLength();
168 }
169 
170 const double tgLinearString::getVelocity() const
171 {
172  return m_muscle->getVelocity();
173 }
174 
175 void tgLinearString::setRestLength(double newLength, float dt)
176 {
177  if (newLength < 0.0)
178  {
179  throw std::invalid_argument("Rest length is negative.");
180  }
181  else
182  {
183  m_preferredLength = newLength;
184 
185  // moveMotors can change m_preferred length, so this goes here for now
186  assert(m_preferredLength == newLength);
187 
188  moveMotors(dt);
189  }
190 
191  // Postcondition
192  assert(invariant());
193 
194 }
195 
197 {
198  // @todo add functions from muscle2P Bounded
199 
200 
201  const double stiffness = m_muscle->getCoefK();
202  // @todo: write invariant that checks this;
203  assert(stiffness > 0.0);
204 
205  // Reverse the sign if restLength >= preferredLength
206  // Velocity limiter
207  double stepSize = m_config.targetVelocity * dt;
208  // Acceleration limiter
209  const double velChange = m_config.maxAcc * dt;
210  const double actualLength = m_muscle->getActualLength();
211  const double mostRecentVelocity = m_prevVelocity;
212 
213 
214  // First, change preferred length so we don't go over max tension
215  if ((actualLength - m_preferredLength) * stiffness
216  > m_config.maxTens)
217  {
218  m_preferredLength = actualLength - m_config.maxTens / stiffness;
219  }
220 
221  double diff = m_preferredLength - m_restLength;
222  const double fabsDiff = abs(diff);
223 
224  // If below actual length, don't shorten any more
225  if ((actualLength > m_config.minActualLength) ||
226  (diff > 0))
227  {
228  if (abs(diff) > stepSize)
229  {
230  //Cap Velocity
231  if (abs((diff/fabsDiff) * m_config.targetVelocity -
232  mostRecentVelocity) >
233  velChange)
234  {
235  // Cap Acceleration
236  stepSize = velChange * dt;
237  }
238  m_restLength += (diff/fabsDiff)*stepSize;
239  }
240  else
241  {
242  if (abs(diff/dt - mostRecentVelocity) > velChange)
243  {
244  // Cap Acceleration
245  if (diff != 0)
246  {
247  diff = (diff/fabsDiff) * velChange * dt;
248  }
249  else
250  {
251  // If m_prevVelocity was zero, it would be smaller than
252  // velChange. Therefore preVelocity is valid for
253  // figuring out direction
254  diff = -(mostRecentVelocity / abs(mostRecentVelocity)) *
255  velChange * dt;
256  }
257  }
258  m_restLength += diff;
259  }
260  }
261 
262  m_restLength =
263  (m_restLength > m_config.minRestLength) ? m_restLength : m_config.minRestLength;
264  #if (0)
265  std::cout << "RL: " << m_restLength << " M2P RL: " << m_muscle->getRestLength() << std::endl;
266 
267 
268  std::cout << "RL: " << m_restLength
269  << " Vel: " << (m_restLength -m_muscle->getRestLength()) / dt
270  << " prev Vel: " << prevVel
271  << " force " << (actualLength - m_restLength)*stiffness << std::endl;
272  prevVel = (m_restLength -m_muscle->getRestLength()) / dt ;
273  #endif
274  m_muscle->setRestLength(m_restLength);
275 
276 }
277 
278 void tgLinearString::tensionMinLengthController(const double targetTension,
279  float dt)
280 {
281 
282  const double stiffness = m_muscle->getCoefK();
283  // @todo: write invariant that checks this;
284  assert(stiffness > 0.0);
285 
286  const double currentTension = m_muscle->getTension();
287  const double delta = targetTension - currentTension;
288  double diff = delta/stiffness;
289  const double currentLength = m_muscle->getRestLength();
290 
291  const double newLength = m_restLength - diff;
292 
293  m_preferredLength =
294  (newLength > m_config.minRestLength) ? newLength : m_config.minRestLength;
295 #if (0)
296  std::cout << "m_preferred: " << m_preferredLength << std::endl;
297 #endif
298  moveMotors(dt);
299 }
300 
301 const tgBaseString::BaseStringHistory& tgLinearString::getHistory() const
302 {
303  return *m_pHistory;
304 }
305 
306 bool tgLinearString::invariant() const
307 {
308  return
309  (m_muscle != NULL) &&
310  (m_pHistory != NULL) &&
311  (m_config.targetVelocity >= 0.0) &&
312  (m_config.maxAcc >= 0.0) &&
313  (m_config.minActualLength >= 0.0) &&
314  (m_preferredLength >= 0.0);
315 }
virtual void teardown()
Definition: tgModel.cpp:73
virtual void setup(tgWorld &world)
Definition: tgModel.cpp:62
tgLinearString(Muscle2P *muscle, const tgTags &tags, tgBaseString::Config &config)
virtual ~tgLinearString()
double m_restLength
Definition: tgBaseString.h:233
virtual void teardown()
virtual void step(double dt)
Definition: tgModel.cpp:86
virtual void step(double dt)
double m_startLength
Definition: tgBaseString.h:240
Config m_config
Definition: tgBaseString.h:223
std::deque< double > lastLengths
Definition: tgBaseString.h:153
std::deque< double > dampingHistory
Definition: tgBaseString.h:159
std::deque< double > tensionHistory
Definition: tgBaseString.h:165
Definitions of classes Muscle2P and MuscleAnchor.
void setRestLength(double newLength, float dt)
virtual void tensionMinLengthController(const double targetTension, float dt)
virtual void setup(tgWorld &world)
virtual void render(const tgRod &rod) const
Contains the definition of interface class tgModelVisitor.
Contains the definition of class tgLinearString.
Contains the definition of class tgWorld $Id$.
virtual void moveMotors(double dt)
double m_prevVelocity
Definition: tgBaseString.h:245
BaseStringHistory *const m_pHistory
Definition: tgBaseString.h:226
virtual void onVisit(const tgModelVisitor &r) const
std::deque< double > lastVelocities
Definition: tgBaseString.h:162
virtual const double getStartLength() const
std::deque< double > restLengths
Definition: tgBaseString.h:156
void notifyStep(double dt)
Definition: tgTags.h:43