33 const
unsigned int INVALID_K =
std::numeric_limits<
unsigned int>::max();
40 m_last_selected_sector(
std::numeric_limits<
unsigned int>::max()) {
42 initialize(*INI_FILE);
46 options.saveToConfigFile(
c, getConfigFileSectionName());
50 options.loadFromConfigFile(
c, getConfigFileSectionName());
60 : k_from(-1), k_to(-1), min_eval(
std::numeric_limits<double>::max()),
61 max_eval(-
std::numeric_limits<double>::max()), contains_target_k(false),
65 void CHolonomicFullEval::evalSingleTarget(
unsigned int target_idx,
68 const auto target = ni.
targets[target_idx];
74 const auto ptg = getAssociatedPTG();
77 const double target_dir = ::atan2(target.y, target.x);
78 const unsigned int target_k =
79 CParameterizedTrajectoryGenerator::alpha2index(target_dir, nDirs);
80 const double target_dist = target.norm();
82 m_dirs_scores.resize(nDirs, options.factorWeights.size() + 2);
85 std::vector<mrpt::math::TPoint2D> obstacles_2d(nDirs);
91 const auto &sc_lut = m_sincos_lut.getSinCosForScan(sp);
93 for (
unsigned int i = 0; i < nDirs; i++) {
94 obstacles_2d[i].x = ni.
obstacles[i] * sc_lut.ccos[i];
95 obstacles_2d[i].y = ni.
obstacles[i] * sc_lut.csin[i];
102 for (
unsigned int i = 0; i < nDirs; i++) {
107 if (ni.
obstacles[i] < options.TOO_CLOSE_OBSTACLE &&
108 !(i == target_k && ni.
obstacles[i] > 1.02 * target_dist)) {
110 m_dirs_scores(i, l) = .0;
117 const double x = d * sc_lut.ccos[i];
118 const double y = d * sc_lut.csin[i];
123 target_dist < 1.0 - options.TOO_CLOSE_OBSTACLE &&
126 scores[0] = std::max(target_dist, ni.
obstacles[i]) / (target_dist * 1.05);
128 scores[0] = std::max(0.0, ni.
obstacles[i] - options.TOO_CLOSE_OBSTACLE);
133 if (ptg !=
nullptr) {
134 const double max_real_freespace = ptg->getActualUnloopedPathLength(i);
135 const double max_real_freespace_norm =
136 max_real_freespace / ptg->getRefDistance();
152 double min_dist_target_along_path = sg.
distance(target);
158 const double endpt_dist_to_target = (target -
TPoint2D(
x,
y)).
norm();
159 const double endpt_dist_to_target_norm =
160 std::min(1.0, endpt_dist_to_target);
162 if ((endpt_dist_to_target_norm > target_dist &&
163 endpt_dist_to_target_norm >= 0.95 * target_dist) &&
165 min_dist_target_along_path >
166 1.05 *
std::min(target_dist, endpt_dist_to_target_norm)) {
170 min_dist_target_along_path = sg.
distance(target);
173 scores[1] = 1.0 / (1.0 +
square(min_dist_target_along_path));
179 scores[2] = std::sqrt(1.01 - endpt_dist_to_target_norm);
180 scores[5] = scores[2];
187 if (m_last_selected_sector != std::numeric_limits<unsigned int>::max()) {
189 const unsigned int hist_dist =
192 if (hist_dist >= options.HYSTERESIS_SECTOR_COUNT)
193 scores[3] =
square(1.0 - (hist_dist - options.HYSTERESIS_SECTOR_COUNT) /
211 double &closest_obs = scores[4];
216 const int i_min = std::max(0, static_cast<int>(i) - W);
218 std::min(static_cast<int>(nDirs) - 1, static_cast<int>(i) + W);
219 for (
int oi = i_min; oi <= i_max; oi++) {
235 if (target_dist < 1.0 - options.TOO_CLOSE_OBSTACLE &&
245 m_dirs_scores(i, l) = scores[l];
252 if (!options.factorNormalizeOrNot[l])
255 const double mmax = m_dirs_scores.col(l).maxCoeff();
256 const double mmin = m_dirs_scores.col(l).minCoeff();
261 m_dirs_scores.col(l).array() -=
mmin;
262 m_dirs_scores.col(l).array() /=
span;
267 const unsigned int NUM_PHASES = options.PHASE_FACTORS.size();
270 std::vector<double> weights_sum_phase(NUM_PHASES, .0),
271 weights_sum_phase_inv(NUM_PHASES);
272 for (
unsigned int i = 0; i < NUM_PHASES; i++) {
273 for (
unsigned int l : options.PHASE_FACTORS[i])
274 weights_sum_phase[i] += options.factorWeights.at(l);
275 ASSERT_(weights_sum_phase[i] > .0);
276 weights_sum_phase_inv[i] = 1.0 / weights_sum_phase[i];
280 NUM_PHASES, std::vector<double>(nDirs, .0));
282 double last_phase_threshold = -1.0;
284 for (
unsigned int phase_idx = 0; phase_idx < NUM_PHASES; phase_idx++) {
285 double phase_min = std::numeric_limits<double>::max(), phase_max = .0;
287 for (
unsigned int i = 0; i < nDirs; i++) {
288 double this_dir_eval = 0;
291 options.TOO_CLOSE_OBSTACLE ||
293 phase_scores[phase_idx - 1][i] <
294 last_phase_threshold)
300 for (
unsigned int l : options.PHASE_FACTORS[phase_idx])
301 this_dir_eval += options.factorWeights.at(l) *
302 std::log(std::max(1e-6, m_dirs_scores(i, l)));
304 this_dir_eval *= weights_sum_phase_inv[phase_idx];
305 this_dir_eval = std::exp(this_dir_eval);
307 phase_scores[phase_idx][i] = this_dir_eval;
314 ASSERT_(options.PHASE_THRESHOLDS.size() == NUM_PHASES);
315 ASSERT_(options.PHASE_THRESHOLDS[phase_idx] > .0 &&
316 options.PHASE_THRESHOLDS[phase_idx] < 1.0);
318 last_phase_threshold =
319 options.PHASE_THRESHOLDS[phase_idx] * phase_max +
320 (1.0 - options.PHASE_THRESHOLDS[phase_idx]) * phase_min;
324 auto &dirs_eval = phase_scores.back();
326 postProcessDirectionEvaluations(dirs_eval, ni, target_idx);
331 double phase_min = std::numeric_limits<double>::max(), phase_max = .0;
332 for (
unsigned int i = 0; i < nDirs; i++) {
336 last_phase_threshold = options.PHASE_THRESHOLDS.back() * phase_max +
337 (1.0 - options.PHASE_THRESHOLDS.back()) * phase_min;
341 for (
unsigned int i = 0; i < nDirs; i++) {
342 double &
val = dirs_eval[i];
343 if (
val < last_phase_threshold)
355 auto log = CLogFileRecord_FullEval::Create();
359 const size_t numTrgs = ni.
targets.size();
360 std::vector<EvalOutput> evals(numTrgs);
361 for (
unsigned int trg_idx = 0; trg_idx < numTrgs; trg_idx++) {
362 evalSingleTarget(trg_idx, ni, evals[trg_idx]);
366 const auto nDirs = evals.front().phase_scores.back().size();
371 std::vector<double> overall_scores;
372 overall_scores.assign(nDirs, .0);
373 for (
const auto &e : evals) {
374 for (
unsigned int i = 0; i < nDirs; i++)
375 overall_scores[i] += e.phase_scores.back()[i];
378 for (
unsigned int i = 0; i < nDirs; i++)
379 overall_scores[i] *= (1.0 / numTrgs);
385 std::vector<TGap> gaps;
386 std::size_t best_gap_idx = std::string::npos;
388 bool inside_gap =
false;
389 for (
unsigned int i = 0; i < nDirs; i++) {
390 const double val = overall_scores[i];
396 auto &active_gap = *gaps.rbegin();
397 active_gap.k_to = i - 1;
407 gaps.emplace_back(new_gap);
413 auto &active_gap = *gaps.rbegin();
414 if (
val >= active_gap.max_eval) {
415 active_gap.k_best_eval = i;
420 if (best_gap_idx == std::string::npos ||
421 val > gaps[best_gap_idx].max_eval) {
422 best_gap_idx = gaps.size() - 1;
429 auto &active_gap = *gaps.rbegin();
430 active_gap.k_to = nDirs - 1;
437 double best_dir_eval = 0;
441 ASSERT_(best_gap_idx < gaps.size());
442 const TGap &best_gap = gaps[best_gap_idx];
443 best_dir_k = best_gap.k_best_eval;
444 best_dir_eval = overall_scores.at(best_dir_k);
448 if (best_dir_eval == .0) {
454 const auto ptg = getAssociatedPTG();
455 const double ptg_ref_dist = ptg ? ptg->getRefDistance() : 1.0;
458 CParameterizedTrajectoryGenerator::index2alpha(best_dir_k, nDirs);
462 const double targetNearnessFactor =
463 m_enableApproachTargetSlowDown
465 (options.TARGET_SLOW_APPROACHING_DISTANCE /
469 const double obs_dist = ni.
obstacles[best_dir_k];
471 const double obs_dist_th =
472 std::max(options.TOO_CLOSE_OBSTACLE,
474 double riskFactor = 1.0;
475 if (obs_dist <= options.TOO_CLOSE_OBSTACLE) {
477 }
else if (obs_dist < obs_dist_th &&
478 obs_dist_th > options.TOO_CLOSE_OBSTACLE) {
479 riskFactor = (obs_dist - options.TOO_CLOSE_OBSTACLE) /
480 (obs_dist_th - options.TOO_CLOSE_OBSTACLE);
486 m_last_selected_sector = best_dir_k;
490 log->selectedTarget = 0;
491 log->selectedSector = best_dir_k;
492 log->evaluation = best_dir_eval;
496 log->dirs_eval = evals.front().phase_scores;
497 log->dirs_eval.back() = overall_scores;
499 if (options.LOG_SCORE_MATRIX) {
500 log->dirs_scores = m_dirs_scores;
505 unsigned int CHolonomicFullEval::direction2sector(
const double a,
506 const unsigned int N) {
511 return static_cast<unsigned int>(idx);
514 CLogFileRecord_FullEval::CLogFileRecord_FullEval()
515 : selectedSector(0), evaluation(.0), dirs_scores(), selectedTarget(0) {}
563 TOO_CLOSE_OBSTACLE(0.15), TARGET_SLOW_APPROACHING_DISTANCE(0.60),
564 OBSTACLE_SLOW_DOWN_DISTANCE(0.15), HYSTERESIS_SECTOR_COUNT(5),
565 LOG_SCORE_MATRIX(false), clearance_threshold_ratio(0.05),
566 gap_width_ratio_threshold(0.25) {
567 factorWeights = mrpt::math::make_vector<5, double>(0.1, 0.5, 0.5, 0.01, 1);
591 c.read_vector(
s,
"factorWeights", std::vector<double>(), factorWeights,
true);
594 c.read_vector(
s,
"factorNormalizeOrNot", factorNormalizeOrNot,
595 factorNormalizeOrNot);
596 ASSERT_EQUAL_(factorNormalizeOrNot.size(), factorWeights.size());
602 PHASE_FACTORS.resize(PHASE_COUNT);
603 PHASE_THRESHOLDS.resize(PHASE_COUNT);
604 for (
int i = 0; i < PHASE_COUNT; i++) {
605 c.read_vector(
s,
mrpt::format(
"PHASE%i_FACTORS", i + 1), PHASE_FACTORS[i],
606 PHASE_FACTORS[i],
true);
609 PHASE_THRESHOLDS[i] =
610 c.read_double(
s,
mrpt::format(
"PHASE%i_THRESHOLD", i + 1), .0,
true);
611 ASSERT_(PHASE_THRESHOLDS[i] >= .0 && PHASE_THRESHOLDS[i] <= 1.0);
626 "Directions with collision-free distances below this threshold are not " 629 TARGET_SLOW_APPROACHING_DISTANCE,
630 "Start to reduce speed when closer than this to target.");
632 OBSTACLE_SLOW_DOWN_DISTANCE,
633 "Start to reduce speed when clearance is below this value ([0,1] ratio " 634 "wrt obstacle reference/max distance)");
636 HYSTERESIS_SECTOR_COUNT,
637 "Range of `sectors` (directions) for hysteresis over successive " 640 "Save the entire score matrix in log files");
642 clearance_threshold_ratio,
643 "Ratio [0,1], times path_count, gives the minimum number of paths at " 644 "each side of a target direction to be accepted as desired direction");
646 gap_width_ratio_threshold,
647 "Ratio [0,1], times path_count, gives the minimum gap width to accept " 648 "a direct motion towards target.");
651 c.write(
s,
"factorWeights",
653 "[0]=Free space, [1]=Dist. in sectors, [2]=Closer to target " 654 "(Euclidean), [3]=Hysteresis, [4]=clearance along path, [5]=Like [2] " 655 "without decimation if path obstructed");
656 c.write(
s,
"factorNormalizeOrNot",
658 "Normalize factors or not (1/0)");
660 c.write(
s,
"PHASE_COUNT", PHASE_FACTORS.size(), WN, WV,
661 "Number of evaluation phases to run (params for each phase below)");
663 for (
unsigned int i = 0; i < PHASE_FACTORS.size(); i++) {
664 c.write(
s,
mrpt::format(
"PHASE%u_THRESHOLD", i + 1), PHASE_THRESHOLDS[i],
666 "Phase scores must be above this relative range threshold [0,1] to " 667 "be considered in next phase (Default:`0.75`)");
670 "Indices of the factors above to be considered in this phase");
740 std::vector<double> &dir_evals,
const NavInput &ni,
unsigned int trg_idx) {
#define ASSERT_EQUAL_(__A, __B)
int BASE_IMPEXP MRPT_SAVE_VALUE_PADDING
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc.
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)
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.
double TOO_CLOSE_OBSTACLE
Directions with collision-free distances below this threshold are not elegible.
#define ASSERT_ABOVE_(__A, __B)
#define MRPT_LOAD_CONFIG_VAR_NO_DEFAULT(variableName, variableType, configFileObject, sectionNameStr)
void readFromStream(mrpt::utils::CStream &in, int version)
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
double distance(const TPoint2D &point) const
Distance to point.
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const
Introduces a pure virtual method responsible for writing to a CStream.
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].
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const
Introduces a pure virtual method responsible for writing to a CStream.
void saveToConfigFile(mrpt::utils::CConfigFileBase &cfg, const std::string §ion) const MRPT_OVERRIDE
This method saves the options to a ".ini"-like file or memory-stored string list. ...
mrpt::nav const unsigned int INVALID_K
int32_t selectedTarget
Normally = 0. Can be >0 if multiple targets passed simultaneously.
std::vector< int32_t > factorNormalizeOrNot
0/1 to normalize factors.
IMPLEMENTS_SERIALIZABLE(CLogFileRecord_FullEval, CHolonomicLogFileRecord, mrpt::nav) IMPLEMENTS_SERIALIZABLE(CHolonomicFullEval
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... scores must be above this relative range threshold [0,1] to be considered in phase 2...
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 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...
int mmin(const int t1, const int t2)
const unsigned NUM_FACTORS
int32_t selectedSector
Member data.
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.
2D segment, consisting of two points.
#define MRPT_SAVE_CONFIG_VAR_COMMENT(variableName, __comment)
Auxiliary struct that holds all the relevant geometry information about a 2D scan.
#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].
std::vector< double > factorWeights
See docs above.
TPoint2D point2
Destiny point.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
GLsizei const GLchar ** string
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Full evaluation of all possible directions within the discrete set of input directions.
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...
TPoint2D point1
Origin point.
double desiredSpeed
The desired motion speed in that direction, from 0 up to NavInput::maxRobotSpeed. ...
#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...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
T square(const T x)
Inline function for the square of a number.
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.
unsigned int m_last_selected_sector
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 readFromStream(mrpt::utils::CStream &in, int version)
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
bool rightToLeft
Angles storage order: true=counterclockwise; false=clockwise.
GLenum GLenum GLvoid GLvoid GLvoid * span
GLubyte GLubyte GLubyte a
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...
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...
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...
int BASE_IMPEXP MRPT_SAVE_NAME_PADDING
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string §ion) MRPT_OVERRIDE
This method load the options from a ".ini"-like file or memory-stored string list.
CONTAINER::Scalar norm(const CONTAINER &v)
CHolonomicLogFileRecordPtr logRecord
The navigation method will create a log record and store it here via a smart pointer.