evorobotexperiment.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
5  * Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it> *
6  * Gianluca Massera <emmegian@yahoo.it> *
7  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the Free Software *
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
22  ********************************************************************************/
23 
24 #include "evorobotexperiment.h"
25 #include "sensors.h"
26 #include "motors.h"
27 #include "evoga.h"
28 #include "configurationhelper.h"
29 #include "factory.h"
30 #include "logger.h"
31 #include "simpletimer.h"
32 
33 #include <QFile>
34 #include <QTextStream>
35 #include <QString>
36 #include <QTime>
37 #include <QThread>
38 #include <iostream>
39 #include <cstdlib>
40 
41 // All the suff below is to avoid warnings on Windows about the use of unsafe
42 // functions. This should be only a temporary workaround, the solution is stop
43 // using C string and file functions...
44 #if defined(_MSC_VER)
45  #pragma warning(push)
46  #pragma warning(disable:4996)
47 #endif
48 
49 namespace farsa {
50 
51 /*
52  * Experiment constructor
53  */
55  : ntrials(1)
56  , nsteps(1)
57  , nstep(0)
58  , ntrial(0)
59  , savedConfigurationParameters(NULL)
60  , savedPrefix(NULL)
61  , ga(NULL)
62  , world(NULL)
63  , timestep(0.05f)
64  , eagents()
65  , agentIdSelected(0)
66  , gaPhase(NONE)
67  , stopCurrentTrial(false)
68  , skipCurrentTrial(false)
69  , restartCurrentTrial(false)
70  , endCurrentIndividualLife(false)
71  , batchRunning(false)
72  , arena(NULL)
73  , stepDelay(timestep*1000)
74 {
75  // Stating which resources we use here. This is here in the constructor so that we are sure to
76  // be the first to declare resources (if we did this later we should have used addUsableResources
77  // because child classes could declare they will use resources before us)
78  usableResources( QStringList() << "world" << "arena" << "experiment" << "robot" << "evonet" << "neuronsIterator" );
79 }
80 
82 {
83  // Removing resources
84  try {
85  deleteResource("experiment");
86  deleteResource("arena");
87  deleteResource("world");
88  deleteResource("robot");
89  deleteResource("evonet");
90  deleteResource("neuronsIterator");
91  } catch (...) {
92  // Doing nothing, this is here just to prevent throwing an exception from the destructor
93  }
94 
95  foreach( EmbodiedAgent* agent, eagents ) {
96  delete agent;
97  }
98 
99  delete savedConfigurationParameters;
100  delete savedPrefix;
101  delete arena;
102  delete world;
103 }
104 
106 {
107  // Saving configuration parameters and prefix for cloning
108  delete savedConfigurationParameters;
109  delete savedPrefix;
110  savedConfigurationParameters = new ConfigurationParameters(params);
111  savedConfigurationParameters->shareObserversWith(params);
112  savedPrefix = new QString(prefix);
113  // Setting ourself as resource manager in the configuration parameters object
114  params.setResourcesUser(this);
115  savedConfigurationParameters->setResourcesUser(this);
116 
117  ntrials = 1;
118  nsteps = 1;
119 
120  batchRunning = ConfigurationHelper::getBool(params, "__INTERNAL__/BatchRunning", batchRunning); // If we are running in batch or not
121  ntrials = ConfigurationHelper::getInt(params, prefix + "ntrials", ntrials); // number of trials to do
122  notifyChangesToParam( "ntrials" );
123  nsteps = ConfigurationHelper::getInt(params, prefix + "nsteps", nsteps); // number of step for each trial
124 
125  // Reading world parameters. We need to do this before calling recreateWorld because that function uses the parameters
126  timestep = ConfigurationHelper::getDouble(params, prefix + "World/timestep", timestep);
127  // initializing the stepDelay at the same amount of timestep
128  // will slow down the simulation at real-time pace when the GUI is on
129  stepDelay = timestep*1000;
130 
131  // create a World by default in order to exit from here with all configured properly
132  // if they are already created it will not destroy and recreate
133  recreateWorld();
134  // Creates the arena (if the group Arena is present)
135  recreateArena();
136  // Creates the Embodied Agents
137  // number of agents to create
138  int nagents = ConfigurationHelper::getInt(params, prefix + "nagents", 1);
139  if ( nagents > 1 ) {
140  // refactor the configuration parameters and create a subgroup foreach agent
141  for( int i=0; i<nagents; i++ ) {
142  QString agentPrefix = prefix + "AGENT:" + QString::number(i) + "/";
143  savedConfigurationParameters->createGroup( agentPrefix );
144  savedConfigurationParameters->copyGroupTree( prefix+"ROBOT", agentPrefix+"ROBOT" );
145  savedConfigurationParameters->copyGroupTree( prefix+"NET", agentPrefix+"NET" );
146  QStringList sensorsList = savedConfigurationParameters->getGroupsWithPrefixList(prefix, "Sensor:");
147  foreach( QString sensorGroup, sensorsList ) {
148  savedConfigurationParameters->copyGroupTree( prefix+sensorGroup, agentPrefix+sensorGroup );
149  }
150  QStringList motorsList = savedConfigurationParameters->getGroupsWithPrefixList(prefix, "Motor:");
151  foreach( QString motorGroup, motorsList ) {
152  savedConfigurationParameters->copyGroupTree( prefix+motorGroup, agentPrefix+motorGroup );
153  }
154  eagents.append( new EmbodiedAgent(i, agentPrefix, this) );
155  eagents.last()->configure();
156  }
157  } else {
158  eagents.append( new EmbodiedAgent(0, prefix, this) );
159  eagents.last()->configure();
160  }
161  selectAgent(0);
162 
163  // Adding robots to the arena (if the arena exists)
164  if (arena != NULL) {
165  QStringList robots;
166  foreach(EmbodiedAgent* e, eagents) {
167  robots.append(e->resourcePrefix+"robot");
168  }
169  arena->addRobots(robots);
170  }
171 
172  // declaring other resources
173  declareResource( "experiment", static_cast<ParameterSettableWithConfigureFunction*>(this) );
174 
175  Logger::info( params.getValue(prefix+"type") + " Configured" );
176 }
177 
179 {
180  Logger::error("NOT IMPLEMENTED (EvoRobotExperiment::save)");
181  abort();
182 }
183 
184 void EvoRobotExperiment::describe( QString type ) {
185  Descriptor d = addTypeDescription( type, "The experimental setup that defines the conditions and the fitness function of the evolutionary experiment" );
186  d.describeInt( "ntrials" ).def(1).limits(1,MaxInteger).runtime( &EvoRobotExperiment::setNTrials, &EvoRobotExperiment::getNTrials ).help("The number of trials the individual will be tested to calculate its fitness");
187  d.describeInt( "nsteps" ).def(1).limits(1,MaxInteger).help("The number of step a trials will last");
188  d.describeInt( "nagents" ).def(1).limits(1,MaxInteger).help("The number of embodied agents to create", "This parameter allow to setup experiments with more than one robot; all agents are clones");
189  d.describeSubgroup( "NET" ).props( IsMandatory ).type( "Evonet" ).help( "The Neural Network controlling the robot");
190  d.describeSubgroup( "ROBOT" ).props( IsMandatory ).type( "Robot" ).help( "The robot");
191  d.describeSubgroup( "Sensor" ).props( AllowMultiple ).type( "Sensor" ).help( "One of the Sensors from which the neural network will receive information about the environment" );
192  d.describeSubgroup( "Motor" ).props( AllowMultiple ).type( "Motor" ).help( "One of the Motors with which the neural network acts on the robot and on the environment" );
193  d.describeSubgroup( "Arena" ).type( "Arena" ).help( "The arena where robots live");
194 
195  SubgroupDescriptor world = d.describeSubgroup( "World" ).help( "Parameters affecting the simulated World" );
196  world.describeReal( "timestep" ).def(0.05).runtime( &EvoRobotExperiment::setWorldTimestep, &EvoRobotExperiment::getWorldTimeStep ).help( "The time in seconds corresponding to one simulated step of the World" );
197 }
198 
200 {
201  if (!batchRunning) {
202  // preventing gas from using multithread, which is not supported if the GUI is present
204  }
205  // Doing evolution by default
206  gaPhase=EvoRobotExperiment::INEVOLUTION;
207 }
208 
209 void EvoRobotExperiment::doTrial()
210 {
211  restartCurrentTrial = false;
212  stopCurrentTrial = false;
213  trialFitnessValue = 0.0;
214  for(nstep = 0; nstep < nsteps; nstep++) {
215  initStep( nstep );
216  if ( ga->commitStep() || restartCurrentTrial ) {
217  break;
218  }
219  doStep();
220  if ( ga->commitStep() ) break;
221  endStep( nstep );
222  if (ga->commitStep() || stopCurrentTrial || restartCurrentTrial) {
223  break;
224  }
225  }
226 }
227 
229 {
230  endCurrentIndividualLife = false;
231  totalFitnessValue = 0.0;
232 
233  initIndividual(individual);
234  if ( ga->commitStep() ) return;
235 
236  for (ntrial = 0; ntrial < ntrials; ntrial++) {
237  skipCurrentTrial = false;
238 
239  initTrial(ntrial);
240  if ( ga->commitStep() ) break;
241  if (skipCurrentTrial) { // && !ga->commitStep()) {
242  continue;
243  }
244  if (!endCurrentIndividualLife) {
245  doTrial();
246  }
247  if ( ga->isStopped() ) break;
248  if (restartCurrentTrial) {
249  ntrial--;
250  continue;
251  }
252  endTrial(ntrial);
253 
254  if (gaPhase == INTEST) {
255  Logger::info("Fitness for trial: " + QString::number(trialFitnessValue));
256  }
257 
258  if ( ga->commitStep() || endCurrentIndividualLife ) {
259  break;
260  }
261 
262  }
263 
264  endIndividual(individual);
265  ga->commitStep();
266 
267 #ifdef FARSA_MAC
268  // If the GUI is active, adding a small delay to let the GUI catch up (this is only done on MacOSX
269  // which seems the most troublesome system)
270  if (!batchRunning) {
271  // Using also the namespace to avoid name clashes
272  farsa::msleep(50);
273  }
274 #endif
275 }
276 
278 {
279 }
280 
282 {
283 }
284 
286 {
287  // reset the neural controller
288  ResourcesLocker locker(this);
289  foreach( EmbodiedAgent* agent, eagents ) {
290  agent->evonet->resetNet();
291  }
292 }
293 
295 {
296 }
297 
299 {
300  return totalFitnessValue;
301 }
302 
304 {
305 }
306 
308 {
309 }
310 
312 {
313 }
314 
316 {
318 }
319 
321 {
322 }
323 
325 {
326 }
327 
328 void EvoRobotExperiment::doStep()
329 {
330  // There is no getResource below, but we are actually using resources so we must take the lock.
331  // We don't acquire the lock here, but lock and unlock when needed in the body of the function
332  ResourcesLocker locker(this, false);
333 
334  if (!batchRunning && stepDelay>0) {
335  // To use platform-independent sleep functions we have to do this...
336  class T : public QThread
337  {
338  public:
339  using QThread::sleep;
340  using QThread::msleep;
341  using QThread::usleep;
342  };
343  T::msleep( stepDelay );
344  }
345 
346  // update sensors
347  foreach( EmbodiedAgent* agent, eagents ) {
348  if (agent->enabled) {
349  for (int s = 0; s < agent->sensors.size(); s++) {
350  agent->sensors[s]->update();
351  }
352  }
353  }
355  // update the neural controller
356  locker.lock();
357  foreach( EmbodiedAgent* agent, eagents ) {
358  if (agent->enabled) {
359  agent->evonet->updateNet();
360  }
361  }
362  locker.unlock();
364  // setting motors
365  foreach( EmbodiedAgent* agent, eagents ) {
366  if (agent->enabled) {
367  for (int m = 0; m < agent->motors.size(); m++) {
368  agent->motors[m]->update();
369  }
370  }
371  }
373  // advance the world simulation
374  locker.lock();
375  if (arena != NULL) {
377  }
378  world->advance();
379  if (arena != NULL) {
381  }
382  locker.unlock();
383 }
384 
386 {
387  stopCurrentTrial = true;
388 }
389 
391 {
392  skipCurrentTrial = true;
393 }
394 
396 {
397  restartCurrentTrial = true;
398 }
399 
401 {
402  endCurrentIndividualLife = true;
403  stopCurrentTrial = true;
404 }
405 
407 {
408  ResourcesLocker locker(this);
409 
410  return eagents[0]->evonet->freeParameters();
411 }
412 
413 Sensor* EvoRobotExperiment::getSensor( QString name, int id ) {
414  if ( !eagents[id]->enabled ) {
415  Logger::error( "getSensor returned NULL pointer because the agent "+QString::number(id)+" is disabled" );
416  return NULL;
417  } else if ( eagents[id]->sensorsMap.contains( name ) ) {
418  return eagents[id]->sensorsMap[name];
419  } else {
420  Logger::error( "getSensor returned NULL pointer because there is no sensor named "+name+" in the agent "+QString::number(id) );
421  return NULL;
422  }
423 }
424 
425 Motor* EvoRobotExperiment::getMotor( QString name, int id ) {
426  if ( !eagents[id]->enabled ) {
427  Logger::error( "getMotor returned NULL pointer because the agent "+QString::number(id)+" is disabled" );
428  return NULL;
429  } else if ( eagents[id]->motorsMap.contains( name ) ) {
430  return eagents[id]->motorsMap[name];
431  } else {
432  Logger::error( "getMotor returned NULL pointer because there is no motor named "+name+" in the agent "+QString::number(id) );
433  return NULL;
434  }
435 }
436 
438 {
439  return batchRunning;
440 }
441 
443  return eagents.size();
444 }
445 
447  if (!eagents[id]->enabled) {
448  return false;
449  }
450  agentIdSelected = id;
451  declareResource( "robot",
452  eagents[agentIdSelected]->robot,
453  eagents[agentIdSelected]->resourcePrefix+"robot" );
454  declareResource( "evonet",
455  static_cast<farsa::ParameterSettable*>(eagents[agentIdSelected]->evonet),
456  eagents[agentIdSelected]->resourcePrefix+"evonet" );
457  declareResource( "neuronsIterator",
458  eagents[agentIdSelected]->neuronsIterator,
459  eagents[agentIdSelected]->resourcePrefix+"neuronsIterator" );
460  return true;
461 }
462 
463 void EvoRobotExperiment::enableAgent( int agentId ) {
464  eagents[agentId]->enable();
465 }
466 
467 void EvoRobotExperiment::disableAgent( int agentId ) {
468  eagents[agentId]->disable();
469 }
470 
471 bool EvoRobotExperiment::agentEnabled( int agentId ) {
472  return eagents[agentId]->enabled;
473 }
474 
476 {
477  return eagents[id]->evonet;
478 }
479 
481 {
482  this->ga = ga;
483 }
484 
486  return ga;
487 }
488 
490 {
491  ResourcesLocker locker(this);
492  foreach( EmbodiedAgent* agent, eagents ) {
493  agent->evonet->setParameters(genes);
494  }
495 }
496 
498 {
499  Logger::error("EvoRobotExperiment::setTestingAgentAndSeed() not yet implemented");
500 }
501 
503  // Saving the old robot, the old arena and world to delete them after the new world has been
504  // created (as world is a resource, we need the old instance to exists during notifications.
505  // It can be safely deleted afterward)
506  World* const old_world = world;
507 
508  // TODO: parametrize the name and the dontUseYarp and all other parameters
509  world = new World( "World" );
510  world->setTimeStep( timestep );
511  world->setSize( wVector( -2.0f, -2.0f, -0.50f ), wVector( +2.0f, +2.0f, +2.0f ) );
512  world->setFrictionModel( "exact" );
513  world->setSolverModel( "exact" );
514  world->setMultiThread( 1 );
515  world->setIsRealTime( false );
516 
517  // Removing deleted resources (if they existed) and then re-declaring world
518  Arena* old_arena = arena;
519  if ( arena != NULL ) {
520  deleteResource( "arena" );
521  arena = NULL;
522  }
523 
524  QList<Robot*> old_robots;
525  if ( eagents.size() > 0 ) {
526  deleteResource( "robot" );
527  for( int i=0; i<eagents.size(); i++ ) {
528  if (eagents[i]->enabled) {
529  deleteResource( eagents[i]->resourcePrefix+"robot" );
530  old_robots.push_back(eagents[i]->robot);
531  eagents[i]->robot = NULL;
532  }
533  }
534  }
535 
536  declareResource( "world", world );
537 
538  // Now we can actually free memory
539  delete old_arena;
540  for (int i = 0; i < old_robots.size(); ++i) {
541  delete old_robots[i];
542  }
543  delete old_world;
544 }
545 
547  if (!eagents[id]->enabled) {
548  return false;
549  }
550  eagents[id]->recreateRobot();
551  if ( id == agentIdSelected ) {
552  // rebind the resource of the robot
553  declareResource( "robot",
554  eagents[agentIdSelected]->robot,
555  eagents[agentIdSelected]->resourcePrefix+"robot" );
556  }
557  return true;
558 }
559 
561  for (int i = 0; i < eagents.size(); i++ ) {
562  if (eagents[i]->enabled) {
563  recreateRobot(i);
564  }
565  }
566 }
567 
569  // First of all we need to check whether there is an Arena group or not
570  if (!ConfigurationHelper::hasGroup( *savedConfigurationParameters, (*savedPrefix) + "Arena" ) ) {
571  // This is just to be sure...
572  arena = NULL;
573  return;
574  }
575 
576  // to be sure that a World exist
577  if ( !world ) {
578  recreateWorld();
579  }
580 
581  // Taking lock because we need to use world
582  ResourcesLocker locker(this);
583  // Saving the old arena to delete it after the new arena has been created
584  Arena* const old_arena = arena;
585 
586  // Now creating the arena. We first set ourself as the resouce manager
587  savedConfigurationParameters->setResourcesUser(this);
588  arena = savedConfigurationParameters->getObjectFromGroup<Arena>((*savedPrefix) + "Arena");
589  arena->shareResourcesWith(this);
590  QStringList robots;
591  foreach(EmbodiedAgent* e, eagents) {
592  robots.append(e->resourcePrefix+"robot");
593  }
594  arena->addRobots(robots);
595 
596  // Unlocking before redeclaring the arena resource
597  locker.unlock();
598 
599  declareResource("arena", static_cast<Resource*>(arena), "world");
600  delete old_arena;
601 }
602 
604  eagents[id]->recreateNeuralNetwork();
605  if ( id == agentIdSelected ) {
606  // rebind the resource of the evonet
607  declareResource( "evonet",
608  static_cast<farsa::ParameterSettable*>(eagents[agentIdSelected]->evonet),
609  eagents[agentIdSelected]->resourcePrefix+"evonet" );
610  }
611 }
612 
614  for (int i = 0; i < eagents.size(); i++ ) {
616  }
617 }
618 
619 void EvoRobotExperiment::setWorldTimestep( float timestep ) {
620  ResourcesLocker locker(this);
621  this->timestep = timestep;
622  if ( !world ) return;
623  world->setTimeStep( timestep );
624 }
625 
627  return timestep;
628 }
629 
631  stepDelay = delay;
632 }
633 
635  return stepDelay;
636 }
637 
638 EvoRobotExperiment::EmbodiedAgent::EmbodiedAgent( int id, QString agentPath, EvoRobotExperiment* exp ) {
639  this->id = id;
640  enabled = true;
641  this->agentPath = agentPath;
642  this->exp = exp;
643  evonet = NULL;
644  neuronsIterator = new EvonetIterator();
645  robot = NULL;
646  resourcePrefix = QString("agent[%1]:").arg(id);
647 }
648 
650  exp->savedConfigurationParameters->setResourcesUser(exp);
651  // add to the experiment the resources will create here
652  exp->addUsableResource( resourcePrefix+"evonet" );
653  exp->addUsableResource( resourcePrefix+"robot" );
654  exp->addUsableResource( resourcePrefix+"neuronsIterator" );
655  recreateRobot();
656 
657  // Reading the sensors parameters. For each sensor there must be a subgroup Sensor:NN where NN is a progressive number
658  // (needed to specify the sensors order). Here we also actually create sensors
659  QStringList sensorsList = exp->savedConfigurationParameters->getGroupsWithPrefixList(agentPath, "Sensor:");
660  sensorsList.sort();
661  foreach( QString sensorGroup, sensorsList ) {
662  // Setting the prefix for resources that depend on the robot.
663  // !! WARNING !! this should only be a temporary implementation, a better implementation is needed
664  exp->savedConfigurationParameters->createParameter(
665  agentPath+sensorGroup, "__resourcePrefix__", resourcePrefix );
666  // !! END OF TRICK !!
667  Sensor* sensor = exp->savedConfigurationParameters->getObjectFromGroup<Sensor>(agentPath + sensorGroup);
668  if ( sensor == NULL ) {
669  Logger::error("Cannot create the Sensor from group " + *(exp->savedPrefix) + sensorGroup + ". Aborting");
670  abort();
671  }
672  // in order to avoid name clash when using more than one Sensor,
673  // the Sensors are renamed using the same name of the Group when they don't have a name assigned
674  if ( sensor->name() == QString("unnamed") ) {
675  sensor->setName( sensorGroup );
676  }
677  sensors.append( sensor );
678  sensors.last()->shareResourcesWith( exp );
679  Logger::info( "Created a Sensor named "+sensor->name() );
680  // if the user manually set the name and create a name clash, it is only reported as error in Logger
681  if ( sensorsMap.contains( sensor->name() ) ) {
682  Logger::error( "More than one sensor has name "+sensor->name()+" !! The name has to be unique !!" );
683  } else {
684  // add to the map
685  sensorsMap[sensor->name()] = sensor;
686  }
687  }
688 
689  // Now we do for motors what we did for sensors. Motor groups are in the form Motor:NN
690  QStringList motorsList = exp->savedConfigurationParameters->getGroupsWithPrefixList(agentPath, "Motor:");
691  motorsList.sort();
692  foreach( QString motorGroup, motorsList ) {
693  // Setting the prefix for resources that depend on the robot.
694  // !! WARNING !! this should only be a temporary implementation, a better implementation is needed
695  exp->savedConfigurationParameters->createParameter(
696  agentPath+motorGroup, "__resourcePrefix__", resourcePrefix );
697  // !! END OF TRICK !!
698  Motor* motor = exp->savedConfigurationParameters->getObjectFromGroup<Motor>(agentPath + motorGroup);
699  if (motor == NULL) {
700  Logger::error("Cannot create the Motor from group " + *(exp->savedPrefix) + motorGroup + ". Aborting");
701  abort();
702  }
703  // in order to avoid name clash when using more than one Motor,
704  // the Motors are renamed using the same name of the Group when they don't have a name assigned
705  if ( motor->name() == QString("unnamed") ) {
706  motor->setName( motorGroup );
707  }
708  motors.append( motor );
709  motors.last()->shareResourcesWith( exp );
710  Logger::info( "Created a Motor named "+motor->name() );
711  // if the user manually set the name and create a name clash, it is only reported as error in Logger
712  if ( motorsMap.contains( motor->name() ) ) {
713  Logger::error( "More than one motor has name "+motor->name()+" !! The name has to be unique !!" );
714  } else {
715  // add to the map
716  motorsMap[motor->name()] = motor;
717  }
718  }
719 
720  recreateNeuralNetwork();
721 
722  exp->declareResource( resourcePrefix+"neuronsIterator", neuronsIterator, resourcePrefix+"evonet" );
723 }
724 
725 EvoRobotExperiment::EmbodiedAgent::~EmbodiedAgent() {
726  delete robot;
727  delete evonet;
728  delete neuronsIterator;
729  for (int i = 0; i < sensors.size(); i++) {
730  delete sensors[i];
731  }
732  for (int i = 0; i < motors.size(); i++) {
733  delete motors[i];
734  }
735 }
736 
738  // to be sure that a World exist
739  if ( !(exp->world) ) {
740  exp->recreateWorld();
741  }
742 
743  // Taking lock because we need to use world
744  ResourcesLocker locker(exp);
745  // Saving the old robot to delete it after the new robot has been created
746  Robot* const old_robot = robot;
747 
748  // Now creating the robot
749  exp->savedConfigurationParameters->setResourcesUser(exp);
750  robot = exp->savedConfigurationParameters->getObjectFromGroup<Robot>(agentPath + "ROBOT");
751 
752  // Unlocking before redeclaring the robot resource
753  locker.unlock();
754 
755  exp->declareResource( resourcePrefix+"robot", robot, "world" );
756  delete old_robot;
757 }
758 
760  // Saving the old evonet to delete it after the new evonet has been created
761  Evonet* const old_evonet = evonet;
762 
763  // Check the subgroup [NET]
764  if ( exp->savedConfigurationParameters->getValue( agentPath+"NET/netFile" ).isEmpty() ) {
765  // calculate the number of sensors and motors neurons
766  int nSensors = 0;
767  foreach( Sensor* sensor, sensors ) {
768  nSensors += sensor->size();
769  }
770  int nMotors = 0;
771  foreach( Motor* motor, motors ) {
772  nMotors += motor->size();
773  }
774  // it inject the calculated nSensor and nMotors
775  exp->savedConfigurationParameters->createParameter( agentPath+"NET", "nSensors", QString::number(nSensors) );
776  exp->savedConfigurationParameters->createParameter( agentPath+"NET", "nMotors", QString::number(nMotors) );
777  }
778  // Now creating the neural network. We first set ourself as the resouce manager, then we lock resources (because during configuration
779  // evonet could use resources, but the resource user it will use is not thread safe (SimpleResourceUser))
780  ResourcesLocker locker(exp);
781  exp->savedConfigurationParameters->setResourcesUser(exp);
782  evonet = exp->savedConfigurationParameters->getObjectFromGroup<Evonet>( agentPath+"NET" );
783  evonet->setNetworkName(QString::number(id));
784  locker.unlock();
785 
786  exp->declareResource( resourcePrefix+"evonet", static_cast<farsa::ParameterSettable*>(evonet) );
787 
788  // Here we have to take the lock again because we are going to change neuronsIterator
789  locker.lock();
790  delete old_evonet;
791  neuronsIterator->setEvonet( evonet );
792  // create the blocks associated to the network
793  int startIndex = 0;
794  foreach( Sensor* sensor, sensors ) {
795  neuronsIterator->defineBlock( sensor->name(), EvonetIterator::InputLayer, startIndex, sensor->size() );
796  startIndex += sensor->size();
797  }
798  startIndex = 0;
799  foreach( Motor* motor, motors ) {
800  neuronsIterator->defineBlock( motor->name(), EvonetIterator::OutputLayer, startIndex, motor->size() );
801  startIndex += motor->size();
802  }
803 }
804 
805 void EvoRobotExperiment::EmbodiedAgent::disable() {
806  if (enabled) {
807  enabled = false;
808 
809  // Deleting the resource for the robot and then robot
810  exp->deleteResource( resourcePrefix+"robot" );
811  delete robot;
812  robot = NULL;
813  }
814 }
815 
816 void EvoRobotExperiment::EmbodiedAgent::enable() {
817  if (!enabled) {
818  enabled = true;
819 
820  recreateRobot();
821  }
822 }
823 
824 } // end namespace farsa
825 
826 // All the suff below is to restore the warning state on Windows
827 #if defined(_MSC_VER)
828  #pragma warning(pop)
829 #endif