32       m_last_selected_sector(
std::numeric_limits<
unsigned int>::max())
    34     if (INI_FILE != 
nullptr) 
initialize(*INI_FILE);
    39     options.loadFromConfigFile(INI_FILE, getConfigFileSectionName());
    43     options.saveToConfigFile(c, getConfigFileSectionName());
    51     const auto ptg = getAssociatedPTG();
    52     const double ptg_ref_dist = ptg ? ptg->getRefDistance() : 1.0;
    56     unsigned int selectedSector;
    57     double riskEvaluation;
    67     const auto trg = *ni.
targets.rbegin();
    73         ni.
obstacles, 1.0 , gaps, trg, selectedSector,
    74         evaluation, situation, riskEvaluation, *log);
    76     if (situation == SITUATION_NO_WAY_FOUND)
    90         const double targetNearnessFactor =
    91             m_enableApproachTargetSlowDown
    94                       trg.norm() / (options.TARGET_SLOW_APPROACHING_DISTANCE /
    98         const double riskFactor =
    99             std::min(1.0, riskEvaluation / options.RISK_EVALUATION_DISTANCE);
   101             ni.
maxRobotSpeed * std::min(riskFactor, targetNearnessFactor);
   104     m_last_selected_sector = selectedSector;
   111             int i, n = gaps.size();
   112             log->gaps_ini.resize(n);
   113             log->gaps_end.resize(n);
   114             for (i = 0; i < n; i++)
   116                 log->gaps_ini[i] = gaps[i].ini;
   117                 log->gaps_end[i] = gaps[i].end;
   121         log->selectedSector = selectedSector;
   122         log->evaluation = evaluation;
   123         log->situation = situation;
   124         log->riskEvaluation = riskEvaluation;
   131 void CHolonomicND::gapsEstimator(
   135     const size_t n = obstacles.size();
   139     const int GAPS_MIN_WIDTH = ceil(n * 0.01);  
   140     const double GAPS_MIN_DEPTH_CONSIDERED = 0.6;
   141     const double GAPS_MAX_RELATIVE_DEPTH = 0.5;
   146     double overall_max_dist = std::numeric_limits<float>::min(),
   147            overall_min_dist = std::numeric_limits<float>::max();
   148     for (
size_t i = 1; i < (n - 1); i++)
   153     double max_depth = overall_max_dist - overall_min_dist;
   158     gaps_temp.reserve(150);
   160     for (
double threshold_ratio = 0.95; threshold_ratio >= 0.05;
   161          threshold_ratio -= 0.05)
   163         const double dist_threshold =
   164             threshold_ratio * overall_max_dist +
   165             (1.0f - threshold_ratio) *
   166                 min(target.
norm(), GAPS_MIN_DEPTH_CONSIDERED);
   168         bool is_inside = 
false;
   169         size_t sec_ini = 0, sec_end = 0;
   172         for (
size_t i = 0; i < n; i++)
   174             if (!is_inside && (obstacles[i] >= dist_threshold))  
   177                 maxDist = obstacles[i];
   182                 (i == (n - 1) || obstacles[i] < dist_threshold))  
   184                 if (obstacles[i] < dist_threshold)
   191                 if ((sec_end - sec_ini) >= (size_t)GAPS_MIN_WIDTH)
   194                     gaps_temp.resize(gaps_temp.size() + 1);
   195                     TGap& newGap = *gaps_temp.rbegin();
   197                     newGap.
ini = sec_ini;
   198                     newGap.
end = sec_end;
   200                         min(obstacles[sec_ini], obstacles[sec_end]);
   205             if (is_inside) maxDist = std::max(maxDist, obstacles[i]);
   212     const size_t nTempGaps = gaps_temp.size();
   214     std::vector<bool> delete_gaps;
   215     delete_gaps.assign(nTempGaps, 
false);
   218     for (
size_t i = 0; i < nTempGaps; i++)
   220         if (delete_gaps[i] == 1) 
continue;
   222         for (
size_t j = i + 1; j < nTempGaps; j++)
   224             if (gaps_temp[i].ini == gaps_temp[j].ini ||
   225                 gaps_temp[i].
end == gaps_temp[j].
end)
   226                 delete_gaps[j] = 
true;
   231     for (
size_t i = 0; i < nTempGaps; i++)
   233         if (delete_gaps[i] == 1) 
continue;
   235         if ((gaps_temp[i].maxDistance - gaps_temp[i].minDistance) >
   236             max_depth * GAPS_MAX_RELATIVE_DEPTH)
   237             delete_gaps[i] = 
true;
   241     for (
size_t i = 0; i < nTempGaps; i++)
   243         if (delete_gaps[i]) 
continue;
   245         unsigned int inner_gap_count = 0;
   247         for (
unsigned int j = 0; j < nTempGaps; j++)
   249             if (i == j || delete_gaps[j]) 
continue;
   252             if (gaps_temp[j].ini >= gaps_temp[i].ini &&
   253                 gaps_temp[j].
end <= gaps_temp[i].
end)
   254                 if (++inner_gap_count > 1)
   256                     delete_gaps[i] = 
true;
   263     for (
size_t i = 0; i < nTempGaps; i++)
   265         if (delete_gaps[i]) 
continue;
   267         for (
unsigned int j = 0; j < nTempGaps; j++)
   269             if (i == j || delete_gaps[j]) 
continue;
   270             if (gaps_temp[i].ini <= gaps_temp[j].ini &&
   271                 gaps_temp[i].
end >= gaps_temp[j].
end)
   272                 delete_gaps[j] = 
true;
   279     gaps_out.reserve(nTempGaps / 2);
   280     for (
size_t i = 0; i < nTempGaps; i++)
   282         if (delete_gaps[i]) 
continue;
   285         calcRepresentativeSectorForGap(gaps_temp[i], target, obstacles);
   287         gaps_out.push_back(gaps_temp[i]);
   294 void CHolonomicND::searchBestGap(
   295     const std::vector<double>& obstacles, 
const double maxObsRange,
   297     unsigned int& out_selDirection, 
double& out_selEvaluation,
   298     TSituations& out_situation, 
double& out_riskEvaluation,
   302     unsigned int min_risk_eval_sector = 0;
   303     unsigned int max_risk_eval_sector = obstacles.size() - 1;
   304     const unsigned int target_sector =
   305         direction2sector(atan2(target.
y, target.
x), obstacles.size());
   306     const double target_dist = std::max(0.01, target.
norm());
   311     const int freeSectorsNearTarget = ceil(0.02 * obstacles.size());
   312     bool theyAreFree = 
true, caseD1 = 
false;
   313     if (target_sector > static_cast<unsigned int>(freeSectorsNearTarget) &&
   315             static_cast<unsigned int>(obstacles.size() - freeSectorsNearTarget))
   317         const double min_free_dist =
   318             std::min(1.05 * target_dist, 0.95 * maxObsRange);
   319         for (
int j = -freeSectorsNearTarget;
   320              theyAreFree && j <= freeSectorsNearTarget; j++)
   321             if (obstacles[(
int(target_sector) + j) % obstacles.size()] <
   324         caseD1 = theyAreFree;
   330         out_selDirection = target_sector;
   334             1.0 + std::max(0.0, (maxObsRange - target_dist) / maxObsRange);
   335         out_situation = SITUATION_TARGET_DIRECTLY;
   340         std::vector<double> gaps_evaluation;
   341         int selected_gap = -1;
   342         double selected_gap_eval = -100;
   345             obstacles, maxObsRange, in_gaps, target_sector, target_dist,
   374         if (selected_gap == -1)
   375             for (
unsigned int i = 0; i < in_gaps.size(); i++)
   376                 if (gaps_evaluation[i] > selected_gap_eval)
   378                     selected_gap_eval = gaps_evaluation[i];
   384         if (selected_gap_eval <= 0)
   388             out_selDirection = 0;
   389             out_selEvaluation = 0.0;  
   390             out_situation = SITUATION_NO_WAY_FOUND;
   395             const TGap& gap = in_gaps[selected_gap];
   397             const unsigned int sectors_to_be_wide =
   398                 round(options.WIDE_GAP_SIZE_PERCENT * obstacles.size());
   400             out_selDirection = in_gaps[selected_gap].representative_sector;
   401             out_selEvaluation = selected_gap_eval;
   405             if ((gap.
end - gap.
ini) < sectors_to_be_wide)
   409                 out_situation = SITUATION_SMALL_GAP;
   415                 out_situation = SITUATION_WIDE_GAP;
   419             min_risk_eval_sector = gap.
ini;
   420             max_risk_eval_sector = gap.
end;
   426     const unsigned int risk_eval_nsectors =
   427         round(options.RISK_EVALUATION_SECTORS_PERCENT * obstacles.size());
   428     const unsigned int sec_ini = std::max(
   429         min_risk_eval_sector, risk_eval_nsectors < out_selDirection
   430                                   ? out_selDirection - risk_eval_nsectors
   432     const unsigned int sec_fin =
   433         std::min(max_risk_eval_sector, out_selDirection + risk_eval_nsectors);
   435     out_riskEvaluation = 0.0;
   436     for (
unsigned int i = sec_ini; i <= sec_fin; i++)
   437         out_riskEvaluation += obstacles[i];
   438     out_riskEvaluation /= (sec_fin - sec_ini + 1);
   445 void CHolonomicND::calcRepresentativeSectorForGap(
   447     const std::vector<double>& obstacles)
   450     const unsigned int sectors_to_be_wide =
   451         round(options.WIDE_GAP_SIZE_PERCENT * obstacles.size());
   452     const unsigned int target_sector =
   453         direction2sector(atan2(target.
y, target.
x), obstacles.size());
   461         float min_dist_obs_near_ini = 1, min_dist_obs_near_end = 1;
   463         for (i = gap.
ini; i >= max(0, gap.
ini - 2); i--)
   464             min_dist_obs_near_ini = min(min_dist_obs_near_ini, obstacles[i]);
   465         for (i = gap.
end; i <= min((
int)obstacles.size() - 1, gap.
end + 2); i++)
   466             min_dist_obs_near_end = min(min_dist_obs_near_end, obstacles[i]);
   468             (min_dist_obs_near_ini * gap.
ini +
   469              min_dist_obs_near_end * gap.
end) /
   470             (min_dist_obs_near_ini + min_dist_obs_near_end));
   479         if (dist_ini > 0.5 * obstacles.size())
   480             dist_ini = obstacles.size() - dist_ini;
   481         if (dist_end > 0.5 * obstacles.size())
   482             dist_end = obstacles.size() - dist_end;
   485         if (dist_ini < dist_end)
   496         sector = sector + 
dir * 
static_cast<int>(sectors_to_be_wide) / 2;
   500     keep_min(sector, static_cast<int>(obstacles.size()) - 1);
   508 void CHolonomicND::evaluateGaps(
   509     const std::vector<double>& obstacles, 
const double maxObsRange,
   510     const TGapArray& gaps, 
const unsigned int target_sector,
   511     const float target_dist, std::vector<double>& out_gaps_evaluation)
   513     out_gaps_evaluation.resize(gaps.size());
   515     const double targetAng = CParameterizedTrajectoryGenerator::index2alpha(
   516         target_sector, obstacles.size());
   517     const double target_x = target_dist * cos(targetAng);
   518     const double target_y = target_dist * sin(targetAng);
   520     for (
unsigned int i = 0; i < gaps.size(); i++)
   523         const TGap* gap = &gaps[i];
   525         const float d = 
min3(
   530         const double phi = CParameterizedTrajectoryGenerator::index2alpha(
   532         const double x = d * cos(phi);
   533         const double y = d * sin(phi);
   538         float meanDist = 0.f;
   539         for (
unsigned int j = gap->
ini; j <= gap->
end; j++)
   540             meanDist += obstacles[j];
   541         meanDist /= (gap->
end - gap->
ini + 1);
   546             factor1 = std::min(target_dist, meanDist) / target_dist;
   556         if (dif > 0.5 * obstacles.size()) dif = obstacles.size() - dif;
   558         const double factor2 = exp(-
square(dif / (obstacles.size() * 0.25)));
   563         double closestX, closestY;
   570         const float factor3 =
   571             (maxObsRange - std::min(maxObsRange, dist_eucl)) / maxObsRange;
   576         double factor_AntiCab;
   578         if (m_last_selected_sector != std::numeric_limits<unsigned int>::max())
   583             if (dist > 
unsigned(0.1 * obstacles.size()))
   584                 factor_AntiCab = 0.0;
   586                 factor_AntiCab = 1.0;
   593         ASSERT_(options.factorWeights.size() == 4);
   596             options.TOO_CLOSE_OBSTACLE)  
   597             out_gaps_evaluation[i] = 0;
   599             out_gaps_evaluation[i] =
   600                 (options.factorWeights[0] * factor1 +
   601                  options.factorWeights[1] * factor2 +
   602                  options.factorWeights[2] * factor3 +
   603                  options.factorWeights[3] * factor_AntiCab) /
   608 unsigned int CHolonomicND::direction2sector(
   609     const double a, 
const unsigned int N)
   615         return static_cast<unsigned int>(idx);
   618 uint8_t CLogFileRecord_ND::serializeGetVersion()
 const { 
return 1; }
   621     out << gaps_ini << gaps_end << gaps_eval;
   622     out << selectedSector << evaluation << riskEvaluation
   623         << (uint32_t)situation;
   626 void CLogFileRecord_ND::serializeFrom(
   638             in.
ReadBuffer(&(*gaps_ini.begin()), 
sizeof(gaps_ini[0]) * n);
   639             in.
ReadBuffer(&(*gaps_end.begin()), 
sizeof(gaps_end[0]) * n);
   643             in.
ReadBuffer(&(*gaps_eval.begin()), 
sizeof(gaps_eval[0]) * n);
   645             in >> selectedSector >> evaluation >> riskEvaluation >> n;
   653             in >> gaps_ini >> gaps_end >> gaps_eval;
   654             in >> selectedSector >> evaluation >> riskEvaluation >> n;
   666 CHolonomicND::TOptions::TOptions() : factorWeights{1.0, 0.5, 2.0, 0.4} {}
   675         MAX_SECTOR_DIST_FOR_D2_PERCENT, 
double, source, section);
   677         RISK_EVALUATION_SECTORS_PERCENT, 
double, source, section);
   681         TARGET_SLOW_APPROACHING_DISTANCE, 
double, source, section);
   684         section, 
"factorWeights", std::vector<double>(), factorWeights, 
true);
   685     ASSERT_(factorWeights.size() == 4);
   701         RISK_EVALUATION_DISTANCE, 
"In normalized ps-meters [0,1]");
   704         TARGET_SLOW_APPROACHING_DISTANCE, 
