MRPT  2.0.4
CHolonomicFullEval.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "nav-precomp.h" // Precomp header
11 //
12 #include <mrpt/core/round.h>
13 #include <mrpt/math/geometry.h>
18 
19 #include <Eigen/Dense> // col(),...
20 #include <cmath>
21 
22 using namespace mrpt;
23 using namespace mrpt::math;
24 using namespace mrpt::nav;
25 using namespace std;
26 
31 
32 const unsigned NUM_FACTORS = 7U;
33 
35  const mrpt::config::CConfigFileBase* INI_FILE)
37  m_last_selected_sector(std::numeric_limits<unsigned int>::max())
38 {
39  if (INI_FILE != nullptr) initialize(*INI_FILE);
40 }
41 
42 void CHolonomicFullEval::saveConfigFile(mrpt::config::CConfigFileBase& c) const
43 {
44  options.saveToConfigFile(c, getConfigFileSectionName());
45 }
46 
48 {
49  options.loadFromConfigFile(c, getConfigFileSectionName());
50 }
51 
52 struct TGap
53 {
54  int k_from{-1}, k_to{-1};
55  double min_eval, max_eval;
56  bool contains_target_k{false};
57  /** Direction with the best evaluation inside the gap. */
58  int k_best_eval{-1};
59 
60  TGap()
61  : min_eval(std::numeric_limits<double>::max()),
62  max_eval(-std::numeric_limits<double>::max())
63 
64  {
65  }
66 };
67 
68 void CHolonomicFullEval::evalSingleTarget(
69  unsigned int target_idx, const NavInput& ni, EvalOutput& eo)
70 {
71  ASSERT_(target_idx < ni.targets.size());
72  const auto target = ni.targets[target_idx];
73 
74  using mrpt::square;
75 
76  eo = EvalOutput();
77 
78  const auto ptg = getAssociatedPTG();
79  const size_t nDirs = ni.obstacles.size();
80 
81  const double target_dir = ::atan2(target.y, target.x);
82  const unsigned int target_k =
83  CParameterizedTrajectoryGenerator::alpha2index(target_dir, nDirs);
84  const double target_dist = target.norm();
85 
86  m_dirs_scores.resize(nDirs, options.factorWeights.size() + 2);
87 
88  // TP-Obstacles in 2D:
89  std::vector<mrpt::math::TPoint2D> obstacles_2d(nDirs);
90 
92  sp.aperture = 2.0 * M_PI;
93  sp.nRays = nDirs;
94  sp.rightToLeft = true;
95  const auto& sc_lut = m_sincos_lut.getSinCosForScan(sp);
96 
97  for (unsigned int i = 0; i < nDirs; i++)
98  {
99  obstacles_2d[i].x = ni.obstacles[i] * sc_lut.ccos[i];
100  obstacles_2d[i].y = ni.obstacles[i] * sc_lut.csin[i];
101  }
102 
103  // Sanity checks:
104  ASSERT_EQUAL_(options.factorWeights.size(), NUM_FACTORS);
105  ASSERT_ABOVE_(nDirs, 3);
106 
107  for (unsigned int i = 0; i < nDirs; i++)
108  {
109  double scores[NUM_FACTORS]; // scores for each criterion
110 
111  // Too close to obstacles? (unless target is in between obstacles and
112  // the robot)
113  if (ni.obstacles[i] < options.TOO_CLOSE_OBSTACLE &&
114  !(i == target_k && ni.obstacles[i] > 1.02 * target_dist))
115  {
116  for (size_t l = 0; l < NUM_FACTORS; l++) m_dirs_scores(i, l) = .0;
117  continue;
118  }
119 
120  const double d = std::min(ni.obstacles[i], 0.95 * target_dist);
121 
122  // The TP-Space representative coordinates for this direction:
123  const double x = d * sc_lut.ccos[i];
124  const double y = d * sc_lut.csin[i];
125 
126  // Factor [0]: collision-free distance
127  // -----------------------------------------------------
128  if (mrpt::abs_diff(i, target_k) <= 1 &&
129  target_dist < 1.0 - options.TOO_CLOSE_OBSTACLE &&
130  ni.obstacles[i] > 1.05 * target_dist)
131  {
132  // Don't count obstacles ahead of the target.
133  scores[0] =
134  std::max(target_dist, ni.obstacles[i]) / (target_dist * 1.05);
135  }
136  else
137  {
138  scores[0] =
139  std::max(0.0, ni.obstacles[i] - options.TOO_CLOSE_OBSTACLE);
140  }
141 
142  // Discount "circular loop aparent free distance" here, but don't count
143  // it for clearance, since those are not real obstacle points.
144  if (ptg != nullptr)
145  {
146  const double max_real_freespace =
147  ptg->getActualUnloopedPathLength(i);
148  const double max_real_freespace_norm =
149  max_real_freespace / ptg->getRefDistance();
150 
151  mrpt::keep_min(scores[0], max_real_freespace_norm);
152  }
153 
154  // Factor [1]: Closest approach to target along straight line
155  // (Euclidean)
156  // -------------------------------------------
158  sg.point1.x = 0;
159  sg.point1.y = 0;
160  sg.point2.x = x;
161  sg.point2.y = y;
162 
163  // Range of attainable values: 0=passes thru target. 2=opposite
164  // direction
165  double min_dist_target_along_path = sg.distance(target);
166 
167  // Idea: if this segment is taking us *away* from target, don't make
168  // the segment to start at (0,0), since all paths "running away"
169  // will then have identical minimum distances to target. Use the
170  // middle of the segment instead:
171  const double endpt_dist_to_target = (target - TPoint2D(x, y)).norm();
172  const double endpt_dist_to_target_norm =
173  std::min(1.0, endpt_dist_to_target);
174 
175  if ((endpt_dist_to_target_norm > target_dist &&
176  endpt_dist_to_target_norm >= 0.95 * target_dist) &&
177  /* the path does not get any closer to trg */
178  min_dist_target_along_path >
179  1.05 * std::min(target_dist, endpt_dist_to_target_norm))
180  {
181  // path takes us away or way blocked:
182  sg.point1.x = x * 0.5;
183  sg.point1.y = y * 0.5;
184  min_dist_target_along_path = sg.distance(target);
185  }
186 
187  scores[1] = 1.0 / (1.0 + square(min_dist_target_along_path));
188 
189  // Factor [2]: Distance of end collision-free point to target
190  // (Euclidean)
191  // Factor [5]: idem (except: no decimation afterwards)
192  // -----------------------------------------------------
193  scores[2] = std::sqrt(1.01 - endpt_dist_to_target_norm);
194  scores[5] = scores[2];
195  // the 1.01 instead of 1.0 is to be 100% sure we don't get a domain
196  // error in sqrt()
197 
198  // Factor [3]: Stabilizing factor (hysteresis) to avoid quick switch
199  // among very similar paths:
200  // ------------------------------------------------------------------------------------------
201  if (m_last_selected_sector != std::numeric_limits<unsigned int>::max())
202  {
203  // It's fine here to consider that -PI is far from +PI.
204  const unsigned int hist_dist =
205  mrpt::abs_diff(m_last_selected_sector, i);
206 
207  if (hist_dist >= options.HYSTERESIS_SECTOR_COUNT)
208  scores[3] = square(
209  1.0 - (hist_dist - options.HYSTERESIS_SECTOR_COUNT) /
210  double(nDirs));
211  else
212  scores[3] = 1.0;
213  }
214  else
215  {
216  scores[3] = 1.0;
217  }
218 
219  // Factor [4]: clearance to nearest obstacle along path
220  // Use TP-obstacles instead of real obstacles in Workspace since
221  // it's way faster, despite being an approximation:
222  // -------------------------------------------------------------------
223  {
224  sg.point1.x = 0;
225  sg.point1.y = 0;
226  sg.point2.x = x;
227  sg.point2.y = y;
228 
229  double& closest_obs = scores[4];
230  closest_obs = 1.0;
231 
232  // eval obstacles within a certain region of this "i" direction only
233  const int W = std::max(1, round(nDirs * 0.1));
234  const int i_min = std::max(0, static_cast<int>(i) - W);
235  const int i_max =
236  std::min(static_cast<int>(nDirs) - 1, static_cast<int>(i) + W);
237  for (int oi = i_min; oi <= i_max; oi++)
238  {
239  // "no obstacle" (norm_dist=1.0) doesn't count as a real obs:
240  if (ni.obstacles[oi] >= 0.99) continue;
241  mrpt::keep_min(closest_obs, sg.distance(obstacles_2d[oi]));
242  }
243  }
244 
245  // Factor [6]: Direct distance in "sectors":
246  // -------------------------------------------------------------------
247  scores[6] =
248  1.0 /
249  (1.0 + mrpt::square((4.0 / nDirs) * mrpt::abs_diff(i, target_k)));
250 
251  // If target is not directly reachable for this i-th direction, decimate
252  // its scorings:
253  if (target_dist < 1.0 - options.TOO_CLOSE_OBSTACLE &&
254  ni.obstacles[i] < 1.01 * target_dist)
255  {
256  // this direction cannot reach target, so assign a low score:
257  scores[1] *= 0.1;
258  scores[2] *= 0.1;
259  scores[6] *= 0.1;
260  }
261 
262  // Save stats for debugging:
263  for (size_t l = 0; l < NUM_FACTORS; l++)
264  m_dirs_scores(i, l) = scores[l];
265 
266  } // end for each direction "i"
267 
268  // Normalize factors?
269  ASSERT_(options.factorNormalizeOrNot.size() == NUM_FACTORS);
270  for (size_t l = 0; l < NUM_FACTORS; l++)
271  {
272  if (!options.factorNormalizeOrNot[l]) continue;
273 
274  const double mmax = m_dirs_scores.col(l).maxCoeff();
275  const double mmin = m_dirs_scores.col(l).minCoeff();
276  const double span = mmax - mmin;
277  if (span <= .0) continue;
278 
279  m_dirs_scores.col(l).array() -= mmin;
280  m_dirs_scores.col(l).array() /= span;
281  }
282 
283  // Phase 1: average of PHASE1_FACTORS and thresholding:
284  // ----------------------------------------------------------------------
285  const unsigned int NUM_PHASES = options.PHASE_FACTORS.size();
286  ASSERT_(NUM_PHASES >= 1);
287 
288  std::vector<double> weights_sum_phase(NUM_PHASES, .0),
289  weights_sum_phase_inv(NUM_PHASES);
290  for (unsigned int i = 0; i < NUM_PHASES; i++)
291  {
292  for (unsigned int l : options.PHASE_FACTORS[i])
293  weights_sum_phase[i] += options.factorWeights.at(l);
294  ASSERT_(weights_sum_phase[i] > .0);
295  weights_sum_phase_inv[i] = 1.0 / weights_sum_phase[i];
296  }
297 
298  eo.phase_scores = std::vector<std::vector<double>>(
299  NUM_PHASES, std::vector<double>(nDirs, .0));
300  auto& phase_scores = eo.phase_scores; // shortcut
301  double last_phase_threshold = -1.0; // don't threshold for the first phase
302 
303  for (unsigned int phase_idx = 0; phase_idx < NUM_PHASES; phase_idx++)
304  {
305  double phase_min = std::numeric_limits<double>::max(), phase_max = .0;
306 
307  for (unsigned int i = 0; i < nDirs; i++)
308  {
309  double this_dir_eval = 0;
310 
311  if (ni.obstacles[i] <
312  options.TOO_CLOSE_OBSTACLE || // Too close to obstacles ?
313  (phase_idx > 0 &&
314  phase_scores[phase_idx - 1][i] <
315  last_phase_threshold) // thresholding of the previous
316  // phase
317  )
318  {
319  this_dir_eval = .0;
320  }
321  else
322  {
323  // Weighted avrg of factors:
324  for (unsigned int l : options.PHASE_FACTORS[phase_idx])
325  this_dir_eval +=
326  options.factorWeights.at(l) *
327  std::log(std::max(1e-6, m_dirs_scores(i, l)));
328 
329  this_dir_eval *= weights_sum_phase_inv[phase_idx];
330  this_dir_eval = std::exp(this_dir_eval);
331  }
332  phase_scores[phase_idx][i] = this_dir_eval;
333 
334  mrpt::keep_max(phase_max, phase_scores[phase_idx][i]);
335  mrpt::keep_min(phase_min, phase_scores[phase_idx][i]);
336 
337  } // for each direction
338 
339  ASSERT_(options.PHASE_THRESHOLDS.size() == NUM_PHASES);
340  ASSERT_(
341  options.PHASE_THRESHOLDS[phase_idx] > .0 &&
342  options.PHASE_THRESHOLDS[phase_idx] < 1.0);
343 
344  last_phase_threshold =
345  options.PHASE_THRESHOLDS[phase_idx] * phase_max +
346  (1.0 - options.PHASE_THRESHOLDS[phase_idx]) * phase_min;
347  } // end for each phase
348 
349  // Give a chance for a derived class to manipulate the final evaluations:
350  auto& dirs_eval = phase_scores.back();
351 
352  postProcessDirectionEvaluations(dirs_eval, ni, target_idx);
353 
354  // Recalculate the threshold just in case the postProcess function above
355  // changed things:
356  {
357  double phase_min = std::numeric_limits<double>::max(), phase_max = .0;
358  for (unsigned int i = 0; i < nDirs; i++)
359  {
360  mrpt::keep_max(phase_max, dirs_eval[i]);
361  mrpt::keep_min(phase_min, dirs_eval[i]);
362  }
363  last_phase_threshold =
364  options.PHASE_THRESHOLDS.back() * phase_max +
365  (1.0 - options.PHASE_THRESHOLDS.back()) * phase_min;
366  }
367 
368  // Thresholding:
369  for (unsigned int i = 0; i < nDirs; i++)
370  {
371  double& val = dirs_eval[i];
372  if (val < last_phase_threshold) val = .0;
373  }
374 }
375 
376 void CHolonomicFullEval::navigate(const NavInput& ni, NavOutput& no)
377 {
378  using mrpt::square;
379 
380  ASSERT_(ni.clearance != nullptr);
381  ASSERT_(!ni.targets.empty());
382 
383  // Create a log record for returning data.
384  auto log = std::make_shared<CLogFileRecord_FullEval>();
385  no.logRecord = log;
386 
387  // Evaluate for each target:
388  const size_t numTrgs = ni.targets.size();
389  std::vector<EvalOutput> evals(numTrgs);
390  for (unsigned int trg_idx = 0; trg_idx < numTrgs; trg_idx++)
391  {
392  evalSingleTarget(trg_idx, ni, evals[trg_idx]);
393  }
394 
395  ASSERT_(!evals.empty());
396  const auto nDirs = evals.front().phase_scores.back().size();
397  ASSERT_EQUAL_(nDirs, ni.obstacles.size());
398 
399  // Now, sum all weights for the last stage for each target into an "overall"
400  // score vector, one score per direction of motion:
401  std::vector<double> overall_scores;
402  overall_scores.assign(nDirs, .0);
403  for (const auto& e : evals)
404  {
405  for (unsigned int i = 0; i < nDirs; i++)
406  overall_scores[i] += e.phase_scores.back()[i];
407  }
408  // Normalize:
409  for (unsigned int i = 0; i < nDirs; i++)
410  overall_scores[i] *= (1.0 / numTrgs);
411 
412  // Search for best direction in the "overall score" vector:
413 
414  // Keep the GAP with the largest maximum value within;
415  // then pick the MIDDLE point as the final selection.
416  std::vector<TGap> gaps;
417  std::size_t best_gap_idx = std::string::npos;
418  {
419  bool inside_gap = false;
420  for (unsigned int i = 0; i < nDirs; i++)
421  {
422  const double val = overall_scores[i];
423  if (val < 0.01)
424  {
425  // This direction didn't pass the cut threshold for the "last
426  // phase":
427  if (inside_gap)
428  {
429  // We just ended a gap:
430  auto& active_gap = *gaps.rbegin();
431  active_gap.k_to = i - 1;
432  inside_gap = false;
433  }
434  }
435  else
436  {
437  // higher or EQUAL to the treshold (equal is important just in
438  // case we have a "flat" diagram...)
439  if (!inside_gap)
440  {
441  // We just started a gap:
442  TGap new_gap;
443  new_gap.k_from = i;
444  gaps.emplace_back(new_gap);
445  inside_gap = true;
446  }
447  }
448 
449  if (inside_gap)
450  {
451  auto& active_gap = *gaps.rbegin();
452  if (val >= active_gap.max_eval)
453  {
454  active_gap.k_best_eval = i;
455  }
456  mrpt::keep_max(active_gap.max_eval, val);
457  mrpt::keep_min(active_gap.min_eval, val);
458 
459  if (best_gap_idx == std::string::npos ||
460  val > gaps[best_gap_idx].max_eval)
461  {
462  best_gap_idx = gaps.size() - 1;
463  }
464  }
465  } // end for i
466 
467  // Handle the case where we end with an open, active gap:
468  if (inside_gap)
469  {
470  auto& active_gap = *gaps.rbegin();
471  active_gap.k_to = nDirs - 1;
472  }
473  }
474 
475  // Not heading to target: go thru the "middle" of the gap to maximize
476  // clearance
477  int best_dir_k = -1;
478  double best_dir_eval = 0;
479 
480  // We may have no gaps if all paths are blocked by obstacles, for example:
481  if (!gaps.empty())
482  {
483  ASSERT_(best_gap_idx < gaps.size());
484  const TGap& best_gap = gaps[best_gap_idx];
485  best_dir_k = best_gap.k_best_eval;
486  best_dir_eval = overall_scores.at(best_dir_k);
487  }
488 
489  // Prepare NavigationOutput data:
490  if (best_dir_eval == .0)
491  {
492  // No way found!
493  no.desiredDirection = 0;
494  no.desiredSpeed = 0;
495  }
496  else
497  {
498  // A valid movement:
499  const auto ptg = getAssociatedPTG();
500  const double ptg_ref_dist = ptg ? ptg->getRefDistance() : 1.0;
501 
502  no.desiredDirection =
503  CParameterizedTrajectoryGenerator::index2alpha(best_dir_k, nDirs);
504 
505  // Speed control: Reduction factors
506  // ---------------------------------------------
507  const double targetNearnessFactor =
508  m_enableApproachTargetSlowDown
509  ? std::min(
510  1.0, ni.targets.front().norm() /
511  (options.TARGET_SLOW_APPROACHING_DISTANCE /
512  ptg_ref_dist))
513  : 1.0;
514 
515  const double obs_dist = ni.obstacles[best_dir_k];
516  // Was: min with obs_clearance too.
517  const double obs_dist_th = std::max(
518  options.TOO_CLOSE_OBSTACLE,
519  options.OBSTACLE_SLOW_DOWN_DISTANCE * ni.maxObstacleDist);
520  double riskFactor = 1.0;
521  if (obs_dist <= options.TOO_CLOSE_OBSTACLE)
522  {
523  riskFactor = 0.0;
524  }
525  else if (
526  obs_dist < obs_dist_th && obs_dist_th > options.TOO_CLOSE_OBSTACLE)
527  {
528  riskFactor = (obs_dist - options.TOO_CLOSE_OBSTACLE) /
529  (obs_dist_th - options.TOO_CLOSE_OBSTACLE);
530  }
531  no.desiredSpeed =
532  ni.maxRobotSpeed * std::min(riskFactor, targetNearnessFactor);
533  }
534 
535  m_last_selected_sector = best_dir_k;
536 
537  // LOG --------------------------
538  if (log)
539  {
540  log->selectedTarget = 0; // was: best_trg_idx
541  log->selectedSector = best_dir_k;
542  log->evaluation = best_dir_eval;
543  // Copy the evaluation of first phases for (arbitrarily) the first
544  // target, then overwrite the scores of its last phase with the OVERALL
545  // phase scores:
546  log->dirs_eval = evals.front().phase_scores;
547  log->dirs_eval.back() = overall_scores;
548 
549  if (options.LOG_SCORE_MATRIX)
550  {
551  log->dirs_scores = m_dirs_scores;
552  }
553  }
554 }
555 
556 unsigned int CHolonomicFullEval::direction2sector(
557  const double a, const unsigned int N)
558 {
559  const int idx = round(0.5 * (N * (1 + mrpt::math::wrapToPi(a) / M_PI) - 1));
560  if (idx < 0)
561  return 0;
562  else
563  return static_cast<unsigned int>(idx);
564 }
565 
566 CLogFileRecord_FullEval::CLogFileRecord_FullEval() : dirs_scores() {}
567 uint8_t CLogFileRecord_FullEval::serializeGetVersion() const { return 3; }
570 {
572  << evaluation << selectedTarget /*v3*/;
573 }
574 
575 /*---------------------------------------------------------------
576  readFromStream
577  ---------------------------------------------------------------*/
579  mrpt::serialization::CArchive& in, uint8_t version)
580 {
581  switch (version)
582  {
583  case 0:
584  case 1:
585  case 2:
586  case 3:
587  {
588  if (version >= 2)
589  {
591  }
592  else
593  {
596  if (version >= 1)
597  {
599  }
600  }
602  if (version >= 3)
603  {
604  in >> selectedTarget;
605  }
606  else
607  {
608  selectedTarget = 0;
609  }
610  }
611  break;
612  default:
614  };
615 }
616 
617 /*---------------------------------------------------------------
618  TOptions
619  ---------------------------------------------------------------*/
621  : factorWeights{0.1, 0.5, 0.5, 0.01, 1, 1, 1},
622  factorNormalizeOrNot{0, 0, 0, 0, 1, 0, 0},
623  PHASE_FACTORS{{1, 2}, {4}, {0, 2}},
624  PHASE_THRESHOLDS{0.5, 0.6, 0.7}
625 
626 {
627 }
628 
630  const mrpt::config::CConfigFileBase& c, const std::string& s)
631 {
632  MRPT_START
633 
634  // Load from config text:
635  MRPT_LOAD_CONFIG_VAR(TOO_CLOSE_OBSTACLE, double, c, s);
636  MRPT_LOAD_CONFIG_VAR(TARGET_SLOW_APPROACHING_DISTANCE, double, c, s);
637  MRPT_LOAD_CONFIG_VAR(OBSTACLE_SLOW_DOWN_DISTANCE, double, c, s);
638  MRPT_LOAD_CONFIG_VAR(HYSTERESIS_SECTOR_COUNT, double, c, s);
639  MRPT_LOAD_CONFIG_VAR(LOG_SCORE_MATRIX, bool, c, s);
640  MRPT_LOAD_CONFIG_VAR(clearance_threshold_ratio, double, c, s);
641  MRPT_LOAD_CONFIG_VAR(gap_width_ratio_threshold, double, c, s);
642 
643  c.read_vector(
644  s, "factorWeights", std::vector<double>(), factorWeights, true);
645  ASSERT_EQUAL_(factorWeights.size(), NUM_FACTORS);
646 
647  c.read_vector(
648  s, "factorNormalizeOrNot", factorNormalizeOrNot, factorNormalizeOrNot);
649  ASSERT_EQUAL_(factorNormalizeOrNot.size(), factorWeights.size());
650 
651  // Phases:
652  int PHASE_COUNT = 0;
653  MRPT_LOAD_CONFIG_VAR_NO_DEFAULT(PHASE_COUNT, int, c, s);
654 
655  PHASE_FACTORS.resize(PHASE_COUNT);
656  PHASE_THRESHOLDS.resize(PHASE_COUNT);
657  for (int i = 0; i < PHASE_COUNT; i++)
658  {
659  c.read_vector(
660  s, mrpt::format("PHASE%i_FACTORS", i + 1), PHASE_FACTORS[i],
661  PHASE_FACTORS[i], true);
662  ASSERT_(!PHASE_FACTORS[i].empty());
663 
664  PHASE_THRESHOLDS[i] = c.read_double(
665  s, mrpt::format("PHASE%i_THRESHOLD", i + 1), .0, true);
666  ASSERT_(PHASE_THRESHOLDS[i] >= .0 && PHASE_THRESHOLDS[i] <= 1.0);
667  }
668 
669  MRPT_END
670 }
671 
673  mrpt::config::CConfigFileBase& c, const std::string& s) const
674 {
675  MRPT_START
676 
677  const int WN = mrpt::config::MRPT_SAVE_NAME_PADDING(),
679 
681  TOO_CLOSE_OBSTACLE,
682  "Directions with collision-free distances below this threshold are not "
683  "elegible.");
685  TARGET_SLOW_APPROACHING_DISTANCE,
686  "Start to reduce speed when closer than this to target.");
688  OBSTACLE_SLOW_DOWN_DISTANCE,
689  "Start to reduce speed when clearance is below this value ([0,1] ratio "
690  "wrt obstacle reference/max distance)");
692  HYSTERESIS_SECTOR_COUNT,
693  "Range of `sectors` (directions) for hysteresis over successive "
694  "timesteps");
696  LOG_SCORE_MATRIX, "Save the entire score matrix in log files");
698  clearance_threshold_ratio,
699  "Ratio [0,1], times path_count, gives the minimum number of paths at "
700  "each side of a target direction to be accepted as desired direction");
702  gap_width_ratio_threshold,
703  "Ratio [0,1], times path_count, gives the minimum gap width to accept "
704  "a direct motion towards target.");
705 
706  ASSERT_EQUAL_(factorWeights.size(), NUM_FACTORS);
707  c.write(
708  s, "factorWeights",
709  mrpt::system::sprintf_container("%.2f ", factorWeights), WN, WV,
710  "[0]=Free space, [1]=Dist. in sectors, [2]=Closer to target "
711  "(Euclidean), [3]=Hysteresis, [4]=clearance along path, [5]=Like [2] "
712  "without decimation if path obstructed");
713  c.write(
714  s, "factorNormalizeOrNot",
715  mrpt::system::sprintf_container("%u ", factorNormalizeOrNot), WN, WV,
716  "Normalize factors or not (1/0)");
717 
718  c.write(
719  s, "PHASE_COUNT", PHASE_FACTORS.size(), WN, WV,
720  "Number of evaluation phases to run (params for each phase below)");
721 
722  for (unsigned int i = 0; i < PHASE_FACTORS.size(); i++)
723  {
724  c.write(
725  s, mrpt::format("PHASE%u_THRESHOLD", i + 1), PHASE_THRESHOLDS[i],
726  WN, WV,
727  "Phase scores must be above this relative range threshold [0,1] to "
728  "be considered in next phase (Default:`0.75`)");
729  c.write(
730  s, mrpt::format("PHASE%u_FACTORS", i + 1),
731  mrpt::system::sprintf_container("%d ", PHASE_FACTORS[i]), WN, WV,
732  "Indices of the factors above to be considered in this phase");
733  }
734 
735  MRPT_END
736 }
737 
738 uint8_t CHolonomicFullEval::serializeGetVersion() const { return 4; }
740 {
741  // Params:
743  << options.PHASE_FACTORS << // v3
745  << options.PHASE_THRESHOLDS // v3
750  ;
751  // State:
753 }
755  mrpt::serialization::CArchive& in, uint8_t version)
756 {
757  switch (version)
758  {
759  case 0:
760  case 1:
761  case 2:
762  case 3:
763  case 4:
764  {
765  // Params:
767 
768  if (version >= 3)
769  {
770  in >> options.PHASE_FACTORS;
771  }
772  else
773  {
774  options.PHASE_THRESHOLDS.resize(2);
776  }
779 
780  if (version >= 3)
781  {
783  }
784  else
785  {
786  options.PHASE_THRESHOLDS.resize(1);
787  in >> options.PHASE_THRESHOLDS[0];
788  }
789 
790  if (version >= 1) in >> options.OBSTACLE_SLOW_DOWN_DISTANCE;
791  if (version >= 2) in >> options.factorNormalizeOrNot;
792 
793  if (version >= 4)
794  {
797  }
798 
799  // State:
801  }
802  break;
803  default:
805  };
806 }
807 
809  std::vector<double>& dir_evals, const NavInput& ni, unsigned int trg_idx)
810 {
811  // Default: do nothing
812 }
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)
If desired, override in a derived class to manipulate the final evaluations of each directions...
double min_eval
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...
#define MRPT_START
Definition: exceptions.h:241
A class for storing extra information about the execution of CHolonomicFullEval navigation.
double distance(const TPoint2D &point) const
Distance to point.
Definition: TSegment2D.cpp:19
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
TPoint2D_< double > TPoint2D
Lightweight 2D point.
Definition: TPoint2D.h:213
app initialize(argc, argv)
double TOO_CLOSE_OBSTACLE
Directions with collision-free distances below this threshold are not elegible.
void saveToConfigFile(mrpt::config::CConfigFileBase &cfg, const std::string &section) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...
T x
X,Y coordinates.
Definition: TPoint2D.h:25
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
int MRPT_SAVE_NAME_PADDING()
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc.
std::vector< double > obstacles
Distance to obstacles in polar coordinates, relative to the robot.
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
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.
std::vector< int32_t > factorNormalizeOrNot
0/1 to normalize factors.
IMPLEMENTS_SERIALIZABLE(CLogFileRecord_FullEval, CHolonomicLogFileRecord, mrpt::nav) IMPLEMENTS_SERIALIZABLE(CHolonomicFullEval
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
double clearance_threshold_ratio
Ratio [0,1], times path_count, gives the minimum number of paths at each side of a target direction t...
std::vector< double > PHASE_THRESHOLDS
Phase 1,2,N-1...
std::vector< mrpt::math::TPoint2D > targets
Relative location (x,y) of target point(s).
TOptions options
Parameters of the algorithm (can be set manually or loaded from CHolonomicFullEval::initialize or opt...
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
Definition: exceptions.h:97
double OBSTACLE_SLOW_DOWN_DISTANCE
Start to reduce speed when clearance is below this value ([0,1] ratio wrt obstacle reference/max dist...
mrpt::nav const unsigned NUM_FACTORS
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
double maxRobotSpeed
Maximum robot speed, in the same units than obstacles, per second.
This class allows loading and storing values and vectors of different types from a configuration text...
This base provides a set of functions for maths stuff.
2D segment, consisting of two points.
Definition: TSegment2D.h:20
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
Definition: exceptions.h:137
Auxiliary struct that holds all the relevant geometry information about a 2D scan.
A base class for log records for different holonomic navigation methods.
double desiredDirection
The desired motion direction, in the range [-PI, PI].
mrpt::config::CConfigFileBase CConfigFileBase
std::vector< double > factorWeights
See docs above.
int val
Definition: mrpt_jpeglib.h:957
int MRPT_SAVE_VALUE_PADDING()
#define MRPT_LOAD_CONFIG_VAR_NO_DEFAULT( variableName, variableType, configFileObject, sectionNameStr)
CHolonomicLogFileRecord::Ptr logRecord
The navigation method will create a log record and store it here via a smart pointer.
double read_double(const std::string &section, const std::string &name, double defaultValue, bool failIfNotFound=false) const
TPoint2D point2
Destiny point.
Definition: TSegment2D.h:30
double maxObstacleDist
Maximum expected value to be found in obstacles.
void serializeFrom(mrpt::serialization::CArchive &in, uint8_t serial_version) override
Pure virtual method for reading (deserializing) from an abstract archive.
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Definition: wrap2pi.h:50
Full evaluation of all possible directions within the discrete set of input directions.
void write(const std::string &section, const std::string &name, enum_t value, const int name_padding_width=-1, const int value_padding_width=-1, const std::string &comment=std::string())
bool empty() const
Definition: ts_hash_map.h:191
std::vector< std::vector< double > > dirs_eval
Final [N-1] and earlier stages [0...N-1] evaluation scores for each direction, in the same order of T...
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...
TPoint2D point1
Origin point.
Definition: TSegment2D.h:26
double desiredSpeed
The desired motion speed in that direction, from 0 up to NavInput::maxRobotSpeed. ...
return_t square(const num_t x)
Inline function for the square of a number.
#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...
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.
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:54
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object.
mrpt::vision::TStereoCalibResults out
#define ASSERT_ABOVE_(__A, __B)
Definition: exceptions.h:155
#define MRPT_END
Definition: exceptions.h:245
double HYSTERESIS_SECTOR_COUNT
Range of "sectors" (directions) for hysteresis over successive timesteps.
#define MRPT_SAVE_CONFIG_VAR_COMMENT(variableName, __comment)
Input parameters for CAbstractHolonomicReactiveMethod::navigate()
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive.
bool rightToLeft
Angles storage order: true=counterclockwise; false=clockwise.
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:125
std::vector< std::vector< double > > phase_scores
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...
T abs_diff(const T a, const T b)
Efficient and portable evaluation of the absolute difference of two unsigned integer values (but will...
void read_vector(const std::string &section, const std::string &name, const VECTOR_TYPE &defaultValue, VECTOR_TYPE &outValues, bool failIfNotFound=false) const
Reads a configuration parameter of type vector, stored in the file as a string: "[v1 v2 v3 ...
CONTAINER::Scalar norm(const CONTAINER &v)
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string &section) override
This method load the options from a ".ini"-like file or memory-stored string list.
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:24



Page generated by Doxygen 1.8.14 for MRPT 2.0.4 Git: 33de1d0ad Sat Jun 20 11:02:42 2020 +0200 at sáb jun 20 17:35:17 CEST 2020