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