NTRT Simulator
 All Classes Files Functions Variables Typedefs Friends Pages
FlemonsSpineModel.cpp
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 
19 #include "FlemonsSpineModel.h"
20 
21 #include "core/tgLinearString.h"
22 
23 #include "btBulletDynamicsCommon.h"
24 #include <iostream>
25 
26 #include "tgcreator/tgRodInfo.h"
30 #include "tgcreator/tgBuildSpec.h"
31 
32 #include "tgcreator/tgStructure.h"
34 #include "tgcreator/tgUtil.h"
35 #include "core/tgString.h"
36 
37 #include "core/tgCast.h"
38 
39 FlemonsSpineModel::FlemonsSpineModel(int segments) :
40  m_segments(segments),
41  tgModel()
42 {
43 }
44 
46 {
47  // Rod and Muscle configuration
48 
49  const double density = 4.2/300.0; // Note: This needs to be high enough or things fly apart...
50  const double radius = 0.5;
51  const tgRod::Config rodConfig(radius, density);
52 
53  tgLinearString::Config muscleConfig(1000, 10);
54 
55  // Calculations for the flemons spine model
56  double v_size = 10.0;
57 
58  // Create the tetrahedra
59  tgStructure tetra;
60 
61  tetra.addNode(0,0,0); // center
62  tetra.addNode(v_size, v_size, v_size); // front
63  tetra.addNode(v_size, -v_size, -v_size); // right
64  tetra.addNode(-v_size, v_size,-v_size); // back
65  tetra.addNode(-v_size, -v_size, v_size); // left
66 
67  tetra.addPair(0,1, "front rod");
68  tetra.addPair(0,2, "right rod");
69  tetra.addPair(0,3, "back rod");
70  tetra.addPair(0,4, "left rod");
71 
72  // Move the first one so we can create a longer snake. Or you could move the snake at the end, up to you.
73  tetra.move(btVector3(0.0,15.0,100.0));
74 
75  // Create our snake segments - these will be tgModels with
76  // tgRods as children
77  tgStructure snake;
78  btVector3 offset(0,0,-v_size * 1.15); // @todo: there seems to be an issue with Muscle2P connections if the front of a tetra is inside the next one.
79  for(int i = 0; i < m_segments; i++) {
80  // @todo: the snake is a temporary variable -- will its destructor be called? If not, where do we delete its children?
81  tgStructure* t = new tgStructure(tetra);
82  t->addTags(tgString("segment num", i + 1));
83  t->move((i + 1)*offset);
84  snake.addChild(t); // Add a child to the snake
85  }
86  //conditionally compile for debugging
87  #if (1)
88  // Add muscles that connect the segments
89  // Tag the muscles with their segment numbers so CPGs can find
90  // them.
91  std::vector<tgStructure*> children = snake.getChildren();
92  for(int i = 1; i < children.size(); i++) {
93  tgNodes n0 = children[i-1]->getNodes();
94  tgNodes n1 = children[i]->getNodes();
95  #if (0) // Conditional compile for "regular" vs "saddle joints"
96  snake.addPair(n0[1], n1[1], tgString("outer front muscle seg", i-1) + tgString(" seg", i));
97  snake.addPair(n0[2], n1[2], tgString("outer right muscle seg", i-1) + tgString(" seg", i));
98  snake.addPair(n0[3], n1[3], tgString("outer back muscle seg", i-1) + tgString(" seg", i));
99  snake.addPair(n0[4], n1[4], tgString("outer top muscle seg", i-1) + tgString(" seg", i));
100  #else
101  // @todo rename tags
102  snake.addPair(n0[4], n1[1], tgString("outer front muscle seg", i-1) + tgString(" seg", i));
103  snake.addPair(n0[1], n1[4], tgString("outer right muscle seg", i-1) + tgString(" seg", i));
104  snake.addPair(n0[2], n1[3], tgString("outer back muscle seg", i-1) + tgString(" seg", i));
105  snake.addPair(n0[3], n1[2], tgString("outer top muscle seg", i-1) + tgString(" seg", i));
106  #endif
107  snake.addPair(n0[2], n1[1], tgString("inner front muscle seg", i-1) + tgString(" seg", i));
108  snake.addPair(n0[2], n1[4], tgString("inner right muscle seg", i-1) + tgString(" seg", i));
109  snake.addPair(n0[3], n1[1], tgString("inner left muscle seg", i-1) + tgString(" seg", i));
110  snake.addPair(n0[3], n1[4], tgString("inner back muscle seg", i-1) + tgString(" seg", i));
111 
112  }
113  #endif
114  // Create the build spec that uses tags to turn the structure into a real model
115  tgBuildSpec spec;
116  spec.addBuilder("rod", new tgRodInfo(rodConfig));
117 
118  #if (1)
119  spec.addBuilder("muscle", new tgLinearStringInfo(muscleConfig));
120  #endif
121 
122  // Create your structureInfo
123  tgStructureInfo structureInfo(snake, spec);
124 
125  // Use the structureInfo to build ourselves
126  structureInfo.buildInto(*this, world);
127 
128  // We could now use tgCast::filter or similar to pull out the models (e.g. muscles) that we want to control.
129 
130  allMuscles = tgCast::filter<tgModel, tgLinearString> (getDescendants());
131 
132 
133  /*
134  // Note that tags don't need to match exactly, we could create
135  // supersets if we wanted to
136  muscleMap["inner left"] = this->find<tgLinearString>("inner left muscle");
137  muscleMap["inner right"] = this->find<tgLinearString>("inner right muscle");
138  muscleMap["inner top"] = this->find<tgLinearString>("inner top muscle");
139  muscleMap["outer left"] = this->find<tgLinearString>("outer left muscle");
140  muscleMap["outer right"] = this->find<tgLinearString>("outer right muscle");
141  muscleMap["outer top"] = this->find<tgLinearString>("outer top muscle");
142  */
143  // Debug printing
144  /*
145  std::cout << "StructureInfo:" << std::endl;
146  std::cout << structureInfo << std::endl;
147  */
148  std::cout << "Model: " << std::endl;
149  std::cout << *this << std::endl;
150 
151  // Showing the find functiont
152  std::vector<tgRod*> rodSegments = tgCast::filter<tgModel, tgRod> (getDescendants());
153  for(int i = 0; i < rodSegments.size(); i++) {
154  std::cout << "Structure: " << *(rodSegments[i]) << std::endl;
155  }
156 
157  allSegments = this->find<tgModel> ("segment");
158  for(int i = 0; i < allSegments.size(); i++) {
159  std::cout << "Segs: " << *(allSegments[i]) << std::endl;
160  }
161 
162  // Actually setup the children
163  tgModel::setup(world);
164 
165 }
166 
167 void FlemonsSpineModel::step(double dt)
168 {
169  // Notify observers (controllers) of the step so that they can take action
170  notifyStep(dt);
171 
172  // TestCode for COM
173  #if (0)
174  std::vector<double> COM = getSegmentCOM(0);
175 
176  std::cout << "X: " << COM[0] << " Y: " << COM[1] << " Z: " << COM[2]
177  <<std::endl;
178  #endif
179 
180  tgModel::step(dt); // Step any children
181 
182 }
183 
184 const std::vector<double> FlemonsSpineModel::getSegmentCOM(const int n) const
185 {
186  if(n < 0) { throw std::range_error("Negative segment number"); }
187  if(n >= m_segments) { throw std::range_error(tgString("Segment number > ", m_segments)); }
188 
189  std::vector<tgRod*> p_rods = tgCast::filter<tgModel, tgRod> (allSegments[n]->getDescendants());
190 
191  // Ensure our segments are being populated correctly
192  assert( p_rods.size() > 0);
193 
194  btVector3 segmentCenterOfMass(0, 0, 0);
195  double segmentMass = 0.0;
196  for (std::size_t i = 0; i < p_rods.size(); i++)
197  {
198  const tgRod* const pRod = p_rods[i];
199  assert(pRod != NULL);
200  const double rodMass = pRod->mass();
201  const btVector3 rodCenterOfMass = pRod->centerOfMass();
202  segmentCenterOfMass += rodCenterOfMass * rodMass;
203  segmentMass += rodMass;
204  }
205 
206  // Check to make sure the rods actually had mass
207  assert(segmentMass > 0.0);
208 
209  segmentCenterOfMass /= segmentMass;
210 
211  // Copy to the result std::vector
212  std::vector<double> result(3);
213  for (size_t i = 0; i < 3; ++i) { result[i] = segmentCenterOfMass[i]; }
214 
215  return result;
216 }
217 
218 void FlemonsSpineModel::changeMuscle (double length, double dt)
219 {
220  for( int i = 0; i < allMuscles.size(); i++){
221  allMuscles[i]->setRestLength(length, dt);
222  }
223 }
224 
virtual void setup(tgWorld &world)
const std::vector< tgStructure * > & getChildren() const
Definition: tgStructure.h:130
virtual void setup(tgWorld &world)
Definition: tgModel.cpp:62
void addChild(tgStructure *child)
Definition of class tgRodInfo.
Convenience function for combining strings with ints, mostly for naming structures.
virtual void step(double dt)
Definition: tgModel.cpp:86
Utility class for class casting and filtering collections by type.
double mass() const
Definition: tgRod.h:98
void addPair(int fromNodeIdx, int toNodeIdx, std::string tags="")
Definition: tgStructure.cpp:65
btVector3 centerOfMass() const
Definition: tgRod.cpp:97
Definition of class tgConnectorInfo.
virtual void step(double dt)
Contains the definition of class tgLinearString.
std::string tgString(std::string s, int i)
Definition: tgString.h:32
Definition of class tgStructure.
Definition of class tgStructureInfo.
Definition of class tgLinearStringInfo.
Contains the definition of class tgUtil and overloaded operator<<() free functions.
Definition of class tgBuildSpec.
Definition of class tgRigidAutoCompound.
Definition: tgRod.h:42
std::vector< tgModel * > getDescendants() const
Definition: tgModel.cpp:174
void addNode(double x, double y, double z, std::string tags="")
Definition: tgStructure.cpp:55