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 MRPT_SAVE_CONFIG_VAR_COMMENT(variableName, __comment)
#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...
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
A base class for holonomic reactive navigation methods.
A base class for log records for different holonomic navigation methods.
An implementation of the holonomic reactive navigation method "Nearness-Diagram".
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...
TOptions options
Parameters of the algorithm (can be set manually or loaded from CHolonomicND::initialize or options....
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const
Introduces a pure virtual method responsible for writing to a CStream.
std::vector< TGap > TGapArray
unsigned int m_last_selected_sector
TSituations
The set of posible situations for each trajectory.
A class for storing extra information about the execution of CHolonomicND navigation.
This class allows loading and storing values and vectors of different types from a configuration text...
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
GLubyte GLubyte GLubyte a
GLsizei const GLchar ** string
GLsizei GLsizei GLchar * source
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
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.
int round(const T value)
Returns the closer integer (int) to x.
#define ASSERT_EQUAL_(__A, __B)
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
This base provides a set of functions for maths stuff.
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
T square(const T x)
Inline function for the square of a number.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
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 BASE_IMPEXP MRPT_SAVE_NAME_PADDING
T abs_diff(const T a, const T b)
Efficient and portable evaluation of the absolute difference of two unsigned integer values (but will...
const T min3(const T &A, const T &B, const T &C)
int BASE_IMPEXP MRPT_SAVE_VALUE_PADDING
Default padding sizes for macros MRPT_SAVE_CONFIG_VAR_COMMENT(), etc.
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 is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
This file implements several operations that operate element-wise on individual or pairs of container...
unsigned __int32 uint32_t
double norm() const
Point norm.
Output for CAbstractHolonomicReactiveMethod::navigate()
CHolonomicLogFileRecordPtr logRecord
The navigation method will create a log record and store it here via a smart pointer.
double desiredDirection
The desired motion direction, in the range [-PI, PI].
double desiredSpeed
The desired motion speed in that direction, from 0 up to NavInput::maxRobotSpeed.
The structure used to store a detected gap in obstacles.
unsigned int representative_sector
double WIDE_GAP_SIZE_PERCENT
double MAX_SECTOR_DIST_FOR_D2_PERCENT
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.
double RISK_EVALUATION_DISTANCE
std::vector< double > factorWeights
Vector of 4 weights: [0]=Free space, [1]=Dist. in sectors, [2]=Closer to target (Euclidean),...
double TARGET_SLOW_APPROACHING_DISTANCE
double TOO_CLOSE_OBSTACLE
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.
double RISK_EVALUATION_SECTORS_PERCENT