"In normalized ps-meters");
   710             "%.2f %.2f %.2f %.2f", factorWeights[0], factorWeights[1],
   711             factorWeights[2], factorWeights[3]),
   713         "[0]=Free space, [1]=Dist. in sectors, [2]=Closer to target "   714         "(Euclidean), [3]=Hysteresis");
 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...
 
app initialize(argc, argv)
 
std::string std::string format(std::string_view fmt, ARGS &&... args)
 
An implementation of the holonomic reactive navigation method "Nearness-Diagram". ...
 
unsigned int m_last_selected_sector
 
int MRPT_SAVE_NAME_PADDING()
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc. 
 
double RISK_EVALUATION_DISTANCE
 
This file implements several operations that operate element-wise on individual or pairs of container...
 
void saveToConfigFile(mrpt::config::CConfigFileBase &cfg, const std::string §ion) const override
This method saves the options to a ".ini"-like file or memory-stored string list. ...
 
A base class for holonomic reactive navigation methods. 
 
double WIDE_GAP_SIZE_PERCENT
 
const T min3(const T &A, const T &B, const T &C)
 
std::vector< TGap > TGapArray
 
TOptions options
Parameters of the algorithm (can be set manually or loaded from CHolonomicND::initialize or options...
 
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations. 
 
unsigned int representative_sector
 
#define ASSERT_(f)
Defines an assertion mechanism. 
 
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string §ion) override
This method load the options from a ".ini"-like file or memory-stored string list. 
 
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. 
 
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure. 
 
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. 
 
