epucksensors.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  * Onofrio Gigliotta <onofrio.gigliotta@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 "epucksensors.h"
25 #include "configurationhelper.h"
26 #include "logger.h"
27 #include "graphicalwobject.h"
28 #include "arena.h"
29 #include <limits>
30 
31 namespace farsa {
32 
34  Sensor(params, prefix),
35  m_epuckResource("robot"),
36  m_neuronsIteratorResource("neuronsIterator")
37 {
38  // Reading parameters
41 
42  // Declaring the resources that are needed here
44 }
45 
47 {
48  // Nothing to do here
49 }
50 
51 void EpuckSensor::save(ConfigurationParameters& params, QString prefix)
52 {
53  // Calling parent function
54  Sensor::save(params, prefix);
55 
56  // Saving parameters
57  params.startObjectParameters(prefix, "EpuckSensor", this);
58  params.createParameter(prefix, "epuck", m_epuckResource);
59  params.createParameter(prefix, "neuronsIterator", m_neuronsIteratorResource);
60 }
61 
62 void EpuckSensor::describe(QString type)
63 {
64  // Calling parent function
65  Sensor::describe(type);
66 
67  // Describing our parameters
68  Descriptor d = addTypeDescription(type, "The base class for e-puck sensors");
69  d.describeString("epuck").def("robot").help("the name of the resource associated with the e-puck robot to use (default is \"robot\")");
70  d.describeString("neuronsIterator").def("neuronsIterator").help("the name of the resource associated with the neural network iterator (default is \"neuronsIterator\")");
71 }
72 
73 void EpuckSensor::resourceChanged(QString resourceName, ResourceChangeType changeType)
74 {
75  // Calling parent function
76  Sensor::resourceChanged(resourceName, changeType);
77 
78  // Here we only check whether the resource has been deleted and reset the check flag, the
79  // actual work is done in subclasses
80  if (changeType == Deleted) {
82  return;
83  }
84 }
85 
87  EpuckSensor(params, prefix),
88  m_robot(NULL),
89  m_neuronsIterator(NULL)
90 {
91 }
92 
94 {
95  // Nothing to do here
96 }
97 
99 {
100  // Calling parent function
101  EpuckSensor::save(params, prefix);
102 
103  // Saving parameters
104  params.startObjectParameters(prefix, "EpuckProximityIRSensor", this);
105 }
106 
108 {
109  // Calling parent function
110  EpuckSensor::describe(type);
111 
112  // Describing our parameters
113  Descriptor d = addTypeDescription(type, "The infrared proximity sensors of the e-puck robot", "The infrared proximity sensors of the e-puck robot. These are the very short range IR sensors all around the base");
114 }
115 
117 {
118  // Checking all resources we need exist
120 
121  // Acquiring the lock to get resources
122  ResourcesLocker locker( this );
123 
124  m_neuronsIterator->setCurrentBlock(name());
125  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
126  m_neuronsIterator->setInput(applyNoise(m_robot->proximityIRSensorController()->activation(i), 0.0, 1.0));
127  }
128 }
129 
131 {
132  return 8;
133 }
134 
135 void EpuckProximityIRSensor::resourceChanged(QString resourceName, ResourceChangeType changeType)
136 {
137  // Calling parent function
138  EpuckSensor::resourceChanged(resourceName, changeType);
139 
140  if (changeType == Deleted) {
141  return;
142  }
143 
144  if (resourceName == m_epuckResource) {
145  m_robot = getResource<PhyEpuck>();
146 
147  // Eanbling sensors
148  m_robot->proximityIRSensorController()->setEnabled(true);
149  } else if (resourceName == m_neuronsIteratorResource) {
150  m_neuronsIterator = getResource<NeuronsIterator>();
151  m_neuronsIterator->setCurrentBlock(name());
152  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
153  m_neuronsIterator->setGraphicProperties("ir" + QString::number(i), 0.0, 1.0, Qt::red);
154  }
155  } else {
156  Logger::info("Unknown resource " + resourceName + " for " + name());
157  }
158 }
159 
161  EpuckSensor(params, prefix),
162  m_robot(NULL),
163  m_neuronsIterator(NULL),
164  m_arena(NULL)
165 {
166  // Here we also need the arena to work
167  addUsableResource("arena");
168 }
169 
171 {
172  // Nothing to do here
173 }
174 
176 {
177  // Calling parent function
178  EpuckSensor::save(params, prefix);
179 
180  // Saving parameters
181  params.startObjectParameters(prefix, "EpuckGroundIRSensor", this);
182 }
183 
185 {
186  // Calling parent function
187  EpuckSensor::describe(type);
188 
189  // Describing our parameters
190  Descriptor d = addTypeDescription(type, "The infrared ground sensors of the e-puck robot", "The infrared ground sensors of the e-puck robot. These are the three ground sensors in the frontal part of the robot.");
191 }
192 
194 {
195  // Checking all resources we need exist
197 
198  // Acquiring the lock to get resources
199  ResourcesLocker locker( this );
200 
201  // Setting neurons activations
202  m_neuronsIterator->setCurrentBlock(name());
203  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
204  const wVector sensorPosition = m_robot->matrix().transformVector(m_robot->groundIRSensorController()->sensors()[i].getPosition());
205  const QColor color = getColorAtArenaGroundPosition(m_arena, sensorPosition);
206  const real actv = real(qGray(color.rgb())) / 255.0;
207 
208  m_neuronsIterator->setInput(applyNoise(actv, 0.0, 1.0));
209  }
210 }
211 
213 {
214  return 3;
215 }
216 
217 void EpuckGroundIRSensor::resourceChanged(QString resourceName, ResourceChangeType changeType)
218 {
219  // Calling parent function
220  EpuckSensor::resourceChanged(resourceName, changeType);
221 
222  if (changeType == Deleted) {
223  return;
224  }
225 
226  if (resourceName == m_epuckResource) {
227  m_robot = getResource<PhyEpuck>();
228 
229  // Eanbling sensors
230  m_robot->groundIRSensorController()->setEnabled(true);
231  } else if (resourceName == m_neuronsIteratorResource) {
232  m_neuronsIterator = getResource<NeuronsIterator>();
233  m_neuronsIterator->setCurrentBlock(name());
234  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
235  m_neuronsIterator->setGraphicProperties("gb" + QString::number(i), 0.0, 1.0, Qt::red);
236  }
237  } else if (resourceName == "arena") {
238  // Storing the pointer to the arena
239  m_arena = getResource<Arena>();
240  } else {
241  Logger::info("Unknown resource " + resourceName + " for " + name());
242  }
243 }
244 
246  EpuckSensor(params, prefix),
247  m_robot(NULL),
248  m_neuronsIterator(NULL),
249  m_numReceptors(ConfigurationHelper::getInt(params, prefix + "numReceptors", 8)),
250  m_aperture(ConfigurationHelper::getDouble(params, prefix + "aperture", 360.0f)),
251  m_camera(NULL),
252  m_drawCamera(ConfigurationHelper::getBool(params, prefix + "drawCamera", true)),
253  m_ignoreWalls(ConfigurationHelper::getBool(params, prefix + "ignoreWalls", false))
254 {
255 }
256 
258 {
259  // Deleting the camera
260  delete m_camera;
261 }
262 
264 {
265  // Calling parent function
266  EpuckSensor::save(params, prefix);
267 
268  // Saving parameters
269  params.startObjectParameters(prefix, "EpuckLinearCameraSensor", this);
270  params.createParameter(prefix, "numReceptors", QString::number(m_numReceptors));
271  params.createParameter(prefix, "aperture", QString::number(m_aperture));
272  params.createParameter(prefix, "drawCamera", (m_drawCamera ? "true" : "false"));
273  params.createParameter(prefix, "ignoreWalls", (m_ignoreWalls ? "true" : "false"));
274 }
275 
277 {
278  // Calling parent function
279  EpuckSensor::describe(type);
280 
281  // Describing our parameters
282  Descriptor d = addTypeDescription(type, "The linear camera sensor of the e-puck robot", "This is a linear camera with configurable aperture");
283  d.describeInt("numReceptors").def(8).limits(1, MaxInteger).help("The number of receptors of the sensor", "Each receptor returns three values, one for each of the three colors (red, green, blue). This means that the size returned by this sensor is 3 * numReceptors (default is 8)");
284  d.describeReal("aperture").def(360.0f).limits(0.0f, 360.0f).help("The aperture of the camera in degrees", "The real e-puck has a camera with an aperture of 36 degrees, but here you can use any value up to 360° (default is 36)");
285  d.describeBool("drawCamera").def(true).help("Whether to draw the camera or not");
286  d.describeBool("ignoreWalls").def(false).help("whether to perceive walls or not (default is false)");
287 }
288 
290 {
291  // Checking all resources we need exist
293 
294  // Acquiring the lock to get resources
295  ResourcesLocker locker( this );
296 
297  // Updating the camera
298  m_camera->update();
299 
300  // Reading activations: first the red one, then the green one and finally the blue one
301  m_neuronsIterator->setCurrentBlock(name());
302  for (int i = 0; i < m_numReceptors; i++, m_neuronsIterator->nextNeuron()) {
303  m_neuronsIterator->setInput(applyNoise(m_camera->colorForReceptor(i).redF(), 0.0, 1.0));
304  }
305  for (int i = 0; i < m_numReceptors; i++, m_neuronsIterator->nextNeuron()) {
306  m_neuronsIterator->setInput(applyNoise(m_camera->colorForReceptor(i).greenF(), 0.0, 1.0));
307  }
308  for (int i = 0; i < m_numReceptors; i++, m_neuronsIterator->nextNeuron()) {
309  m_neuronsIterator->setInput(applyNoise(m_camera->colorForReceptor(i).blueF(), 0.0, 1.0));
310  }
311 }
312 
314 {
315  return m_numReceptors * 3;
316 }
317 
318 void EpuckLinearCameraSensor::resourceChanged(QString resourceName, ResourceChangeType changeType)
319 {
320  // Calling parent function
321  EpuckSensor::resourceChanged(resourceName, changeType);
322 
323  if (changeType == Deleted) {
324  // Deleting the camera if the robot was deleted
325  if (resourceName == m_epuckResource) {
326  delete m_camera;
327  m_camera = NULL;
328  }
329 
330  return;
331  }
332 
333  if (resourceName == m_epuckResource) {
334  m_robot = getResource<PhyEpuck>();
335 
336  // Now we can also create the camera
337  wMatrix mtr = wMatrix::roll(-PI_GRECO / 2.0);
338 #if defined(__GNUC__) && defined(DEVELOPER_WARNINGS)
339  #warning QUI INVECE DI UNA COSTANTE, CALCOLARSI UNA POSIZIONE DALLE DIMENSIONI DEL ROBOT
340 #endif
341  mtr.w_pos.z = 0.06f;
342  m_camera = new LinearCamera(m_robot, mtr, toRad(m_aperture), m_numReceptors, std::numeric_limits<double>::infinity(), Qt::black);
343 
344  // Sharing resources with the camera
345  m_camera->shareResourcesWith(this);
346  m_camera->drawCamera(m_drawCamera);
347  m_camera->ignoreWalls(m_ignoreWalls);
348  } else if (resourceName == m_neuronsIteratorResource) {
349  m_neuronsIterator = getResource<NeuronsIterator>();
350  m_neuronsIterator->setCurrentBlock(name());
351  int i = 0;
352  for (; i < m_numReceptors; i++, m_neuronsIterator->nextNeuron()) {
353  m_neuronsIterator->setGraphicProperties("lr" + QString::number(i % m_numReceptors), 0.0, 1.0, Qt::red);
354  }
355  for (; i < 2 * m_numReceptors; i++, m_neuronsIterator->nextNeuron()) {
356  m_neuronsIterator->setGraphicProperties("lg" + QString::number(i % m_numReceptors), 0.0, 1.0, Qt::red);
357  }
358  for (; i < 3 * m_numReceptors; i++, m_neuronsIterator->nextNeuron()) {
359  m_neuronsIterator->setGraphicProperties("lb" + QString::number(i % m_numReceptors), 0.0, 1.0, Qt::red);
360  }
361  } else {
362  Logger::info("Unknown resource " + resourceName + " for " + name());
363  }
364 }
365 
367  EpuckSensor(params, prefix),
368  m_robot(NULL),
369  m_arena(NULL),
370  m_neuronsIterator(NULL),
371  m_roundSamples(ConfigurationHelper::getString(params, prefix + "roundSamples", "round.sam")),
372  m_smallSamples(ConfigurationHelper::getString(params, prefix + "smallSamples", "small.sam")),
373  m_wallSamples(ConfigurationHelper::getString(params, prefix + "wallSamples", "wall.sam"))
374 {
375  // Checking that the sampled files have the right number of IR sensors
376  if (m_roundSamples.numIR() != 8) {
377  ConfigurationHelper::throwUserConfigError(prefix + "roundSamples", m_roundSamples.filename(), "The file has samples for the wrong number of sensors, expected 8, got " + QString::number(m_roundSamples.numIR()));
378  }
379  if (m_smallSamples.numIR() != 8) {
380  ConfigurationHelper::throwUserConfigError(prefix + "smallSamples", m_smallSamples.filename(), "The file has samples for the wrong number of sensors, expected 8, got " + QString::number(m_smallSamples.numIR()));
381  }
382  if (m_wallSamples.numIR() != 8) {
383  ConfigurationHelper::throwUserConfigError(prefix + "wallSamples", m_wallSamples.filename(), "The file has samples for the wrong number of sensors, expected 8, got " + QString::number(m_wallSamples.numIR()));
384  }
385 
386  // Here we also need the arena to work
387  addUsableResource("arena");
388 }
389 
391 {
392  // Nothing to do here
393 }
394 
396 {
397  // Calling parent function
398  EpuckSensor::save(params, prefix);
399 
400  // Saving parameters
401  params.startObjectParameters(prefix, "EpuckSampledProximityIRSensor", this);
402  params.createParameter(prefix, "roundSamples", m_roundSamples.filename());
403  params.createParameter(prefix, "smallSamples", m_smallSamples.filename());
404  params.createParameter(prefix, "wallSamples", m_wallSamples.filename());
405 }
406 
408 {
409  // Calling parent function
410  EpuckSensor::describe(type);
411 
412  // Describing our parameters
413  Descriptor d = addTypeDescription(type, "The sampled proximity infrared sensors of the e-puck", "This is the sampled version of the proximity infrared sensors of the e-puck. This sensor only works with objects created using the Arena");
414  d.describeString("roundSamples").def("round.sam").help("The name of the file with samples for big round objects");
415  d.describeString("smallSamples").def("small.sam").help("The name of the file with samples for small round objects");
416  d.describeString("wallSamples").def("wall.sam").help("The name of the file with samples for walls");
417 }
418 
420 {
421  // Checking all resources we need exist
423 
424  // Acquiring the lock to get resources
425  ResourcesLocker locker(this);
426 
427  // Getting the list of objects in the arena
428  const QVector<PhyObject2DWrapper*>& objectsList = m_arena->getObjects();
429 
430  // Preparing the vector with activations and setting all values to 0
431  QVector<real> activations(size(), 0.0);
432 
433  // Cycling through the list of objects. We first need to get the current position and orientation of the robot
434  //const wVector robotPos = m_robot->position();
435  //const real robotAng = m_robot->orientation(m_arena->getPlane());
436  foreach(const PhyObject2DWrapper* obj, objectsList) {
437  // Computing angle and distance. We don't need to remove the robot to which this sensor belongs because
438  // the calculatations will give a negative distance
439  double distance;
440  double angle;
441 
442  // If computeDistanceAndOrientationFromRobot returns false, we have to discard this object
443  if (!obj->computeDistanceAndOrientationFromRobot(*(m_arena->getRobotWrapper(m_epuckResource)), distance, angle)) {
444  continue;
445  }
446 
447  // Getting the activation. The switch is to understand which samples to use
448  QVector<unsigned int>::const_iterator actIt = QVector<unsigned int>::const_iterator();
449  switch (obj->type()) {
450  case PhyObject2DWrapper::Wall:
451  actIt = m_wallSamples.getActivation(distance, angle);
452  break;
453  case PhyObject2DWrapper::SmallCylinder:
454  actIt = m_smallSamples.getActivation(distance, angle);
455  break;
456  case PhyObject2DWrapper::BigCylinder:
457  case PhyObject2DWrapper::WheeledRobot:
458  actIt = m_roundSamples.getActivation(distance, angle);
459  break;
460  default:
461  //Logger::warning("The sampled infrared sensor only works with Small Cylinders, Big Cylinders, Walls and other Robots");
462  continue;
463  }
464 
465  // Adding activations in the activations vector
466  for (int i = 0; i < size(); ++i, ++actIt) {
467  activations[i] = min(1.0, activations[i] + (real(*actIt) / 1024.0));
468  }
469  }
470 
471  // Finally activating neurons
472  m_neuronsIterator->setCurrentBlock(name());
473  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
474  m_neuronsIterator->setInput(applyNoise(activations[i], 0.0, 1.0));
475  }
476 }
477 
479 {
480  return 8;
481 }
482 
483 void EpuckSampledProximityIRSensor::resourceChanged(QString resourceName, ResourceChangeType changeType)
484 {
485  // Calling parent function
486  EpuckSensor::resourceChanged(resourceName, changeType);
487 
488  if (changeType == Deleted) {
489  return;
490  }
491 
492  if (resourceName == m_epuckResource) {
493  m_robot = getResource<Epuck>();
494 
495  // Disabling proximity IR sensors, they are not used here
496  m_robot->proximityIRSensorController()->setEnabled(false);
497  } else if (resourceName == m_neuronsIteratorResource) {
498  m_neuronsIterator = getResource<NeuronsIterator>();
499  m_neuronsIterator->setCurrentBlock(name());
500  for (int i = 0; i < size(); i++, m_neuronsIterator->nextNeuron()) {
501  m_neuronsIterator->setGraphicProperties("ir" + QString::number(i), 0.0, 1.0, Qt::red);
502  }
503  } else if (resourceName == "arena") {
504  // Storing the pointer to the arena
505  m_arena = getResource<Arena>();
506  } else {
507  Logger::info("Unknown resource " + resourceName + " for " + name());
508  }
509 }
510 
511 }