direcs  2012-09-30
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
obstacleCheckThread.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) Markus Knapp *
3  * www.direcs.de *
4  * *
5  * This file is part of direcs. *
6  * *
7  * direcs is free software: you can redistribute it and/or modify it *
8  * under the terms of the GNU General Public License as published *
9  * by the Free Software Foundation, version 3 of the License. *
10  * *
11  * direcs is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License *
17  * along with direcs. If not, see <http://www.gnu.org/licenses/>. *
18  * *
19  *************************************************************************/
20 
21 #include "obstacleCheckThread.h"
22 
24 {
25  // get the name of this class (this is for debugging messages)
26  className = this->staticMetaObject.className();
27 
28  initCompleted = false;
29  stopped = false;
30 
31  // copy the pointer from the original SensorThread object
32  sensThread = s;
33  laserThread = l;
34 
35  // basic init
36  // has to be here, not in init() since we would reset these values when calling init again!
40  sensorValue = NONE;
41 
43  actualFreeAreaEnd = -1;
44 
47 
52 
57 
58  robotSlotWidth = 1; // 1 cm
60 
62  laserResolutionRear = 0.0;
63  laserAngleFront = 0;
64  laserAngleRear = 0;
65 }
66 
67 
69 {
70 }
71 
72 
74 {
75  if (initCompleted == false)
76  {
77  // Note: init of the laser scanner flags is now done in the laserThread
78 
79  // get resolution and angle from the laser thread for all laser scanners
80  if (laserThread->isRunning())
81  {
84 
87  }
88  else
89  {
90  emit message("ERROR getting laser angle and resolution from laserThread for front laser. LaserThread is not running! ObstacleCheckThread::run()");
92  laserAngleFront = 0;
93 
94  emit message("ERROR getting laser angle and resolution from laserThread for rear laser. LaserThread is not running! ObstacleCheckThread::run()");
95  laserResolutionRear = 0.0;
96  laserAngleRear = 0;
97  }
98 
99 
100  // Delete the previous found areas for the next analysis.
101  freeStartAreas.clear();
102  freeEndAreas.clear();
103 
104  // init completed
105  initCompleted = true;
106  }
107 }
108 
109 
111 {
112  stopped = true;
113 }
114 
115 
117 {
118  int first = 0;
119  int last = 0;
120  double currentWidth = 0.0;
121  double largestWidth = 0.0;
122  float currentDistance = 0.0;
123  float b = 0.0;
124  float c = 0.0;
125  int largestFreeAreaStart = 0;
126  int largestFreeAreaEnd = 0;
127  float centerOfFreeWayFront = 0;
128  float middleOfLaser = 0.0;
129 
130 
131 
132  if (initCompleted == false)
133  {
134  emit message(QString("<font color=\"#FF0000\">%1::init not called! Stopping thread!</font>").arg(className));
135  stopped = false;
136 
137  return;
138  }
139 
140 
141  // start "threading"...
142  while (!stopped)
143  {
144  // This value contains the sum of all SENSORx values!
145  sensorValue = NONE;
146 
147  // reset "drive to angle" to "middle of the number of laser lines" -> FORWARD
148  centerOfFreeWayFront = ( (laserAngleFront / laserResolutionFront) / 2);
149 
150 
151 /* infrared Sensors temporarily removed from robot!!
152  //-------------------------------------------------------------
153  // if obstacle in front of sensor 1
154  // (measured distance is smaller than the minObStacleDistance)
155  //-------------------------------------------------------------
156  if (sensThread->getDistance(SENSOR1) <= minObstacleDistance)
157  {
158  // Add the sensor value to the return value
159  sensorValue += SENSOR1;
160  }
161 
162 
163  //-----------------------------------
164  // if obstacle in front of sensor 2
165  //-----------------------------------
166  if (sensThread->getDistance(SENSOR2) <= minObstacleDistance)
167  {
168  // Add the sensor value to the return value
169  sensorValue += SENSOR2;
170  }
171 
172 
173  //-----------------------------------
174  // if obstacle in front of sensor 3
175  //-----------------------------------
176  if (sensThread->getDistance(SENSOR3) <= minObstacleDistance)
177  {
178  // Add the sensor value to the return value
179  sensorValue += SENSOR3;
180  }
181 
182 
183  //-----------------------------------
184  // if obstacle in front of sensor 4
185  //-----------------------------------
186  if (sensThread->getDistance(SENSOR4) <= minObstacleDistance)
187  {
188  // Add the sensor value to the return value
189  sensorValue += SENSOR4;
190  }
191 
192 
193  //-----------------------------------
194  // if obstacle in front of sensor 5
195  //-----------------------------------
196  if (sensThread->getDistance(SENSOR5) <= minObstacleDistance)
197  {
198  // Add the sensor value to the return value
199  sensorValue += SENSOR5;
200  }
201 
202 
203  //-----------------------------------
204  // if obstacle in front of sensor 6
205  //-----------------------------------
206  if (sensThread->getDistance(SENSOR6) <= minObstacleDistance)
207  {
208  // Add the sensor value to the return value
209  sensorValue += SENSOR6;
210  }
211 
212 
213  //-----------------------------------
214  // if obstacle in front of sensor 7
215  //-----------------------------------
216  if (sensThread->getDistance(SENSOR7) <= minObstacleDistance)
217  {
218  // Add the sensor value to the return value
219  sensorValue += SENSOR7;
220  }
221 
222 
223  //-----------------------------------
224  // if obstacle in front of sensor 8
225  //-----------------------------------
226  if (sensThread->getDistance(SENSOR8) <= minObstacleDistance)
227  {
228  // Add the sensor value to the return value
229  sensorValue += SENSOR8;
230  }
231 
232  //=======================================================================================================
233 
234  //---------------------------------------------------------
235  // if obstacle in front of sensor 16 (ultra sonic sensor!)
236  //---------------------------------------------------------
237  if (sensThread->getUsSensorValue(SENSOR16) <= minObstacleDistance)
238  {
239  // Add the sensor value to the return value
240  sensorValue += SENSOR16;
241  }
242 
243 
244  //=======================================================================================================
245  //
246  // First e m i t of the sensor data
247  //
248  //qDebug("obstacleCheckThread: emit sensorValue: %d", sensorValue);
249  emit obstacleDetected(sensorValue, QDateTime::currentDateTime());
250  //=======================================================================================================
251 */
252 
253 
254  //---------------------------------------------------------
255  // set the indexes for the upcoming loops
256  //---------------------------------------------------------
257  first = 0;
259  // e.g. 180 degrees with resolution 1 degree result in an index from 0 to 179
260  // e.g. 270 degrees with resolution 0,5 degrees result in an index from 0 to 539
261 
262  //---------------------------------------------------------
263  // LASER SCANNER 1 DATA ANALYSIS - STEP I
264  //---------------------------------------------------------
265  // If obstacle in front of the laser scanner,
266  // set a flag at the corresponding angles
267  //---------------------------------------------------------
268  for (int angleIndex=first; angleIndex <= last; angleIndex++)
269  {
270 // // first set if we ignore this area and than mark this as such
271 // if (
272 // ((angleIndex >= (laserscannerFrontIgnoreArea1Start*(1/laserResolutionFront))) && (angleIndex <= (laserscannerFrontIgnoreArea1End*(1/laserResolutionFront)))) ||
273 // ((angleIndex >= (laserscannerFrontIgnoreArea2Start*(1/laserResolutionFront))) && (angleIndex <= (laserscannerFrontIgnoreArea2End*(1/laserResolutionFront))))
274 // )
275 // {
276 // //------------------------------
277 // // first set the "ignore flag"
278 // //------------------------------
279 // laserThread->setFlag(LASER1, angleIndex, IGNORETHIS);
280 // }
281 // else
282 // {
283  // if obstacle detected
284  if ( ((int) (laserThread->getValue(LASER1, angleIndex) * 100)) < minObstacleDistanceLaserFront)
285  {
286  //-----------------------------
287  // set the "obstacle flag"
288  //-----------------------------
289  laserThread->setFlag(LASER1, angleIndex, OBSTACLE);
290  }
291  else
292  {
293  //---------------------------------------------------------------------------
294  // set the "no obstacle flag" -> free way at the current angle
295  //---------------------------------------------------------------------------
296  laserThread->setFlag(LASER1, angleIndex, FREEWAY);
297  }
298  }
299 // }
300 
301 
302  //------------------------------------------------------------------
303  // LASER SCANNER 1 DATA ANALYSIS - STEP II
304  //------------------------------------------------------------------
305  // Find all free areas and store start and end angle.
306  // Since we analyse the previos, the current and the next angle
307  // and we have to take care of the first, "middle" and last angle
308  // we have to check all 24x3 posibilities and react on these.
309  // In the end I ended up in three different "actions".
310  //------------------------------------------------------------------
311 
312  //--------------------------------------------------------------------------------
313  // Check all angles
314  //--------------------------------------------------------------------------------
315 
316  //--------------------------------------------------------------------------------
317  // Set the 'new' first and 'last' angles
318  // due to the 'ignore areas' at the beging and at the and of all lines
319  //
320  // Be aware of setting the ignore areas than only at start and end lines!
321  //--------------------------------------------------------------------------------
322 
323 // // this is one angle index after the 1st ignore area ends
324 // first = (laserscannerFrontIgnoreArea1End*(1/laserResolutionFront)) + 1;
325 
326 // // this is one angle index before the 2nd ignore area starts
327 // last = (laserscannerFrontIgnoreArea2Start*(1/laserResolutionFront)) - 1;
328 
329 
330 // TEST TEST TEST
331 
332 // ingore the IGNORE AREAS and mark ALL areas
333 
334  first = 0;
336 // TEST TEST TEST
337 
338 
339  for (int angleIndex = first; angleIndex <= last; angleIndex++)
340  {
341  //qDebug("%d -----------", angleIndex);
342 
343 // // check only lines with which are *not* in an area to be ognored
344 // if (laserThread->getFlag(LASER1, angleIndex) != IGNORETHIS )
345 // {
346  // green
347  if(
348  ((angleIndex == first) &&
349  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY) &&
350  (laserThread->getFlag(LASER1, angleIndex+1) == FREEWAY))
351  ||
352  ((angleIndex != first) && (angleIndex != last) && // any in between
353  (laserThread->getFlag(LASER1, angleIndex-1) == OBSTACLE) &&
354  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY) &&
355  (laserThread->getFlag(LASER1, angleIndex+1) == FREEWAY))
356  )
357  {
358  // store current angle index as free
359  freeStartAreas.append(angleIndex);
360  //qDebug("%d = green", angleIndex);
361  }
362  else
363  // blue
364  if(
365  ((angleIndex == last) &&
366  (laserThread->getFlag(LASER1, angleIndex-1) == FREEWAY) &&
367  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY))
368  ||
369  ((angleIndex != first) && (angleIndex != last) && // any in between
370  (laserThread->getFlag(LASER1, angleIndex-1) == FREEWAY) &&
371  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY) &&
372  (laserThread->getFlag(LASER1, angleIndex+1) == OBSTACLE))
373  )
374  {
375  // store current angle index as free
376  freeEndAreas.append(angleIndex);
377  //qDebug("%d = blue", angleIndex);
378  }
379  else
380  // yellow
381  if(
382  ((angleIndex == last) &&
383  (laserThread->getFlag(LASER1, angleIndex-1) == OBSTACLE) &&
384  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY))
385  ||
386  ((angleIndex == first) &&
387  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY) &&
388  (laserThread->getFlag(LASER1, angleIndex+1) == OBSTACLE))
389  ||
390  ((angleIndex != first) && (angleIndex != last) && // any in between
391  (laserThread->getFlag(LASER1, angleIndex-1) == OBSTACLE) &&
392  (laserThread->getFlag(LASER1, angleIndex) == FREEWAY) &&
393  (laserThread->getFlag(LASER1, angleIndex+1) == OBSTACLE))
394  )
395  {
396  // store current angle index as free
397  freeStartAreas.append(angleIndex);
398  freeEndAreas.append(angleIndex);
399  //qDebug("%d = yellow", angleIndex);
400  }
401 // } // flag != IGNORETHIS
402  }
403 
404 
405  //------------------------------------------------------------------
406  // LASER SCANNER 1 DATA ANALYSIS - STEP III
407  //------------------------------------------------------------------
408  // do a logic check of the found free areas:
409  // do have the same amount of 'start' and 'end' angles?
410  //------------------------------------------------------------------
411  if (freeStartAreas.count() != freeEndAreas.count())
412  {
413  emit message(QString("ERROR in logical check of free laser areas in %1!").arg(className));
414  emit message("Reaction to be implemented!!!");
415  // qDebug() << "ERROR in logical check of free laser areas in:" << className;
416  }
417 
418 
419  // t e s t
420  // t e s t
421  // t e s t
422 // qDebug() << "freeStartAreas:" << freeStartAreas;
423 // qDebug() << "freeEndAreas:" << freeEndAreas;
424 
425 
426  //----------------------------------------------------------------------------
427  // LASER SCANNER 1 DATA ANALYSIS - STEP IV
428  //----------------------------------------------------------------------------
429  // Calculate the width of the drive-trough direction/area
430  // and choose the area which is the widest free one.
431  //----------------------------------------------------------------------------
432 
433  // Look in all free found areas
434  for (int i=0; i<freeStartAreas.count() ; i++ )
435  {
436  // set the triangle sides
437  b = (laserThread->getValue(LASER1, freeStartAreas.at(i)) * 100); // * 100 since we se cm here
438  c = (laserThread->getValue(LASER1, freeEndAreas.at(i)) * 100);
439 
440 // qDebug("b=%.1f", b);
441 // qDebug("c=%.1f", c);
442 
443  // use the shorter angle to be sure we fit really through.
444  // make the triangle to be one with same-length-sides of b and c!
445  if (c < b)
446  {
447  currentDistance = c;
448  }
449  else
450  {
451  currentDistance = b;
452  }
453 
454 
455  // get the width of one side of the triangle using alpha, b and c.
456  // where b and c have to be in cm here!
457  currentWidth = calculateDriveThroughWidth(LASER1, ((freeEndAreas.at(i) - freeStartAreas.at(i)) * laserResolutionFront ), currentDistance, currentDistance);
458 
459 // qDebug("robotSlotWidth: %d cm", robotSlotWidth);
460 // qDebug("currentWidth: %.1f cm",currentWidth);
461 // qDebug("largestWidth: %.1f cm",largestWidth);
462 
463 
464  //----------------------------------------------------------------------------
465  // LASER SCANNER 1 DATA ANALYSIS - STEP V
466  //----------------------------------------------------------------------------
467  // Is the current width wide enough for the robot ("robot slot width")
468  //----------------------------------------------------------------------------
469  if (currentWidth >= robotSlotWidth)
470  {
471 
472  // is the current width the widest so far?
473  if (currentWidth > largestWidth)
474  {
475  // use this width as the most far
476  largestWidth = currentWidth;
477 
478  //
479  // Enable *this* code to chose the widest area, which is also the area with the largest free distance:
480  //
481  // check if this width is the width which is the farest away
482  // if (currentDistance > farestDistance)
483  // {
484  // // use this!
485  // farestDistance = currentDistance;
486  //
487  // // store the corresponing angles, too!
488  // largestFreeAreaStart = freeStartAreas.at(i);
489  // largestFreeAreaEnd = freeEndAreas.at(i);
490  // }
491 
492 
493  //
494  // Use *the following* code for just using the widest area as direction of choice:
495  //
496  // store the corresponing angles
497  largestFreeAreaStart = freeStartAreas.at(i);
498  largestFreeAreaEnd = freeEndAreas.at(i);
499  }
500  }
501 
502 // qDebug("Using largestWidth: %.1f",largestWidth);
503  // Nothing *else* here! we use the last width and distance as the best choice ? ? ? ? ? ?
504  }
505 
506 // qDebug("Final largestWidth: %.1f",largestWidth);
507 // qDebug() << "\n";
508 
509 // qDebug() << "largestFreeAreaStart:" << largestFreeAreaStart;
510 // qDebug() << "largestFreeAreaEnd:" << largestFreeAreaEnd;
511 
512 
513  //----------------------------------------------------------------------------
514  // LASER SCANNER 1 DATA ANALYSIS - STEP VI
515  //----------------------------------------------------------------------------
516  // Then tag the *largest* free area
517  // (to show it in the GUI and to know, where to drive)
518  //----------------------------------------------------------------------------
519 
520  // free area found?
521  if (largestFreeAreaEnd != 0)
522  {
523  for (int angleIndex=largestFreeAreaStart; angleIndex<=largestFreeAreaEnd; angleIndex++)
524  {
525  laserThread->setFlag(LASER1, angleIndex, LARGESTFREEWAY);
526  }
527 
528  // get the middle of the free area (this is for displaying reasons in the GUI only)
529  centerOfFreeWayFront = largestFreeAreaStart + ((largestFreeAreaEnd - largestFreeAreaStart) / 2);
530 
531  // set driving direction flag to "light green"
532  laserThread->setFlag(LASER1, centerOfFreeWayFront, CENTEROFLARGESTFREEWAY);
533 
534  // this signal is only used to display the values and the "driection arrow" in the GUI
535  // // the values are multiplied by the resolution to have the correct value in degrees!
536  // emit newDrivingAngleSet((largestFreeAreaStart * laserResolutionFront), (largestFreeAreaEnd * laserResolutionFront), (centerOfFreeWayFront * laserResolutionFront), largestWidth);
537  emit newDrivingAngleSet(largestFreeAreaStart, largestFreeAreaEnd, centerOfFreeWayFront, largestWidth);
538 
539 
540  //----------------------------------------------------------------------------
541  // LASER SCANNER 1 DATA ANALYSIS - STEP VII
542  //----------------------------------------------------------------------------
543  // Emit driving direction to the GUI
544  //----------------------------------------------------------------------------
545 
546  // get the middle of the laser (when we have 180 deg, the middle is as 90 deg)
547  // this is needed later for detecting the driving direction
548  middleOfLaser = (laserAngleFront / laserResolutionFront) / 2;
549 
550  // value within the tolerance range (deviation to 90 deg.)?
551  if (
552  // when we are within the allowed deviation from the center, we still drive forward
553  ( (centerOfFreeWayFront < middleOfLaser) && (centerOfFreeWayFront >= (middleOfLaser - (straightForwardDeviation / laserResolutionFront))) ) ||
554  ( (centerOfFreeWayFront > middleOfLaser) && (centerOfFreeWayFront <= (middleOfLaser + (straightForwardDeviation / laserResolutionFront))) ) ||
555  ( centerOfFreeWayFront == middleOfLaser ) // straight forward
556  )
557  {
558  // NO obstacle
559  emit obstacleDetected(NONE, QDateTime::currentDateTime());
560 // qDebug("NONE");
561  }
562  else
563  {
564  if ( (centerOfFreeWayFront < middleOfLaser) && (centerOfFreeWayFront > -1) )
565  {
566  // free way left -> obstacle RIGHT
567  emit obstacleDetected(OBSTACLEFRONTRIGHT, QDateTime::currentDateTime());
568 // qDebug("OBSTACLEFRONTRIGHT");
569  }
570  else
571  {
572  if (centerOfFreeWayFront > middleOfLaser)
573  {
574  // free way right -> obstacle LEFT
575  emit obstacleDetected(OBSTACLEFRONTLEFT, QDateTime::currentDateTime());
576 // qDebug("OBSTACLEFRONTLEFT");
577  }
578  }
579  }
580  }
581  else
582  {
583  // this signal is only used to display the values and the "direction arrow" in the GUI
584  emit newDrivingAngleSet(0, 0, 0, 0);
585 
586  // obstacles EVERYWHERE IN FRONT (no free area found)
587  emit obstacleDetected(OBSTACLESEVERYWHEREINFRONT, QDateTime::currentDateTime());
588 // qDebug("OBSTACLESEVERYWHEREINFRONT");
589  }
590 
591 
592 
593  //----------------------------------------------------------------------------
594  // LASER SCANNER 1 DATA ANALYSIS - STEP VIII
595  //----------------------------------------------------------------------------
596  // Reset the previous found areas, angles and width for the next analysis.
597  //----------------------------------------------------------------------------
598  freeStartAreas.clear();
599  freeEndAreas.clear();
600  currentWidth = 0.0;
601  largestWidth = 0.0;
602  currentDistance = 0.0;
603  b = 0.0;
604  c = 0.0;
605  largestFreeAreaStart = 0;
606  largestFreeAreaEnd = 0;
607  centerOfFreeWayFront = 0.0;
608 
609 
610 
611 
612  //================================= START LASER 2 =========================================
613  //================================= START LASER 2 =========================================
614  //================================= START LASER 2 =========================================
615 
616 
617 
618  //================================= END LASER 2 =========================================
619  //================================= END LASER 2 =========================================
620  //================================= END LASER 2 =========================================
621 
622  //-------------------------------------------------
623  // Let the thread sleep some time,
624  // for having a bit more time fo the other threads!
625  //-------------------------------------------------
626  msleep(THREADSLEEPTIME);
627  } // while
628 
629  stopped = false;
630 }
631 
632 
633 double ObstacleCheckThread::calculateDriveThroughWidth(short int laserscanner, int alpha, float b, float c)
634 {
635  // calculate
636  // WARNING: "cos" functions use radians!! so we convert the degrees to radions here!
637 
638  if (laserscanner == LASER1)
639  return sqrt( pow(b, 2.0) + pow(c, 2.0) - 2.0*b*c * cos(alpha*M_PI / (double) laserAngleFront) );
640 
641  if (laserscanner == LASER2)
642  return sqrt( pow(b, 2.0) + pow(c, 2.0) - 2.0*b*c * cos(alpha*M_PI / (double) laserAngleRear) );
643 
644  emit message(QString("ERROR: laser no. %1 not supported (calculateDriveThroughWidth::%2)").arg(laserscanner).arg(className));
645  return 0.0;
646 }
647 
648 
650 {
651  minObstacleDistance = distance;
652 }
653 
654 
656 {
658 }
659 
660 
662 {
663  minObstacleDistanceLaserRear = distance;
664 }
665 
666 
667 void ObstacleCheckThread::setIgnoreArea(short int laser, int area, int start, int end)
668 {
669  if (laser==LASER1)
670  {
671  if (area==AREA1)
672  {
675  return;
676  }
677 
678  if (area==AREA2)
679  {
682  return;
683  }
684  }
685 
686 
687  if (laser==LASER2)
688  {
689  if (area==AREA1)
690  {
693  return;
694  }
695 
696  if (area==AREA2)
697  {
700  return;
701  }
702  }
703 
704  emit message(QString("<font color=\"#FF0000\">ERROR in %1::setIgnoreArea: laser number %2 or area %3 not implemented!<font>").arg(className).arg(laser).arg(area));
705 }
706 
707 
709 {
710  robotSlotWidth = width;
711 }
712 
713 
715 {
716  straightForwardDeviation = deviation;
717 }
718 
719 
721 {
722  simulationMode = status;
723  /*
724 
725  if (simulationMode == true)
726  {
727  // some nice simulation values
728 
729  }
730  else
731  {
732  // initialisation
733 
734 
735  // for refreshing the gui
736  obstacleDetected(NONE);
737  }
738  */
739 }
740 
741 
743 {
744  if (errorlevel == -1)
745  {
746 // wtf? // obstacles EVERYWHERE IN FRONT
747 // wtf? emit obstacleDetected(OBSTACLESEVERYWHEREINFRONT, QDateTime::currentDateTime());
748 
749  emit message("<font color=\"#FF0000\">Error received from other module. Stopping obstacle check thread.</font>");
750 
751  // stop this thread
752  stop();
753  }
754 }