sensorcontrollers.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 "sensorcontrollers.h"
25 #include "mathutils.h"
26 #include "phyobject.h"
27 #include "graphicalwobject.h"
28 
29 namespace farsa {
30 
32  Ownable(),
33  m_world(world),
34  m_enabled(true)
35 {
36 }
37 
39 {
40  // Nothing to do here
41 }
42 
43 IRSensorController::IRSensorController(World* world, unsigned int numSensors) :
44  SensorController(world),
45  m_activations(numSensors)
46 {
47 }
48 
50 {
51  // Nothing to do here
52 }
53 
54 namespace __SingleIR_internal {
55  #ifndef GLMultMatrix
56  #define GLMultMatrix glMultMatrixf
57  // for double glMultMatrixd
58  #endif
59 
63  const float sensorCubeSide = 0.005f;
64 
69  {
70  public:
98  SingleIRGraphic(WObject *object, const wMatrix& offset, const QVector<wVector>& startingRayPoints, const QVector<wVector>& endingRayPoints, bool drawRay, bool drawRealRay, QString name = "unamed") :
99  GraphicalWObject(object->world(), name),
100  m_object(object),
101  m_offset(offset),
102  m_startingRayPoints(startingRayPoints),
103  m_endingRayPoints(endingRayPoints),
104  m_drawRay(drawRay),
105  m_drawRealRay(drawRealRay)
106  {
107  // Attaching to handPiece (which also becomes our owner)
108  attachToObject(m_object, true);
109 
110  // We also use our own color and texture
112  setTexture("");
113  setColor(Qt::black);
114  }
115 
120  {
121  }
122 
123  protected:
132  virtual void render(RenderWObject* renderer, QGLContext* gw)
133  {
134  // Pushing the transformation matrices separately because the box needs both of them
135  // while rays doesn't need the offset (they are already in the solid frame of reference)
136  // Bringing the coordinate system on the sensor
137  wMatrix mtr = tm * m_offset;
138 
139  glPushMatrix();
140  GLMultMatrix(&tm[0][0]);
141 
142  glPushMatrix();
143  GLMultMatrix(&m_offset[0][0]);
144 
145  renderer->container()->setupColorTexture(gw, renderer);
146 
147  // First drawing the cube representing the sensor. The cube will just be drawn as
148  // six quads for the sake of simplicity. For each face, we specify the quad normal
149  // (for lighting), then specify the quad's 4 vertices. The top part of the front
150  // face is drawn in green to understand if the sensor is mounted upside-down
151  glBegin(GL_QUADS);
152  const float hside = sensorCubeSide / 2.0;
153 
154  // front (top part)
155  glColor3f(0.0, 1.0, 0.0);
156  glNormal3f(0.0, 0.0, 1.0);
157  glVertex3f(-hside, 0.0, hside);
158  glVertex3f( hside, 0.0, hside);
159  glVertex3f( hside, hside, hside);
160  glVertex3f(-hside, hside, hside);
161 
162  // front (bottom part)
163  glColor3f(0.0, 0.0, 0.0);
164  glNormal3f(0.0, 0.0, 1.0);
165  glVertex3f(-hside, -hside, hside);
166  glVertex3f( hside, -hside, hside);
167  glVertex3f( hside, 0.0, hside);
168  glVertex3f(-hside, 0.0, hside);
169 
170  // back
171  glNormal3f(0.0, 0.0, -1.0);
172  glVertex3f( hside, -hside, -hside);
173  glVertex3f(-hside, -hside, -hside);
174  glVertex3f(-hside, hside, -hside);
175  glVertex3f( hside, hside, -hside);
176 
177  // top
178  glNormal3f(0.0, 1.0, 0.0);
179  glVertex3f(-hside, hside, hside);
180  glVertex3f( hside, hside, hside);
181  glVertex3f( hside, hside, -hside);
182  glVertex3f(-hside, hside, -hside);
183 
184  // bottom
185  glNormal3f(0.0, -1.0, 0.0);
186  glVertex3f(-hside, -hside, -hside);
187  glVertex3f( hside, -hside, -hside);
188  glVertex3f( hside, -hside, hside);
189  glVertex3f(-hside, -hside, hside);
190 
191  // right
192  glNormal3f(-1.0, 0.0, 0.0);
193  glVertex3f(-hside, -hside, -hside);
194  glVertex3f(-hside, -hside, hside);
195  glVertex3f(-hside, hside, hside);
196  glVertex3f(-hside, hside, -hside);
197 
198  // left
199  glNormal3f(1.0, 0.0, 0.0);
200  glVertex3f( hside, -hside, hside);
201  glVertex3f( hside, -hside, -hside);
202  glVertex3f( hside, hside, -hside);
203  glVertex3f( hside, hside, hside);
204 
205  glEnd();
206 
207  // Popping only one matrix because ray need the other one
208  glPopMatrix();
209 
210  // Disabling lighting here (we want pure red lines no matter from where we look at them)
211  glPushAttrib(GL_LIGHTING_BIT);
212  glDisable(GL_LIGHTING);
213 
214  // Now drawing the ray if we have to
215  if (m_drawRay) {
216  glLineWidth(2.5);
217  glColor3f(1.0, 0.0, 0.0);
218 
219  glBegin(GL_LINES);
220  for (int i = 0; i < m_startingRayPoints.size(); i++) {
221  const wVector& s = m_startingRayPoints[i];
222  const wVector& e = m_endingRayPoints[i];
223  if (m_drawRealRay) {
224  glVertex3f(s.x, s.y, s.z);
225  glVertex3f(e.x, e.y, e.z);
226  } else {
227  const wVector d = (e - s).normalize().scale(sensorCubeSide * 5.0);
228  glVertex3f(m_offset.w_pos.x, m_offset.w_pos.y, m_offset.w_pos.z);
229  glVertex3f(m_offset.w_pos.x + d.x, m_offset.w_pos.y + d.y, m_offset.w_pos.z + d.z);
230  }
231  }
232  glEnd();
233  }
234 
235  // Restoring lighting status
236  glPopAttrib();
237 
238  glPopMatrix();
239  }
240 
246 
252 
259  const QVector<wVector> m_startingRayPoints;
260 
267  const QVector<wVector> m_endingRayPoints;
268 
273  const bool m_drawRay;
274 
282  const bool m_drawRealRay;
283  };
284 }
285 
286 using namespace __SingleIR_internal;
287 
289  m_object(NULL),
290  m_transformation(wMatrix::identity()),
291  m_minDist(0.0),
292  m_maxDist(0.0),
293  m_aperture(0.0),
294  m_numRays(0),
295  m_drawSensor(false),
296  m_drawRay(false),
297  m_drawRealRay(false),
298  m_startingRayPoints(),
299  m_endingRayPoints(),
300  m_rayCastHit(),
301  m_sensorGraphics(NULL)
302 {
303  m_rayCastHit.object = NULL;
304  m_rayCastHit.distance = 1.0;
305 }
306 
307 SingleIR::SingleIR(WObject* obj, wMatrix mtr, double minDist, double maxDist, double aperture, unsigned int numRays) :
308  m_object(obj),
309  m_transformation(mtr),
310  m_minDist(minDist),
311  m_maxDist(maxDist),
312  m_aperture(aperture),
313  m_numRays(numRays),
314  m_drawSensor(false),
315  m_drawRay(false),
316  m_drawRealRay(false),
317  m_startingRayPoints(),
318  m_endingRayPoints(),
319  m_rayCastHit(),
320  m_sensorGraphics(NULL)
321 {
322  m_rayCastHit.object = NULL;
323  m_rayCastHit.distance = 1.0;
324 
325  if (m_numRays != 0) {
326  m_startingRayPoints.resize(m_numRays);
327  m_endingRayPoints.resize(m_numRays);
328  }
329 
330  // computing the starting and ending point of rays and updating the graphical representation
331  computeRayPoints();
332  updateGraphicalRepresentation();
333 }
334 
336  m_object(other.m_object),
337  m_transformation(other.m_transformation),
338  m_minDist(other.m_minDist),
339  m_maxDist(other.m_maxDist),
340  m_aperture(other.m_aperture),
341  m_numRays(other.m_numRays),
342  m_drawSensor(other.m_drawSensor),
343  m_drawRay(other.m_drawRay),
344  m_drawRealRay(other.m_drawRealRay),
345  m_startingRayPoints(other.m_startingRayPoints),
346  m_endingRayPoints(other.m_endingRayPoints),
347  m_rayCastHit(other.m_rayCastHit),
348  m_sensorGraphics(NULL)
349 {
350  updateGraphicalRepresentation();
351 }
352 
354 {
355  if (&other == this) {
356  return *this;
357  }
358 
359  // Copying data members
360  m_object = other.m_object;
361  m_transformation = other.m_transformation;
362  m_minDist = other.m_minDist;
363  m_maxDist = other.m_maxDist;
364  m_aperture = other.m_aperture;
365  m_numRays = other.m_numRays;
366  m_drawSensor = other.m_drawSensor;
367  m_drawRay = other.m_drawRay;
368  m_drawRealRay = other.m_drawRealRay;
369  m_startingRayPoints = other.m_startingRayPoints;
370  m_endingRayPoints = other.m_endingRayPoints;
371  m_rayCastHit = other.m_rayCastHit;
372 
373  updateGraphicalRepresentation();
374 
375  return *this;
376 }
377 
379 {
380  // Nothing to do here
381 }
382 
384 {
385  // Checking if the sensor is valid
386  if (!isValid()) {
387  return;
388  }
389 
390  // Resetting the current RayCastHit object
391  m_rayCastHit.object = NULL;
392  m_rayCastHit.distance = 1.0;
393 
394  // If we are attached to a phyobject, we ignore it in collisions
395  QSet<PhyObject*> ignoredObjs;
396  PhyObject* phyObj = dynamic_cast<PhyObject*>(m_object);
397  if (phyObj != NULL) {
398  ignoredObjs.insert(phyObj);
399  }
400 
401  // The minimum distance (distances range from 0.0 to 1.0)
402  double minDist = 2.0;
403  for (unsigned int i = 0; i < m_numRays; i++) {
404  // Computing the start and end point of the ray in the global frame of reference
405  const wVector start = m_object->matrix().transformVector(m_startingRayPoints[i]);
406  const wVector end = m_object->matrix().transformVector(m_endingRayPoints[i]);
407 
408  // Casting the ray
409  const rayCastHitVector v = m_object->world()->worldRayCast(start, end, true, ignoredObjs);
410 
411  // Taking the lowest distance: this sensor only reports the distance of the closest
412  // object
413  if ((v.size() != 0) && (v[0].distance < minDist)) {
414  minDist = v[0].distance;
415  m_rayCastHit = v[0];
416  }
417  }
418 }
419 
420 void SingleIR::set(WObject* obj, wMatrix mtr, double minDist, double maxDist, double aperture, unsigned int numRays)
421 {
422  // First of all saving the parameters
423  m_object = obj;
424  m_transformation = mtr;
425  m_minDist = minDist;
426  m_maxDist = maxDist;
427  m_aperture = aperture;
428  m_numRays = numRays;
429  if (m_numRays != 0) {
430  m_startingRayPoints.resize(m_numRays);
431  m_endingRayPoints.resize(m_numRays);
432  } else {
433  m_startingRayPoints.clear();
434  m_endingRayPoints.clear();
435  }
436  m_rayCastHit.object = NULL;
437  m_rayCastHit.distance = 1.0;
438 
439  computeRayPoints();
440  updateGraphicalRepresentation();
441 }
442 
443 void SingleIR::setGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
444 {
445  m_drawSensor = drawSensor;
446  m_drawRay = drawRay;
447  m_drawRealRay = drawRealRay;
448 
449  updateGraphicalRepresentation();
450 }
451 
452 void SingleIR::computeRayPoints()
453 {
454  // Checking the sensor is valid
455  if (!isValid()) {
456  return;
457  }
458 
459  // First of all we need to compute the starting angle of the rays and the angular distance
460  // between them. If there is only one ray it is at angle 0.0 (i.e. along the local Z axis).
461  // The angles computed here are in radiants.
462  const double startAngle = (m_numRays == 1) ? 0.0 : -(deg2rad(m_aperture) / 2.0);
463  const double angularIncrement = (m_numRays == 1) ? 0.0 : (deg2rad(m_aperture) / double(m_numRays - 1));
464 
465  // Now computing the angles in the object fame of reference
466  for (unsigned int i = 0; i < m_numRays; i++) {
467  const double curAngle = startAngle + i * angularIncrement;
468 
469  // To get the ray in the sensor frame of reference we have to rotate the Z axis
470  // around the Y axis. Then we compute the starting and ending point
471  const wVector localRay = wVector::Z().rotateAround(wVector::Y(), curAngle);
472  const wVector localStart = localRay.scale(m_minDist);
473  const wVector localEnd = localRay.scale(m_maxDist);
474 
475  // Finally we can compute the start and end in the object frame of reference
476  m_startingRayPoints[i] = m_transformation.transformVector(localStart);
477  m_endingRayPoints[i] = m_transformation.transformVector(localEnd);
478  }
479 }
480 
481 void SingleIR::updateGraphicalRepresentation()
482 {
483  delete m_sensorGraphics;
484  m_sensorGraphics = NULL;
485 
486  // Checking the sensor is valid
487  if (m_drawSensor && isValid()) {
488  // creating the graphical representation of the sensor
489  m_sensorGraphics = new SingleIRGraphic(m_object, m_transformation, m_startingRayPoints, m_endingRayPoints, m_drawRay, m_drawRealRay);
490  }
491 }
492 
494  IRSensorController(world, sensors.size()),
495  m_sensors(sensors)
496 {
497  // Nothing to do here
498 }
499 
501 {
502  // Nothing to do here
503 }
504 
506 {
507  for (int i = 0; i < m_sensors.size(); i++) {
508  m_sensors[i].update();
509  // If there was no hit, distance is 1.0 and activation 0.0
510  m_activations[i] = 1.0 - m_sensors[i].getRayCastHit().distance;
511  }
512 }
513 
514 void SimulatedIRProximitySensorController::setGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
515 {
516  for (int i = 0; i < m_sensors.size(); i++) {
517  m_sensors[i].setGraphicalProperties(drawSensor, drawRay, drawRealRay);
518  }
519 }
520 
522  IRSensorController(world, sensors.size()),
523  m_sensors(sensors)
524 {
525 }
526 
528 {
529  // Nothing to do here
530 }
531 
533 {
534  for (int i = 0; i < m_sensors.size(); i++) {
535  m_sensors[i].update();
536 
537  // Now taking the color of the nearest solid, converting to HSL and taking
538  // normalized lightness as activation
539  if (m_sensors[i].getRayCastHit().object != NULL) {
540  m_activations[i] = m_sensors[i].getRayCastHit().object->color().lightnessF();
541  } else {
542  m_activations[i] = 0.0;
543  }
544  }
545 }
546 
547 void SimulatedIRGroundSensorController::setGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
548 {
549  for (int i = 0; i < m_sensors.size(); i++) {
550  m_sensors[i].setGraphicalProperties(drawSensor, drawRay, drawRealRay);
551  }
552 }
553 
555  SensorController(world),
556  m_joint(j)
557 {
558 }
559 
561 {
562 }
563 
565 {
566  // Nothing to do here, we read the traction force directly in the traction() function
567 }
568 
570 {
571  return -m_joint.getForceOnJoint();
572 }
573 
574 } // end namespace farsa