| Prev: Declaring and accessing resources | Up: Home | Next: The Component and BaseExperiment classes |
|---|---|---|
Table of contents
Here we explain how to create a new experiment using the EvoRobotExperiment class that is particularly suitable for evolutionary robotics experiments. You might use this class also for different kind of experiments, e.g. experiments that do not involve an evolutionary process (as in the BraitenbergExperiment example shown below). Alternatively, you can use the Component or BaseExperiment classes which are more flexible but which requires a greater programming effort.
Your new experimental plugin will contain at least an experiment.cpp and experiment.h files (where "experiment" stands for an arbitrary name of your choice) that will define your EvoRobotExperiment sub-class. In the case of the Braitenberg Vehicle Experiment example illustrated below, the name of the files are braitenbergexperiment.cpp and braitenbergexperiment.h and the name of the class is BraitenbergExperiment.
FARSA assumes that an EvoRobotExperiment experiment involves a certain number of generations and a certain number of robots or robot's team that are evaluated (in the case of non-evolutionary experiment the number of generations and the number of robots can be simply set to 1, i.e. only a single robot or a single team of robot is created and evaluated). Moreover it assumes that each robot or team of robots is evaluated for a certain number of trials each lasting a certain number of steps. These parameters and the time lenght of each step can be set by using the ntrials and nsteps parameters of the GA/Experiment component and the timestep parameter in the GA/Experiment/World group. During each step, first the state of the robots' sensors are updated, then the state of the robots' controllers are updated, then the state of the robots' motors are updated, and finally the robots and the environment are updated as a result of the robots' actions.
The EvoRobotExperiment class will automatically creates the robot/s, the robots' controllers, the robots' sensors and motors, and the evolutionary algorithm on the basis of parameters specified in the your .ini file. However, the characteristics of the environment and the initialization of the robot/s position and orientation should be specified by writing the appropriate source code inside the functions of your EvoRobotExperiment subclass. The available functions, which are called at critical point of the process, are described below:
In addition, as all components, the EvoRobotExperiment class should include a describe() and configure() functions that are used to describe the component and eventually to define component-dependent parameters, if required.
You only have to implement the functions you need, with the exception of endStep(), which is pure virtual and should always be defined. For example if your experiment does not involve an evolutionary process you will not implement the initGeneration() and endGeneration() functions. Moreover, if you do not need to do anything at the beginning of a step, you do not need to implement the initStep() function (or you can leave the function empty).
In case you want to implement your own robot controller (without using the neural network controller component provided by FARSA), you can use the beforeWorldAdvance() function to set the state of the robots' motors on the basis of your own controller.
Below we use the BraitenbergExperiment exemplificative experiment to illustrate with an example how you can create a simple experiment by using the EvoRobotExperiment class.
Remember that the in the .ini file you must istantiate an EvoRobotComponent and Evoga component, as shown in the example below, even if you will not use the evolutionary component.
This example involves a Khepera robot provided with few sensors, motors, and with a neural network controller. This experiment does not involve evolution or learning (the free parameters of the neural controller are set manually through the neural network graphic interface). Below we describe the configuration file, the braitenbergexperiment.cpp file, and the braintenbergexperiment.h file.
This is the configuration file (comments are included in the right side after the "#" symbol):
:::INI
[TOTAL99]
mainComponent = Component # The main component is called component
name = Braintenberg Vehicles
logLevel = LogAll
pluginFile = BraitenbergExperiment # This is the name of the plugin file
[Component] # Here we specify the main component of this experiment
type = EvoRobotComponent # belong to the EvoRobotComponent class
[Component/GA] # The EvoRobotExperiment class necessarily requires
type = Evoga # to istantiate a GA even if we do not use it
[Component/GA/Experiment] # Here we specify the name of the sub-class
type = BraitenbergExperiment # and the ntrials and nsteps parameters
ntrials = 10
nsteps = 1000
[Component/GA/Experiment/Arena] # Here we specify that we will use the arena component
type = Arena # for creating the environment and the size of the
planeHeight = 1.0 # arena plane
planeWidth = 1.0
[Component/GA/Experiment/ROBOT] # Here we specify what type of robot we use
type = Khepera # and we specify that we use a kinematic simulation
kinematicRobot = true
[Component/GA/Experiment/NET] # Here we specify that we use a neural network
type = Evonet # controller which does not have internal neurons
biasOnHiddenNeurons = false # and which have bias on motor neurons
biasOnOutputNeurons = true # the number of sensory and motor neurons is
nHiddens = 0 # automatically calculated on the basis of the sensors
# and motors specified below
[Component/GA/Experiment/Motor:0] # This is a motor that control the velocity and
type = KheperaWheelVelocityMotor # direction of the robot
name = Wheels
[Component/GA/Experiment/Sensor:0] # This is a sensor of ambient light that use
type = KheperaSampledLightSensor # only two of the 8 available physical sensors
name = Light # located on the left and on the right side
activeSensors = 01001000
[Component/GA/Experiment/Sensor:1] # This is a sensor that detect the color of
type = KheperaGroundSensor # the ground
name = Ground
The header file, shown below, includes the declaration of the BraitenbergExperiment class and of its functions, namely the configure() and describe() functions (which are required in all components) and the postConfigureInitialization(), initTrial() and endStep() functions. Notice that the experiment class is declared as a component, and is part of a plugin that can be loaded at runtime. More information about components and plugins are provided in the Plugins, components and resources documentation.
:::C++
#ifndef BRAITENBERGEXPERIMENT_H
#define BRAITENBERGEXPERIMENT_H
#include "farsaplugin.h"
#include "evorobotexperiment.h"
class FARSA_PLUGIN_API BraitenbergExperiment : public farsa::EvoRobotExperiment
{
Q_OBJECT
FARSA_REGISTER_CLASS(EvoRobotExperiment)
public:
BraitenbergExperiment();
virtual void configure(farsa::ConfigurationParameters& params, QString prefix);
static void describe(QString type);
virtual void postConfigureInitialization();
virtual void initTrial(int trial);
virtual void endStep(int step);
};
#endif
Below you see the .cpp file. The configure() and describe() functions are used just to describe the name of the component, i.e. no experiment-dependent parameter have been defined in this case. The postConfigureInitialization() function initializes the environment. It sets the color of the plane, creates black rectangular stripes on the ground around the arena, creates a lightbulb in the centre of the arena, and sets the initial position of the robot. The initTria() function puts the robot in a random position with a random orientation at the beginning of each trial. The endStep() function is empty and has been defined since it is a pure virtual function that should be always specified. For a full description of the classes and methods used see the API documentation and the manual pages describing the Arena component and the wheeled robots.
:::C++
#include "braitenbergexperiment.h"
#include "randomgenerator.h"
#include "robots.h"
BraitenbergExperiment::BraitenbergExperiment() :
farsa::EvoRobotExperiment()
{
}
void BraitenbergExperiment::configure(farsa::ConfigurationParameters& params, QString prefix)
{
farsa::EvoRobotExperiment::configure(params, prefix);
}
void BraitenbergExperiment::describe(QString type)
{
farsa::EvoRobotExperiment::describe(type);
Descriptor d = addTypeDescription(type, "Enable the user to experiment with Braintenberg's vehicles");
}
void BraitenbergExperiment::postConfigureInitialization()
{
EvoRobotExperiment::postConfigureInitialization();
farsa::ResourcesLocker locker(this);
farsa::Arena* arena = getResource<farsa::Arena>("arena");
arena->getPlane()->setColor(Qt::white);
farsa::Box2DWrapper* e;
const double tickness = 0.2;
const double playgroundWidth = arena->getWidth() - (tickness * 2.0);
const double playgroundHeight = arena->getHeight()- (tickness * 2.0);
e = arena->createRectangularTargetArea(tickness, playgroundHeight + (tickness * 2), Qt::black);
e->setPosition((playgroundWidth + tickness) / 2, 0.0);
e = arena->createRectangularTargetArea(tickness, playgroundHeight + (tickness * 2), Qt::black);
e->setPosition(-(playgroundWidth + tickness) / 2, 0.0);
e = arena->createRectangularTargetArea(playgroundWidth, tickness, Qt::black);
e->setPosition(0.0, (playgroundHeight + tickness) / 2);
e = arena->createRectangularTargetArea(playgroundWidth, tickness, Qt::black);
e->setPosition(0.0, -(playgroundHeight + tickness) / 2);
if ((arena->getWidth() < 0.6) || (arena->getHeight() < 0.6)) {
farsa::throwUserRuntimeError("Error in Braitenberg Experiment: the width and/or the height of the arena is too small");
}
farsa::Sphere2DWrapper* lightbulb = arena->createLightBulb(Qt::yellow);
lightbulb->setPosition(0.0, 0.0);
farsa::RobotOnPlane* robot = getResource<farsa::RobotOnPlane>("agent[0]:robot");
robot->setPosition(arena->getPlane(), 0.1f, 0.1f);
}
void BraitenbergExperiment::initTrial(int)
{
farsa::ResourcesLocker locker(this);
farsa::Arena* arena = getResource<farsa::Arena>("arena");
farsa::RobotOnPlane* robot = getResource<farsa::RobotOnPlane>("agent[0]:robot");
const farsa::real rx = farsa::globalRNG->getDouble(-(arena->getWidth() / 2.0) - 0.2, (arena->getWidth() / 2.0) - 0.2);
const farsa::real ry = farsa::globalRNG->getDouble(-(arena->getHeight() / 2.0) - 0.2, (arena->getHeight() / 2.0) - 0.2);
robot->setPosition(arena->getPlane(), rx, ry);
robot->setOrientation(arena->getPlane(), farsa::globalRNG->getDouble(-PI_GRECO, PI_GRECO));
}
void BraitenbergExperiment::endStep(int)
{
}
Once the experimental plugin is compiled and is loaded together with the .ini file from the total99 graphic interface, the behaviour of the robot situated in the environment can be observed by opening the View->RenderWorld window and by executing the command Test->CurrentIndividual.
Manual: APIDoc
Manual: ArenaComponent
Manual: BraitenbergExperiment
Manual: ComponentBaseExperiment
Manual: ComponentsPluginAndResources
Manual: CustomizeEnvironment
Manual: Home
Manual: Resources
Manual: WheeledRobots
Anonymous