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