33 m_last_selected_sector(
std::numeric_limits<
unsigned int>::max())
35 if (INI_FILE !=
nullptr) initialize(*INI_FILE);
40 options.loadFromConfigFile(INI_FILE, getConfigFileSectionName());
44 options.saveToConfigFile(
c, getConfigFileSectionName());
52 const auto ptg = getAssociatedPTG();
53 const double ptg_ref_dist = ptg ? ptg->getRefDistance() : 1.0;
57 unsigned int selectedSector;
58 double riskEvaluation;
68 const auto trg = *ni.
targets.rbegin();
74 ni.
obstacles, 1.0 , gaps, trg, selectedSector,
75 evaluation, situation, riskEvaluation, *log);
77 if (situation == SITUATION_NO_WAY_FOUND)
91 const double targetNearnessFactor =
92 m_enableApproachTargetSlowDown
95 trg.norm() / (options.TARGET_SLOW_APPROACHING_DISTANCE /
99 const double riskFactor =
100 std::min(1.0, riskEvaluation / options.RISK_EVALUATION_DISTANCE);
105 m_last_selected_sector = selectedSector;
112 int i,
n = gaps.size();
113 log->gaps_ini.resize(
n);
114 log->gaps_end.resize(
n);
115 for (i = 0; i <
n; i++)
117 log->gaps_ini[i] = gaps[i].ini;
118 log->gaps_end[i] = gaps[i].end;
122 log->selectedSector = selectedSector;
123 log->evaluation = evaluation;
124 log->situation = situation;
125 log->riskEvaluation = riskEvaluation;
132 void CHolonomicND::gapsEstimator(
136 const size_t n = obstacles.size();
140 const int GAPS_MIN_WIDTH = ceil(
n * 0.01);
141 const double GAPS_MIN_DEPTH_CONSIDERED = 0.6;
142 const double GAPS_MAX_RELATIVE_DEPTH = 0.5;
148 overall_min_dist = std::numeric_limits<float>::max();
149 for (
size_t i = 1; i < (
n - 1); i++)
154 double max_depth = overall_max_dist - overall_min_dist;
159 gaps_temp.reserve(150);
161 for (
double threshold_ratio = 0.95; threshold_ratio >= 0.05;
162 threshold_ratio -= 0.05)
164 const double dist_threshold =
165 threshold_ratio * overall_max_dist +
166 (1.0f - threshold_ratio) *
167 min(target.
norm(), GAPS_MIN_DEPTH_CONSIDERED);
169 bool is_inside =
false;
170 size_t sec_ini = 0, sec_end = 0;
173 for (
size_t i = 0; i <
n; i++)
175 if (!is_inside && (obstacles[i] >= dist_threshold))
178 maxDist = obstacles[i];
183 (i == (
n - 1) || obstacles[i] < dist_threshold))
185 if (obstacles[i] < dist_threshold)
192 if ((sec_end - sec_ini) >= (size_t)GAPS_MIN_WIDTH)
195 gaps_temp.resize(gaps_temp.size() + 1);
196 TGap& newGap = *gaps_temp.rbegin();
198 newGap.
ini = sec_ini;
199 newGap.
end = sec_end;
201 min(obstacles[sec_ini], obstacles[sec_end]);
206 if (is_inside) maxDist = std::max(maxDist, obstacles[i]);
213 const size_t nTempGaps = gaps_temp.size();
215 std::vector<bool> delete_gaps;
216 delete_gaps.assign(nTempGaps,
false);
219 for (
size_t i = 0; i < nTempGaps; i++)
221 if (delete_gaps[i] == 1)
continue;
223 for (
size_t j = i + 1; j < nTempGaps; j++)
225 if (gaps_temp[i].ini == gaps_temp[j].ini ||
226 gaps_temp[i].
end == gaps_temp[j].
end)
232 for (
size_t i = 0; i < nTempGaps; i++)
234 if (delete_gaps[i] == 1)
continue;
236 if ((gaps_temp[i].maxDistance - gaps_temp[i].minDistance) >
237 max_depth * GAPS_MAX_RELATIVE_DEPTH)
242 for (
size_t i = 0; i < nTempGaps; i++)
244 if (delete_gaps[i])
continue;
246 unsigned int inner_gap_count = 0;
248 for (
unsigned int j = 0; j < nTempGaps; j++)
250 if (i == j || delete_gaps[j])
continue;
253 if (gaps_temp[j].ini >= gaps_temp[i].ini &&
254 gaps_temp[j].
end <= gaps_temp[i].
end)
255 if (++inner_gap_count > 1)
264 for (
size_t i = 0; i < nTempGaps; i++)
266 if (delete_gaps[i])
continue;
268 for (
unsigned int j = 0; j < nTempGaps; j++)
270 if (i == j || delete_gaps[j])
continue;
271 if (gaps_temp[i].ini <= gaps_temp[j].ini &&
272 gaps_temp[i].
end >= gaps_temp[j].
end)
280 gaps_out.reserve(nTempGaps / 2);
281 for (
size_t i = 0; i < nTempGaps; i++)
283 if (delete_gaps[i])
continue;
286 calcRepresentativeSectorForGap(gaps_temp[i], target, obstacles);
288 gaps_out.push_back(gaps_temp[i]);
295 void CHolonomicND::searchBestGap(
296 const std::vector<double>& obstacles,
const double maxObsRange,
298 unsigned int& out_selDirection,
double& out_selEvaluation,
299 TSituations& out_situation,
double& out_riskEvaluation,
303 unsigned int min_risk_eval_sector = 0;
304 unsigned int max_risk_eval_sector = obstacles.size() - 1;
305 const unsigned int target_sector =
306 direction2sector(atan2(target.
y, target.
x), obstacles.size());
307 const double target_dist = std::max(0.01, target.
norm());
312 const int freeSectorsNearTarget = ceil(0.02 * obstacles.size());
313 bool theyAreFree =
true, caseD1 =
false;
314 if (target_sector > static_cast<unsigned int>(freeSectorsNearTarget) &&
316 static_cast<unsigned int>(obstacles.size() - freeSectorsNearTarget))
318 const double min_free_dist =
319 std::min(1.05 * target_dist, 0.95 * maxObsRange);
320 for (
int j = -freeSectorsNearTarget;
321 theyAreFree && j <= freeSectorsNearTarget; j++)
322 if (obstacles[(
int(target_sector) + j) % obstacles.size()] <
325 caseD1 = theyAreFree;
331 out_selDirection = target_sector;
335 1.0 + std::max(0.0, (maxObsRange - target_dist) / maxObsRange);
336 out_situation = SITUATION_TARGET_DIRECTLY;
341 std::vector<double> gaps_evaluation;
342 int selected_gap = -1;
343 double selected_gap_eval = -100;
346 obstacles, maxObsRange, in_gaps, target_sector, target_dist,
375 if (selected_gap == -1)
376 for (
unsigned int i = 0; i < in_gaps.size(); i++)
377 if (gaps_evaluation[i] > selected_gap_eval)
379 selected_gap_eval = gaps_evaluation[i];
385 if (selected_gap_eval <= 0)
389 out_selDirection = 0;
390 out_selEvaluation = 0.0;
391 out_situation = SITUATION_NO_WAY_FOUND;
396 const TGap& gap = in_gaps[selected_gap];
398 const unsigned int sectors_to_be_wide =
399 round(options.WIDE_GAP_SIZE_PERCENT * obstacles.size());
401 out_selDirection = in_gaps[selected_gap].representative_sector;
402 out_selEvaluation = selected_gap_eval;
406 if ((gap.
end - gap.
ini) < sectors_to_be_wide)
410 out_situation = SITUATION_SMALL_GAP;
416 out_situation = SITUATION_WIDE_GAP;
420 min_risk_eval_sector = gap.
ini;
421 max_risk_eval_sector = gap.
end;
427 const unsigned int risk_eval_nsectors =
428 round(options.RISK_EVALUATION_SECTORS_PERCENT * obstacles.size());
429 const unsigned int sec_ini = std::max(
430 min_risk_eval_sector, risk_eval_nsectors < out_selDirection
431 ? out_selDirection - risk_eval_nsectors
433 const unsigned int sec_fin =
434 std::min(max_risk_eval_sector, out_selDirection + risk_eval_nsectors);
436 out_riskEvaluation = 0.0;
437 for (
unsigned int i = sec_ini; i <= sec_fin; i++)
438 out_riskEvaluation += obstacles[i];
439 out_riskEvaluation /= (sec_fin - sec_ini + 1);
446 void CHolonomicND::calcRepresentativeSectorForGap(
448 const std::vector<double>& obstacles)
451 const unsigned int sectors_to_be_wide =
452 round(options.WIDE_GAP_SIZE_PERCENT * obstacles.size());
453 const unsigned int target_sector =
454 direction2sector(atan2(target.
y, target.
x), obstacles.size());
462 float min_dist_obs_near_ini = 1, min_dist_obs_near_end = 1;
464 for (i = gap.
ini; i >= max(0, gap.
ini - 2); i--)
465 min_dist_obs_near_ini =
min(min_dist_obs_near_ini, obstacles[i]);
466 for (i = gap.
end; i <=
min((
int)obstacles.size() - 1, gap.
end + 2); i++)
467 min_dist_obs_near_end =
min(min_dist_obs_near_end, obstacles[i]);
469 (min_dist_obs_near_ini * gap.
ini +
470 min_dist_obs_near_end * gap.
end) /
471 (min_dist_obs_near_ini + min_dist_obs_near_end));
480 if (dist_ini > 0.5 * obstacles.size())
481 dist_ini = obstacles.size() - dist_ini;
482 if (dist_end > 0.5 * obstacles.size())
483 dist_end = obstacles.size() - dist_end;
486 if (dist_ini < dist_end)
497 sector = sector + dir *
static_cast<int>(sectors_to_be_wide) / 2;
501 keep_min(sector, static_cast<int>(obstacles.size()) - 1);
509 void CHolonomicND::evaluateGaps(
510 const std::vector<double>& obstacles,
const double maxObsRange,
511 const TGapArray& gaps,
const unsigned int target_sector,
512 const float target_dist, std::vector<double>& out_gaps_evaluation)
514 out_gaps_evaluation.resize(gaps.size());
516 const double targetAng = CParameterizedTrajectoryGenerator::index2alpha(
517 target_sector, obstacles.size());
518 const double target_x = target_dist * cos(targetAng);
519 const double target_y = target_dist * sin(targetAng);
521 for (
unsigned int i = 0; i < gaps.size(); i++)
524 const TGap* gap = &gaps[i];
526 const float d =
min3(
531 const double phi = CParameterizedTrajectoryGenerator::index2alpha(
533 const double x = d * cos(phi);
534 const double y = d * sin(phi);
539 float meanDist = 0.f;
540 for (
unsigned int j = gap->
ini; j <= gap->
end; j++)
541 meanDist += obstacles[j];
542 meanDist /= (gap->
end - gap->
ini + 1);
548 factor1 =
std::min(target_dist, meanDist) / target_dist;
558 if (dif > 0.5 * obstacles.size()) dif = obstacles.size() - dif;
560 const double factor2 = exp(-
square(dif / (obstacles.size() * 0.25)));
565 double closestX, closestY;
572 const float factor3 =
573 (maxObsRange -
std::min(maxObsRange, dist_eucl)) / maxObsRange;
578 double factor_AntiCab;
580 if (m_last_selected_sector != std::numeric_limits<unsigned int>::max())
585 if (dist >
unsigned(0.1 * obstacles.size()))
586 factor_AntiCab = 0.0;
588 factor_AntiCab = 1.0;
595 ASSERT_(options.factorWeights.size() == 4);
598 options.TOO_CLOSE_OBSTACLE)
599 out_gaps_evaluation[i] = 0;
601 out_gaps_evaluation[i] =
602 (options.factorWeights[0] * factor1 +
603 options.factorWeights[1] * factor2 +
604 options.factorWeights[2] * factor3 +
605 options.factorWeights[3] * factor_AntiCab) /
610 unsigned int CHolonomicND::direction2sector(
611 const double a,
const unsigned int N)
617 return static_cast<unsigned int>(idx);
625 void CLogFileRecord_ND::writeToStream(
632 out << gaps_ini << gaps_end << gaps_eval;
633 out << selectedSector << evaluation << riskEvaluation
652 in.ReadBuffer(&(*gaps_ini.begin()),
sizeof(gaps_ini[0]) *
n);
653 in.ReadBuffer(&(*gaps_end.begin()),
sizeof(gaps_end[0]) *
n);
657 in.ReadBuffer(&(*gaps_eval.begin()),
sizeof(gaps_eval[0]) *
n);
659 in >> selectedSector >> evaluation >> riskEvaluation >>
n;
667 in >> gaps_ini >> gaps_end >> gaps_eval;
668 in >> selectedSector >> evaluation >> riskEvaluation >>
n;
680 CHolonomicND::TOptions::TOptions()
682 TOO_CLOSE_OBSTACLE(0.15),
683 WIDE_GAP_SIZE_PERCENT(0.25),
684 RISK_EVALUATION_SECTORS_PERCENT(0.10),
685 RISK_EVALUATION_DISTANCE(0.4),
686 MAX_SECTOR_DIST_FOR_D2_PERCENT(0.25),
687 TARGET_SLOW_APPROACHING_DISTANCE(0.60),
688 factorWeights{1.0, 0.5, 2.0, 0.4}
700 MAX_SECTOR_DIST_FOR_D2_PERCENT,
double,
source, section);
702 RISK_EVALUATION_SECTORS_PERCENT,
double,
source, section);
706 TARGET_SLOW_APPROACHING_DISTANCE,
double,
source, section);
709 section,
"factorWeights", std::vector<double>(), factorWeights,
true);
710 ASSERT_(factorWeights.size() == 4);
726 RISK_EVALUATION_DISTANCE,
"In normalized ps-meters [0,1]");
729 TARGET_SLOW_APPROACHING_DISTANCE,
"In normalized ps-meters");
735 "%.2f %.2f %.2f %.2f", factorWeights[0], factorWeights[1],
736 factorWeights[2], factorWeights[3]),
738 "[0]=Free space, [1]=Dist. in sectors, [2]=Closer to target " 739 "(Euclidean), [3]=Hysteresis");
#define ASSERT_EQUAL_(__A, __B)
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
const T min3(const T &A, const T &B, const T &C)
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
An implementation of the holonomic reactive navigation method "Nearness-Diagram". ...
unsigned int m_last_selected_sector
double RISK_EVALUATION_DISTANCE
This file implements several operations that operate element-wise on individual or pairs of container...
A base class for holonomic reactive navigation methods.
std::vector< TGap > TGapArray
double WIDE_GAP_SIZE_PERCENT
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...
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.
TOptions options
Parameters of the algorithm (can be set manually or loaded from CHolonomicND::initialize or options...
unsigned int representative_sector
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
This base provides a set of functions for maths stuff.
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
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_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].
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
std::vector< double > factorWeights
Vector of 4 weights: [0]=Free space, [1]=Dist.
CHolonomicLogFileRecord::Ptr logRecord
The navigation method will create a log record and store it here via a smart pointer.
GLsizei const GLchar ** string
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
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...
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini"-like file or memory-stored string list.
double norm() const
Point norm.
double desiredSpeed
The desired motion speed in that direction, from 0 up to NavInput::maxRobotSpeed. ...
double RISK_EVALUATION_SECTORS_PERCENT
double MAX_SECTOR_DIST_FOR_D2_PERCENT
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
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...
The structure used to store a detected gap in obstacles.
std::shared_ptr< CLogFileRecord_ND > Ptr
double TARGET_SLOW_APPROACHING_DISTANCE
A class for storing extra information about the execution of CHolonomicND navigation.
GLsizei GLsizei GLchar * source
int round(const T value)
Returns the closer integer (int) to x.
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...
#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...
IMPLEMENTS_SERIALIZABLE(CHolonomicND, CAbstractHolonomicReactiveMethod, mrpt::nav) CHolonomicND
Initialize the parameters of the navigator, from some configuration file, or default values if filena...
T abs_diff(const T a, const T b)
Efficient and portable evaluation of the absolute difference of two unsigned integer values (but will...
std::vector< double > gaps_eval
unsigned __int32 uint32_t
double minimumDistanceFromPointToSegment(const double Px, const double Py, const double x1, const double y1, const double x2, const double y2, T &out_x, T &out_y)
Computes the closest point from a given point to a segment, and returns that minimum distance...
GLubyte GLubyte GLubyte a
Output for CAbstractHolonomicReactiveMethod::navigate()
double TOO_CLOSE_OBSTACLE
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()
TSituations
The set of posible situations for each trajectory.
void saveToConfigFile(mrpt::utils::CConfigFileBase &cfg, const std::string §ion) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...