32 m_last_selected_sector (
std::numeric_limits<
unsigned int>::max() )
35 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;
62 CLogFileRecord_NDPtr log = CLogFileRecord_ND::Create();
68 const auto trg = *ni.
targets.rbegin();
74 searchBestGap(ni.
obstacles,1.0, gaps,trg,selectedSector,evaluation,situation,riskEvaluation,log);
76 if (situation == SITUATION_NO_WAY_FOUND)
89 const double targetNearnessFactor = m_enableApproachTargetSlowDown ?
90 std::min(1.0, trg.norm() / (options.TARGET_SLOW_APPROACHING_DISTANCE / ptg_ref_dist))
94 const double riskFactor =
std::min(1.0, riskEvaluation / options.RISK_EVALUATION_DISTANCE );
98 m_last_selected_sector = selectedSector;
105 int i,
n = gaps.size();
106 log->gaps_ini.resize(
n);
107 log->gaps_end.resize(
n);
110 log->gaps_ini[i] = gaps[i].ini;
111 log->gaps_end[i] = gaps[i].end;
115 log->selectedSector = selectedSector;
116 log->evaluation = evaluation;
117 log->situation = situation;
118 log->riskEvaluation = riskEvaluation;
128 void CHolonomicND::gapsEstimator(
129 const std::vector<double> & obstacles,
133 const size_t n = obstacles.size();
137 const int GAPS_MIN_WIDTH = ceil(
n*0.01);
138 const double GAPS_MIN_DEPTH_CONSIDERED = 0.6;
139 const double GAPS_MAX_RELATIVE_DEPTH = 0.5;
145 for (
size_t i=1;i<(
n-1);i++)
150 double max_depth = overall_max_dist - overall_min_dist;
155 gaps_temp.reserve( 150 );
157 for (
double threshold_ratio = 0.95;threshold_ratio>=0.05;threshold_ratio-=0.05)
159 const double dist_threshold = threshold_ratio* overall_max_dist + (1.0f-threshold_ratio)*
min(target.
norm(), GAPS_MIN_DEPTH_CONSIDERED);
161 bool is_inside =
false;
162 size_t sec_ini=0, sec_end=0;
165 for (
size_t i=0;i<
n;i++)
167 if ( !is_inside && ( obstacles[i]>=dist_threshold) )
170 maxDist = obstacles[i];
173 else if (is_inside && (i==(
n-1) || obstacles[i]<dist_threshold ))
175 if (obstacles[i]<dist_threshold)
182 if ( (sec_end-sec_ini) >= (size_t)GAPS_MIN_WIDTH )
185 gaps_temp.resize( gaps_temp.size() + 1 );
186 TGap & newGap = *gaps_temp.rbegin();
188 newGap.
ini = sec_ini;
189 newGap.
end = sec_end;
190 newGap.
minDistance =
min( obstacles[sec_ini], obstacles[sec_end] );
196 maxDist = std::max( maxDist, obstacles[i] );
203 const size_t nTempGaps = gaps_temp.size();
205 std::vector<bool> delete_gaps;
206 delete_gaps.assign( nTempGaps,
false);
209 for (
size_t i=0;i<nTempGaps;i++)
211 if (delete_gaps[i] == 1)
214 for (
size_t j=i+1;j<nTempGaps;j++)
216 if (gaps_temp[i].ini == gaps_temp[j].ini || gaps_temp[i].
end == gaps_temp[j].
end)
222 for (
size_t i=0;i<nTempGaps;i++)
224 if (delete_gaps[i] == 1)
227 if ((gaps_temp[i].maxDistance - gaps_temp[i].minDistance) > max_depth*GAPS_MAX_RELATIVE_DEPTH)
232 for (
size_t i=0;i<nTempGaps;i++)
237 unsigned int inner_gap_count = 0;
239 for (
unsigned int j=0;j<nTempGaps;j++)
241 if (i==j || delete_gaps[j])
245 if (gaps_temp[j].ini >= gaps_temp[i].ini && gaps_temp[j].
end <= gaps_temp[i].
end )
246 if (++inner_gap_count>1)
255 for (
size_t i=0;i<nTempGaps;i++)
260 for (
unsigned int j=0;j<nTempGaps;j++)
262 if (i==j || delete_gaps[j])
264 if (gaps_temp[i].ini <= gaps_temp[j].ini && gaps_temp[i].
end >= gaps_temp[j].
end)
273 gaps_out.reserve( nTempGaps/2 );
274 for (
size_t i=0;i<nTempGaps;i++)
276 if (delete_gaps[i])
continue;
279 calcRepresentativeSectorForGap( gaps_temp[i], target, obstacles);
281 gaps_out.push_back( gaps_temp[i] );
290 void CHolonomicND::searchBestGap(
291 const std::vector<double> & obstacles,
292 const double maxObsRange,
295 unsigned int & out_selDirection,
296 double & out_selEvaluation,
298 double & out_riskEvaluation,
299 CLogFileRecord_NDPtr log)
302 unsigned int min_risk_eval_sector = 0;
303 unsigned int max_risk_eval_sector = obstacles.size()-1;
304 const unsigned int target_sector = direction2sector(atan2(target.
y,target.
x),obstacles.size());
305 const double target_dist = std::max(0.01,target.
norm());
310 const int freeSectorsNearTarget = ceil(0.02*obstacles.size());
311 bool theyAreFree =
true, caseD1 =
false;
312 if (target_sector>static_cast<unsigned int>(freeSectorsNearTarget) &&
313 target_sector<static_cast<unsigned int>(obstacles.size()-freeSectorsNearTarget) )
315 const double min_free_dist =
std::min(1.05*target_dist, 0.95*maxObsRange);
316 for (
int j=-freeSectorsNearTarget;theyAreFree && j<=freeSectorsNearTarget;j++)
317 if (obstacles[ (
int(target_sector) + j) % obstacles.size()]<min_free_dist)
319 caseD1 = theyAreFree;
325 out_selDirection = target_sector;
328 out_selEvaluation = 1.0 + std::max( 0.0, (maxObsRange - target_dist) / maxObsRange );
329 out_situation = SITUATION_TARGET_DIRECTLY;
334 std::vector<double> gaps_evaluation;
335 int selected_gap =-1;
336 double selected_gap_eval = -100;
346 if (log) log->gaps_eval = gaps_evaluation;
369 if ( selected_gap==-1 )
370 for (
unsigned int i=0;i<in_gaps.size();i++ )
371 if ( gaps_evaluation[i]>selected_gap_eval )
373 selected_gap_eval = gaps_evaluation[i];
379 if ( selected_gap_eval <= 0 )
383 out_selDirection = 0;
384 out_selEvaluation = 0.0;
385 out_situation = SITUATION_NO_WAY_FOUND;
390 const TGap & gap = in_gaps[selected_gap];
392 const unsigned int sectors_to_be_wide =
round( options.WIDE_GAP_SIZE_PERCENT * obstacles.size() );
394 out_selDirection = in_gaps[selected_gap].representative_sector;
395 out_selEvaluation = selected_gap_eval;
399 if ( (gap.
end-gap.
ini) < sectors_to_be_wide )
403 out_situation = SITUATION_SMALL_GAP;
409 out_situation = SITUATION_WIDE_GAP;
413 min_risk_eval_sector = gap.
ini;
414 max_risk_eval_sector = gap.
end;
419 const unsigned int risk_eval_nsectors =
round( options.RISK_EVALUATION_SECTORS_PERCENT * obstacles.size() );
420 const unsigned int sec_ini = std::max(min_risk_eval_sector, risk_eval_nsectors<out_selDirection ? out_selDirection-risk_eval_nsectors : 0 );
421 const unsigned int sec_fin =
std::min(max_risk_eval_sector, out_selDirection + risk_eval_nsectors );
423 out_riskEvaluation = 0.0;
424 for (
unsigned int i=sec_ini;i<=sec_fin;i++) out_riskEvaluation+= obstacles[ i ];
425 out_riskEvaluation /= (sec_fin - sec_ini + 1 );
433 void CHolonomicND::calcRepresentativeSectorForGap(
436 const std::vector<double> & obstacles)
439 const unsigned int sectors_to_be_wide =
round( options.WIDE_GAP_SIZE_PERCENT * obstacles.size());
440 const unsigned int target_sector = direction2sector( atan2(target.
y,target.
x), obstacles.size() );
442 if ( (gap.
end-gap.
ini) < sectors_to_be_wide )
447 float min_dist_obs_near_ini=1, min_dist_obs_near_end=1;
449 for ( i= gap.
ini;i>=max(0,gap.
ini-2);i--)
450 min_dist_obs_near_ini =
min(min_dist_obs_near_ini, obstacles[i]);
451 for ( i= gap.
end;i<=
min((
int)obstacles.size()-1,gap.
end+2);i++)
452 min_dist_obs_near_end =
min(min_dist_obs_near_end, obstacles[i]);
453 sector =
round((min_dist_obs_near_ini*gap.
ini+min_dist_obs_near_end*gap.
end)/(min_dist_obs_near_ini+min_dist_obs_near_end));
461 if (dist_ini > 0.5*obstacles.size())
462 dist_ini = obstacles.size() - dist_ini;
463 if (dist_end > 0.5*obstacles.size())
464 dist_end = obstacles.size() - dist_end;
467 if (dist_ini<dist_end) {
474 sector = sector + dir*
static_cast<int>(sectors_to_be_wide)/2;
478 keep_min(sector, static_cast<int>(obstacles.size())-1 );
488 void CHolonomicND::evaluateGaps(
489 const std::vector<double> &obstacles,
490 const double maxObsRange,
492 const unsigned int target_sector,
493 const float target_dist,
494 std::vector<double> &out_gaps_evaluation )
496 out_gaps_evaluation.resize( gaps.size());
498 const double targetAng = CParameterizedTrajectoryGenerator::index2alpha(target_sector, obstacles.size());
499 const double target_x = target_dist*cos(targetAng);
500 const double target_y = target_dist*sin(targetAng);
502 for (
unsigned int i=0;i<gaps.size();i++)
505 const TGap *gap = &gaps[i];
507 const float d =
min3(
513 const double phi = CParameterizedTrajectoryGenerator::index2alpha(gap->
representative_sector, obstacles.size());
514 const double x = d*cos(phi);
515 const double y = d*sin(phi);
521 float meanDist = 0.f;
522 for (
unsigned int j=gap->
ini;j<=gap->
end;j++)
523 meanDist+= obstacles[j];
524 meanDist/= ( gap->
end - gap->
ini + 1);
528 factor1 =
std::min(target_dist,meanDist) / target_dist;
529 else factor1 = meanDist;
538 if (dif> 0.5*obstacles.size())
539 dif = obstacles.size() - dif;
541 const double factor2= exp(-
square( dif / (obstacles.size()*0.25))) ;
547 double closestX,closestY;
554 const float factor3 = ( maxObsRange -
std::min(maxObsRange ,dist_eucl) ) / maxObsRange;
560 double factor_AntiCab;
563 if (m_last_selected_sector != std::numeric_limits<unsigned int>::max() )
567 if (dist >
unsigned(0.1*obstacles.size()))
568 factor_AntiCab = 0.0;
570 factor_AntiCab = 1.0;
578 ASSERT_(options.factorWeights.size()==4);
581 out_gaps_evaluation[i] = 0;
582 else out_gaps_evaluation[i] = (
583 options.factorWeights[0] * factor1 +
584 options.factorWeights[1] * factor2 +
585 options.factorWeights[2] * factor3 +
586 options.factorWeights[3] * factor_AntiCab ) / (
math::sum(options.factorWeights)) ;
590 unsigned int CHolonomicND::direction2sector(
const double a,
const unsigned int N)
594 else return static_cast<unsigned int>(idx);
608 out << gaps_ini << gaps_end << gaps_eval;
609 out << selectedSector << evaluation << riskEvaluation << (
uint32_t) situation;
627 in.ReadBuffer( &(*gaps_ini.begin()),
sizeof(gaps_ini[0]) *
n );
628 in.ReadBuffer( &(*gaps_end.begin()),
sizeof(gaps_end[0]) *
n );
632 in.ReadBuffer( &(*gaps_eval.begin()),
sizeof(gaps_eval[0]) *
n );
634 in >> selectedSector >> evaluation >> riskEvaluation >>
n;
641 in >> gaps_ini >> gaps_end >> gaps_eval;
642 in >> selectedSector >> evaluation >> riskEvaluation >>
n;
654 CHolonomicND::TOptions::TOptions() :
656 TOO_CLOSE_OBSTACLE ( 0.15 ),
657 WIDE_GAP_SIZE_PERCENT ( 0.25 ),
658 RISK_EVALUATION_SECTORS_PERCENT ( 0.10 ),
659 RISK_EVALUATION_DISTANCE ( 0.4 ),
660 MAX_SECTOR_DIST_FOR_D2_PERCENT ( 0.25 ),
661 TARGET_SLOW_APPROACHING_DISTANCE ( 0.60 )
682 source.read_vector(section,
"factorWeights", std::vector<double>(), factorWeights,
true );
683 ASSERT_(factorWeights.size()==4);
701 c.write(
s,
"factorWeights",
mrpt::format(
"%.2f %.2f %.2f %.2f",factorWeights[0],factorWeights[1],factorWeights[2],factorWeights[3]), WN,WV,
"[0]=Free space, [1]=Dist. in sectors, [2]=Closer to target (Euclidean), [3]=Hysteresis");
#define ASSERT_EQUAL_(__A, __B)
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.
int BASE_IMPEXP MRPT_SAVE_VALUE_PADDING
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc.
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)
An implementation of the holonomic reactive navigation method "Nearness-Diagram". ...
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
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.
#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].
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const
Introduces a pure virtual method responsible for writing to a CStream.
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. in sectors, [2]=Closer to target (Euclidean), [3]=Hysteresis.
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.
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 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
#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.
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.
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.
T abs_diff(const T a, const T b)
Efficient and portable evaluation of the absolute difference of two unsigned integer values (but will...
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...
TSituations
The set of posible situations for each trajectory.
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...
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. ...
int BASE_IMPEXP MRPT_SAVE_NAME_PADDING
CHolonomicLogFileRecordPtr logRecord
The navigation method will create a log record and store it here via a smart pointer.