Main MRPT website > C++ reference for MRPT 1.9.9
CHolonomicFullEval.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "nav-precomp.h" // Precomp header
11 
13 #include <mrpt/utils/CStream.h>
14 #include <mrpt/utils/round.h>
15 #include <mrpt/math/geometry.h>
18 #include <cmath>
19 
20 using namespace mrpt;
21 using namespace mrpt::utils;
22 using namespace mrpt::math;
23 using namespace mrpt::nav;
24 using namespace std;
25 
30 
31 const unsigned int INVALID_K = std::numeric_limits<unsigned int>::max();
32 
34  const mrpt::utils::CConfigFileBase* INI_FILE)
36  m_last_selected_sector(std::numeric_limits<unsigned int>::max())
37 {
38  if (INI_FILE != nullptr) initialize(*INI_FILE);
39 }
40 
41 void CHolonomicFullEval::saveConfigFile(mrpt::utils::CConfigFileBase& c) const
42 {
43  options.saveToConfigFile(c, getConfigFileSectionName());
44 }
45 
46 void CHolonomicFullEval::initialize(const mrpt::utils::CConfigFileBase& c)
47 {
48  options.loadFromConfigFile(c, getConfigFileSectionName());
49 }
50 
51 struct TGap
52 {
53  int k_from, k_to;
54  double min_eval, max_eval;
56  /** Direction with the best evaluation inside the gap. */
58 
59  TGap()
60  : k_from(-1),
61  k_to(-1),
62  min_eval(std::numeric_limits<double>::max()),
63  max_eval(-std::numeric_limits<double>::max()),
64  contains_target_k(false),
65  k_best_eval(-1)
66  {
67  }
68 };
69 
70 CHolonomicFullEval::EvalOutput::EvalOutput() : best_k(INVALID_K), best_eval(.0)
71 {
72 }
73 
75  unsigned int target_idx, const NavInput& ni, EvalOutput& eo)
76 {
77  ASSERT_(target_idx < ni.targets.size());
78  const auto target = ni.targets[target_idx];
79 
80  using mrpt::math::square;
81 
82  eo = EvalOutput();
83 
84  const auto ptg = getAssociatedPTG();
85  const double ptg_ref_dist = ptg ? ptg->getRefDistance() : 1.0;
86  const size_t nDirs = ni.obstacles.size();
87 
88  const double target_dir = ::atan2(target.y, target.x);
89  const unsigned int target_k =
91  const double target_dist = target.norm();
92 
93  m_dirs_scores.resize(nDirs, options.factorWeights.size() + 2);
94 
95  // TP-Obstacles in 2D:
96  std::vector<mrpt::math::TPoint2D> obstacles_2d(nDirs);
97  std::vector<double> k2dir(nDirs);
98 
99  for (unsigned int i = 0; i < nDirs; i++)
100  {
102  obstacles_2d[i].x = ni.obstacles[i] * cos(k2dir[i]);
103  obstacles_2d[i].y = ni.obstacles[i] * sin(k2dir[i]);
104  }
105 
106  const int NUM_FACTORS = 5;
107 
108  ASSERT_(options.factorWeights.size() == NUM_FACTORS);
109 
110  for (unsigned int i = 0; i < nDirs; i++)
111  {
112  double scores[NUM_FACTORS]; // scores for each criterion
113 
114  if (ni.obstacles[i] < options.TOO_CLOSE_OBSTACLE &&
115  !(i == target_k &&
116  ni.obstacles[i] > 1.02 * target_dist)) // Too close to obstacles?
117  // (unless target is in
118  // between obstacles and
119  // the robot)
120  {
121  for (int l = 0; l < NUM_FACTORS; l++) m_dirs_scores(i, l) = .0;
122  continue;
123  }
124 
125  const double d = std::min(ni.obstacles[i], 0.95 * target_dist);
126 
127  // The TP-Space representative coordinates for this direction:
128  const double x = d * cos(k2dir[i]);
129  const double y = d * sin(k2dir[i]);
130 
131  // Factor #1: collision-free distance
132  // -----------------------------------------------------
133  if (mrpt::utils::abs_diff(i, target_k) <= 1 &&
134  target_dist < 1.0 - options.TOO_CLOSE_OBSTACLE &&
135  ni.obstacles[i] > 1.05 * target_dist)
136  {
137  // Don't count obstacles ahead of the target.
138  scores[0] =
139  std::max(target_dist, ni.obstacles[i]) / (target_dist * 1.05);
140  }
141  else
142  {
143  scores[0] =
144  std::max(0.0, ni.obstacles[i] - options.TOO_CLOSE_OBSTACLE);
145  }
146 
147  // Discount "circular loop aparent free distance" here, but don't count
148  // it for clearance, since those are not real obstacle points.
149  if (ptg != nullptr)
150  {
151  const double max_real_freespace =
152  ptg->getActualUnloopedPathLength(i);
153  const double max_real_freespace_norm =
154  max_real_freespace / ptg->getRefDistance();
155 
156  mrpt::utils::keep_min(scores[0], max_real_freespace_norm);
157  }
158 
159  // Factor #2: Closest approach to target along straight line (Euclidean)
160  // -------------------------------------------
162  sg.point1.x = 0;
163  sg.point1.y = 0;
164  sg.point2.x = x;
165  sg.point2.y = y;
166 
167  // Range of attainable values: 0=passes thru target. 2=opposite
168  // direction
169  double min_dist_target_along_path = sg.distance(target);
170 
171  // Idea: if this segment is taking us *away* from target, don't make the
172  // segment to start at (0,0), since all
173  // paths "running away" will then have identical minimum distances to
174  // target. Use the middle of the segment instead:
175  const double endpt_dist_to_target = (target - TPoint2D(x, y)).norm();
176  const double endpt_dist_to_target_norm =
177  std::min(1.0, endpt_dist_to_target);
178 
179  if ((endpt_dist_to_target_norm > target_dist &&
180  endpt_dist_to_target_norm >= 0.95 * target_dist) &&
181  min_dist_target_along_path >
182  1.05 * std::min(
183  target_dist,
184  endpt_dist_to_target_norm) // the path does not get
185  // any closer to trg
186  //|| (ni.obstacles[i]<0.95*target_dist)
187  )
188  {
189  // path takes us away or way blocked:
190  sg.point1.x = x * 0.5;
191  sg.point1.y = y * 0.5;
192  min_dist_target_along_path = sg.distance(target);
193  }
194 
195  scores[1] = 1.0 / (1.0 + square(min_dist_target_along_path));
196 
197  // Factor #3: Distance of end collision-free point to target (Euclidean)
198  // -----------------------------------------------------
199  {
200  scores[2] = std::sqrt(
201  1.01 - endpt_dist_to_target_norm); // the 1.01 instead of 1.0
202  // is to be 100% sure we
203  // don't get a domain error
204  // in sqrt()
205  }
206 
207  // Factor #4: Stabilizing factor (hysteresis) to avoid quick switch
208  // among very similar paths:
209  // ------------------------------------------------------------------------------------------
210  if (m_last_selected_sector != std::numeric_limits<unsigned int>::max())
211  {
212  const unsigned int hist_dist = mrpt::utils::abs_diff(
214  i); // It's fine here to consider that -PI is far from +PI.
215 
216  if (hist_dist >= options.HYSTERESIS_SECTOR_COUNT)
217  scores[3] = square(
218  1.0 -
219  (hist_dist - options.HYSTERESIS_SECTOR_COUNT) /
220  double(nDirs));
221  else
222  scores[3] = 1.0;
223  }
224  else
225  {
226  scores[3] = 1.0;
227  }
228 
229  // Factor #5: clearance to nearest obstacle along path
230  // ------------------------------------------------------------------------------------------
231  {
232  const double query_dist_norm = std::min(0.99, target_dist * 0.95);
233  const double avr_path_clearance = ni.clearance->getClearance(
234  i /*path index*/, query_dist_norm, true /*interpolate path*/);
235  const double point_clearance = ni.clearance->getClearance(
236  i /*path index*/, query_dist_norm, false /*interpolate path*/);
237  scores[4] = 0.5 * (avr_path_clearance + point_clearance);
238  }
239 
240  // Save stats for debugging:
241  for (int l = 0; l < NUM_FACTORS; l++) m_dirs_scores(i, l) = scores[l];
242  }
243 
244  // Normalize factors?
245  ASSERT_(options.factorNormalizeOrNot.size() == NUM_FACTORS);
246  for (int l = 0; l < NUM_FACTORS; l++)
247  {
248  if (!options.factorNormalizeOrNot[l]) continue;
249 
250  const double mmax = m_dirs_scores.col(l).maxCoeff();
251  const double mmin = m_dirs_scores.col(l).minCoeff();
252  const double span = mmax - mmin;
253  if (span <= .0) continue;
254 
255  m_dirs_scores.col(l).array() -= mmin;
256  m_dirs_scores.col(l).array() /= span;
257  }
258 
259  // Phase 1: average of PHASE1_FACTORS and thresholding:
260  // ----------------------------------------------------------------------
261  const unsigned int NUM_PHASES = options.PHASE_FACTORS.size();
262  ASSERT_(NUM_PHASES >= 1);
263 
264  std::vector<double> weights_sum_phase(NUM_PHASES, .0),
265  weights_sum_phase_inv(NUM_PHASES);
266  for (unsigned int i = 0; i < NUM_PHASES; i++)
267  {
268  for (unsigned int l : options.PHASE_FACTORS[i])
269  weights_sum_phase[i] += options.factorWeights[l];
270  ASSERT_(weights_sum_phase[i] > .0);
271  weights_sum_phase_inv[i] = 1.0 / weights_sum_phase[i];
272  }
273 
274  eo.phase_scores = std::vector<std::vector<double>>(
275  NUM_PHASES, std::vector<double>(nDirs, .0));
276  auto& phase_scores = eo.phase_scores; // shortcut
277  double last_phase_threshold = -1.0; // don't threshold for the first phase
278 
279  for (unsigned int phase_idx = 0; phase_idx < NUM_PHASES; phase_idx++)
280  {
281  double phase_min = std::numeric_limits<double>::max(), phase_max = .0;
282 
283  for (unsigned int i = 0; i < nDirs; i++)
284  {
285  double this_dir_eval = 0;
286 
287  if (ni.obstacles[i] <
288  options.TOO_CLOSE_OBSTACLE || // Too close to obstacles ?
289  (phase_idx > 0 &&
290  phase_scores[phase_idx - 1][i] <
291  last_phase_threshold) // thresholding of the previous
292  // phase
293  )
294  {
295  this_dir_eval = .0;
296  }
297  else
298  {
299  // Weighted avrg of factors:
300  for (unsigned int l : options.PHASE_FACTORS[phase_idx])
301  this_dir_eval +=
303  std::log(std::max(1e-6, m_dirs_scores(i, l)));
304 
305  this_dir_eval *= weights_sum_phase_inv[phase_idx];
306  this_dir_eval = std::exp(this_dir_eval);
307  }
308  phase_scores[phase_idx][i] = this_dir_eval;
309 
310  mrpt::utils::keep_max(phase_max, phase_scores[phase_idx][i]);
311  mrpt::utils::keep_min(phase_min, phase_scores[phase_idx][i]);
312 
313  } // for each direction
314 
315  ASSERT_(options.PHASE_THRESHOLDS.size() == NUM_PHASES);
316  ASSERT_(
317  options.PHASE_THRESHOLDS[phase_idx] > .0 &&
318  options.PHASE_THRESHOLDS[phase_idx] < 1.0);
319 
320  last_phase_threshold =
321  options.PHASE_THRESHOLDS[phase_idx] * phase_max +
322  (1.0 - options.PHASE_THRESHOLDS[phase_idx]) * phase_min;
323  } // end for each phase
324 
325  // Give a chance for a derived class to manipulate the final evaluations:
326  auto& dirs_eval = *phase_scores.rbegin();
327 
328  postProcessDirectionEvaluations(dirs_eval, ni, target_idx);
329 
330  // Recalculate the threshold just in case the postProcess function above
331  // changed things:
332  {
333  double phase_min = std::numeric_limits<double>::max(), phase_max = .0;
334  for (unsigned int i = 0; i < nDirs; i++)
335  {
336  mrpt::utils::keep_max(phase_max, phase_scores[NUM_PHASES - 1][i]);
337  mrpt::utils::keep_min(phase_min, phase_scores[NUM_PHASES - 1][i]);
338  }
339  last_phase_threshold =
340  options.PHASE_THRESHOLDS[NUM_PHASES - 1] * phase_max +
341  (1.0 - options.PHASE_THRESHOLDS[NUM_PHASES - 1]) * phase_min;
342  }
343 
344  // Search for best direction:
345 
346  // Of those directions above "last_phase_threshold", keep the GAP with the
347  // largest maximum value within;
348  // then pick the MIDDLE point as the final selection.
349  std::vector<TGap> gaps;
350  int best_gap_idx = -1;
351  int gap_idx_for_target_dir = -1;
352  {
353  bool inside_gap = false;
354  for (unsigned int i = 0; i < nDirs; i++)
355  {
356  const double val = dirs_eval[i];
357  if (val < last_phase_threshold)
358  {
359  if (inside_gap)
360  {
361  // We just ended a gap:
362  auto& active_gap = *gaps.rbegin();
363  active_gap.k_to = i - 1;
364  inside_gap = false;
365  }
366  }
367  else
368  {
369  // higher or EQUAL to the treshold (equal is important just in
370  // case we have a "flat" diagram...)
371  if (!inside_gap)
372  {
373  // We just started a gap:
374  TGap new_gap;
375  new_gap.k_from = i;
376  gaps.emplace_back(new_gap);
377  inside_gap = true;
378  }
379  }
380 
381  if (inside_gap)
382  {
383  auto& active_gap = *gaps.rbegin();
384  if (val >= active_gap.max_eval)
385  {
386  active_gap.k_best_eval = i;
387  }
388  mrpt::utils::keep_max(active_gap.max_eval, val);
389  mrpt::utils::keep_min(active_gap.min_eval, val);
390 
391  if (target_k == i)
392  {
393  active_gap.contains_target_k = true;
394  gap_idx_for_target_dir = gaps.size() - 1;
395  }
396 
397  if (best_gap_idx == -1 || val > gaps[best_gap_idx].max_eval)
398  {
399  best_gap_idx = gaps.size() - 1;
400  }
401  }
402  } // end for i
403 
404  // Handle the case where we end with an open, active gap:
405  if (inside_gap)
406  {
407  auto& active_gap = *gaps.rbegin();
408  active_gap.k_to = nDirs - 1;
409  }
410  }
411 
412  ASSERT_(!gaps.empty());
413  ASSERT_(best_gap_idx >= 0 && best_gap_idx < int(gaps.size()));
414 
415  const TGap& best_gap = gaps[best_gap_idx];
416 
417  eo.best_eval = best_gap.max_eval;
418 
419  // Different qualitative situations:
420  if (best_gap_idx == gap_idx_for_target_dir) // Gap contains target, AND
421  {
422  // the way seems to have clearance enought:
423  const auto cl_left =
424  mrpt::utils::abs_diff(target_k, (unsigned int)best_gap.k_from);
425  const auto cl_right =
426  mrpt::utils::abs_diff(target_k, (unsigned int)best_gap.k_to);
427 
428  const auto smallest_clearance_in_k_units = std::min(cl_left, cl_right);
429  const unsigned int clearance_threshold =
431 
432  const unsigned int gap_width = best_gap.k_to - best_gap.k_from;
433  const unsigned int width_threshold =
435 
436  // Move straight to target?
437  if (smallest_clearance_in_k_units >= clearance_threshold &&
438  gap_width >= width_threshold &&
439  ni.obstacles[target_k] > target_dist * 1.01)
440  {
441  eo.best_k = target_k;
442  }
443  }
444 
445  if (eo.best_k == INVALID_K) // did not fulfill conditions above
446  {
447  // Not heading to target: go thru the "middle" of the gap to maximize
448  // clearance
449  eo.best_k = mrpt::utils::round(0.5 * (best_gap.k_to + best_gap.k_from));
450  }
451 
452  // Alternative, simpler method to decide motion:
453  // If target can be reached without collision *and* with a minimum of
454  // clearance,
455  // then select that direction, with the score as computed with the regular
456  // formulas above
457  // (even if that score was not the maximum!).
458  if (target_dist < 0.99 &&
459  (
460  /* No obstacles to target + enough clearance: */
461  (ni.obstacles[target_k] > target_dist * 1.01 &&
463  target_k /*path index*/, std::min(0.99, target_dist * 0.95),
464  true /*interpolate path*/) > options.TOO_CLOSE_OBSTACLE) ||
465  /* Or: no obstacles to target with extra margin, target is really
466  near, dont check clearance: */
467  (ni.obstacles[target_k] >
468  (target_dist + 0.15 /*meters*/ / ptg_ref_dist) &&
469  target_dist < (1.5 /*meters*/ / ptg_ref_dist))) &&
470  dirs_eval[target_k] >
471  0 /* the direct target direction has at least a minimum score */
472  )
473  {
474  eo.best_k = target_k;
475  eo.best_eval = dirs_eval[target_k];
476 
477  // Reflect this decision in the phase score plots:
478  phase_scores[NUM_PHASES - 1][target_k] += 2.0;
479  }
480 }
481 
483 {
484  using mrpt::math::square;
485 
486  ASSERT_(ni.clearance != nullptr);
487  ASSERT_(!ni.targets.empty());
488 
489  // Create a log record for returning data.
491  mrpt::make_aligned_shared<CLogFileRecord_FullEval>();
492  no.logRecord = log;
493 
494  const size_t numTrgs = ni.targets.size();
495 
496  std::vector<EvalOutput> evals(numTrgs);
497  double best_eval = .0;
498  unsigned int best_trg_idx = 0;
499 
500  for (unsigned int trg_idx = 0; trg_idx < numTrgs; trg_idx++)
501  {
502  auto& eo = evals[trg_idx];
503  evalSingleTarget(trg_idx, ni, eo);
504 
505  if (eo.best_eval >=
506  best_eval) // >= because we prefer the most advanced targets...
507  {
508  best_eval = eo.best_eval;
509  best_trg_idx = trg_idx;
510  }
511  }
512 
513  // Prepare NavigationOutput data:
514  if (best_eval == .0)
515  {
516  // No way found!
517  no.desiredDirection = 0;
518  no.desiredSpeed = 0;
519  }
520  else
521  {
522  // A valid movement:
523  const auto ptg = getAssociatedPTG();
524  const double ptg_ref_dist = ptg ? ptg->getRefDistance() : 1.0;
525 
527  evals[best_trg_idx].best_k, ni.obstacles.size());
528 
529  // Speed control: Reduction factors
530  // ---------------------------------------------
531  const double targetNearnessFactor =
533  ? std::min(
534  1.0, ni.targets[best_trg_idx].norm() /
536  ptg_ref_dist))
537  : 1.0;
538 
539  const double obs_dist =
540  ni.obstacles[evals[best_trg_idx].best_k]; // Was: min with
541  // obs_clearance too.
542  const double obs_dist_th = std::max(
544  (options.OBSTACLE_SLOW_DOWN_DISTANCE / ptg_ref_dist) *
545  ni.maxObstacleDist);
546  double riskFactor = 1.0;
547  if (obs_dist <= options.TOO_CLOSE_OBSTACLE)
548  {
549  riskFactor = 0.0;
550  }
551  else if (
552  obs_dist < obs_dist_th && obs_dist_th > options.TOO_CLOSE_OBSTACLE)
553  {
554  riskFactor = (obs_dist - options.TOO_CLOSE_OBSTACLE) /
555  (obs_dist_th - options.TOO_CLOSE_OBSTACLE);
556  }
557  no.desiredSpeed =
558  ni.maxRobotSpeed * std::min(riskFactor, targetNearnessFactor);
559  }
560 
561  m_last_selected_sector = evals[best_trg_idx].best_k;
562 
563  // LOG --------------------------
564  if (log)
565  {
566  log->selectedTarget = best_trg_idx;
567  log->selectedSector = evals[best_trg_idx].best_k;
568  log->evaluation = evals[best_trg_idx].best_eval;
569  log->dirs_eval = evals[best_trg_idx].phase_scores;
570 
572  {
573  log->dirs_scores = m_dirs_scores;
574  }
575  }
576 }
577 
579  const double a, const unsigned int N)
580 {
581  const int idx = round(0.5 * (N * (1 + mrpt::math::wrapToPi(a) / M_PI) - 1));
582  if (idx < 0)
583  return 0;
584  else
585  return static_cast<unsigned int>(idx);
586 }
587 
589  : selectedSector(0), evaluation(.0), dirs_scores(), selectedTarget(0)
590 {
591 }
592 
594  mrpt::utils::CStream& out, int* version) const
595 {
596  if (version)
597  *version = 3;
598  else
599  {
601  << selectedSector << evaluation << selectedTarget /*v3*/;
602  }
603 }
604 
605 /*---------------------------------------------------------------
606  readFromStream
607  ---------------------------------------------------------------*/
609  mrpt::utils::CStream& in, int version)
610 {
611  switch (version)
612  {
613  case 0:
614  case 1:
615  case 2:
616  case 3:
617  {
618  if (version >= 2)
619  {
621  }
622  else
623  {
626  if (version >= 1)
627  {
629  }
630  }
632  if (version >= 3)
633  {
634  in >> selectedTarget;
635  }
636  else
637  {
638  selectedTarget = 0;
639  }
640  }
641  break;
642  default:
644  };
645 }
646 
647 /*---------------------------------------------------------------
648  TOptions
649  ---------------------------------------------------------------*/
651  : // Default values:
652  TOO_CLOSE_OBSTACLE(0.15),
653  TARGET_SLOW_APPROACHING_DISTANCE(0.60),
654  OBSTACLE_SLOW_DOWN_DISTANCE(0.15),
655  HYSTERESIS_SECTOR_COUNT(5),
656  factorWeights{0.1, 0.5, 0.5, 0.01, 1},
657  factorNormalizeOrNot{0, 0, 0, 0, 1},
658  PHASE_FACTORS{{1, 2}, {4}, {0, 2}},
659  PHASE_THRESHOLDS{0.5, 0.6, 0.7},
660  LOG_SCORE_MATRIX(false),
661  clearance_threshold_ratio(0.05),
662  gap_width_ratio_threshold(0.25)
663 {
664 }
665 
668 {
669  MRPT_START
670 
671  // Load from config text:
672  MRPT_LOAD_CONFIG_VAR(TOO_CLOSE_OBSTACLE, double, c, s);
673  MRPT_LOAD_CONFIG_VAR(TARGET_SLOW_APPROACHING_DISTANCE, double, c, s);
674  MRPT_LOAD_CONFIG_VAR(OBSTACLE_SLOW_DOWN_DISTANCE, double, c, s);
675  MRPT_LOAD_CONFIG_VAR(HYSTERESIS_SECTOR_COUNT, double, c, s);
676  MRPT_LOAD_CONFIG_VAR(LOG_SCORE_MATRIX, bool, c, s);
677  MRPT_LOAD_CONFIG_VAR(clearance_threshold_ratio, double, c, s);
678  MRPT_LOAD_CONFIG_VAR(gap_width_ratio_threshold, double, c, s);
679 
680  c.read_vector(
681  s, "factorWeights", std::vector<double>(), factorWeights, true);
682  ASSERT_(factorWeights.size() == 5);
683 
684  c.read_vector(
685  s, "factorNormalizeOrNot", factorNormalizeOrNot, factorNormalizeOrNot);
686  ASSERT_(factorNormalizeOrNot.size() == factorWeights.size());
687 
688  // Phases:
689  int PHASE_COUNT = 0;
690  MRPT_LOAD_CONFIG_VAR_NO_DEFAULT(PHASE_COUNT, int, c, s);
691 
692  PHASE_FACTORS.resize(PHASE_COUNT);
693  PHASE_THRESHOLDS.resize(PHASE_COUNT);
694  for (int i = 0; i < PHASE_COUNT; i++)
695  {
696  c.read_vector(
697  s, mrpt::format("PHASE%i_FACTORS", i + 1), PHASE_FACTORS[i],
698  PHASE_FACTORS[i], true);
699  ASSERT_(!PHASE_FACTORS[i].empty());
700 
701  PHASE_THRESHOLDS[i] = c.read_double(
702  s, mrpt::format("PHASE%i_THRESHOLD", i + 1), .0, true);
703  ASSERT_(PHASE_THRESHOLDS[i] >= .0 && PHASE_THRESHOLDS[i] <= 1.0);
704  }
705 
706  MRPT_END
707 }
708 
711 {
712  MRPT_START;
713 
714  const int WN = mrpt::utils::MRPT_SAVE_NAME_PADDING(),
716 
718  TOO_CLOSE_OBSTACLE,
719  "Directions with collision-free distances below this threshold are not "
720  "elegible.");
722  TARGET_SLOW_APPROACHING_DISTANCE,
723  "Start to reduce speed when closer than this to target.");
725  OBSTACLE_SLOW_DOWN_DISTANCE,
726  "Start to reduce speed when clearance is below this value ([0,1] ratio "
727  "wrt obstacle reference/max distance)");
729  HYSTERESIS_SECTOR_COUNT,
730  "Range of `sectors` (directions) for hysteresis over successive "
731  "timesteps");
733  LOG_SCORE_MATRIX, "Save the entire score matrix in log files");
735  clearance_threshold_ratio,
736  "Ratio [0,1], times path_count, gives the minimum number of paths at "
737  "each side of a target direction to be accepted as desired direction");
739  gap_width_ratio_threshold,
740  "Ratio [0,1], times path_count, gives the minimum gap width to accept "
741  "a direct motion towards target.");
742 
743  ASSERT_EQUAL_(factorWeights.size(), 5)
744  c.write(
745  s, "factorWeights",
746  mrpt::system::sprintf_container("%.2f ", factorWeights), WN, WV,
747  "[0]=Free space, [1]=Dist. in sectors, [2]=Closer to target "
748  "(Euclidean), [3]=Hysteresis, [4]=clearance along path");
749  c.write(
750  s, "factorNormalizeOrNot",
751  mrpt::system::sprintf_container("%u ", factorNormalizeOrNot), WN, WV,
752  "Normalize factors or not (1/0)");
753 
754  c.write(
755  s, "PHASE_COUNT", PHASE_FACTORS.size(), WN, WV,
756  "Number of evaluation phases to run (params for each phase below)");
757 
758  for (unsigned int i = 0; i < PHASE_FACTORS.size(); i++)
759  {
760  c.write(
761  s, mrpt::format("PHASE%u_THRESHOLD", i + 1), PHASE_THRESHOLDS[i],
762  WN, WV,
763  "Phase scores must be above this relative range threshold [0,1] to "
764  "be considered in next phase (Default:`0.75`)");
765  c.write(
766  s, mrpt::format("PHASE%u_FACTORS", i + 1),
767  mrpt::system::sprintf_container("%d ", PHASE_FACTORS[i]), WN, WV,
768  "Indices of the factors above to be considered in this phase");
769  }
770 
771  MRPT_END;
772 }
773 
775  mrpt::utils::CStream& out, int* version) const
776 {
777  if (version)
778  *version = 4;
779  else
780  {
781  // Params:
783  << options.PHASE_FACTORS << // v3
790  ;
791  // State:
792  out << m_last_selected_sector;
793  }
794 }
796 {
797  switch (version)
798  {
799  case 0:
800  case 1:
801  case 2:
802  case 3:
803  case 4:
804  {
805  // Params:
807 
808  if (version >= 3)
809  {
811  }
812  else
813  {
814  options.PHASE_THRESHOLDS.resize(2);
816  }
819 
820  if (version >= 3)
821  {
823  }
824  else
825  {
826  options.PHASE_THRESHOLDS.resize(1);
828  }
829 
830  if (version >= 1) in >> options.OBSTACLE_SLOW_DOWN_DISTANCE;
831  if (version >= 2) in >> options.factorNormalizeOrNot;
832 
833  if (version >= 4)
834  {
837  }
838 
839  // State:
841  }
842  break;
843  default:
845  };
846 }
847 
849  std::vector<double>& dir_evals, const NavInput& ni, unsigned int trg_idx)
850 {
851  // Default: do nothing
852 }
#define ASSERT_EQUAL_(__A, __B)
double index2alpha(uint16_t k) const
Alpha value for the discrete corresponding value.
unsigned int direction2sector(const double a, const unsigned int N)
double gap_width_ratio_threshold
Ratio [0,1], times path_count, gives the minimum gap width to accept a direct motion towards target...
virtual void postProcessDirectionEvaluations(std::vector< double > &dir_evals, const NavInput &ni, unsigned int trg_idx)
double min_eval
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
int k_best_eval
Direction with the best evaluation inside the gap.
EIGEN_STRONG_INLINE bool empty() const
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
A class for storing extra information about the execution of CHolonomicFullEval navigation.
#define min(a, b)
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
double x
X,Y coordinates.
double max_eval
double TOO_CLOSE_OBSTACLE
Directions with collision-free distances below this threshold are not elegible.
std::vector< double > obstacles
Distance to obstacles in polar coordinates, relative to the robot.
double distance(const TPoint2D &point) const
Distance to point.
This file implements several operations that operate element-wise on individual or pairs of container...
A base class for holonomic reactive navigation methods.
double TARGET_SLOW_APPROACHING_DISTANCE
Start to reduce speed when closer than this to target [m].
STL namespace.
#define M_PI
Definition: bits.h:92
mrpt::nav const unsigned int INVALID_K
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
std::vector< int32_t > factorNormalizeOrNot
0/1 to normalize factors.
IMPLEMENTS_SERIALIZABLE(CLogFileRecord_FullEval, CHolonomicLogFileRecord, mrpt::nav) IMPLEMENTS_SERIALIZABLE(CHolonomicFullEval
GLdouble s
Definition: glext.h:3676
bool m_enableApproachTargetSlowDown
Whether to decrease speed when approaching target.
double clearance_threshold_ratio
Ratio [0,1], times path_count, gives the minimum number of paths at each side of a target direction t...
void keep_min(T &var, const K test_val)
If the second argument is below the first one, set the first argument to this lower value...
std::vector< double > PHASE_THRESHOLDS
Phase 1,2,N-1...
std::vector< mrpt::math::TPoint2D > targets
Relative location (x,y) of target point(s).
bool contains_target_k
This class allows loading and storing values and vectors of different types from a configuration text...
T square(const T x)
Inline function for the square of a number.
Definition: bits.h:55
TOptions options
Parameters of the algorithm (can be set manually or loaded from CHolonomicFullEval::initialize or opt...
double OBSTACLE_SLOW_DOWN_DISTANCE
Start to reduce speed when clearance is below this value ([0,1] ratio wrt obstacle reference/max dist...
double getClearance(uint16_t k, double TPS_query_distance, bool integrate_over_path) const
Gets the clearance for path k and distance TPS_query_distance in one of two modes: ...
int mmin(const int t1, const int t2)
Definition: xmlParser.cpp:37
double maxRobotSpeed
Maximum robot speed, in the same units than obstacles, per second.
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
2D segment, consisting of two points.
int MRPT_SAVE_NAME_PADDING()
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc.
#define MRPT_SAVE_CONFIG_VAR_COMMENT(variableName, __comment)
#define MRPT_END
const GLubyte * c
Definition: glext.h:6313
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
A base class for log records for different holonomic navigation methods.
double desiredDirection
The desired motion direction, in the range [-PI, PI].
void saveToConfigFile(mrpt::utils::CConfigFileBase &cfg, const std::string &section) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...
std::vector< double > factorWeights
See docs above.
int val
Definition: mrpt_jpeglib.h:955
std::shared_ptr< CLogFileRecord_FullEval > Ptr
void evalSingleTarget(unsigned int target_idx, const NavInput &ni, EvalOutput &eo)
Evals one single target of the potentially many of them in NavInput.
CHolonomicLogFileRecord::Ptr logRecord
The navigation method will create a log record and store it here via a smart pointer.
TPoint2D point2
Destiny point.
double maxObstacleDist
Maximum expected value to be found in obstacles.
GLsizei const GLchar ** string
Definition: glext.h:4101
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:53
Full evaluation of all possible directions within the discrete set of input directions.
std::vector< std::vector< double > > dirs_eval
Final [0] and alternative [1..N] evaluation scores for each direction, in the same order of TP-Obstac...
TPoint2D point1
Origin point.
double desiredSpeed
The desired motion speed in that direction, from 0 up to NavInput::maxRobotSpeed. ...
#define MRPT_START
const mrpt::nav::ClearanceDiagram * clearance
The computed clearance for each direction (optional in some implementations).
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void navigate(const NavInput &ni, NavOutput &no) override
Invokes the holonomic navigation algorithm itself.
mrpt::math::CMatrixD m_dirs_scores
Individual scores for each direction: (i,j), i (row) are directions, j (cols) are scores...
T square(const T x)
Inline function for the square of a number.
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
GLuint in
Definition: glext.h:7274
#define ASSERT_(f)
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
double HYSTERESIS_SECTOR_COUNT
Range of "sectors" (directions) for hysteresis over successive timesteps.
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:25
#define MRPT_LOAD_CONFIG_VAR_NO_DEFAULT( variableName, variableType, configFileObject, sectionNameStr)
GLenum GLint GLint y
Definition: glext.h:3538
Input parameters for CAbstractHolonomicReactiveMethod::navigate()
#define MRPT_LOAD_CONFIG_VAR( variableName, variableType, configFileObject, sectionNameStr)
An useful macro for loading variables stored in a INI-like file under a key with the same name that t...
GLenum GLint x
Definition: glext.h:3538
T abs_diff(const T a, const T b)
Efficient and portable evaluation of the absolute difference of two unsigned integer values (but will...
Lightweight 2D point.
GLenum GLenum GLvoid GLvoid GLvoid * span
Definition: glext.h:3576
GLubyte GLubyte GLubyte a
Definition: glext.h:6279
Output for CAbstractHolonomicReactiveMethod::navigate()
mrpt::math::CMatrixD dirs_scores
Individual scores for each direction: (i,j), i (row) are directions, j (cols) are scores...
std::string sprintf_container(const char *fmt, const T &V)
Generates a string for a container in the format [A,B,C,...], and the fmt string for each vector elem...
Definition: string_utils.h:117
std::vector< std::vector< double > > phase_scores
void keep_max(T &var, const K test_val)
If the second argument is above the first one, set the first argument to this higher value...
int MRPT_SAVE_VALUE_PADDING()
mrpt::nav::CParameterizedTrajectoryGenerator * getAssociatedPTG() const
Returns the pointer set by setAssociatedPTG()
std::vector< std::vector< int32_t > > PHASE_FACTORS
Factor indices [0,4] for the factors to consider in each phase 1,2,...N of the movement decision (Def...
bool LOG_SCORE_MATRIX
(default:false, to save space)
uint16_t alpha2index(double alpha) const
Discrete index value for the corresponding alpha value.
CONTAINER::Scalar norm(const CONTAINER &v)



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019