NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
AppGoalTensionNNW.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 "AppGoalTensionNNW.h"
28 
29 #include "helpers/FileHelpers.h"
30 #include "tgcreator/tgUtil.h"
31 
32 #include "dev/btietz/JSONTests/tgCPGJSONLogger.h"
33 
34 #include <json/json.h>
35 
36 AppGoalTensionNNW::AppGoalTensionNNW(int argc, char** argv)
37 {
38  bSetup = false;
39  use_graphics = false;
40  add_controller = true;
41  add_blocks = false;
42  add_hills = false;
43  all_terrain = false;
44  timestep_physics = 1.0f/1000.0f;
45  timestep_graphics = 1.0f/60.0f;
46  nEpisodes = 1;
47  nSteps = 60000;
48  nSegments = 6;
49  nTypes = 3;
50 
51  startX = 0;
52  startY = 20;
53  startZ = 0;
54  startAngle = 0;
55  goalAngle = 0;
56 
57  suffix = "default";
58 
59  handleOptions(argc, argv);
60 
61  tgUtil::seedRandom();
62 }
63 
65 {
66  // First create the world
67  world = createWorld();
68 
69  // Second create the view
70  if (use_graphics)
71  view = createGraphicsView(world); // For visual experimenting on one tensegrity
72  else
73  view = createView(world); // For running multiple episodes
74 
75  // Third create the simulation
76  simulation = new tgSimulation(*view);
77 
78  // Fourth create the models with their controllers and add the models to the
79  // simulation
80 #if (0)
81  startAngle = ((rand() / (double)RAND_MAX) - 0.5) * 3.1415;
82 #endif
83  FlemonsSpineModelGoal* myModel =
84  new FlemonsSpineModelGoal(nSegments, goalAngle, startAngle);
85 
86  // Fifth create the controllers, attach to model
87  if (add_controller)
88  {
89  Json::Value root; // will contains the root value after parsing.
90  Json::Reader reader;
91 
92  std::string resourcePath = "bmirletz/TC_nn_Tension/";
93  std::string controlFilePath = FileHelpers::getResourcePath(resourcePath);
94  std::string controlFilename = controlFilePath + suffix;
95 
96  bool parsingSuccessful = reader.parse( FileHelpers::getFileString(controlFilename.c_str()), root );
97  if ( !parsingSuccessful )
98  {
99  // report to the user the failure and their locations in the document.
100  std::cout << "Failed to parse configuration\n"
101  << reader.getFormattedErrorMessages();
102  throw std::invalid_argument("Bad filename for JSON, check that resource path exists");
103  }
104  // Get the value of the member of root named 'encoding', return 'UTF-8' if there is no
105  // such member.
106  Json::Value impedenceVals = root.get("impedenceVals", "UTF-8");
107  impedenceVals = impedenceVals.get("params", "UTF-8");
108 
109  // Keep drilling if necessary
110  if (impedenceVals[0].isArray())
111  {
112  impedenceVals = impedenceVals[0];
113  }
114 
115  const double impedanceMax = 2000.0;
116 
117  const int segmentSpan = 3;
118  const int numMuscles = 8;
119  const int numParams = 2;
120  const int segNumber = 5; // For learning results
121  const double controlTime = .01;
122  const double lowPhase = -1 * M_PI;
123  const double highPhase = M_PI;
124  const double lowAmplitude = 0.0;
125  const double highAmplitude = 300.0;
126  // JSONCPP's .get really wants this to be typed...
127  int j = 0;
128  const double kt = impedanceMax * (impedenceVals.get(j, 0.0)).asDouble();
129  const double kp = impedanceMax * (impedenceVals.get(1, 0.0)).asDouble();
130  const double kv = impedanceMax * (impedenceVals.get(2, 0.0)).asDouble();
131  const bool def = true;
132 
133  // Overridden by def being true
134  const double cl = 10.0;
135  const double lf = 0.0;
136  const double hf = 30.0;
137 
138  // Feedback parameters
139  const double ffMin = -0.5;
140  const double ffMax = 10.0;
141  const double afMin = 0.0;
142  const double afMax = 200.0;
143  const double pfMin = -0.5;
144  const double pfMax = 6.28;
145  const double tensionFeedback = impedanceMax *(impedenceVals.get(3, 0.0)).asDouble();
146 
147  JSONGoalControl::Config control_config(segmentSpan,
148  numMuscles,
149  numMuscles,
150  numParams,
151  segNumber,
152  controlTime,
153  lowAmplitude,
154  highAmplitude,
155  lowPhase,
156  highPhase,
157  kt,
158  kp,
159  kv,
160  def,
161  cl,
162  lf,
163  hf,
164  ffMin,
165  ffMax,
166  afMin,
167  afMax,
168  pfMin,
169  pfMax,
170  tensionFeedback
171  );
172 
174  JSONGoalTensionNNW* const myControl =
175  new JSONGoalTensionNNW(control_config, suffix, resourcePath);
176 
177 #if (1)
178  tgCPGJSONLogger* const myLogger =
179  new tgCPGJSONLogger("logs/CPGValues.txt");
180 
181  myControl->attach(myLogger);
182 #endif
183 
184  myModel->attach(myControl);
185  }
186 
187  // Sixth add model & controller to simulation
188  simulation->addModel(myModel);
189 
190  if (add_blocks)
191  {
192  tgModel* blockField = getBlocks();
193  simulation->addObstacle(blockField);
194  }
195 
196  bSetup = true;
197  return bSetup;
198 }
199 
200 void AppGoalTensionNNW::handleOptions(int argc, char **argv)
201 {
202  // Declare the supported options.
203  po::options_description desc("Allowed options");
204  desc.add_options()
205  ("help,h", "produce help message")
206  ("graphics,G", po::value<bool>(&use_graphics), "Test using graphical view")
207  ("controller,c", po::value<bool>(&add_controller), "Attach the controller to the model.")
208  ("blocks,b", po::value<bool>(&add_blocks)->implicit_value(false), "Add a block field as obstacles.")
209  ("hills,H", po::value<bool>(&add_hills)->implicit_value(false), "Use hilly terrain.")
210  ("all_terrain,A", po::value<bool>(&all_terrain)->implicit_value(false), "Alternate through terrain types. Only works with graphics off")
211  ("phys_time,p", po::value<double>(), "Physics timestep value (Hz). Default=1000")
212  ("graph_time,g", po::value<double>(), "Graphics timestep value a.k.a. render rate (Hz). Default = 60")
213  ("episodes,e", po::value<int>(&nEpisodes), "Number of episodes to run. Default=1")
214  ("steps,s", po::value<int>(&nSteps), "Number of steps per episode to run. Default=60K (60 seconds)")
215  ("segments,S", po::value<int>(&nSegments), "Number of segments in the tensegrity spine. Default=6")
216  ("start_x,x", po::value<double>(&startX), "X Coordinate of starting position for robot. Default = 0")
217  ("start_y,y", po::value<double>(&startY), "Y Coordinate of starting position for robot. Default = 20")
218  ("start_z,z", po::value<double>(&startZ), "Z Coordinate of starting position for robot. Default = 0")
219  ("angle,a", po::value<double>(&startAngle), "Angle of starting rotation for robot. Degrees. Default = 0")
220  ("goal_angle,B", po::value<double>(&goalAngle), "Angle of starting rotation for goal box. Degrees. Default = 0")
221  ("learning_controller,l", po::value<std::string>(&suffix), "Which learned controller to write to or use. Default = default")
222  ;
223 
224  po::variables_map vm;
225  po::store(po::parse_command_line(argc, argv, desc), vm);
226 
227  if (vm.count("help"))
228  {
229  std::cout << desc << "\n";
230  exit(0);
231  }
232 
233  po::notify(vm);
234 
235  if (vm.count("phys_time"))
236  {
237  timestep_physics = 1/vm["phys_time"].as<double>();
238  std::cout << "Physics timestep set to: " << timestep_physics << " seconds.\n";
239  }
240 
241  if (vm.count("graph_time"))
242  {
243  timestep_graphics = 1/vm["graph_time"].as<double>();
244  std::cout << "Graphics timestep set to: " << timestep_graphics << " seconds.\n";
245  }
246 }
247 
248 const tgHillyGround::Config AppGoalTensionNNW::getHillyConfig()
249 {
250  btVector3 eulerAngles = btVector3(0.0, 0.0, 0.0);
251  btScalar friction = 0.5;
252  btScalar restitution = 0.0;
253  // Size doesn't affect hilly terrain
254  btVector3 size = btVector3(0.0, 0.1, 0.0);
255  btVector3 origin = btVector3(0.0, 0.0, 0.0);
256  size_t nx = 240;
257  size_t ny = 240;
258  double margin = 0.5;
259  double triangleSize = 4.0;
260  double waveHeight = 2.0;
261  double offset = 0.0;
262  const tgHillyGround::Config hillGroundConfig(eulerAngles, friction, restitution,
263  size, origin, nx, ny, margin, triangleSize,
264  waveHeight, offset);
265  return hillGroundConfig;
266 }
267 
268 const tgBoxGround::Config AppGoalTensionNNW::getBoxConfig()
269 {
270  const double yaw = 0.0;
271  const double pitch = 0.0;
272  const double roll = 0.0;
273  const double friction = 0.5;
274  const double restitution = 0.0;
275  const btVector3 size(1000.0, 1.5, 1000.0);
276 
277  const tgBoxGround::Config groundConfig(btVector3(yaw, pitch, roll),
278  friction,
279  restitution,
280  size );
281 
282  return groundConfig;
283 }
284 
285 tgModel* AppGoalTensionNNW::getBlocks()
286 {
287  // Room to add a config
288  tgBlockField* myObstacle = new tgBlockField();
289  return myObstacle;
290 }
291 
292 tgWorld* AppGoalTensionNNW::createWorld()
293 {
294  const tgWorld::Config config(
295  981 // gravity, cm/sec^2
296  );
297 
298  tgBulletGround* ground;
299 
300  if (add_hills)
301  {
302  const tgHillyGround::Config hillGroundConfig = getHillyConfig();
303  ground = new tgHillyGround(hillGroundConfig);
304  }
305  else
306  {
307  const tgBoxGround::Config groundConfig = getBoxConfig();
308  ground = new tgBoxGround(groundConfig);
309  }
310 
311  return new tgWorld(config, ground);
312 }
313 
314 tgSimViewGraphics *AppGoalTensionNNW::createGraphicsView(tgWorld *world)
315 {
316  return new tgSimViewGraphics(*world, timestep_physics, timestep_graphics);
317 }
318 
319 tgSimView *AppGoalTensionNNW::createView(tgWorld *world)
320 {
321  return new tgSimView(*world, timestep_physics, timestep_graphics);
322 }
323 
325 {
326  if (!bSetup)
327  {
328  setup();
329  }
330 
331  if (use_graphics)
332  {
333  // Run until the user stops
334  simulation->run();
335  }
336  else
337  {
338  // or run for a specific number of steps
339  simulate(simulation);
340  }
341 
343  delete simulation;
344  delete view;
345  delete world;
346 
347  return true;
348 }
349 
350 void AppGoalTensionNNW::simulate(tgSimulation *simulation)
351 {
352  for (int i=0; i<nEpisodes; i++) {
353  fprintf(stderr,"Episode %d\n", i);
354  try
355  {
356  simulation->run(nSteps);
357  }
358  catch (std::runtime_error e)
359  {
360  // Nothing to do here, score will be set to -1
361  }
362 
363  // Don't change the terrain before the last episode to avoid leaks
364  if (i != nEpisodes - 1)
365  {
366 
367  if (all_terrain)
368  {
369  // Next run has Hills
370  if (i % nTypes == 0)
371  {
372 
373  const tgHillyGround::Config hillGroundConfig = getHillyConfig();
374  tgBulletGround* ground = new tgHillyGround(hillGroundConfig);
375  simulation->reset(ground);
376  }
377  // Flat
378  else if (i % nTypes == 1)
379  {
380  const tgBoxGround::Config groundConfig = getBoxConfig();
381  tgBulletGround* ground = new tgBoxGround(groundConfig);
382  simulation->reset(ground);
383  }
384  // Flat with blocks
385  else if (i % nTypes == 2)
386  {
387  simulation->reset();
388  tgModel* obstacle = getBlocks();
389  simulation->addObstacle(obstacle);
390  }
391  }
392  else if(add_blocks)
393  {
394  simulation->reset();
395  tgModel* obstacle = getBlocks();
396  simulation->addObstacle(obstacle);
397  }
398  // Avoid resetting twice on the last run
399  else
400  {
401  simulation->reset();
402  }
403  }
404  }
405 }
406 
413 int main(int argc, char** argv)
414 {
415  std::cout << "AppGoalTensionNNW" << std::endl;
416  AppGoalTensionNNW app (argc, argv);
417 
418  if (app.setup())
419  app.run();
420 
421  //Teardown is handled by delete, so that should be automatic
422  return 0;
423 }
424 
void addObstacle(tgModel *pObstacle)
int main(int argc, char **argv)
void addModel(tgModel *pModel)
A series of functions to assist with file input/output.
static std::string getResourcePath(std::string relPath)
Definition: FileHelpers.cpp:40
void run() const
Rand seeding simular to the evolution and terrain classes.
void attach(tgObserver< T > *pObserver)
Definition: tgSubject.h:91