mrpt::config::CConfigFileBase CConfigFileBase
 
std::vector< double > factorWeights
Vector of 4 weights: [0]=Free space, [1]=Dist. 
 
int MRPT_SAVE_VALUE_PADDING()
 
CHolonomicLogFileRecord::Ptr logRecord
The navigation method will create a log record and store it here via a smart pointer. 
 
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. 
 
void write(const std::string §ion, 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())
 
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...
 
double desiredSpeed
The desired motion speed in that direction, from 0 up to NavInput::maxRobotSpeed. ...
 
double RISK_EVALUATION_SECTORS_PERCENT
 
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...
 
double MAX_SECTOR_DIST_FOR_D2_PERCENT
 
const_iterator end() const
 
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries. 
 
Virtual base class for "archives": classes abstracting I/O streams. 
 
The structure used to store a detected gap in obstacles. 
 
mrpt::vision::TStereoCalibResults out
 
double TARGET_SLOW_APPROACHING_DISTANCE
 
A class for storing extra information about the execution of CHolonomicND navigation. 
 
size_t ReadBuffer(void *Buffer, size_t Count)
Reads a block of bytes from the stream into Buffer. 
 
T norm() const
Point norm: |v| = sqrt(x^2+y^2) 
 
#define MRPT_SAVE_CONFIG_VAR_COMMENT(variableName, __comment)
 
uint8_t serializeGetVersion() const override
Must return the current versioning number of the object. 
 
IMPLEMENTS_SERIALIZABLE(CHolonomicND, CAbstractHolonomicReactiveMethod, mrpt::nav) CHolonomicND
Initialize the parameters of the navigator, from some configuration file, or default values if filena...
 
void serializeTo(mrpt::serialization::CArchive &out) const override
Pure virtual method for writing (serializing) to an abstract archive. 
 
std::vector< double > gaps_eval
 
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...
 
Output for CAbstractHolonomicReactiveMethod::navigate() 
 
double TOO_CLOSE_OBSTACLE
 
TSituations
The set of posible situations for each trajectory. 
 
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 §ion, 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 ...
 
int round(const T value)
Returns the closer integer (int) to x.