11 #ifndef CLOOPCLOSERERD_IMPL_H 12 #define CLOOPCLOSERERD_IMPL_H 14 namespace mrpt {
namespace graphslam {
namespace deciders {
18 template<
class GRAPH_T>
20 m_visualize_curr_node_covariance(false),
21 m_curr_node_covariance_color(160, 160, 160, 255),
22 m_partitions_full_update(false),
23 m_is_first_time_node_reg(true),
24 m_dijkstra_node_count_thresh(3)
32 template<
class GRAPH_T>
38 for (
typename std::map<
41 it = m_node_optimal_paths.begin();
42 it != m_node_optimal_paths.end();
52 template<
class GRAPH_T>
54 mrpt::obs::CActionCollectionPtr action,
55 mrpt::obs::CSensoryFramePtr observations,
56 mrpt::obs::CObservationPtr observation ) {
59 this->m_time_logger.enter(
"updateState");
70 CObservation2DRangeScanPtr scan =
71 getObservation<CObservation2DRangeScan>(observations, observation);
72 if (scan.present()) { m_last_laser_scan2D = scan; }
75 if (!m_first_laser_scan.present()) {
76 m_first_laser_scan = m_last_laser_scan2D;
80 size_t num_registered =
absDiff(
81 this->m_last_total_num_nodes, this->m_graph->nodeCount());
82 bool registered_new_node = num_registered > 0;
84 if (registered_new_node) {
86 registered_new_node =
true;
90 if (!this->m_override_registered_nodes_check) {
91 if (!((num_registered == 1) ^ (num_registered == 2 && m_is_first_time_node_reg))) {
93 "Invalid number of registered nodes since last call to updateStates| " 94 "Found \"" << num_registered <<
"\" new nodes.");
103 if (m_is_first_time_node_reg) {
105 this->m_nodes_to_laser_scans2D[this->m_graph->root] = m_first_laser_scan;
106 m_is_first_time_node_reg =
false;
110 this->m_nodes_to_laser_scans2D[this->m_graph->nodeCount()-1] =
113 if (m_laser_params.use_scan_matching) {
115 this->addScanMatchingEdges(this->m_graph->nodeCount()-1);
119 m_partitions_full_update = (
120 (this->m_graph->nodeCount() %
121 m_lc_params.full_partition_per_nodes) == 0 ||
122 this->m_just_inserted_lc) ?
true:
false;
124 this->updateMapPartitions(m_partitions_full_update,
125 num_registered == 2);
129 this->checkPartitionsForLC(&partitions_for_LC);
130 this->evaluatePartitionsForLC(partitions_for_LC);
132 if (m_visualize_curr_node_covariance) {
133 this->execDijkstraProjection();
136 this->m_last_total_num_nodes = this->m_graph->nodeCount();
139 this->m_time_logger.leave(
"updateState");
144 template<
class GRAPH_T>
147 std::set<mrpt::utils::TNodeID>* nodes_set) {
152 int fetched_nodeIDs = 0;
153 for (
int nodeID_i = static_cast<int>(curr_nodeID)-1;
154 ((fetched_nodeIDs <= this->m_laser_params.prev_nodes_for_ICP) &&
157 nodes_set->insert(nodeID_i);
162 template<
class GRAPH_T>
167 using namespace mrpt;
176 std::set<TNodeID> nodes_set;
177 this->fetchNodeIDsForScanMatching(curr_nodeID, &nodes_set);
182 node_it != nodes_set.end(); ++node_it) {
188 <<
"==> " << curr_nodeID);
190 bool found_edge = this->getICPEdge(
195 if (!found_edge)
continue;
200 m_laser_params.goodness_threshold_win.addNewMeasurement(icp_info.
goodness);
202 double goodness_thresh =
203 m_laser_params.goodness_threshold_win.getMedian() *
204 m_consec_icp_constraint_factor;
205 bool accept_goodness = icp_info.
goodness > goodness_thresh;
207 <<
"|\t Threshold: " << goodness_thresh <<
" => " << (accept_goodness?
"ACCEPT" :
"REJECT"));
211 bool accept_mahal_distance = this->mahalanobisDistanceOdometryToICPEdge(
212 *node_it, curr_nodeID, rel_edge);
215 if (accept_goodness && accept_mahal_distance) {
216 this->registerNewEdge(*node_it, curr_nodeID, rel_edge);
222 template<
class GRAPH_T>
231 this->m_time_logger.enter(
"getICPEdge");
241 CObservation2DRangeScanPtr from_scan, to_scan;
253 bool from_success = this->getPropsOfNodeID(from, &from_pose, from_scan, from_params);
256 bool to_success = this->getPropsOfNodeID(to, &to_pose, to_scan, to_params);
259 if (!from_success || !to_success) {
261 "Either node #" << from <<
262 " or node #" << to <<
263 " doesn't contain a valid LaserScan. Ignoring this...");
274 initial_estim = to_pose - from_pose;
278 <<
"| to_pose: " << to_pose
279 <<
"| init_estim: " << initial_estim);
281 range_ops_t::getICPEdge(
289 this->m_time_logger.leave(
"getICPEdge");
294 template<
class GRAPH_T>
297 const std::map<mrpt::utils::TNodeID, node_props_t>& group_params,
307 search = group_params.find(nodeID);
309 if (search == group_params.end()) {
313 *node_props = search->second;
323 template<
class GRAPH_T>
327 mrpt::obs::CObservation2DRangeScanPtr& scan,
333 bool filled_pose =
false;
334 bool filled_scan =
false;
339 *pose = node_props->
pose;
343 if (node_props->
scan.present()) {
344 scan = node_props->
scan;
351 format(
"Either BOTH or NONE of the filled_pose, filled_scan should be set." 352 "NodeID: [%lu]", static_cast<unsigned long>(nodeID)));
360 this->m_graph->nodes.find(nodeID);
361 if (search != this->m_graph->nodes.end()) {
362 *pose = search->second;
371 this->m_nodes_to_laser_scans2D.find(nodeID);
372 if (search != this->m_nodes_to_laser_scans2D.end()) {
373 scan = search->second;
378 return filled_pose && filled_scan;
381 template<
class GRAPH_T>
385 this->m_time_logger.enter(
"LoopClosureEvaluation");
388 using namespace mrpt;
392 partitions_for_LC->clear();
398 if (m_partitions_full_update) {
399 m_partitionID_to_prev_nodes_list.clear();
405 partitions_it = m_curr_partitions.begin();
406 partitions_it != m_curr_partitions.end();
407 ++partitions_it, ++partitionID)
411 if (m_lc_params.LC_check_curr_partition_only) {
412 bool curr_node_in_curr_partition =
413 ((
find(partitions_it->begin(),
414 partitions_it->end(),
415 this->m_graph->nodeCount()-1))
416 != partitions_it->end());
417 if (!curr_node_in_curr_partition) {
423 finder = m_partitionID_to_prev_nodes_list.find(partitionID);
424 if (finder == m_partitionID_to_prev_nodes_list.end()) {
426 m_partitionID_to_prev_nodes_list.insert(make_pair(partitionID, *partitions_it));
429 if (*partitions_it == finder->second) {
436 finder->second = *partitions_it;
442 int curr_node_index = 1;
443 size_t prev_nodeID = *(partitions_it->begin());
445 it != partitions_it->end(); ++it, ++curr_node_index) {
446 size_t curr_nodeID = *it;
450 if ((curr_nodeID - prev_nodeID) > m_lc_params.LC_min_nodeid_diff) {
453 int num_after_nodes = partitions_it->size() - curr_node_index;
454 int num_before_nodes = partitions_it->size() - num_after_nodes;
455 if (num_after_nodes >= m_lc_params.LC_min_remote_nodes &&
456 num_before_nodes >= m_lc_params.LC_min_remote_nodes ) {
458 "Found potential loop closures:" << endl <<
459 "\tPartitionID: " << partitionID << endl <<
461 <<
"\t" << prev_nodeID <<
" ==> " << curr_nodeID << endl <<
462 "\tNumber of LC nodes: " << num_after_nodes);
463 partitions_for_LC->push_back(*partitions_it);
469 prev_nodeID = curr_nodeID;
471 this->logFmt(LVL_DEBUG,
"Successfully checked partition: %d", partitionID);
474 this->m_time_logger.leave(
"LoopClosureEvaluation");
478 template<
class GRAPH_T>
482 using namespace mrpt;
487 this->m_time_logger.enter(
"LoopClosureEvaluation");
489 if (partitions.size() == 0)
return;
491 this->logFmt(LVL_DEBUG,
"Evaluating partitions for loop closures...\n%s\n",
492 this->header_sep.c_str());
496 p_it != partitions.end();
503 this->splitPartitionToGroups(partition,
509 this->generateHypotsPool(groupA, groupB, &hypots_pool);
512 CMatrixDouble consist_matrix(hypots_pool.size(), hypots_pool.size());
513 this->generatePWConsistenciesMatrix(
514 groupA, groupB, hypots_pool, &consist_matrix);
518 this->evalPWConsistenciesMatrix(
524 if (valid_hypots.size()) {
527 it = valid_hypots.begin(); it != valid_hypots.end(); ++it) {
528 this->registerHypothesis(**it);
534 it = hypots_pool.begin(); it != hypots_pool.end(); ++it) {
540 this->m_time_logger.leave(
"LoopClosureEvaluation");
545 template<
class GRAPH_T>
556 valid_hypots->clear();
561 bool valid_lambda_ratio =
562 this->computeDominantEigenVector(
565 if (!valid_lambda_ratio)
return;
573 double dot_product = 0;
574 for (
int i = 0; i !=
w.size(); ++i) {
580 double potential_dot_product = ((
w.transpose() * u) /
w.squaredNorm()).
value();
581 ss <<
mrpt::format(
"current: %f | potential_dot_product: %f",
582 dot_product, potential_dot_product);
583 if (potential_dot_product > dot_product) {
585 dot_product = potential_dot_product;
594 cout <<
"Outcome of discretization: " <<
w.transpose() << endl;
599 for (
int wi = 0; wi !=
w.size(); ++wi) {
603 valid_hypots->push_back(this->findHypotByID(hypots_pool, wi));
612 template<
class GRAPH_T>
617 int max_nodes_in_group) {
620 using namespace mrpt;
625 ASSERTMSG_(groupA,
"Pointer to groupA is not valid");
626 ASSERTMSG_(groupB,
"Pointer to groupB is not valid");
627 ASSERTMSG_(max_nodes_in_group == -1 || max_nodes_in_group > 0,
629 "Value %d not permitted for max_nodes_in_group" 630 "Either use a positive integer, " 631 "or -1 for non-restrictive partition size",
632 max_nodes_in_group));
637 size_t index_to_split = 1;
639 it != partition.end(); ++it, ++index_to_split) {
642 if ((curr_nodeID - prev_nodeID) > m_lc_params.LC_min_nodeid_diff) {
646 prev_nodeID = curr_nodeID;
648 ASSERT_(partition.size() > index_to_split);
651 *groupA =
vector_uint(partition.begin(), partition.begin() + index_to_split);
652 *groupB =
vector_uint(partition.begin() + index_to_split, partition.end());
654 if (max_nodes_in_group != -1) {
656 if (groupA->size() >
static_cast<size_t>(max_nodes_in_group)) {
658 groupA->begin() + max_nodes_in_group);
661 if (groupB->size() >
static_cast<size_t>(max_nodes_in_group)) {
662 *groupB =
vector_uint(groupB->end() - max_nodes_in_group,
671 template<
class GRAPH_T>
679 using namespace mrpt;
682 "generateHypotsPool: Given hypotsp_t pointer is invalid.");
683 generated_hypots->clear();
687 " - size: " << groupA.size() << endl);
689 " - size: " << groupB.size() << endl);
700 size_t nodes_count = groupA.size();
704 format(
"Size mismatch between nodeIDs in group [%lu]" 705 " and corresponding properties map [%lu]",
715 int hypot_counter = 0;
716 int invalid_hypots = 0;
720 b_it = groupB.begin();
721 b_it != groupB.end();
724 a_it = groupA.begin();
725 a_it != groupA.end();
732 hypot->
id = hypot_counter++;
746 fillNodePropsFromGroupParams(
749 fillNodePropsFromGroupParams(
768 bool found_edge = this->getICPEdge(
781 double goodness_thresh =
782 m_laser_params.goodness_threshold_win.getMedian() *
783 m_lc_icp_constraint_factor;
784 bool accept_goodness = icp_info.
goodness > goodness_thresh;
786 <<
"|\t Threshold: " << goodness_thresh <<
" => " <<
787 (accept_goodness?
"ACCEPT" :
"REJECT") << endl);
789 if (!found_edge || !accept_goodness) {
793 generated_hypots->push_back(hypot);
798 delete icp_ad_params;
802 "Generated pool of hypotheses...\tsize = " 803 << generated_hypots->size()
804 <<
"\tinvalid hypotheses: " << invalid_hypots);
811 template<
class GRAPH_T>
815 bool use_power_method) {
817 using namespace mrpt;
823 this->m_time_logger.enter(
"DominantEigenvectorComputation");
825 double lambda1, lambda2;
826 bool is_valid_lambda_ratio =
false;
828 if (use_power_method) {
830 "\nPower method for computing the first two eigenvectors/eigenvalues hasn't been implemented yet\n");
834 consist_matrix.eigenVectors(eigvecs, eigvals);
839 eigvecs.size() == eigvals.size() &&
840 consist_matrix.size() == eigvals.size(),
842 "Size of eigvecs \"%lu\"," 844 "consist_matrix \"%lu\" don't match",
845 static_cast<unsigned long>(eigvecs.size()),
846 static_cast<unsigned long>(eigvals.size()),
847 static_cast<unsigned long>(consist_matrix.size())));
849 eigvecs.extractCol(eigvecs.getColCount()-1, *eigvec);
850 lambda1 = eigvals(eigvals.getRowCount()-1, eigvals.getColCount()-1);
851 lambda2 = eigvals(eigvals.getRowCount()-2, eigvals.getColCount()-2);
855 for (
int i = 0; i != eigvec->size(); ++i) {
856 (*eigvec)(i) = abs((*eigvec)(i));
863 <<
" => Skipping current evaluation." << endl);
866 double curr_lambda_ratio = lambda1 / lambda2;
868 "lambda1 = " << lambda1 <<
" | lambda2 = " << lambda2
869 <<
"| ratio = " << curr_lambda_ratio << endl);
871 is_valid_lambda_ratio =
872 (curr_lambda_ratio > m_lc_params.LC_eigenvalues_ratio_thresh);
874 this->m_time_logger.leave(
"DominantEigenvectorComputation");
875 return is_valid_lambda_ratio;
880 template<
class GRAPH_T>
886 const paths_t* groupA_opt_paths,
887 const paths_t* groupB_opt_paths) {
890 using namespace mrpt;
894 ASSERTMSG_(consist_matrix,
"Invalid pointer to the Consistency matrix is given");
896 static_cast<unsigned long>(consist_matrix->rows()) == hypots_pool.size() &&
897 static_cast<unsigned long>(consist_matrix->rows()) == hypots_pool.size(),
898 "Consistency matrix dimensions aren't equal to the hypotheses pool size");
901 <<
"In generatePWConsistencyMatrix:\n" 904 <<
"\tHypots pool Size: " << hypots_pool.size());
908 b1_it = groupB.begin(); b1_it != groupB.end(); ++b1_it) {
913 b2_it = b1_it+1; b2_it != groupB.end(); ++b2_it) {
918 a1_it = groupA.begin(); a1_it != groupA.end(); ++a1_it) {
921 hypot_t* hypot_b2_a1 = this->findHypotByEnds(hypots_pool,
b2,
a1);
926 a2_it = a1_it+1; a2_it != groupA.end(); ++a2_it) {
928 hypot_t* hypot_b1_a2 = this->findHypotByEnds(hypots_pool,
b1,
a2);
938 extracted_hypots.push_back(hypot_b2_a1);
939 extracted_hypots.push_back(hypot_b1_a2);
942 if (groupA_opt_paths || groupB_opt_paths) {
943 curr_opt_paths =
new paths_t();
947 if (curr_opt_paths) {
949 if (groupA_opt_paths) {
950 const path_t*
p = this->findPathByEnds(
951 *groupA_opt_paths,
a1,
a2,
true);
952 curr_opt_paths->push_back(*
p);
955 curr_opt_paths->push_back(
path_t());
958 if (groupB_opt_paths) {
959 const path_t*
p = this->findPathByEnds(
960 *groupB_opt_paths,
b1,
b2,
true);
961 curr_opt_paths->push_back(*
p);
964 curr_opt_paths->push_back(
path_t());
969 consistency = this->generatePWConsistencyElement(
974 delete curr_opt_paths;
987 int id1 = hypot_b2_a1->
id;
988 int id2 = hypot_b1_a2->
id;
990 (*consist_matrix)(id1, id2) = consistency;
991 (*consist_matrix)(id2, id1) = consistency;
1009 template<
class GRAPH_T>
1018 using namespace std;
1019 using namespace mrpt;
1039 if (opt_paths) {
ASSERT_(opt_paths->size() == 2); }
1045 const path_t* path_a1_a2;
1046 if (!opt_paths || opt_paths->begin()->isEmpty()) {
1048 execDijkstraProjection(
a1,
a2);
1049 path_a1_a2 = this->queryOptimalPath(
a2);
1053 path_a1_a2 = &(*opt_paths->begin());
1059 const path_t* path_b1_b2;
1060 if (!opt_paths || opt_paths->rend()->isEmpty()) {
1062 execDijkstraProjection(
b1,
b2);
1063 path_b1_b2 = this->queryOptimalPath(
b2);
1066 path_b1_b2 = &(*opt_paths->rbegin());
1074 hypot_t* hypot_b1_a2 = this->findHypotByEnds(hypots,
b1,
a2);
1076 hypot_t* hypot_b2_a1 = this->findHypotByEnds(hypots,
b2,
a1);
1083 res_transform += hypot_b2_a1->
getEdge();
1086 << hypot_b1_a2->
id <<
", #" << hypot_b2_a1->
id << endl
1087 <<
"a1 --> a2 => b1 --> b2 => a1: " 1088 <<
a1 <<
" --> " <<
a2 <<
" => " <<
b1 <<
" --> " <<
b2 <<
" => " <<
a1 << endl
1089 << res_transform << endl << endl
1090 <<
"DIJKSTRA: " <<
a1 <<
" --> " <<
a2 <<
": " << path_a1_a2->
curr_pose_pdf << endl
1091 <<
"DIJKSTRA: " <<
b1 <<
" --> " <<
b2 <<
": " << path_b1_b2->
curr_pose_pdf << endl
1092 <<
"hypot_b1_a2(inv):\n" << hypot_b1_a2->
getInverseEdge() << endl
1093 <<
"hypot_b2_a1:\n" << hypot_b2_a1->
getEdge() << endl);
1097 res_transform.getMeanVal().getAsVector(T);
1101 res_transform.getCovariance(cov_mat);
1106 double exponent = (-T.transpose() * cov_mat * T).
value();
1107 double consistency_elem = exp(exponent);
1114 return consistency_elem;
1118 template<
class GRAPH_T>
1125 using namespace mrpt;
1131 cit = vec_paths.begin();
1132 cit != vec_paths.end();
1135 if (cit->getSource() ==
src && cit->getDestination() ==
dst) {
1140 if (throw_exc && !
res) {
1142 format(
"Path for %lu => %lu is not found. Exiting...\n",
1143 static_cast<unsigned long>(
src),
1144 static_cast<unsigned long>(
dst)));
1150 template<
class GRAPH_T>
1158 using namespace std;
1162 v_cit != vec_hypots.end();
1165 if ((*v_cit)->hasEnds(from, to)) {
1181 template<
class GRAPH_T>
1191 v_cit != vec_hypots.end();
1194 if ((*v_cit)->id ==
id) {
1208 template<
class GRAPH_T>
1213 using namespace std;
1214 using namespace mrpt;
1222 this->m_time_logger.enter(
"Dijkstra Projection");
1224 "----------- Done with Dijkstra Projection... ----------";
1229 (ending_node >= 0 && ending_node < this->m_graph->nodeCount()) );
1230 ASSERTMSG_(starting_node != ending_node,
"Starting and Ending nodes coincede");
1233 stringstream ss_debug(
"");
1234 ss_debug <<
"Executing Dijkstra Projection: " << starting_node <<
" => ";
1236 ss_debug <<
"..." << endl;
1239 ss_debug << ending_node <<endl;
1242 if (this->m_graph->nodeCount() < m_dijkstra_node_count_thresh) {
1247 std::vector<bool> visited_nodes(this->m_graph->nodeCount(),
false);
1248 m_node_optimal_paths.clear();
1251 std::map<TNodeID, std::set<TNodeID> > neighbors_of;
1252 this->m_graph->getAdjacencyMatrix(neighbors_of);
1256 std::set<path_t*> pool_of_paths;
1258 std::set<TNodeID> starting_node_neighbors(neighbors_of.at(starting_node));
1260 starting_node_neighbors.begin();
1261 n_it != starting_node_neighbors.end(); ++n_it) {
1263 path_t* path_between_neighbors =
1265 this->getMinUncertaintyPath(starting_node, *n_it, path_between_neighbors);
1267 pool_of_paths.insert(path_between_neighbors);
1270 visited_nodes.at(starting_node) =
true;
1287 it != visited_nodes.end(); ++it) {
1296 if (visited_nodes.at(ending_node)) {
1298 this->m_time_logger.leave(
"Dijkstra Projection");
1304 this->popMinUncertaintyPath(&pool_of_paths);
1328 if (!visited_nodes.at(dest)) {
1329 m_node_optimal_paths[dest] = optimal_path;
1330 visited_nodes.at(dest)=
true;
1334 this->addToPaths(&pool_of_paths, *optimal_path, neighbors_of.at(dest));
1339 this->m_time_logger.leave(
"Dijkstra Projection");
1343 template<
class GRAPH_T>
1345 std::set<path_t*>* pool_of_paths,
1346 const path_t& current_path,
1347 const std::set<mrpt::utils::TNodeID>& neighbors)
const {
1350 using namespace std;
1360 neigh_it != neighbors.end(); ++neigh_it) {
1361 if (*neigh_it == second_to_last_node)
continue;
1364 path_t path_between_nodes;
1365 this->getMinUncertaintyPath(node_to_append_from, *neigh_it,
1366 &path_between_nodes);
1371 *path_to_append = current_path;
1372 *path_to_append += path_between_nodes;
1374 pool_of_paths->insert(path_to_append);
1380 template<
class GRAPH_T>
1383 using namespace std;
1388 search = m_node_optimal_paths.find(node);
1389 if (search != m_node_optimal_paths.end()) {
1390 path = search->second;
1398 template<
class GRAPH_T>
1402 path_t* path_between_nodes)
const {
1406 using namespace std;
1409 this->m_graph->edgeExists(from, to) ||
1410 this->m_graph->edgeExists(to, from),
1412 "(%lu <-> %lu) does not exist\n", from, to) );
1418 path_between_nodes->
clear();
1422 double curr_determinant = 0;
1424 std::pair<edges_citerator, edges_citerator> fwd_edges_pair =
1425 this->m_graph->getEdges(from, to);
1434 edges_it != fwd_edges_pair.second; ++edges_it) {
1438 curr_edge.copyFrom(edges_it->second);
1442 curr_edge.getInformationMatrix(inf_mat);
1446 curr_edge.cov_inv = inf_mat;
1456 *path_between_nodes = curr_path;
1460 std::pair<edges_citerator, edges_citerator> bwd_edges_pair =
1461 this->m_graph->getEdges(to, from);
1470 edges_it != bwd_edges_pair.second; ++edges_it) {
1474 (edges_it->second).
inverse(curr_edge);
1478 curr_edge.getInformationMatrix(inf_mat);
1482 curr_edge.cov_inv = inf_mat;
1492 *path_between_nodes = curr_path;
1499 template<
class GRAPH_T>
1502 typename std::set<path_t*>* pool_of_paths)
const {
1504 using namespace std;
1507 path_t* optimal_path = NULL;
1508 double curr_determinant = 0;
1510 it = pool_of_paths->begin();
1511 it != pool_of_paths->end();
1516 if (curr_determinant < (*it)->getDeterminant()) {
1523 pool_of_paths->erase(optimal_path);
1525 return optimal_path;
1529 template<
class GRAPH_T>
1535 using namespace std;
1540 pose_t initial_estim = this->m_graph->nodes.at(to) - this->m_graph->nodes.at(from);
1542 (rel_edge.getMeanVal()-initial_estim).getAsVector(mean_diff);
1549 bool mahal_distance_null =
isNaN(mahal_distance);
1550 if (!mahal_distance_null) {
1551 m_laser_params.mahal_distance_ICP_odom_win.addNewMeasurement(mahal_distance);
1556 double threshold = m_laser_params.mahal_distance_ICP_odom_win.getMedian()*4;
1557 bool accept_edge = (threshold >= mahal_distance && !mahal_distance_null) ?
true :
false;
1567 template<
class GRAPH_T>
1571 this->registerNewEdge(hypot.
from, hypot.
to, hypot.
getEdge());
1574 template<
class GRAPH_T>
1582 using namespace std;
1583 parent_t::registerNewEdge(from, to, rel_edge);
1586 m_edge_types_to_nums[
"ICP2D"]++;
1589 if (
absDiff(to, from) > m_lc_params.LC_min_nodeid_diff) {
1590 m_edge_types_to_nums[
"LC"]++;
1591 this->m_just_inserted_lc =
true;
1592 this->logFmt(LVL_INFO,
"\tLoop Closure edge!");
1595 this->m_just_inserted_lc =
false;
1599 this->m_graph->insertEdge(from, to, rel_edge);
1604 template<
class GRAPH_T>
1608 parent_t::setWindowManagerPtr(win_manager);
1613 if (this->m_win_manager) {
1615 if (this->m_win_observer) {
1616 this->m_win_observer->registerKeystroke(m_laser_params.keystroke_laser_scans,
1617 "Toggle LaserScans Visualization");
1618 this->m_win_observer->registerKeystroke(m_lc_params.keystroke_map_partitions,
1619 "Toggle Map Partitions Visualization");
1623 this->logFmt(LVL_DEBUG,
1624 "Fetched the window manager, window observer successfully.");
1628 template<
class GRAPH_T>
1630 const std::map<std::string, bool>& events_occurred) {
1632 parent_t::notifyOfWindowEvents(events_occurred);
1635 if (events_occurred.at(m_laser_params.keystroke_laser_scans)) {
1636 this->toggleLaserScansVisualization();
1639 if (events_occurred.at(m_lc_params.keystroke_map_partitions)) {
1640 this->toggleMapPartitionsVisualization();
1646 template<
class GRAPH_T>
1648 using namespace mrpt;
1654 if (!m_lc_params.LC_check_curr_partition_only) {
1655 this->m_win_manager->assignTextMessageParameters(
1656 &m_lc_params.offset_y_map_partitions,
1657 &m_lc_params.text_index_map_partitions);
1661 CSetOfObjectsPtr map_partitions_obj = CSetOfObjects::Create();
1662 map_partitions_obj->setName(
"map_partitions");
1664 COpenGLScenePtr& scene = this->m_win->get3DSceneAndLock();
1665 scene->insert(map_partitions_obj);
1666 this->m_win->unlockAccess3DScene();
1667 this->m_win->forceRepaint();
1671 template<
class GRAPH_T>
1673 using namespace mrpt;
1681 if (!m_lc_params.LC_check_curr_partition_only) {
1682 std::stringstream title;
1683 title <<
"# Partitions: " << m_curr_partitions.size();
1684 this->m_win_manager->addTextMessage(5,-m_lc_params.offset_y_map_partitions,
1687 m_lc_params.text_index_map_partitions);
1692 COpenGLScenePtr& scene = this->m_win->get3DSceneAndLock();
1695 CSetOfObjectsPtr map_partitions_obj;
1697 CRenderizablePtr
obj = scene->getByName(
"map_partitions");
1699 map_partitions_obj =
static_cast<CSetOfObjectsPtr
>(
obj);
1702 int partitionID = 0;
1703 bool partition_contains_last_node =
false;
1704 bool found_last_node =
false;
1706 << (this->m_graph->nodeCount()-1));
1709 p_it != m_curr_partitions.end(); ++p_it, ++partitionID) {
1718 this->m_graph->nodeCount()-1) != nodes_list.end()) {
1719 partition_contains_last_node =
true;
1721 found_last_node =
true;
1724 partition_contains_last_node =
false;
1731 CRenderizablePtr
obj = map_partitions_obj->getByName(partition_obj_name);
1732 CSetOfObjectsPtr curr_partition_obj;
1737 curr_partition_obj =
static_cast<CSetOfObjectsPtr
>(
obj);
1738 if (m_lc_params.LC_check_curr_partition_only) {
1739 curr_partition_obj->setVisibility(partition_contains_last_node);
1744 "\tCreating a new CSetOfObjects partition object for partition #" <<
1746 curr_partition_obj = CSetOfObjects::Create();
1747 curr_partition_obj->setName(partition_obj_name);
1748 if (m_lc_params.LC_check_curr_partition_only) {
1750 curr_partition_obj->setVisibility(partition_contains_last_node);
1754 CSpherePtr balloon_obj = CSphere::Create();
1755 balloon_obj->setName(balloon_obj_name);
1756 balloon_obj->setRadius(m_lc_params.balloon_radius);
1757 balloon_obj->setColor_u8(m_lc_params.balloon_std_color);
1758 balloon_obj->enableShowName();
1760 curr_partition_obj->insert(balloon_obj);
1765 CSetOfLinesPtr connecting_lines_obj = CSetOfLines::Create();
1766 connecting_lines_obj->setName(
"connecting_lines");
1767 connecting_lines_obj->setColor_u8(m_lc_params.connecting_lines_color);
1768 connecting_lines_obj->setLineWidth(0.1f);
1770 curr_partition_obj->insert(connecting_lines_obj);
1774 map_partitions_obj->insert(curr_partition_obj);
1779 std::pair<double, double> centroid_coords;
1780 this->computeCentroidOfNodesVector(nodes_list, ¢roid_coords);
1782 TPoint3D balloon_location(centroid_coords.first, centroid_coords.second,
1783 m_lc_params.balloon_elevation);
1787 CSpherePtr balloon_obj;
1790 CRenderizablePtr
obj = curr_partition_obj->getByName(balloon_obj_name);
1791 balloon_obj =
static_cast<CSpherePtr
>(
obj);
1792 balloon_obj->setLocation(balloon_location);
1793 if (partition_contains_last_node)
1794 balloon_obj->setColor_u8(m_lc_params.balloon_curr_color);
1796 balloon_obj->setColor_u8(m_lc_params.balloon_std_color);
1803 CSetOfLinesPtr connecting_lines_obj;
1806 CRenderizablePtr
obj = curr_partition_obj->getByName(
"connecting_lines");
1807 connecting_lines_obj =
static_cast<CSetOfLinesPtr
>(
obj);
1809 connecting_lines_obj->clear();
1812 it != nodes_list.end(); ++it) {
1813 CPose3D curr_pose(this->m_graph->nodes.at(*it));
1814 TPoint3D curr_node_location(curr_pose);
1816 TSegment3D connecting_line(curr_node_location, balloon_location);
1817 connecting_lines_obj->appendLine(connecting_line);
1824 if (!found_last_node) {
1833 size_t prev_size = m_last_partitions.size();
1834 size_t curr_size = m_curr_partitions.size();
1835 if (curr_size < prev_size) {
1837 for (
size_t partitionID = curr_size; partitionID != prev_size; ++partitionID) {
1841 static_cast<unsigned long>(partitionID));
1843 CRenderizablePtr
obj = map_partitions_obj->getByName(partition_obj_name);
1846 <<
" was not found.");
1849 map_partitions_obj->removeObject(
obj);
1855 this->m_win->unlockAccess3DScene();
1856 this->m_win->forceRepaint();
1859 template<
class GRAPH_T>
1862 ASSERTMSG_(this->m_win,
"No CDisplayWindow3D* was provided");
1863 ASSERTMSG_(this->m_win_manager,
"No CWindowManager* was provided");
1867 this->logFmt(LVL_INFO,
"Toggling map partitions visualization...");
1868 mrpt::opengl::COpenGLScenePtr scene = this->m_win->get3DSceneAndLock();
1870 if (m_lc_params.visualize_map_partitions) {
1871 mrpt::opengl::CRenderizablePtr
obj = scene->getByName(
"map_partitions");
1872 obj->setVisibility(!
obj->isVisible());
1875 this->dumpVisibilityErrorMsg(
"visualize_map_partitions");
1878 this->m_win->unlockAccess3DScene();
1879 this->m_win->forceRepaint();
1884 template<
class GRAPH_T>
1887 std::pair<double, double>* centroid_coords)
const {
1892 double centroid_x = 0;
1893 double centroid_y = 0;
1895 node_it != nodes_list.end(); ++node_it) {
1896 pose_t curr_node_pos = this->m_graph->nodes.at(*node_it);
1897 centroid_x += curr_node_pos.x();
1898 centroid_y += curr_node_pos.y();
1903 centroid_coords->first = centroid_x/
static_cast<double>(nodes_list.size());
1904 centroid_coords->second = centroid_y/
static_cast<double>(nodes_list.size());
1909 template<
class GRAPH_T>
1915 if (m_laser_params.visualize_laser_scans) {
1916 mrpt::opengl::COpenGLScenePtr scene = this->m_win->get3DSceneAndLock();
1918 mrpt::opengl::CPlanarLaserScanPtr laser_scan_viz =
1920 laser_scan_viz->enablePoints(
true);
1921 laser_scan_viz->enableLine(
true);
1922 laser_scan_viz->enableSurface(
true);
1923 laser_scan_viz->setSurfaceColor(
1924 m_laser_params.laser_scans_color.R,
1925 m_laser_params.laser_scans_color.G,
1926 m_laser_params.laser_scans_color.B,
1927 m_laser_params.laser_scans_color.A);
1929 laser_scan_viz->setName(
"laser_scan_viz");
1931 scene->insert(laser_scan_viz);
1932 this->m_win->unlockAccess3DScene();
1933 this->m_win->forceRepaint();
1939 template<
class GRAPH_T>
1944 if (m_laser_params.visualize_laser_scans && !m_last_laser_scan2D.null()) {
1945 mrpt::opengl::COpenGLScenePtr scene = this->m_win->get3DSceneAndLock();
1947 mrpt::opengl::CRenderizablePtr
obj = scene->getByName(
"laser_scan_viz");
1948 mrpt::opengl::CPlanarLaserScanPtr laser_scan_viz =
1949 static_cast<mrpt::opengl::CPlanarLaserScanPtr
>(
obj);
1950 ASSERT_(laser_scan_viz.present());
1951 laser_scan_viz->setScan(*m_last_laser_scan2D);
1955 this->m_graph->nodes.find(this->m_graph->nodeCount()-1);
1956 if (search != this->m_graph->nodes.end()) {
1957 laser_scan_viz->setPose(search->second);
1961 laser_scan_viz->getPoseX(), laser_scan_viz->getPoseY(), -0.15,
1968 this->m_win->unlockAccess3DScene();
1969 this->m_win->forceRepaint();
1976 template<
class GRAPH_T>
1979 ASSERTMSG_(this->m_win,
"No CDisplayWindow3D* was provided");
1980 ASSERTMSG_(this->m_win_manager,
"No CWindowManager* was provided");
1983 this->logFmt(LVL_INFO,
"Toggling LaserScans visualization...");
1985 mrpt::opengl::COpenGLScenePtr scene = this->m_win->get3DSceneAndLock();
1987 if (m_laser_params.visualize_laser_scans) {
1988 mrpt::opengl::CRenderizablePtr
obj = scene->getByName(
"laser_scan_viz");
1989 obj->setVisibility(!
obj->isVisible());
1992 this->dumpVisibilityErrorMsg(
"visualize_laser_scans");
1995 this->m_win->unlockAccess3DScene();
1996 this->m_win->forceRepaint();
2002 template<
class GRAPH_T>
2004 std::map<std::string, int>* edge_types_to_num)
const {
2006 *edge_types_to_num = m_edge_types_to_nums;
2010 template<
class GRAPH_T>
2013 parent_t::initializeVisuals();
2015 this->m_time_logger.enter(
"Visuals");
2018 "Configuration parameters aren't loaded yet");
2019 if (m_laser_params.visualize_laser_scans) {
2020 this->initLaserScansVisualization();
2022 if (m_lc_params.visualize_map_partitions) {
2023 this->initMapPartitionsVisualization();
2026 if (m_visualize_curr_node_covariance) {
2027 this->initCurrCovarianceVisualization();
2030 this->m_time_logger.leave(
"Visuals");
2033 template<
class GRAPH_T>
2036 parent_t::updateVisuals();
2038 this->m_time_logger.enter(
"Visuals");
2040 if (m_laser_params.visualize_laser_scans) {
2041 this->updateLaserScansVisualization();
2043 if (m_lc_params.visualize_map_partitions) {
2044 this->updateMapPartitionsVisualization();
2046 if (m_visualize_curr_node_covariance) {
2047 this->updateCurrCovarianceVisualization();
2050 this->m_time_logger.leave(
"Visuals");
2054 template<
class GRAPH_T>
2057 using namespace std;
2061 this->m_win_manager->assignTextMessageParameters(
2062 &m_offset_y_curr_node_covariance,
2063 &m_text_index_curr_node_covariance);
2066 this->m_win_manager->addTextMessage(5,-m_offset_y_curr_node_covariance,
2069 m_text_index_curr_node_covariance);
2073 CEllipsoidPtr cov_ellipsis_obj = CEllipsoid::Create();
2074 cov_ellipsis_obj->setName(
"cov_ellipsis_obj");
2075 cov_ellipsis_obj->setColor_u8(m_curr_node_covariance_color);
2076 cov_ellipsis_obj->setLocation(0, 0, 0);
2079 mrpt::opengl::COpenGLScenePtr scene = this->m_win->get3DSceneAndLock();
2080 scene->insert(cov_ellipsis_obj);
2081 this->m_win->unlockAccess3DScene();
2082 this->m_win->forceRepaint();
2087 template<
class GRAPH_T>
2090 using namespace std;
2098 path_t* path = queryOptimalPath(curr_node);
2104 pose_t curr_position = this->m_graph->nodes.at(curr_node);
2106 stringstream ss_mat; ss_mat << mat;
2107 this->logFmt(LVL_DEBUG,
"In updateCurrCovarianceVisualization\n" 2108 "Covariance matrix:\n%s\n" 2109 "determinant : %f", ss_mat.str().c_str(), mat.det() );
2111 mrpt::opengl::COpenGLScenePtr scene = this->m_win->get3DSceneAndLock();
2112 CRenderizablePtr
obj = scene->getByName(
"cov_ellipsis_obj");
2113 CEllipsoidPtr cov_ellipsis_obj =
static_cast<CEllipsoidPtr
>(
obj);
2116 cov_ellipsis_obj->setLocation(curr_position.x(), curr_position.y(), 0);
2119 cov_ellipsis_obj->setCovMatrix(mat, 2);
2121 this->m_win->unlockAccess3DScene();
2122 this->m_win->forceRepaint();
2127 template<
class GRAPH_T>
2132 this->logFmt(mrpt::utils::LVL_ERROR,
2133 "Cannot toggle visibility of specified object.\n " 2134 "Make sure that the corresponding visualization flag ( %s " 2135 ") is set to true in the .ini file.\n",
2143 template<
class GRAPH_T>
2146 parent_t::loadParams(source_fname);
2148 m_partitioner.options.loadFromConfigFileName(source_fname,
2149 "EdgeRegistrationDeciderParameters");
2150 m_laser_params.loadFromConfigFileName(source_fname,
2151 "EdgeRegistrationDeciderParameters");
2152 m_lc_params.loadFromConfigFileName(source_fname,
2153 "EdgeRegistrationDeciderParameters");
2157 m_consec_icp_constraint_factor =
source.read_double(
2158 "EdgeRegistrationDeciderParameters",
2159 "consec_icp_constraint_factor",
2161 m_lc_icp_constraint_factor =
source.read_double(
2162 "EdgeRegistrationDeciderParameters",
2163 "lc_icp_constraint_factor",
2168 int min_verbosity_level =
source.read_int(
2169 "EdgeRegistrationDeciderParameters",
2174 this->setMinLoggingLevel(mrpt::utils::VerbosityLevel(min_verbosity_level));
2177 template<
class GRAPH_T>
2180 using namespace std;
2182 cout <<
"------------------[Pair-wise Consistency of ICP Edges - Registration Procedure Summary]------------------" << endl;
2184 parent_t::printParams();
2185 m_partitioner.options.dumpToConsole();
2186 m_laser_params.dumpToConsole();
2187 m_lc_params.dumpToConsole();
2189 cout <<
"Scan-matching ICP Constraint factor: " << m_consec_icp_constraint_factor << endl;
2190 cout <<
"Loop-closure ICP Constraint factor: " << m_lc_icp_constraint_factor << endl;
2196 template<
class GRAPH_T>
2201 std::stringstream class_props_ss;
2203 "Pair-wise Consistency of ICP Edges - Registration Procedure Summary: " <<
2205 class_props_ss << this->header_sep << std::endl;
2208 const std::string time_res = this->m_time_logger.getStatsAsText();
2209 const std::string output_res = this->getLogAsString();
2212 report_str->clear();
2213 parent_t::getDescriptiveReport(report_str);
2215 *report_str += class_props_ss.str();
2216 *report_str += this->report_sep;
2218 *report_str += time_res;
2219 *report_str += this->report_sep;
2221 *report_str += output_res;
2222 *report_str += this->report_sep;
2227 template<
class GRAPH_T>
2230 *partitions_out = this->getCurrPartitions();
2233 template<
class GRAPH_T>
2234 const std::vector<mrpt::vector_uint>&
2236 return m_curr_partitions;
2239 template<
class GRAPH_T>
2242 bool is_first_time_node_reg ) {
2246 using namespace std;
2248 this->m_time_logger.enter(
"updateMapPartitions");
2253 this->logFmt(LVL_INFO,
2254 "updateMapPartitions: Full partitioning of map was issued");
2257 m_partitioner.clear();
2258 nodes_to_scans = this->m_nodes_to_laser_scans2D;
2262 if (is_first_time_node_reg) {
2263 nodes_to_scans.insert(
2264 make_pair(this->m_graph->root,
2265 this->m_nodes_to_laser_scans2D.at(this->m_graph->root)));
2269 nodes_to_scans.insert(
2271 this->m_graph->nodeCount()-1,
2272 this->m_nodes_to_laser_scans2D.at(this->m_graph->nodeCount()-1)));
2279 it = nodes_to_scans.begin();
2280 it != nodes_to_scans.end(); ++it) {
2281 if ((it->second).null()) {
2283 "nodeID \"" << it->first <<
"\" has invalid laserScan");
2290 search = this->m_graph->nodes.find(it->first);
2291 if (search == this->m_graph->nodes.end()) {
2297 pose_t curr_pose = search->second;
2298 mrpt::poses::CPosePDFPtr posePDF(
new constraint_t(curr_pose));
2302 sf->insert(it->second);
2304 m_partitioner.addMapFrame(sf, posePDF);
2309 size_t curr_size = m_curr_partitions.size();
2310 m_last_partitions.resize(curr_size);
2311 for (
size_t i = 0; i < curr_size; i++) {
2312 m_last_partitions[i] = m_curr_partitions[i];
2315 m_partitioner.updatePartitions(m_curr_partitions);
2318 this->m_time_logger.leave(
"updateMapPartitions");
2325 template<
class GRAPH_T>
2327 laser_scans_color(0, 20, 255),
2328 keystroke_laser_scans(
"l"),
2329 has_read_config(false)
2335 template<
class GRAPH_T>
2338 template<
class GRAPH_T>
2343 out.
printf(
"Use scan-matching constraints = %s\n",
2344 use_scan_matching?
"TRUE":
"FALSE");
2345 out.
printf(
"Num. of previous nodes to check ICP against = %d\n",
2346 prev_nodes_for_ICP);
2347 out.
printf(
"Visualize laser scans = %s\n",
2348 visualize_laser_scans?
"TRUE":
"FALSE");
2352 template<
class GRAPH_T>
2358 use_scan_matching =
source.read_bool(
2360 "use_scan_matching",
2362 prev_nodes_for_ICP =
source.read_int(
2364 "prev_nodes_for_ICP",
2366 visualize_laser_scans =
source.read_bool(
2367 "VisualizationParameters",
2368 "visualize_laser_scans",
2372 has_read_config =
true;
2379 template<
class GRAPH_T>
2381 keystroke_map_partitions(
"b"),
2382 balloon_elevation(3),
2383 balloon_radius(0.5),
2384 balloon_std_color(153, 0, 153),
2385 balloon_curr_color(62, 0, 80),
2386 connecting_lines_color(balloon_std_color),
2387 has_read_config(false)
2391 template<
class GRAPH_T>
2394 template<
class GRAPH_T>
2398 using namespace std;
2401 ss <<
"Min. node difference for loop closure = " <<
2402 LC_min_nodeid_diff << endl;
2403 ss <<
"Remote NodeIDs to consider the potential loop closure = " <<
2404 LC_min_remote_nodes << endl;
2405 ss <<
"Min EigenValues ratio for accepting a hypotheses set = " <<
2406 LC_eigenvalues_ratio_thresh << endl;
2407 ss <<
"Check only current node's partition for loop closures = " <<
2408 (LC_check_curr_partition_only?
"TRUE":
"FALSE") << endl;
2409 ss <<
"New registered nodes required for full partitioning = " <<
2410 full_partition_per_nodes << endl;
2411 ss <<
"Visualize map partitions = " <<
2412 (visualize_map_partitions?
"TRUE":
"FALSE") << endl;
2414 out.
printf(
"%s", ss.str().c_str());
2418 template<
class GRAPH_T>
2424 LC_min_nodeid_diff =
source.read_int(
2425 "GeneralConfiguration",
2426 "LC_min_nodeid_diff",
2428 LC_min_remote_nodes =
source.read_int(
2430 "LC_min_remote_nodes",
2432 LC_eigenvalues_ratio_thresh =
source.read_double(
2434 "LC_eigenvalues_ratio_thresh",
2436 LC_check_curr_partition_only =
source.read_bool(
2438 "LC_check_curr_partition_only",
2440 full_partition_per_nodes =
source.read_int(
2442 "full_partition_per_nodes",
2444 visualize_map_partitions =
source.read_bool(
2445 "VisualizationParameters",
2446 "visualize_map_partitions",
2449 has_read_config =
true;
void toggleMapPartitionsVisualization()
Toggle the map partitions visualization objects.
void updateVisuals()
Update the relevant visual features in CDisplayWindow.
std::vector< mrpt::utils::TNodeID > nodes_traversed
Nodes that the Path comprises of.
bool mahalanobisDistanceOdometryToICPEdge(const mrpt::utils::TNodeID &from, const mrpt::utils::TNodeID &to, const constraint_t &rel_edge)
brief Compare the suggested ICP edge against the initial node difference.
GRAPH_T::global_pose_t pose
void initializeVisuals()
Initialize visual objects in CDisplayWindow (e.g.
double goodness
Goodness value corresponding to the hypothesis edge.
parent_t::nodes_to_scans2D_t nodes_to_scans2D_t
Holds the data of an information path.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
void loadParams(const std::string &source_fname)
Fetch the latest observation that the current instance received (most probably during a call to the u...
void addToPath(const mrpt::utils::TNodeID &node, const constraint_t &edge)
add a new link in the current path.
static const path_t * findPathByEnds(const paths_t &vec_paths, const mrpt::utils::TNodeID &src, const mrpt::utils::TNodeID &dst, bool throw_exc=true)
Given a vector of TUncertaintyPath objects, find the one that has the given source and destination no...
std::vector< uint32_t > vector_uint
double DEG2RAD(const double x)
Degrees to radians.
void initMapPartitionsVisualization()
Initialize the visualization of the map partition objects.
void computeCentroidOfNodesVector(const vector_uint &nodes_list, std::pair< double, double > *centroid_coords) const
Compute the Centroid of a group of a vector of node positions.
void getEdge(constraint_t *edge) const
Getter methods for the underlying edge.
void resizeWindow(size_t new_size)
Resize the window.
void updateCurrCovarianceVisualization()
This class allows loading and storing values and vectors of different types from ".ini" files easily.
#define THROW_EXCEPTION(msg)
void getDescriptiveReport(std::string *report_str) const
Fill the provided string with a detailed report of the decider/optimizer state.
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
std::string getSTLContainerAsString(const T &t)
Return a STL container in std::string form.
const Scalar * const_iterator
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string §ion)
This method load the options from a ".ini"-like file or memory-stored string list.
pose_t init_estim
Initial ICP estimation.
const_iterator find(const KEY &key) const
TSlidingWindow mahal_distance_ICP_odom_win
Keep track of the mahalanobis distance between the initial pose difference and the suggested new edge...
static hypot_t * findHypotByID(const hypotsp_t &vec_hypots, const size_t &id, bool throw_exc=true)
Given a vector of THypothesis objects, find the one that has the given ID.
GRAPH_T::edges_map_t::const_iterator edges_citerator
virtual bool getICPEdge(const mrpt::utils::TNodeID &from, const mrpt::utils::TNodeID &to, constraint_t *rel_edge, mrpt::slam::CICP::TReturnInfo *icp_info=NULL, const TGetICPEdgeAdParams *ad_params=NULL)
Get the ICP Edge between the provided nodes.
virtual ~CLoopCloserERD()
GLsizei GLsizei GLuint * obj
node_props_t from_params
Ad.
Struct for passing additional parameters to the getICPEdge call.
void addToPaths(std::set< path_t *> *pool_of_paths, const path_t &curr_path, const std::set< mrpt::utils::TNodeID > &neibors) const
Append the paths starting from the current node.
void registerHypothesis(const hypot_t &h)
Wrapper around the registerNewEdge method which accepts a THypothesis object instead.
void getAsString(std::string *str) const
GLubyte GLubyte GLubyte GLubyte w
void evaluatePartitionsForLC(const partitions_t &partitions)
Evaluate the given partitions for loop closures.
mrpt::utils::TNodeID from
Starting node of the hypothesis.
This class allows loading and storing values and vectors of different types from a configuration text...
bool BASE_IMPEXP isNaN(float f) MRPT_NO_THROWS
Returns true if the number is NaN.
bool is_valid
Field that specifies if the hypothesis is to be considered.
float goodness
A goodness measure for the alignment, it is a [0,1] range indicator of percentage of correspondences...
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
SLAM methods related to graphs of pose constraints.
This base provides a set of functions for maths stuff.
3D segment, consisting of two points.
uint64_t TNodeID
The type for node IDs in graphs of different types.
constraint_t curr_pose_pdf
Current path position + corresponding covariance.
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
virtual void addScanMatchingEdges(const mrpt::utils::TNodeID &curr_nodeID)
Addd ICP constraints from X previous nodeIDs up to the given nodeID.
void BASE_IMPEXP sleep(int time_ms) MRPT_NO_THROWS
An OS-independent method for sending the current thread to "sleep" for a given period of time...
virtual void fetchNodeIDsForScanMatching(const mrpt::utils::TNodeID &curr_nodeID, std::set< mrpt::utils::TNodeID > *nodes_set)
Fetch a list of nodes with regards prior to the given nodeID for which to try and add scan matching e...
This namespace contains representation of robot actions and observations.
Eigen::Matrix< dataType, 4, 4 > inverse(Eigen::Matrix< dataType, 4, 4 > &pose)
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
const partitions_t & getCurrPartitions() const
CMatrixFixedNumeric< double, 3, 3 > CMatrixDouble33
#define MRPT_LOG_WARN_STREAM(__CONTENTS)
uint64_t TNodeID
The type for node IDs in graphs of different types.
std::map< std::string, int > m_edge_types_to_nums
Keep track of the registered edge types.
virtual void initializeLoggers(const std::string &name)
Initialize the COutputLogger, CTimeLogger instances given the name of the decider/optimizer at hand...
std::string BASE_IMPEXP format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
std::vector< path_t > paths_t
GLsizei const GLchar ** string
bool computeDominantEigenVector(const mrpt::math::CMatrixDouble &consist_matrix, mrpt::math::dynamic_vector< double > *eigvec, bool use_power_method=false)
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
MAT::Scalar mahalanobisDistance2(const VECTORLIKE1 &X, const VECTORLIKE2 &MU, const MAT &COV)
Computes the squared mahalanobis distance of a vector X given the mean MU and the covariance inverse ...
void setWindowManagerPtr(mrpt::graphslam::CWindowManager *win_manager)
Fetch a CWindowManager pointer.
void dumpToTextStream(mrpt::utils::CStream &out) const
This method should clearly display all the contents of the structure in textual form, sending it to a CStream.
GRAPH_T::global_pose_t global_pose_t
void assertIsBetweenNodeIDs(const mrpt::utils::TNodeID &from, const mrpt::utils::TNodeID &to) const
Assert that the current path is between the given nodeIDs.
void evalPWConsistenciesMatrix(const mrpt::math::CMatrixDouble &consist_matrix, const hypotsp_t &hypots_pool, hypotsp_t *valid_hypots)
Evalute the consistencies matrix, fill the valid hypotheses.
void getInverseEdge(constraint_t *edge) const
Getter methods for the inverse of the underlying edge.
double generatePWConsistencyElement(const mrpt::utils::TNodeID &a1, const mrpt::utils::TNodeID &a2, const mrpt::utils::TNodeID &b1, const mrpt::utils::TNodeID &b2, const hypotsp_t &hypots, const paths_t *opt_paths=NULL)
Return the pair-wise consistency between the observations of the given nodes.
std::vector< mrpt::vector_uint > partitions_t
Typedef for referring to a list of partitions.
void printParams() const
Print the problem parameters - relevant to the decider/optimizer to the screen in a unified/compact w...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::vector< hypot_t * > hypotsp_t
void registerNewEdge(const mrpt::utils::TNodeID &from, const mrpt::utils::TNodeID &to, const constraint_t &rel_edge)
Register a new constraint/edge in the current graph.
void dumpToTextStream(mrpt::utils::CStream &out) const
This method should clearly display all the contents of the structure in textual form, sending it to a CStream.
void splitPartitionToGroups(vector_uint &partition, vector_uint *groupA, vector_uint *groupB, int max_nodes_in_group=5)
Split an existing partition to Groups.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
static CPlanarLaserScanPtr Create()
mrpt::utils::TNodeID to
Ending node of the hypothesis.
node_props_t to_params
Ad.
void updateLaserScansVisualization()
virtual bool updateState(mrpt::obs::CActionCollectionPtr action, mrpt::obs::CSensoryFramePtr observations, mrpt::obs::CObservationPtr observation)
Generic method for fetching the incremental action/observation readings from the calling function...
void checkPartitionsForLC(partitions_t *partitions_for_LC)
Check the registered so far partitions for potential loop closures.
Struct for passing additional parameters to the generateHypotsPool call.
The ICP algorithm return information.
void setEdge(const constraint_t &edge)
Setter method for the underlying edge.
void generatePWConsistenciesMatrix(const vector_uint &groupA, const vector_uint &groupB, const hypotsp_t &hypots_pool, mrpt::math::CMatrixDouble *consist_matrix, const paths_t *groupA_opt_paths=NULL, const paths_t *groupB_opt_paths=NULL)
Compute the pair-wise consistencies Matrix.
static hypot_t * findHypotByEnds(const hypotsp_t &vec_hypots, const mrpt::utils::TNodeID &from, const mrpt::utils::TNodeID &to, bool throw_exc=true)
Given a vector of THypothesis objects, find the one that has the given start and end nodes...
The namespace for 3D scene representation and rendering.
GLsizei GLsizei GLchar * source
A RGB color - floats in the range [0,1].
void toggleLaserScansVisualization()
togle the LaserScans visualization on and off
void updateMapPartitions(bool full_update=false, bool is_first_time_node_reg=false)
Split the currently registered graph nodes into partitions.
GRAPH_T::constraint_t::type_value pose_t
type of underlying poses (2D/3D).
void getMinUncertaintyPath(const mrpt::utils::TNodeID from, const mrpt::utils::TNodeID to, path_t *path) const
Given two nodeIDs compute and return the path connecting them.
std::map< mrpt::utils::TNodeID, node_props_t > group_t
void generateHypotsPool(const vector_uint &groupA, const vector_uint &groupB, hypotsp_t *generated_hypots, const TGenerateHypotsPoolAdParams *ad_params=NULL)
Generate the hypothesis pool for all the inter-group constraints between two groups of nodes...
Classes for creating GUI windows for 2D and 3D visualization.
T absDiff(const T &lhs, const T &rhs)
Absolute difference between two numbers.
mrpt::graphslam::TUncertaintyPath< GRAPH_T > * popMinUncertaintyPath(std::set< path_t *> *pool_of_paths) const
Find the minimum uncertainty path from te given pool of TUncertaintyPath instances.
GLsizei const GLfloat * value
void initCurrCovarianceVisualization()
void execDijkstraProjection(mrpt::utils::TNodeID starting_node=0, mrpt::utils::TNodeID ending_node=INVALID_NODEID)
compute the minimum uncertainty of each node position with regards to the graph root.
void updateMapPartitionsVisualization()
Update the map partitions visualization.
static CSensoryFramePtr Create()
void initLaserScansVisualization()
size_t id
ID of the current hypothesis.
void notifyOfWindowEvents(const std::map< std::string, bool > &events_occurred)
Get a list of the window events that happened since the last call.
An edge hypothesis between two nodeIDs.
void dumpVisibilityErrorMsg(std::string viz_flag, int sleep_time=500)
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
#define ASSERTMSG_(f, __ERROR_MSG)
#define MRPT_LOG_ERROR_STREAM(__CONTENTS)
GLenum const GLfloat * params
void getEdgesStats(std::map< std::string, int > *edge_types_to_num) const
Fill the given map with the type of registered edges as well as the corresponding number of registrat...
Internal auxiliary classes.
void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source, const std::string §ion)
This method load the options from a ".ini"-like file or memory-stored string list.
bool fillNodePropsFromGroupParams(const mrpt::utils::TNodeID &nodeID, const std::map< mrpt::utils::TNodeID, node_props_t > &group_params, node_props_t *node_props)
Fill the TNodeProps instance using the parameters from the map.
mrpt::obs::CObservation2DRangeScanPtr scan
const mrpt::utils::TNodeID & getDestination() const
Return the Destination node of this path.
bool getPropsOfNodeID(const mrpt::utils::TNodeID &nodeID, global_pose_t *pose, mrpt::obs::CObservation2DRangeScanPtr &scan, const node_props_t *node_props=NULL) const
Fill the pose and LaserScan for the given nodeID.
Class acts as a container for storing pointers to mrpt::gui::CDisplayWindow3D, mrpt::graphslam::CWind...
bool approximatelyEqual(T1 a, T1 b, T2 epsilon)
Compare 2 floats and determine whether they are equal.
virtual int printf(const char *fmt,...) MRPT_printf_format_check(2
Writes a string to the stream in a textual form.
GRAPH_T::constraint_t constraint_t
Handy typedefs.
std::string getAsString(bool oneline=true) const
Return a string representation of the object at hand.
mrpt::graphslam::TUncertaintyPath< GRAPH_T > * queryOptimalPath(const mrpt::utils::TNodeID node) const
Query for the optimal path of a nodeID.
TSlidingWindow goodness_threshold_win
Keep track of ICP Goodness values for ICP between nearby nodes and adapt the Goodness threshold based...