marxbotmotors.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
6  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21  ********************************************************************************/
22 
23 #include "marxbotmotors.h"
24 #include "configurationhelper.h"
25 #include "randomgenerator.h"
26 #include "logger.h"
27 
28 namespace farsa {
29 
31  Motor(params, prefix),
32  m_marxbotResource("robot"),
33  m_neuronsIteratorResource("neuronsIterator")
34 {
35  // Reading parameters
38 
39  // Declaring the resources that are needed here
41 }
42 
44 {
45  // Nothing to do here
46 }
47 
48 void MarXbotMotor::save(ConfigurationParameters& params, QString prefix)
49 {
50  // Calling parent function
51  Motor::save(params, prefix);
52 
53  // Saving parameters
54  params.startObjectParameters(prefix, "MarXbotMotor", this);
55  params.createParameter(prefix, "marxbot", m_marxbotResource);
56  params.createParameter(prefix, "neuronsIterator", m_neuronsIteratorResource);
57 }
58 
59 void MarXbotMotor::describe(QString type)
60 {
61  // Calling parent function
62  Motor::describe(type);
63 
64  // Describing our parameters
65  Descriptor d = addTypeDescription(type, "The base class for MarXbot motors");
66  d.describeString("marxbot").def("robot").help("The name of the resource associated with the MarXbot robot to use (default is \"robot\")");
67  d.describeString("neuronsIterator").def("neuronsIterator").help("The name of the resource associated with the neural network iterator (default is \"neuronsIterator\")");
68 }
69 
70 void MarXbotMotor::resourceChanged(QString resourceName, ResourceChangeType changeType)
71 {
72  // Calling parent function
73  Motor::resourceChanged(resourceName, changeType);
74 
75  // Here we only check whether the resource has been deleted and reset the check flag, the
76  // actual work is done in subclasses
77  if (changeType == Deleted) {
79  return;
80  }
81 }
82 
84  MarXbotMotor(params, prefix),
85  m_robot(NULL),
86  m_neuronsIterator(NULL)
87 {
88 }
89 
91 {
92  // Nothing to do here
93 }
94 
96 {
97  // Calling parent function
98  MarXbotMotor::save(params, prefix);
99 
100  // Saving parameters
101  params.startObjectParameters(prefix, "MarXbotWheelVelocityMotor", this);
102 }
103 
105 {
106  // Calling parent function
108 
109  // Describing our parameters
110  Descriptor d = addTypeDescription(type, "The motor controlling the velocity of the wheels of the MarXbot robot");
111 }
112 
114 {
115  // Checking all resources we need exist
117 
118  // Acquiring the lock to get resources
119  ResourcesLocker locker(this);
120 
121  // Getting limit velocities for wheels
122  double minSpeed1;
123  double minSpeed2;
124  double maxSpeed1;
125  double maxSpeed2;
126  m_robot->wheelsController()->getSpeedLimits(minSpeed1, minSpeed2, maxSpeed1, maxSpeed2);
127 
128  // Computing desired wheel velocities. When appying noise we don't check boundaries, so robots could go a bit faster than their maximum speed
129  m_neuronsIterator->setCurrentBlock(name());
130  const double v1 = (maxSpeed1 - minSpeed1) * applyNoise(m_neuronsIterator->getOutput(), 0.0, -1.0) + minSpeed1;
131  m_neuronsIterator->nextNeuron();
132  const double v2 = (maxSpeed2 - minSpeed2) * applyNoise(m_neuronsIterator->getOutput(), 0.0, -1.0) + minSpeed2;
133 
134  m_robot->wheelsController()->setSpeeds(v1, v2);
135 
136 }
137 
139 {
140  return 2;
141 }
142 
143 void MarXbotWheelVelocityMotor::resourceChanged(QString resourceName, ResourceChangeType changeType)
144 {
145  // Calling parent function
146  MarXbotMotor::resourceChanged(resourceName, changeType);
147 
148  if (changeType == Deleted) {
149  return;
150  }
151 
152  if (resourceName == m_marxbotResource) {
153  m_robot = getResource<PhyMarXbot>();
154  } else if (resourceName == m_neuronsIteratorResource) {
155  m_neuronsIterator = getResource<NeuronsIterator>();
156  m_neuronsIterator->setCurrentBlock(name());
157  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
158  m_neuronsIterator->setGraphicProperties("W" + QString::number(i), 0.0, 1.0, Qt::red);
159  }
160  } else {
161  Logger::info("Unknown resource " + resourceName + " for " + name());
162  }
163 }
164 
166  MarXbotMotor(params, prefix),
167  m_robot(NULL),
168  m_neuronsIterator(NULL)
169 {
170 }
171 
173 {
174  // Nothing to do here
175 }
176 
178 {
179  // Calling parent function
180  MarXbotMotor::save(params, prefix);
181 
182  // Saving parameters
183  params.startObjectParameters(prefix, "MarXbotWheelVelOrient", this);
184 }
185 
187 {
188  // Calling parent function
190 
191  // Describing our parameters
192  Descriptor d = addTypeDescription(type, "The motor controlling the velocity of the wheels of the MarXbot robot");
193 }
194 
196 {
197  // Checking all resources we need exist
199 
200  // Acquiring the lock to get resources
201  ResourcesLocker locker(this);
202 
203  // Getting limit velocities for wheels
204  double minSpeed1;
205  double minSpeed2;
206  double maxSpeed1;
207  double maxSpeed2;
208  m_robot->wheelsController()->getSpeedLimits(minSpeed1, minSpeed2, maxSpeed1, maxSpeed2);
209 
210  // Computing desired wheel velocities
211  m_neuronsIterator->setCurrentBlock(name());
212 
213  const double vel = (maxSpeed1 - minSpeed1) * applyNoise(m_neuronsIterator->getOutput(), 0.0, -1.0) + minSpeed1;
214  m_neuronsIterator->nextNeuron();
215  const double dir = applyNoise(m_neuronsIterator->getOutput(), 0.0, 1.0);
216 
217  // the delta parameter determine how sharply the direction change (a delta=2 or 3 would lead to smooter orientation change than delta=1)
218  // dir=0.5 means no orientation change.
219  const double delta = 1.0;
220  const double offset = (pow(-2.0, delta * 2 + 1) * pow(dir - 0.5, delta * 2)) + 1;
221  double v1;
222  double v2;
223 
224  if (dir > 0.5) {
225  v1 = vel * offset;
226  v2 = vel;
227  } else {
228  v1 = vel;
229  v2 = vel * offset;
230  }
231 
232  m_robot->wheelsController()->setSpeeds(v1, v2);
233 }
234 
236 {
237  return 2;
238 }
239 
240 void MarXbotWheelVelOrient::resourceChanged(QString resourceName, ResourceChangeType changeType)
241 {
242  // Calling parent function
243  MarXbotMotor::resourceChanged(resourceName, changeType);
244 
245  if (changeType == Deleted) {
246  return;
247  }
248 
249  if (resourceName == m_marxbotResource) {
250  m_robot = getResource<PhyMarXbot>();
251  } else if (resourceName == m_neuronsIteratorResource) {
252  m_neuronsIterator = getResource<NeuronsIterator>();
253  m_neuronsIterator->setCurrentBlock(name());
254  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
255  m_neuronsIterator->setGraphicProperties("W" + QString::number(i), 0.0, 1.0, Qt::red);
256  }
257  } else {
258  Logger::info("Unknown resource " + resourceName + " for " + name());
259  }
260 }
261 
263  MarXbotMotor(params, prefix),
264  m_robot(NULL),
265  m_neuronsIterator(NULL),
266  m_onColor(ConfigurationHelper::getString(params, prefix + "onColor", "+00FF00").replace("+", "#")), // We have to do this because # is for comments in .ini files
267  m_offColor(ConfigurationHelper::getString(params, prefix + "offColor", "+0000FF").replace("+", "#")), // We have to do this because # is for comments in .ini files
268  m_onThreshold(ConfigurationHelper::getDouble(params, prefix + "onThreshold", 0.8f)),
269  m_offThreshold(ConfigurationHelper::getDouble(params, prefix + "offThreshold", 0.2f))
270 {
271  if (m_onThreshold < m_offThreshold) {
272  ConfigurationHelper::throwUserConfigError(prefix + "offThreshold", params.getValue(prefix + "offThreshold"), "The offThreshold must be less than the onThreshold");
273  }
274  if (!m_onColor.isValid()) {
275  ConfigurationHelper::throwUserConfigError(prefix + "onColor", params.getValue(prefix + "onColor"), "The onColor value is not a valid color");
276  }
277  if (!m_offColor.isValid()) {
278  ConfigurationHelper::throwUserConfigError(prefix + "offColor", params.getValue(prefix + "offColor"), "The offColor value is not a valid color");
279  }
280 }
281 
283 {
284  // Nothing to do here
285 }
286 
288 {
289  // Calling parent function
290  MarXbotMotor::save(params, prefix);
291 
292  // Saving our parameters
293  params.startObjectParameters(prefix, "MarXbotColorMotor", this);
294  params.createParameter(prefix, "onColor", m_onColor.name().replace("#", "+"));
295  params.createParameter(prefix, "offColor", m_offColor.name().replace("#", "+"));
296  params.createParameter(prefix, "onThreshold", QString::number(m_onThreshold));
297  params.createParameter(prefix, "offThreshold", QString::number(m_offThreshold));
298 }
299 
300 void MarXbotColorMotor::describe(QString type)
301 {
302  // Calling parent function
304 
305  Descriptor d = addTypeDescription(type, "The MarXbot motor changing the robot color");
306  d.describeString("onColor").def("+00FF00").help("The \"on\" color of the robot.", "This is a string. Its format can be: +RGB, +RRGGBB, +RRRGGGBBB, +RRRRGGGGBBBB (each of R, G, and B is a single hex digit) or a name from the list of colors defined in the list of SVG color keyword names provided by the World Wide Web Consortium (see http://www.w3.org/TR/SVG/types.html#ColorKeywords). The default value is \"+00FF00\"");
307  d.describeString("offColor").def("+0000FF").help("The \"off\" color of the robot.", "This is a string. Its format can be: +RGB, +RRGGBB, +RRRGGGBBB, +RRRRGGGGBBBB (each of R, G, and B is a single hex digit) or a name from the list of colors defined in the list of SVG color keyword names provided by the World Wide Web Consortium (see http://www.w3.org/TR/SVG/types.html#ColorKeywords). The default value is \"+0000FF\"");
308  d.describeReal("onThreshold").def(0.8f).limits(0.0f, 1.0f).help("The value above which the color is switched to the \"on\" color", "This is the threshold above which the color of the robot is set to the one defined by the onColor parameter. The default value is 0.8");
309  d.describeReal("offThreshold").def(0.2f).limits(0.0f, 1.0f).help("The value below which the color is switched to the \"off\" color", "This is the threshold below which the color of the robot is set to the one defined by the offColor parameter. The default value is 0.2");
310 }
311 
313 {
314  // Checking all resources we need exist
316 
317  // Acquiring the lock to get resources
318  ResourcesLocker locker(this);
319 
320  // Getting the value of the output neuron
321  m_neuronsIterator->setCurrentBlock(name());
322  const real output = m_neuronsIterator->getOutput();
323 
324  // Setting the color of the robot
325  if (output > m_onThreshold) {
326  m_robot->setColor(m_onColor);
327  } else if (output < m_offThreshold) {
328  m_robot->setColor(m_offColor);
329  }
330 }
331 
333 {
334  return 1;
335 }
336 
337 void MarXbotColorMotor::resourceChanged(QString resourceName, ResourceChangeType changeType)
338 {
339  // Calling parent function
340  MarXbotMotor::resourceChanged(resourceName, changeType);
341 
342  if (changeType == Deleted) {
343  return;
344  }
345 
346  if (resourceName == m_marxbotResource) {
347  m_robot = getResource<PhyMarXbot>();
348 
349  // Setting color to the off color
350  m_robot->setColor(m_offColor);
351  } else if (resourceName == m_neuronsIteratorResource) {
352  m_neuronsIterator = getResource<NeuronsIterator>();
353  m_neuronsIterator->setCurrentBlock(name());
354  m_neuronsIterator->setGraphicProperties("C", 0.0, 1.0, Qt::red);
355  } else {
356  Logger::info("Unknown resource " + resourceName + " for " + name());
357  }
358 }
359 
361  MarXbotMotor(params, prefix),
362  m_robot(NULL),
363  m_neuronsIterator(NULL),
364  m_typeOfClosure(typeOfClosureFromString(ConfigurationHelper::getString(params, prefix + "typeOfClosure", "onlyClose"))),
365  m_noMotionRange(ConfigurationHelper::getDouble(params, prefix + "noMotionRange", 0.3f)),
366  m_noMotionRangeLow(0.5 - (m_noMotionRange / 2.0)),
367  m_noMotionRangeUp(0.5 + (m_noMotionRange / 2.0))
368 {
369  if (m_typeOfClosure == Invalid) {
370  ConfigurationHelper::throwUserConfigError(prefix + "typeOfClosure", params.getValue(prefix + "typeOfClosure"), "The typeOfClosure value is not valid");
371  }
372  if ((m_noMotionRange < 0.0) || (m_noMotionRange > 1.0)) {
373  ConfigurationHelper::throwUserConfigError(prefix + "noMotionRange", params.getValue(prefix + "noMotionRange"), "The noMotionRange value must be between 0.0 and 1.0");
374  }
375 }
376 
378 {
379  // Nothing to do here
380 }
381 
383 {
384  // Calling parent function
385  MarXbotMotor::save(params, prefix);
386 
387  // Saving our parameters
388  params.startObjectParameters(prefix, "MarXbotAttachmentDeviceMotor", this);
389  params.createParameter(prefix, "typeOfClosure", typeOfClosureToString(m_typeOfClosure));
390  params.createParameter(prefix, "noMotionRange", QString::number(m_noMotionRange));
391 }
392 
394 {
395  // Calling parent function
397 
398  Descriptor d = addTypeDescription(type, "The motor controlling the attachment device of the MarXbot");
399  d.describeEnum("typeOfClosure").def("onlyClose").values(QStringList() << "onlyClose" << "onlyHalfClose" << "both").help("How the attachment device is closed", "this parameter controls how the attachement device is closed. Possible values are: \"onlyClose\", \"onlyHalfClose\" and \"both\" (default is \"onlyClose\")");
400  d.describeReal("noMotionRange").def(0.3f).limits(0.0f, 1.0f).help("The dimension of the range corresponding to no movement", "This parameter defines how big is the range of activation which corresponds to no movement of the attachement device. If, for example, the value is 0.4, it means that activations from 0.3 to 0.7 cause no movement of the attachment device (default is 0.3)");
401 }
402 
404 {
405  // Checking all resources we need exist
407 
408  // Acquiring the lock to get resources
409  ResourcesLocker locker(this);
410 
411  // Getting the value of the output neurons
412  m_neuronsIterator->setCurrentBlock(name());
413  const real outVel = m_neuronsIterator->getOutput();
414  m_neuronsIterator->nextNeuron();
415  const real outStatus = m_neuronsIterator->getOutput();
416 
417  // Getting the controller for the attachment device
419 
420  // First computing the actual velocity
421  real velocity;
422  if (outVel < m_noMotionRangeLow) {
423  velocity = ((outVel - m_noMotionRangeLow) / m_noMotionRangeLow) * ctrl->getMaxVelocity();
424  } else if (outVel > m_noMotionRangeUp) {
425  velocity = ((outVel - m_noMotionRangeUp) / (1.0 - m_noMotionRangeUp)) * ctrl->getMaxVelocity();
426  } else {
427  velocity = 0;
428  }
429  ctrl->setDesiredVelocity(velocity);
430 
431  // Now computing the new desired status of the attachment device
432  MarXbotAttachmentDeviceMotorController::Status status = MarXbotAttachmentDeviceMotorController::Open;
433  switch (m_typeOfClosure) {
434  case OnlyClose:
435  if (outStatus > 0.5) {
436  status = MarXbotAttachmentDeviceMotorController::Closed;
437  }
438  break;
439  case OnlyHalfClose:
440  if (outStatus > 0.5) {
441  status = MarXbotAttachmentDeviceMotorController::HalfClosed;
442  }
443  break;
444  case Both:
445  if (outStatus > 0.66) {
446  status = MarXbotAttachmentDeviceMotorController::Closed;
447  } else if (outStatus > 0.33) {
448  status = MarXbotAttachmentDeviceMotorController::HalfClosed;
449  }
450  break;
451  default:
452  // We should never get here
453  abort();
454  break;
455  }
456  ctrl->setDesiredStatus(status);
457 }
458 
460 {
461  return 2;
462 }
463 
464 void MarXbotAttachmentDeviceMotor::resourceChanged(QString resourceName, ResourceChangeType changeType)
465 {
466  // Calling parent function
467  MarXbotMotor::resourceChanged(resourceName, changeType);
468 
469  if (changeType == Deleted) {
470  return;
471  }
472 
473  if (resourceName == m_marxbotResource) {
474  m_robot = getResource<PhyMarXbot>();
475 
476  // Enabling the attachment device motor controller
477  m_robot->enableAttachmentDevice(true);
478  m_robot->attachmentDeviceController()->setEnabled(true);
479  } else if (resourceName == m_neuronsIteratorResource) {
480  m_neuronsIterator = getResource<NeuronsIterator>();
481  m_neuronsIterator->setCurrentBlock(name());
482 
483  m_neuronsIterator->setGraphicProperties("AV", 0.0, 1.0, Qt::red);
484  m_neuronsIterator->nextNeuron();
485  m_neuronsIterator->setGraphicProperties("AC", 0.0, 1.0, Qt::red);
486  } else {
487  Logger::info("Unknown resource " + resourceName + " for " + name());
488  }
489 }
490 
491 MarXbotAttachmentDeviceMotor::TypeOfClosure MarXbotAttachmentDeviceMotor::typeOfClosureFromString(QString value)
492 {
493  value = value.toUpper();
494 
495  if (value == "ONLYCLOSE") {
496  return OnlyClose;
497  } else if (value == "ONLYHALFCLOSE") {
498  return OnlyHalfClose;
499  } else if (value == "BOTH") {
500  return Both;
501  } else {
502  return Invalid;
503  }
504 }
505 
506 QString MarXbotAttachmentDeviceMotor::typeOfClosureToString(MarXbotAttachmentDeviceMotor::TypeOfClosure value)
507 {
508  switch(value) {
509  case OnlyClose:
510  return "OnlyClose";
511  case OnlyHalfClose:
512  return "OnlyHalfClose";
513  case Both:
514  return "Both";
515  default:
516  return "Invalid";
517  }
518 }
519 
520 }
void usableResources(QStringList resources)
MarXbotWheelVelOrient(ConfigurationParameters &params, QString prefix)
Constructor.
double applyNoise(double v, double minValue, double maxValue) const
Adds noise to the value.
MarXbotAttachmentDeviceMotorController * attachmentDeviceController()
static QString getString(ConfigurationParameters &params, QString paramPath, QString def=QString())
void save(ConfigurationParameters &params, QString prefix)
Save the parameters into the ConfigurationParameters.
MarXbotWheelVelocityMotor(ConfigurationParameters &params, QString prefix)
Constructor.
MarXbotColorMotor(ConfigurationParameters &params, QString prefix)
Constructor.
void setSpeeds(QVector< double > speeds)
QString name()
Return the name of the Sensor.
static void describe(QString type)
Describes all the parameters for this sensor.
virtual ~MarXbotColorMotor()
Destructor.
virtual void save(ConfigurationParameters &params, QString prefix)
Saves current parameters into the given ConfigurationParameters object.
void checkAllNeededResourcesExist()
Checks whether all resources we need are existing and throws an exception if they aren't...
virtual void save(ConfigurationParameters &params, QString prefix)
Saves current parameters into the given ConfigurationParameters object.
virtual ~MarXbotWheelVelocityMotor()
Destructor.
void resetNeededResourcesCheck()
Resets the check on needed resources so that the next call to checkAllNeededResourcesExist() will per...
virtual double getOutput()=0
Get the output of the current neuron.
virtual bool nextNeuron()=0
Go to the next neuron of the current block.
virtual bool setCurrentBlock(QString blockName)=0
Set the current blocks of neurons to iterate.
void setColor(QColor c)
virtual void save(ConfigurationParameters &params, QString prefix)
Saves current parameters into the given ConfigurationParameters object.
virtual int size()
Returns the number of neurons required by this motor.
virtual void save(ConfigurationParameters &params, QString prefix)
Saves the parameters of the sensor into the ConfigurationParameters object.
virtual void resourceChanged(QString name, ResourceChangeType changeType)
static void throwUserConfigError(QString paramName, QString paramValue, QString description)
virtual void update()
Performs the motor update.
static void describe(QString type)
Generates a description of this class and its parameters.
virtual void update()
Performs the motor update.
virtual ~MarXbotAttachmentDeviceMotor()
Destructor.
void setEnabled(bool b)
virtual void update()
Performs the motor update.
virtual void save(ConfigurationParameters &params, QString prefix)
Saves current parameters into the given ConfigurationParameters object.
void getSpeedLimits(QVector< double > &minSpeeds, QVector< double > &maxSpeeds) const
static void info(QString msg)
virtual ~MarXbotMotor()
Destructor.
virtual int size()
Returns the number of neurons required by this motor.
static void describe(QString type)
Generates a description of this class and its parameters.
bool startObjectParameters(QString groupPath, QString typeName, ParameterSettable *object)
virtual int size()
Returns the number of neurons required by this motor.
MarXbotMotor(ConfigurationParameters &params, QString prefix)
Constructor.
static Descriptor addTypeDescription(QString type, QString shortHelp, QString longHelp=QString(""))
QString getValue(QString path, bool alsoMatchParents=false) const
QString m_marxbotResource
The name of the resource associated with the MarXbot robot.
QString actualResourceNameForMultirobot(QString resourceName) const
Returns the actual resource name to use.
MarXbotAttachmentDeviceMotor(ConfigurationParameters &params, QString prefix)
Constructor.
virtual void resourceChanged(QString resourceName, ResourceChangeType changeType)
The function called when a resource used here is changed.
float real
virtual void update()
Performs the motor update.
void enableAttachmentDevice(bool enable)
QString m_neuronsIteratorResource
The name of th resource associated with the neural network iterator.
The base abstract class for the Motor hierarchy.
virtual void setGraphicProperties(QString label, double minValue, double maxValue, QColor color)=0
Set the graphic properties for the current neuron (in case it will be visualized on a GUI) ...
virtual ~MarXbotWheelVelOrient()
Destructor.
virtual int size()
Returns the number of neurons required by this motor.
static void describe(QString type)
Describe all the parameter for configuring the Motor.
void createParameter(QString groupPath, QString parameter)
static void describe(QString type)
Generates a description of this class and its parameters.
static void describe(QString type)
Generates a description of this class and its parameters.
The base abstract class for MarXbot motors.
Definition: marxbotmotors.h:53
WheelMotorController * wheelsController()