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