NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
JSONGoalTensionNNW.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 #include "JSONGoalTensionNNW.h"
28 
29 
30 // Should include tgString, but compiler complains since its been
31 // included from BaseSpineModelLearning. Perhaps we should move things
32 // to a cpp over there
34 #include "core/tgBasicActuator.h"
37 #include "examples/learningSpines/tgCPGCableControl.h"
38 #include "examples/learningSpines/tgSCASineControl.h"
39 
42 #include "helpers/FileHelpers.h"
43 
44 #include "util/CPGEquationsFB.h"
45 #include "examples/learningSpines/tgCPGCableControl.h"
46 
47 #include "neuralNet/Neural Network v2/neuralNetwork.h"
48 
49 #include <json/json.h>
50 
51 #include <string>
52 #include <iostream>
53 #include <vector>
54 
55 //#define LOGGING
56 #define USE_KINEMATIC
57 
58 using namespace std;
59 
66  std::string args,
67  std::string resourcePath) :
68 JSONGoalControl(config, args, resourcePath)
69 {
70  // Path and filename handled by base class
71 
72 }
73 
74 JSONGoalTensionNNW::~JSONGoalTensionNNW()
75 {
76 }
77 
79 {
80  m_totalTime = 0;
81  m_pCPGSys = new CPGEquationsFB(200);
82 
83  Json::Value root; // will contains the root value after parsing.
84  Json::Reader reader;
85 
86  bool parsingSuccessful = reader.parse( FileHelpers::getFileString(controlFilename.c_str()), root );
87  if ( !parsingSuccessful )
88  {
89  // report to the user the failure and their locations in the document.
90  std::cout << "Failed to parse configuration\n"
91  << reader.getFormattedErrorMessages();
92  throw std::invalid_argument("Bad filename for JSON");
93  }
94  // Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
95  // such member.
96  Json::Value nodeVals = root.get("nodeVals", "UTF-8");
97  Json::Value edgeVals = root.get("edgeVals", "UTF-8");
98 
99  nodeVals = nodeVals.get("params", "UTF-8");
100  edgeVals = edgeVals.get("params", "UTF-8");
101 
102  array_4D edgeParams = scaleEdgeActions(edgeVals);
103  array_2D nodeParams = scaleNodeActions(nodeVals);
104 
105  setupCPGs(subject, nodeParams, edgeParams);
106 
107  Json::Value feedbackParams = root.get("feedbackVals", "UTF-8");
108  feedbackParams = feedbackParams.get("params", "UTF-8");
109 
110  // Setup neural network
111  m_config.numStates = feedbackParams.get("numStates", "UTF-8").asInt();
112  m_config.numActions = feedbackParams.get("numActions", "UTF-8").asInt();
113  m_config.numHidden = feedbackParams.get("numHidden", "UTF-8").asInt();
114 
115  std::string nnFile = controlFilePath + feedbackParams.get("neuralFilename", "UTF-8").asString();
116 
117  nn = new neuralNetwork(m_config.numStates, m_config.numHidden, m_config.numActions);
118 
119  nn->loadWeights(nnFile.c_str());
120 
121 
122  Json::Value goalParams = root.get("goalVals", "UTF-8");
123  goalParams = goalParams.get("params", "UTF-8");
124 
125  // Setup neural network
126  m_config.goalStates = goalParams.get("numStates", "UTF-8").asInt();
127  m_config.goalActions = goalParams.get("numActions", "UTF-8").asInt();
128  m_config.goalHidden = goalParams.get("numHidden", "UTF-8").asInt();
129 
130  std::string nnFile_goal = controlFilePath + goalParams.get("neuralFilename", "UTF-8").asString();
131 
132  nn_goal = new neuralNetwork(m_config.goalStates, m_config.goalHidden, m_config.goalActions);
133 
134  nn_goal->loadWeights(nnFile_goal.c_str());
135 
136  initConditions = subject.getSegmentCOM(m_config.segmentNumber);
137 #ifdef LOGGING // Conditional compile for data logging
138  m_dataObserver.onSetup(subject);
139 #endif
140 
141 #if (0) // Conditional Compile for debug info
142  std::cout << *m_pCPGSys << std::endl;
143 #endif
144  m_updateTime = 0.0;
145  bogus = false;
146 }
147 
149 {
150  m_updateTime += dt;
151  m_totalTime += dt;
152  double currentHeight = subject.getSegmentCOM(m_config.segmentNumber)[1];
153 
154  if (m_updateTime >= m_config.controlTime)
155  {
156 
157 
158 #if (1) // Goal and cable
159 
160  std::vector<double> desComs = getFeedback(subject);
161 
162  const BaseSpineModelGoal* goalSubject = tgCast::cast<BaseSpineModelLearning, BaseSpineModelGoal>(subject);
163 
164  getGoalFeedback(goalSubject);
165 
166 #else // Just goal
167  std::size_t numControllers = subject.getNumberofMuslces() * 3;
168 
169  double descendingCommand = 0.0;
170  std::vector<double> desComs (numControllers, descendingCommand);
171 
172  const BaseSpineModelGoal* goalSubject = tgCast::cast<BaseSpineModelLearning, BaseSpineModelGoal>(subject);
173 
174  getGoalFeedback(goalSubject);
175 
176 #endif
177  try
178  {
179  m_pCPGSys->update(desComs, m_updateTime);
180  }
181  catch (std::runtime_error& e)
182  {
183  // Stops the trial immediately, lets teardown know it broke
184  bogus = true;
185  throw (e);
186  }
187 
188 #ifdef LOGGING // Conditional compile for data logging
189  m_dataObserver.onStep(subject, m_updateTime);
190 #endif
191  notifyStep(m_updateTime);
192  m_updateTime = 0;
193  //std::cout << m_totalTime << " " << currentHeight<< std::endl;
194  }
195 
196 
197 #if (0)
198 
200  if (currentHeight > 25 || currentHeight < 1.0)
201  {
203  bogus = true;
204  throw std::runtime_error("Height out of range");
205  }
206 #endif
207 }
208 
210 {
211  scores.clear();
212  // @todo - check to make sure we ran for the right amount of time
213 
214  std::vector<double> finalConditions = subject.getSegmentCOM(m_config.segmentNumber);
215 
216  const double newX = finalConditions[0];
217  const double newZ = finalConditions[2];
218  const double oldX = initConditions[0];
219  const double oldZ = initConditions[2];
220 
221  const BaseSpineModelGoal* goalSubject = tgCast::cast<BaseSpineModelLearning, BaseSpineModelGoal>(subject);
222 
223  const double totalDistanceMoved = sqrt((newX-oldX) * (newX-oldX) +
224  (newZ-oldZ) * (newZ-oldZ));
225 
226  const double distanceMoved = calculateDistanceMoved(goalSubject);
227 
228  if (bogus)
229  {
230  scores.push_back(-1.0);
231  }
232  else
233  {
234  scores.push_back(distanceMoved);
235  }
236 
239  double totalEnergySpent=0;
240 
241  std::vector<tgSpringCableActuator* > tmpStrings = subject.getAllMuscles();
242 
243  for(std::size_t i=0; i<tmpStrings.size(); i++)
244  {
245  tgSpringCableActuator::SpringCableActuatorHistory stringHist = tmpStrings[i]->getHistory();
246 
247  std::size_t histSize = stringHist.tensionHistory.size();
248 
249  double dt = m_totalTime / (double)histSize;
250 
251  //std::cout << "Estimated dt: " << dt << std::endl;
252  #if (0)
253 
254  for(std::size_t j=1; j<stringHist.tensionHistory.size(); j++)
255  {
256  const double previousTension = stringHist.tensionHistory[j-1];
257  const double previousLength = stringHist.restLengths[j-1];
258  const double currentLength = stringHist.restLengths[j];
259  //TODO: examine this assumption - free spinning motor may require more power
260  double motorSpeed = (currentLength-previousLength);
261  if(motorSpeed > 0) // Vestigial code
262  motorSpeed = 0;
263  const double workDone = previousTension * motorSpeed;
264  totalEnergySpent += workDone;
265  }
266 
267  #else
268  for(std::size_t j=0; j < histSize; j++)
269  {
270  const double previousTension = stringHist.tensionHistory[j];
271  double motorSpeed = stringHist.lastVelocities[j];
272  // Integrating power over time
273  const double workDone = previousTension * motorSpeed * dt;
274  totalEnergySpent += workDone;
275  }
276  #endif
277  }
278 
279  scores.push_back(totalEnergySpent);
280 
281  std::cout << "Dist travelled towards goal " << scores[0] << " Total Distance Travelled " << totalDistanceMoved ;
282  std::cout << " Energy Spent: " << scores[1] << std::endl;
283 
284  Json::Value root; // will contains the root value after parsing.
285  Json::Reader reader;
286 
287  bool parsingSuccessful = reader.parse( FileHelpers::getFileString(controlFilename.c_str()), root );
288  if ( !parsingSuccessful )
289  {
290  // report to the user the failure and their locations in the document.
291  std::cout << "Failed to parse configuration\n"
292  << reader.getFormattedErrorMessages();
293  throw std::invalid_argument("Bad filename for JSON");
294  }
295 
296  Json::Value prevScores = root.get("scores", Json::nullValue);
297 
298  Json::Value subScores;
299  subScores["distance"] = distanceMoved;
300  subScores["energy"] = totalEnergySpent;
301 
302  prevScores.append(subScores);
303  root["scores"] = prevScores;
304 
305  ofstream payloadLog;
306  payloadLog.open(controlFilename.c_str(),ofstream::out);
307 
308  payloadLog << root << std::endl;
309 
310  delete m_pCPGSys;
311  m_pCPGSys = NULL;
312 
313  for(size_t i = 0; i < m_allControllers.size(); i++)
314  {
315  delete m_allControllers[i];
316  }
317  m_allControllers.clear();
318 
319  delete nn_goal;
320 }
321 
322 std::vector<double> JSONGoalTensionNNW::getGoalFeedback(const BaseSpineModelGoal* subject)
323 {
324  const int nSeg = subject->getSegments() - 1;
325 
326  // Only one segment has no actuators, and means we can't get heading.
327  assert(nSeg > 0);
328 
329  // Get heading and generate feedback vector
330  const btVector3 currentPosVector = subject->getSegmentCOMVector(m_config.segmentNumber);
331 
332  const btVector3 goalPosition = subject->goalBoxPosition();
333 
334  btVector3 desiredHeading = (goalPosition - currentPosVector).normalize();
335 
336  // Get current orientation
338  const btVector3 firstSegment = subject->getSegmentCOMVector(0);
339  const btVector3 secondSegment = subject->getSegmentCOMVector(1);
340 
341  btVector3 currentHeading = (firstSegment - secondSegment).normalize();
342 
343  std::vector<double> state;
344  state.push_back(desiredHeading.getX());
345  state.push_back(desiredHeading.getZ());
346  state.push_back(currentHeading.getX());
347  state.push_back(currentHeading.getZ());
348 
349  double *inputs = new double[m_config.goalStates];
350  for (std::size_t i = 0; i < state.size(); i++)
351  {
352  assert(state[i] >= -1.0 && state[i] <= 1.0);
353  // Don't scale! Sigmoid can handle this range
354  inputs[i]=state[i];
355  }
356 
357  double *output = nn_goal->feedForwardPattern(inputs);
358 
359  vector<double> actions;
360 
361 #if (0)
362  for(int j=0;j<m_config.goalActions;j++)
363  {
364  std::cout << output[j] << " ";
365  }
366  std::cout << std::endl;
367 #endif
368 
369  for(int j=0;j<m_config.goalActions;j++)
370  {
371  actions.push_back(output[j]);
372  }
373 
374  transformFeedbackActions(actions);
375 
376  assert(m_config.goalActions * nSeg == m_allControllers.size());
377 
378  // Duplicate the actions across segments
379  for (int i = 0; i != nSeg; i++)
380  {
381  for(int j=0;j<m_config.goalActions;j++)
382  {
383  m_allControllers[i * m_config.goalActions + j]->updateTensionSetpoint(actions[j] * m_config.tensFeedback + m_config.tensFeedback);
384  }
385  }
386 
387 
388 
389  return actions;
390 }
391 
Contains the definition of class ImpedanceControl. $Id$.
void update(std::vector< double > &descCom, double dt)
virtual array_4D scaleEdgeActions(Json::Value edgeParam)
virtual void onSetup(BaseSpineModelLearning &subject)
Definition of the tgCPGStringControl observer class.
A controller for the template class BaseSpineModelLearning.
Implementing the tetrahedral complex spine inspired by Tom Flemons.
JSONGoalTensionNNW(JSONGoalControl::Config config, std::string args, std::string resourcePath="")
virtual std::vector< double > getGoalFeedback(const BaseSpineModelGoal *subject)
virtual void onStep(BaseSpineModelLearning &subject, double dt)
neuralNetwork * nn
A template base class for a tensegrity spine.
Contains the definition of abstract base class tgSpringCableActuator. Assumes that the string is line...
A series of functions to assist with file input/output.
Contains the definition of class tgBasicActuator.
virtual void onStep(tgModel &model, double dt)
Definition of class CPGEquationsFB.
virtual void onSetup(tgModel &model)
void notifyStep(double dt)
virtual void onTeardown(BaseSpineModelLearning &subject)