28 #include "JSONMGFeedbackControl.h"
38 #include "tgCPGMGCableControl.h"
47 #include "examples/learningSpines/tgCPGCableControl.h"
49 #include "neuralNet/Neural Network v2/neuralNetwork.h"
51 #include <json/json.h>
88 lp, hp, kt, kp, kv, def, cl, lf, hf),
89 freqFeedbackMin(ffMin),
90 freqFeedbackMax(ffMax),
91 ampFeedbackMin(afMin),
92 ampFeedbackMax(afMax),
93 phaseFeedbackMin(pfMin),
94 phaseFeedbackMax(pfMax),
107 std::string resourcePath) :
115 JSONMGFeedbackControl::~JSONMGFeedbackControl()
127 bool parsingSuccessful = reader.parse( FileHelpers::getFileString(controlFilename.c_str()), root );
128 if ( !parsingSuccessful )
131 std::cout <<
"Failed to parse configuration\n"
132 << reader.getFormattedErrorMessages();
133 throw std::invalid_argument(
"Bad filename for JSON");
137 Json::Value nodeVals = root.get(
"nodeVals",
"UTF-8");
138 Json::Value edgeVals = root.get(
"edgeVals",
"UTF-8");
140 std::cout << nodeVals << std::endl;
142 nodeVals = nodeVals.get(
"params",
"UTF-8");
143 edgeVals = edgeVals.get(
"params",
"UTF-8");
146 array_2D nodeParams = scaleNodeActions(nodeVals);
148 setupCPGs(subject, nodeParams, edgeParams);
150 Json::Value feedbackParams = root.get(
"feedbackVals",
"UTF-8");
151 feedbackParams = feedbackParams.get(
"params",
"UTF-8");
154 m_config.numStates = feedbackParams.get(
"numStates",
"UTF-8").asInt();
155 m_config.numActions = feedbackParams.get(
"numActions",
"UTF-8").asInt();
158 std::string nnFile = controlFilePath + feedbackParams.get(
"neuralFilename",
"UTF-8").asString();
160 nn =
new neuralNetwork(m_config.numStates, m_config.numStates*2, m_config.numActions);
162 nn->loadWeights(nnFile.c_str());
164 initConditions = subject.getSegmentCOM(m_config.segmentNumber);
165 for (
int i = 0; i < initConditions.size(); i++)
167 std::cout << initConditions[i] <<
" ";
169 std::cout << std::endl;
170 #ifdef LOGGING // Conditional compile for data logging
171 m_dataObserver.
onSetup(subject);
174 #if (0) // Conditional Compile for debug info
175 std::cout << *m_pCPGSys << std::endl;
184 std::vector<double> structureCOM = subject.getCOM(m_config.segmentNumber);
186 for(std::size_t i=0; i<3; i++)
188 metrics.push_back(structureCOM[i]);
193 Json::Value prevMetrics = root.get(
"metrics", Json::nullValue);
195 Json::Value subMetrics;
196 subMetrics[
"initial COM x"] = metrics[0];
197 subMetrics[
"initial COM y"] = metrics[1];
198 subMetrics[
"initial COM z"] = metrics[2];
200 prevMetrics.append(subMetrics);
201 root[
"metrics"] = prevMetrics;
204 payloadLog.open(controlFilename.c_str(),ofstream::out);
206 payloadLog << root << std::endl;
213 if (m_updateTime >= m_config.controlTime)
216 std::vector<double> desComs = getFeedback(subject);
219 std::size_t numControllers = subject.getNumberofMuslces() * 3;
221 double descendingCommand = 0.0;
222 std::vector<double> desComs (numControllers, descendingCommand);
226 m_pCPGSys->
update(desComs, m_updateTime);
228 catch (std::runtime_error& e)
235 #ifdef LOGGING // Conditional compile for data logging
236 m_dataObserver.
onStep(subject, m_updateTime);
242 double currentHeight = subject.getSegmentCOM(m_config.segmentNumber)[1];
245 if (currentHeight > m_config.maxHeight || currentHeight < m_config.minHeight)
249 throw std::runtime_error(
"Height out of range");
253 static int count = 0;
255 std::cout << m_totalTime << std::endl;
258 std::vector<double> structureCOM = subject.getCOM(m_config.segmentNumber);
259 std::cout <<
"COM: " << structureCOM[0] <<
" " << structureCOM[1] <<
" " << structureCOM[2] <<
" ";
260 std::cout << std::endl;
266 for(std::size_t i=0; i<tmpStrings.size(); i++)
268 std::cout <<
"Muscle Tension " << i <<
": " << tmpStrings[i]->getTension() << std::endl;
270 std::cout << std::endl;
272 for(std::size_t i=0; i<tmpStrings.size(); i++)
274 std::cout <<
"Muscle Length " << i <<
": " << tmpStrings[i]->getCurrentLength() << std::endl;
276 std::cout << std::endl;
292 std::vector<double> finalConditions = subject.getSegmentCOM(m_config.segmentNumber);
294 const double newX = finalConditions[0];
295 const double newZ = finalConditions[2];
296 const double oldX = initConditions[0];
297 const double oldZ = initConditions[2];
299 const double distanceMoved = sqrt((newX-oldX) * (newX-oldX) +
300 (newZ-oldZ) * (newZ-oldZ));
304 scores.push_back(-1.0);
308 scores.push_back(distanceMoved);
313 double totalEnergySpent=0;
317 for(std::size_t i=0; i<tmpStrings.size(); i++)
324 const double previousLength = stringHist.
restLengths[j-1];
325 const double currentLength = stringHist.
restLengths[j];
327 double motorSpeed = (currentLength-previousLength);
330 const double workDone = previousTension * motorSpeed;
331 totalEnergySpent += workDone;
335 scores.push_back(totalEnergySpent);
338 std::vector<double> structureCOM = subject.getCOM(m_config.segmentNumber);
340 for(std::size_t i=0; i<3; i++)
342 metrics.push_back(structureCOM[i]);
345 std::cout <<
"Dist travelled " << scores[0] << std::endl;
350 bool parsingSuccessful = reader.parse( FileHelpers::getFileString(controlFilename.c_str()), root );
351 if ( !parsingSuccessful )
354 std::cout <<
"Failed to parse configuration\n"
355 << reader.getFormattedErrorMessages();
356 throw std::invalid_argument(
"Bad filename for JSON");
359 Json::Value prevScores = root.get(
"scores", Json::nullValue);
360 Json::Value prevMetrics = root.get(
"metrics", Json::nullValue);
362 Json::Value subScores;
363 subScores[
"distance"] = scores[0];
364 subScores[
"energy"] = scores[1];
366 Json::Value subMetrics;
367 subMetrics[
"final COM x"] = metrics[0];
368 subMetrics[
"final COM y"] = metrics[1];
369 subMetrics[
"final COM z"] = metrics[2];
371 prevScores.append(subScores);
372 prevMetrics.append(subMetrics);
374 root[
"scores"] = prevScores;
375 root[
"metrics"] = prevMetrics;
378 payloadLog.open(controlFilename.c_str(),ofstream::out);
380 payloadLog << root << std::endl;
385 for(
size_t i = 0; i < m_spineControllers.size(); i++)
387 delete m_spineControllers[i];
389 m_spineControllers.clear();
392 void JSONMGFeedbackControl::setupCPGs(
BaseQuadModelLearning& subject, array_2D nodeActions, array_3D edgeActions)
397 CPGEquationsFB& m_CPGFBSys = *(tgCast::cast<CPGEquations, CPGEquationsFB>(m_pCPGSys));
399 for (std::size_t i = 0; i < spineMuscles.size(); i++)
405 spineMuscles[i]->attach(pStringControl);
410 m_spineControllers.push_back(pStringControl);
414 for (std::size_t i = 0; i < m_spineControllers.size(); i++)
417 assert(pStringInfo != NULL);
424 if (m_config.useDefault)
426 pStringInfo->setupControl(*p_ipc);
430 pStringInfo->setupControl(*p_ipc, m_config.controlLength);
436 array_2D JSONMGFeedbackControl::scaleNodeActions (Json::Value actions)
438 std::size_t numControllers = actions.size();
439 std::size_t numActions = actions[0].size();
441 array_2D nodeActions(boost::extents[numControllers][numActions]);
443 array_2D limits(boost::extents[2][numActions]);
446 assert(numActions == 5);
448 limits[0][0] = m_config.lowFreq;
449 limits[1][0] = m_config.highFreq;
450 limits[0][1] = m_config.lowAmp;
451 limits[1][1] = m_config.highAmp;
452 limits[0][2] = m_config.freqFeedbackMin;
453 limits[1][2] = m_config.freqFeedbackMax;
454 limits[0][3] = m_config.ampFeedbackMin;
455 limits[1][3] = m_config.ampFeedbackMax;
456 limits[0][4] = m_config.phaseFeedbackMin;
457 limits[1][4] = m_config.phaseFeedbackMax;
459 Json::Value::iterator nodeIt = actions.begin();
462 for( std::size_t i = 0; i < numControllers; i++)
464 Json::Value nodeParam = *nodeIt;
465 for( std::size_t j = 0; j < numActions; j++)
467 nodeActions[i][j] = ( (nodeParam.get(j, 0.0)).asDouble() *
468 (limits[1][j] - limits[0][j])) + limits[0][j];
478 (Json::Value edgeParam)
480 assert(edgeParam[0].size() == 2);
482 double lowerLimit = m_config.lowPhase;
483 double upperLimit = m_config.highPhase;
484 double range = upperLimit - lowerLimit;
486 array_3D actionList(boost::extents[m_config.theirMuscles]
487 [m_config.ourMuscles]
500 Json::Value::iterator edgeIt = edgeParam.end();
504 while(j < m_config.theirMuscles)
506 while(k < m_config.ourMuscles)
508 if (edgeIt == edgeParam.begin())
510 std::cout <<
"ran out before table populated!"
525 Json::Value edgeParam = *edgeIt;
526 assert(edgeParam.size() == 2);
528 actionList[j][k][0] = edgeParam[0].asDouble();
531 actionList[j][k][1] = edgeParam[1].asDouble() *
532 (range) + lowerLimit;
545 std::cout<<
"Params used: " << count << std::endl;
547 assert(edgeParam.begin() == edgeIt);
554 std::vector<double> feedback;
558 double *inputs =
new double[m_config.numStates];
560 std::size_t n = spineCables.size();
561 for(std::size_t i = 0; i != n; i++)
563 std::vector< std::vector<double> > actions;
566 std::vector<double > state = getCableState(cable);
569 for (std::size_t i = 0; i < state.size(); i++)
571 inputs[i]=state[i] / 2.0 + 0.5;
574 double *output =
nn->feedForwardPattern(inputs);
575 vector<double> tmpAct;
576 for(
int j=0;j<m_config.numActions;j++)
578 tmpAct.push_back(output[j]);
580 actions.push_back(tmpAct);
582 std::vector<double> cableFeedback = transformFeedbackActions(actions);
584 feedback.insert(feedback.end(), cableFeedback.begin(), cableFeedback.end());
595 std::vector<double> state;
601 const double maxTension = cable.
getConfig().maxTens;
602 state.push_back((cable.
getTension() - maxTension / 2.0) / maxTension);
607 std::vector<double> JSONMGFeedbackControl::transformFeedbackActions(std::vector< std::vector<double> >& actions)
610 std::vector<double> feedback;
613 const std::size_t numControllers = 1;
614 const std::size_t numActions = m_config.numActions;
616 assert( actions.size() == numControllers);
617 assert( actions[0].size() == numActions);
620 for( std::size_t i = 0; i < numControllers; i++)
622 for( std::size_t j = 0; j < numActions; j++)
624 feedback.push_back(actions[i][j] * 2.0 - 1.0);
Contains the definition of class ImpedanceControl. $Id$.
Definition of the tgCPGStringControl observer class.
void update(std::vector< double > &descCom, double dt)
virtual void onSetup(BaseQuadModelLearning &subject)
std::deque< double > tensionHistory
Implementing the Flemons quadruped model (roughly), but as a subclass of Brian's BaseSpineModelLearni...
virtual const double getTension() const
virtual const double getStartLength() const
void setConnectivity(const std::vector< tgCPGMGActuatorControl * > &allStrings, array_3D edgeParams)
std::deque< double > restLengths
virtual void onStep(BaseQuadModelLearning &subject, double dt)
A class to read a learning configuration from a .ini file.
virtual array_3D scaleEdgeActions(Json::Value edgeParam)
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 AnnealEvolution. Adapting NeuroEvolution to do Simulated Annealing...
Contains the definition of class tgBasicActuator.
const Config & getConfig() const
std::vector< T * > find(const tgTagSearch &tagSearch)
virtual void onStep(tgModel &model, double dt)
Definition of class CPGEquationsFB.
virtual void onSetup(tgModel &model)
virtual void onTeardown(BaseQuadModelLearning &subject)
JSONMGFeedbackControl(JSONMGFeedbackControl::Config config, std::string args, std::string resourcePath="")
virtual const double getCurrentLength() const
void assignNodeNumberFB(CPGEquationsFB &CPGSys, array_2D nodeParams)
void notifyStep(double dt)
Config(int ss, int tm, int om, int param, int segnum=6, double ct=0.1, double la=0, double ha=30, double lp=-1 *M_PI, double hp=M_PI, double kt=0.0, double kp=1000.0, double kv=100.0, bool def=true, double cl=10.0, double lf=0.0, double hf=30.0, double ffMin=0.0, double ffMax=0.0, double afMin=0.0, double afMax=0.0, double pfMin=0.0, double pfMax=0.0, double maxH=60.0, double minH=1.0)