CGraphSlamEngine_MR_impl.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002          |                     Mobile Robot Programming Toolkit (MRPT)               |
00003          |                          http://www.mrpt.org/                             |
00004          |                                                                           | | Copyright (c) 2005-2016, Individual contributors, see AUTHORS file        |
00005          | See: http://www.mrpt.org/Authors - All rights reserved.                   |
00006          | Released under BSD License. See details in http://www.mrpt.org/License    |
00007          +---------------------------------------------------------------------------+ */
00008 
00009 #ifndef CGRAPHSLAMENGINE_MR_IMPL_H
00010 #define CGRAPHSLAMENGINE_MR_IMPL_H
00011 
00012 namespace mrpt { namespace graphslam {
00013 
00014 template<class GRAPH_T>
00015 CGraphSlamEngine_MR<GRAPH_T>::CGraphSlamEngine_MR(
00016                 ros::NodeHandle* nh,
00017                 const std::string& config_file,
00018                 const std::string& rawlog_fname/* ="" */,
00019                 const std::string& fname_GT /* ="" */,
00020                 mrpt::graphslam::CWindowManager* win_manager /* = NULL */,
00021                 mrpt::graphslam::deciders::CNodeRegistrationDecider<GRAPH_T>* node_reg /* = NULL */,
00022                 mrpt::graphslam::deciders::CEdgeRegistrationDecider<GRAPH_T>* edge_reg /* = NULL */,
00023                 mrpt::graphslam::optimizers::CGraphSlamOptimizer<GRAPH_T>* optimizer /* = NULL */):
00024         parent_t::CGraphSlamEngine_ROS(
00025                         nh,
00026                         config_file,
00027                         rawlog_fname,
00028                         fname_GT,
00029                         win_manager,
00030                         node_reg,
00031                         edge_reg,
00032                         optimizer),
00033         m_conn_manager(
00034                         dynamic_cast<mrpt::utils::COutputLogger*>(this), nh),
00035         m_nh(nh),
00036         m_graph_nodes_last_size(0),
00037         m_registered_multiple_nodes(false),
00038         cm_graph_async_spinner(/* threads_num: */ 1, &this->custom_service_queue),
00039         m_pause_exec_on_mr_registration(false),
00040         m_sec_alignment_params("AlignmentParameters"),
00041         m_sec_mr_slam_params("MultiRobotParameters"),
00042         m_opts(*this)
00043 {
00044         this->initClass();
00045 }
00046 
00047 template<class GRAPH_T>
00048 CGraphSlamEngine_MR<GRAPH_T>::~CGraphSlamEngine_MR() {
00049         MRPT_LOG_DEBUG_STREAM(
00050                 "In Destructor: Deleting CGraphSlamEngine_MR instance...");
00051         cm_graph_async_spinner.stop();
00052 
00053         for (typename neighbors_t::iterator
00054                         neighbors_it = m_neighbors.begin();
00055                         neighbors_it != m_neighbors.end();
00056                         ++neighbors_it) {
00057                 delete *neighbors_it;
00058         }
00059 
00060 }
00061 
00062 template<class GRAPH_T>
00063 bool CGraphSlamEngine_MR<GRAPH_T>::addNodeBatchesFromAllNeighbors() {
00064         MRPT_START;
00065         using namespace mrpt::graphslam::detail;
00066 
00067         bool ret_val = false;
00068         for (const auto& neighbor : m_neighbors) {
00069                 if (!isEssentiallyZero(
00070                                         neighbor->tf_self_to_neighbor_first_integrated_pose) && // inter-graph TF found
00071                                 neighbor->hasNewData() &&
00072                                 neighbor->hasNewNodesBatch(m_opts.nodes_integration_batch_size)) {
00073                         bool loc_ret_val = this->addNodeBatchFromNeighbor(neighbor);
00074                         if (loc_ret_val) { ret_val = true; }
00075                 }
00076         }
00077 
00078         return ret_val;
00079         MRPT_END;
00080 } // end of addNodeBatchesFromAllNeighbors
00081 
00082 template<class GRAPH_T>
00083 bool CGraphSlamEngine_MR<GRAPH_T>::
00084 addNodeBatchFromNeighbor(TNeighborAgentProps* neighbor) {
00085         MRPT_START;
00086         ASSERT_(neighbor);
00087         using namespace mrpt::utils;
00088         using namespace mrpt::poses;
00089         using namespace mrpt::math;
00090         using namespace std;
00091 
00092 
00093         vector_uint nodeIDs;
00094         std::map<mrpt::utils::TNodeID, node_props_t> nodes_params;
00095         neighbor->getCachedNodes(&nodeIDs, &nodes_params, /*only unused=*/ true);
00096 
00097         //
00098         // get the condensed measurements graph of the new nodeIDs
00099         //
00100         mrpt_msgs::GetCMGraph cm_graph_srv;
00101         //mrpt_msgs::GetCMGraphRequest::_nodeIDs_type& cm_graph_nodes =
00102         //cm_graph_srv.request.nodeIDs;
00103         for (const auto n : nodeIDs) {
00104                 cm_graph_srv.request.nodeIDs.push_back(n);
00105         }
00106 
00107         MRPT_LOG_DEBUG_STREAM("Asking for the graph.");
00108         bool res = neighbor->cm_graph_srvclient.call(cm_graph_srv); // blocking
00109         if (!res) {
00110                 MRPT_LOG_ERROR_STREAM("Service call for CM_Graph failed.");
00111                 return false; // skip this if failed to fetch other's graph
00112         }
00113         MRPT_LOG_DEBUG_STREAM("Fetched graph successfully.");
00114         MRPT_LOG_DEBUG_STREAM(cm_graph_srv.response.cm_graph);
00115 
00116         GRAPH_T other_graph;
00117         mrpt_bridge::convert(cm_graph_srv.response.cm_graph, other_graph);
00118 
00119         //
00120         // merge batch of nodes in own graph
00121         //
00122         MRPT_LOG_WARN_STREAM("Merging new batch from \"" << neighbor->getAgentNs() << "\"..." << endl
00123                 << "Batch: " << getSTLContainerAsString(cm_graph_srv.request.nodeIDs));
00124         hypots_t graph_conns;
00125         // build a hypothesis connecting the new batch with the last integrated
00126         // pose of the neighbor
00127         {
00128                 pair<TNodeID, node_props_t> node_props_to_connect = *nodes_params.begin();
00129 
00130                 hypot_t graph_conn;
00131                 constraint_t c;
00132                 c.mean = node_props_to_connect.second.pose -
00133                         neighbor->last_integrated_pair_neighbor_frame.second;
00134                 c.cov_inv.unit();
00135                 graph_conn.setEdge(c);
00136 
00137                 graph_conn.from = INVALID_NODEID;
00138                 // get the nodeID of the last integrated neighbor node after remapping
00139                 // in own graph numbering
00140                 for (const auto n : this->m_graph.nodes) {
00141                         if (n.second.agent_ID_str == neighbor->getAgentNs() &&
00142                                         n.second.nodeID_loc == neighbor->last_integrated_pair_neighbor_frame.first) {
00143                                 graph_conn.from = n.first;
00144                                 break;
00145                         }
00146                 }
00147                 ASSERT_(graph_conn.from != INVALID_NODEID);
00148                 graph_conn.to = node_props_to_connect.first; // other
00149 
00150                 MRPT_LOG_DEBUG_STREAM("Hypothesis for adding the batch of nodes: " << graph_conn);
00151                 graph_conns.push_back(graph_conn);
00152         }
00153 
00154         std::map<TNodeID, TNodeID> old_to_new_mappings;
00155         this->m_graph.mergeGraph(
00156                         other_graph, graph_conns,
00157                         /*hypots_from_other_to_self=*/ false,
00158                         &old_to_new_mappings);
00159 
00160         //
00161         // Mark Nodes/LaserScans as integrated
00162         //
00163         MRPT_LOG_WARN_STREAM("Marking used nodes as integrated - Integrating LSs");
00164         nodes_to_scans2D_t new_nodeIDs_to_scans_pairs;
00165         for (typename vector_uint::const_iterator
00166                         n_cit = nodeIDs.begin();
00167                         n_cit != nodeIDs.end();
00168                         ++n_cit) {
00169 
00170                 // Mark the neighbor's used nodes as integrated
00171                 neighbor->nodeID_to_is_integrated.at(*n_cit) = true;
00172 
00173                 // Integrate LaserScans at the newly integrated nodeIDs in own
00174                 // nodes_to_laser_scans2D map
00175                 new_nodeIDs_to_scans_pairs.insert(make_pair(
00176                                         old_to_new_mappings.at(*n_cit),
00177                                         nodes_params.at(*n_cit).scan));
00178                 MRPT_LOG_INFO_STREAM("Adding nodeID-LS of nodeID: "
00179                         << "\t[old:] " << *n_cit << endl
00180                         << "| [new:] " << old_to_new_mappings.at(*n_cit));
00181         }
00182 
00183         this->m_nodes_to_laser_scans2D.insert(
00184                         new_nodeIDs_to_scans_pairs.begin(),
00185                         new_nodeIDs_to_scans_pairs.end());
00186         edge_reg_mr_t* edge_reg_mr =
00187                 dynamic_cast<edge_reg_mr_t*>(this->m_edge_reg);
00188         edge_reg_mr->addBatchOfNodeIDsAndScans(new_nodeIDs_to_scans_pairs);
00189 
00190         this->execDijkstraNodesEstimation();
00191         neighbor->resetFlags();
00192 
00193         // keep track of the last integrated nodeID
00194         {
00195                 TNodeID last_node = *nodeIDs.rbegin();
00196                 neighbor->last_integrated_pair_neighbor_frame = make_pair(
00197                                 last_node,
00198                                 nodes_params.at(last_node).pose);
00199         }
00200 
00201         if (m_pause_exec_on_mr_registration) this->pauseExec();
00202         return true;
00203         MRPT_END;
00204 } // end of addNodeBatchFromNeighbor
00205 
00206 template<class GRAPH_T>
00207 bool CGraphSlamEngine_MR<GRAPH_T>::findTFsWithAllNeighbors() {
00208         MRPT_START;
00209         using namespace mrpt::utils;
00210         using namespace mrpt::math;
00211 
00212         if (this->m_graph.nodeCount() < m_opts.inter_group_node_count_thresh) {
00213                 return false;
00214         }
00215 
00216 
00217         // cache the gridmap so that it is computed only once during all the
00218         // findMatches*  calls
00219         this->computeMap();
00220 
00221         bool ret_val = false; // at *any* node registration, change to true
00222 
00223         // iterate over all neighbors - run map-matching proc.
00224         for (typename neighbors_t::iterator
00225                         neighbors_it = m_neighbors.begin();
00226                         neighbors_it != m_neighbors.end();
00227                         ++neighbors_it) {
00228 
00229                 // run matching proc with neighbor only if I haven't found an initial
00230                 // inter-graph TF
00231                 if (!m_neighbor_to_found_initial_tf.at(*neighbors_it)) {
00232 
00233                         bool loc_ret_val = findTFWithNeighbor(*neighbors_it);
00234                         if (loc_ret_val) {
00235                                 MRPT_LOG_DEBUG_STREAM(
00236                                         "Updating own cached map after successful node registration...");
00237                                 // update own map if new nodes have been added.
00238                                 this->computeMap();
00239 
00240                                 // mark current neighbor tf as found.
00241                                 m_neighbor_to_found_initial_tf.at(*neighbors_it) = true;
00242 
00243                                 ret_val = true;
00244                         }
00245                 }
00246         }
00247 
00248         return ret_val;
00249         MRPT_END;
00250 } // end of findTFsWithAllNeighbors
00251 
00252 template<class GRAPH_T>
00253 bool CGraphSlamEngine_MR<GRAPH_T>::
00254 findTFWithNeighbor(TNeighborAgentProps* neighbor) {
00255         MRPT_START;
00256         using namespace mrpt::slam;
00257         using namespace mrpt::math;
00258         using namespace mrpt::poses;
00259         using namespace mrpt::utils;
00260         using namespace mrpt::maps;
00261         using namespace mrpt::graphslam::detail;
00262 
00263         bool ret_val = false;
00264 
00265         vector_uint neighbor_nodes;
00266         std::map<mrpt::utils::TNodeID, node_props_t> nodes_params;
00267         neighbor->getCachedNodes(&neighbor_nodes, &nodes_params, /*only unused=*/ false);
00268         if (neighbor_nodes.size() < m_opts.inter_group_node_count_thresh ||
00269                         !neighbor->hasNewData()) {
00270                 return false;
00271         }
00272 
00273         //
00274         // run alignment procedure
00275         //
00276         COccupancyGridMap2DPtr neighbor_gridmap = neighbor->getGridMap();
00277         CGridMapAligner gridmap_aligner;
00278         gridmap_aligner.options = m_alignment_options;
00279 
00280         CGridMapAligner::TReturnInfo results;
00281         float run_time = 0;
00282         // TODO - make use of agents' rendez-vous in the initial estimation
00283         CPosePDFGaussian init_estim;
00284         init_estim.mean = neighbor->tf_self_to_neighbor_first_integrated_pose;
00285         this->logFmt(LVL_INFO,
00286                         "Trying to align the maps, initial estimation: %s",
00287                         init_estim.mean.asString().c_str());
00288 
00289         // Save them for debugging reasons
00290         //neighbor_gridmap->saveMetricMapRepresentationToFile(this->getLoggerName() + "_other");
00291         //this->m_gridmap_cached->saveMetricMapRepresentationToFile(this->getLoggerName() + "_self");
00292 
00293         const CPosePDFPtr pdf_tmp = gridmap_aligner.AlignPDF(
00294                         this->m_gridmap_cached.pointer(), neighbor_gridmap.pointer(),
00295                         init_estim,
00296                         &run_time, &results);
00297         this->logFmt(LVL_INFO, "Elapsed Time: %f", run_time);
00298         CPosePDFSOGPtr pdf_out = CPosePDFSOG::Create();
00299         pdf_out->copyFrom(*pdf_tmp);
00300 
00301         CPose2D pose_out; CMatrixDouble33 cov_out;
00302         pdf_out->getMostLikelyCovarianceAndMean(cov_out, pose_out);
00303 
00304         this->logFmt(LVL_INFO, "%s\n",
00305                         getGridMapAlignmentResultsAsString(*pdf_tmp, results).c_str());
00306 
00307         // dismiss this?
00308         if (results.goodness > 0.999 ||
00309                         isEssentiallyZero(pose_out)) {
00310                 return false;
00311         }
00312 
00313         //
00314         //
00315         // Map-merging operation is successful. Integrate graph into own.
00317 
00318         //
00319         // ask for condensed measurements graph
00320         //
00321         mrpt_msgs::GetCMGraph cm_graph_srv;
00322         typedef mrpt_msgs::GetCMGraphRequest::_nodeIDs_type nodeID_type;
00323         nodeID_type& matched_nodeIDs =
00324                 cm_graph_srv.request.nodeIDs;
00325 
00326         // which nodes to ask the condensed graph for
00327         // I assume that no nodes of the other graph have been integrated yet.
00328         for (typename vector_uint::const_iterator
00329                         n_cit = neighbor_nodes.begin();
00330                         n_cit != neighbor_nodes.end();
00331                         ++n_cit) {
00332                 matched_nodeIDs.push_back(*n_cit); // all used nodes
00333         }
00334 
00335         MRPT_LOG_DEBUG_STREAM("Asking for the graph.");
00336         bool res = neighbor->cm_graph_srvclient.call(cm_graph_srv); // blocking
00337         if (!res) {
00338                 MRPT_LOG_ERROR_STREAM("Service call for CM_Graph failed.");
00339                 return false; // skip this if failed to fetch other's graph
00340         }
00341         MRPT_LOG_DEBUG_STREAM("Fetched graph successfully.");
00342         MRPT_LOG_DEBUG_STREAM(cm_graph_srv.response.cm_graph);
00343 
00344         GRAPH_T other_graph;
00345         mrpt_bridge::convert(cm_graph_srv.response.cm_graph, other_graph);
00346 
00347         //
00348         // merge graphs
00349         //
00350         MRPT_LOG_WARN_STREAM("Merging graph of \"" << neighbor->getAgentNs() << "\"...");
00351         hypots_t graph_conns;
00352         // build the only hypothesis connecting graph with neighbor subgraph
00353         // own origin -> first valid nodeID of neighbor
00354         {
00355                 hypot_t graph_conn;
00356                 constraint_t c;
00357                 c.mean = pose_out;
00358                 cov_out.inv(c.cov_inv); // assign the inverse of the found covariance to c
00359                 graph_conn.setEdge(c);
00360                 // TODO - change this.
00361                 graph_conn.from = 0; // self
00362                 graph_conn.to = *neighbor_nodes.begin(); // other
00363 
00364                 graph_conn.goodness = results.goodness;
00365                 graph_conns.push_back(graph_conn);
00366         }
00367 
00368         std::map<TNodeID, TNodeID> old_to_new_mappings;
00369         this->m_graph.mergeGraph(
00370                         other_graph, graph_conns,
00371                         /*hypots_from_other_to_self=*/ false,
00372                         &old_to_new_mappings);
00373 
00374         //
00375         // Mark Nodes/LaserScans as integrated
00376         //
00377         MRPT_LOG_WARN_STREAM("Marking used nodes as integrated - Integrating LSs");
00378         nodes_to_scans2D_t new_nodeIDs_to_scans_pairs;
00379         for (typename vector_uint::const_iterator
00380                         n_cit = neighbor_nodes.begin();
00381                         n_cit != neighbor_nodes.end();
00382                         ++n_cit) {
00383 
00384                 // Mark the neighbor's used nodes as integrated
00385                 neighbor->nodeID_to_is_integrated.at(*n_cit) = true;
00386 
00387                 // Integrate LaserScans at the newly integrated nodeIDs in own
00388                 // nodes_to_laser_scans2D map
00389                 new_nodeIDs_to_scans_pairs.insert(make_pair(
00390                                         old_to_new_mappings.at(*n_cit),
00391                                         nodes_params.at(*n_cit).scan));
00392                 MRPT_LOG_INFO_STREAM("Adding nodeID-LS of nodeID: "
00393                         << "\t[old:] " << *n_cit << endl
00394                         << "| [new:] " << old_to_new_mappings.at(*n_cit));
00395         }
00396 
00397         this->m_nodes_to_laser_scans2D.insert(
00398                         new_nodeIDs_to_scans_pairs.begin(),
00399                         new_nodeIDs_to_scans_pairs.end());
00400         edge_reg_mr_t* edge_reg_mr =
00401                 dynamic_cast<edge_reg_mr_t*>(this->m_edge_reg);
00402         edge_reg_mr->addBatchOfNodeIDsAndScans(new_nodeIDs_to_scans_pairs);
00403 
00404         // Call for a Full graph visualization update and Dijkstra update -
00405         // CGraphSlamOptimizer
00406         //MRPT_LOG_WARN_STREAM("Optimizing graph..." << endl);
00407         //this->m_optimizer->optimizeGraph();
00408         MRPT_LOG_WARN_STREAM("Executing Dijkstra..." << endl);
00409         this->execDijkstraNodesEstimation();
00410 
00411         neighbor->resetFlags();
00412 
00413         // update the initial tf estimation
00414         neighbor->tf_self_to_neighbor_first_integrated_pose = pose_out;
00415 
00416         // keep track of the last integrated nodeID
00417         {
00418                 TNodeID last_node = *neighbor_nodes.rbegin();
00419                 neighbor->last_integrated_pair_neighbor_frame = make_pair(
00420                                 last_node,
00421                                 nodes_params.at(last_node).pose);
00422         }
00423 
00424         MRPT_LOG_WARN_STREAM("Nodes of neighbor [" << neighbor->getAgentNs()
00425                 << "] have been integrated successfully");
00426 
00427         if (m_pause_exec_on_mr_registration) this->pauseExec();
00428         ret_val = true;
00429 
00430         return ret_val;
00431         MRPT_END;
00432 } // end if findTFWithNeighbor
00433 
00434 template<class GRAPH_T>
00435 bool CGraphSlamEngine_MR<GRAPH_T>::_execGraphSlamStep(
00436                 mrpt::obs::CActionCollectionPtr& action,
00437                 mrpt::obs::CSensoryFramePtr& observations,
00438                 mrpt::obs::CObservationPtr& observation,
00439                 size_t& rawlog_entry) {
00440         MRPT_START;
00441         using namespace mrpt::graphslam::deciders;
00442         using namespace mrpt;
00443 
00444         // call parent method
00445         bool continue_exec = parent_t::_execGraphSlamStep(
00446                         action, observations, observation, rawlog_entry);
00447 
00448         // find matches between own nodes and those of the neighbors
00449   bool did_register_from_map_merge;
00450   if (!m_opts.conservative_find_initial_tfs_to_neighbors) {
00451         did_register_from_map_merge = this->findTFsWithAllNeighbors();
00452   }
00453   else { // inter-graph TF is available - add new nodes
00454         THROW_EXCEPTION("Conservative inter-graph TF computation is not yet implemented.");
00455   }
00456 
00457   bool did_register_from_batches = this->addNodeBatchesFromAllNeighbors();
00458   m_registered_multiple_nodes = (did_register_from_map_merge || did_register_from_batches);
00459 
00460   if (m_registered_multiple_nodes) {
00461         if (this->m_enable_visuals) {
00462                 this->updateAllVisuals();
00463         }
00464   }
00465 
00466   return continue_exec;
00467   MRPT_END;
00468 } // end of _execGraphSlamStep
00469 
00470 template<class GRAPH_T>
00471 void CGraphSlamEngine_MR<GRAPH_T>::initClass() {
00472         using namespace mrpt::graphslam;
00473         using namespace mrpt::utils;
00474         using namespace std;
00475 
00476         // initialization of topic namespace names
00477         // TODO - put these into seperate method
00478         m_mr_ns = "mr_info";
00479 
00480         // initialization of topic names / services
00481         m_list_neighbors_topic   = m_mr_ns + "/" + "neighbors";
00482         m_last_regd_id_scan_topic = m_mr_ns + "/" + "last_nodeID_laser_scan";
00483         m_last_regd_nodes_topic = m_mr_ns + "/" + "last_regd_nodes";
00484         m_cm_graph_service = m_mr_ns + "/" + "get_cm_graph";
00485 
00486         this->m_class_name = "CGraphSlamEngine_MR_" + m_conn_manager.getTrimmedNs();
00487         this->setLoggerName(this->m_class_name);
00488         this->setupComm();
00489 
00490         // Make sure that master_discovery and master_sync are up before trying to
00491         // connect to other agents
00492         std::vector<string> nodes_up;
00493         ros::master::getNodes(nodes_up);
00494         // If both master_dicovery and master_sync are running, then the
00495         // /master_sync/get_sync_info service should be available
00496         MRPT_LOG_INFO_STREAM("Waiting for master_discovery, master_sync nodes to come up....");
00497         ros::service::waitForService("/master_sync/get_sync_info"); // block until it is
00498         MRPT_LOG_INFO_STREAM("master_discovery, master_sync are available.");
00499 
00500         this->m_node_reg->setClassName(
00501                   this->m_node_reg->getClassName() + "_" + m_conn_manager.getTrimmedNs());
00502         this->m_edge_reg->setClassName(
00503                   this->m_edge_reg->getClassName() + "_" + m_conn_manager.getTrimmedNs());
00504         this->m_optimizer->setClassName(
00505                   this->m_optimizer->getClassName() + "_" + m_conn_manager.getTrimmedNs());
00506 
00507         // in case of Multi-robot specific deciders/optimizers (they
00508         // inherit from the CDeciderOrOptimizer_ROS interface) set the
00509         // CConnectionManager*
00510         // NOTE: It's not certain, even though we are running multi-robot graphSLAM
00511         // that all these classes do inherit from the
00512         // CRegistrationDeciderOrOptimizer_MR base class. They might be more generic
00513         // and not care about the multi-robot nature of the algorithm (e.g.
00514         // optimization scheme)
00515         { // NRD
00516                 CRegistrationDeciderOrOptimizer_MR<GRAPH_T>* dec_opt_mr =
00517                         dynamic_cast<CRegistrationDeciderOrOptimizer_MR<GRAPH_T>*>(this->m_node_reg);
00518 
00519                 if (dec_opt_mr) {
00520                         dec_opt_mr->setCConnectionManagerPtr(&m_conn_manager);
00521                 }
00522         }
00523         { // ERD
00524                 CRegistrationDeciderOrOptimizer_MR<GRAPH_T>* dec_opt_mr =
00525                         dynamic_cast<CRegistrationDeciderOrOptimizer_MR<GRAPH_T>*>(this->m_edge_reg);
00526                 ASSERT_(dec_opt_mr);
00527                 dec_opt_mr->setCConnectionManagerPtr(&m_conn_manager);
00528                 dec_opt_mr->setCGraphSlamEnginePtr(this);
00529         }
00530         { // GSO
00531                 CRegistrationDeciderOrOptimizer_MR<GRAPH_T>* dec_opt_mr =
00532                         dynamic_cast<CRegistrationDeciderOrOptimizer_MR<GRAPH_T>*>(this->m_optimizer);
00533                 if (dec_opt_mr) {
00534                         dec_opt_mr->setCConnectionManagerPtr(&m_conn_manager);
00535                 }
00536         }
00537         // display messages with the names of the deciders, optimizer and agent string ID
00538         if (this->m_enable_visuals) {
00539                 // NRD
00540                 this->m_win_manager->assignTextMessageParameters(
00541                                 /* offset_y* = */ &m_offset_y_nrd,
00542                                 /* text_index* = */ &m_text_index_nrd);
00543                 this->m_win_manager->addTextMessage(this->m_offset_x_left, -m_offset_y_nrd,
00544                                 mrpt::format("NRD: %s", this->m_node_reg->getClassName().c_str()),
00545                                 TColorf(0,0,0),
00546                                 /* unique_index = */ m_text_index_nrd);
00547 
00548                 // ERD
00549                 this->m_win_manager->assignTextMessageParameters(
00550                                 /* offset_y* = */ &m_offset_y_erd,
00551                                 /* text_index* = */ &m_text_index_erd);
00552                 this->m_win_manager->addTextMessage(
00553                                 this->m_offset_x_left, -m_offset_y_erd,
00554                                 mrpt::format("ERD: %s", this->m_edge_reg->getClassName().c_str()),
00555                                 TColorf(0,0,0),
00556                                 /* unique_index = */ m_text_index_erd);
00557 
00558                 // GSO
00559                 this->m_win_manager->assignTextMessageParameters(
00560                                 /* offset_y* = */ &m_offset_y_gso,
00561                                 /* text_index* = */ &m_text_index_gso);
00562                 this->m_win_manager->addTextMessage(
00563                                 this->m_offset_x_left, -m_offset_y_gso,
00564                                 mrpt::format("GSO: %s", this->m_optimizer->getClassName().c_str()),
00565                                 TColorf(0,0,0),
00566                                 /* unique_index = */ m_text_index_gso);
00567 
00568                 // Agent Namespace
00569                 this->m_win_manager->assignTextMessageParameters(
00570                                 /* offset_y* = */ &m_offset_y_namespace,
00571                                 /* text_index* = */ &m_text_index_namespace);
00572                 this->m_win_manager->addTextMessage(
00573                                 this->m_offset_x_left, -m_offset_y_namespace,
00574                                 mrpt::format("Agent ID: %s", m_conn_manager.getTrimmedNs().c_str()),
00575                                 TColorf(0,0,0),
00576                                 /* unique_index = */ m_text_index_namespace);
00577 
00578         }
00579         this->readParams();
00580 
00581         this->m_optimized_map_color = m_neighbor_colors_manager.getNextTColor();
00582 
00583         // start the spinner for asynchronously servicing cm_graph requests
00584         cm_graph_async_spinner.start();
00585 } // end of initClass
00586 
00587 template<class GRAPH_T>
00588 mrpt::poses::CPose3D CGraphSlamEngine_MR<GRAPH_T>::
00589 getLSPoseForGridMapVisualization(
00590                 const mrpt::utils::TNodeID nodeID) const {
00591         MRPT_START;
00592         using namespace mrpt::graphs::detail;
00593 
00594         // if this is my own node ID return the corresponding CPose2D, otherwise
00595         // return the pose connecting own graph with the neighbor's graph
00596 
00597         const TMRSlamNodeAnnotations* node_annots = dynamic_cast<const TMRSlamNodeAnnotations*>(
00598                         &this->m_graph.nodes.at(nodeID));
00599 
00600         // Is the current nodeID registered by a neighboring agent or is it my own?
00601         TNeighborAgentProps* neighbor = NULL;
00602         this->getNeighborByAgentID(node_annots->agent_ID_str, neighbor);
00603 
00604         CPose3D laser_pose;
00605         if (!neighbor) { // own node
00606                 laser_pose = parent_t::getLSPoseForGridMapVisualization(nodeID);
00607         }
00608         else { // not by me - return TF to neighbor graph
00609                 laser_pose = CPose3D(neighbor->tf_self_to_neighbor_first_integrated_pose);
00610         }
00611         return laser_pose;
00612 
00613         MRPT_END;
00614 }
00615 
00616 template<class GRAPH_T>
00617 bool CGraphSlamEngine_MR<GRAPH_T>::
00618 getNeighborByAgentID(const std::string& agent_ID_str,
00619                 TNeighborAgentProps*& neighbor) const {
00620         MRPT_START;
00621 
00622         bool ret= false;
00623         for (auto neighbors_it = m_neighbors.begin();
00624                         neighbors_it != m_neighbors.end();
00625                         ++neighbors_it) {
00626 
00627                 if ((*neighbors_it)->getAgentNs() == agent_ID_str) {
00628                         ret = true;
00629                         neighbor = *neighbors_it;
00630                         break;
00631                 }
00632         }
00633 
00634         return ret;
00635         MRPT_END;
00636 }
00637 
00638 template<class GRAPH_T>
00639 void CGraphSlamEngine_MR<GRAPH_T>::usePublishersBroadcasters() {
00640         MRPT_START;
00641         using namespace mrpt_bridge;
00642         using namespace mrpt_msgs;
00643         using namespace std;
00644         using namespace mrpt::math;
00645         using ::operator==;
00646 
00647         // call the parent class
00648         parent_t::usePublishersBroadcasters();
00649 
00650         // update list of neighbors that the current agent can communicate with.
00651         mrpt_msgs::GraphSlamAgents nearby_slam_agents;
00652         m_conn_manager.getNearbySlamAgents(
00653                                 &nearby_slam_agents,
00654                                 /*ignore_self = */ true);
00655         m_list_neighbors_pub.publish(nearby_slam_agents);
00656 
00657         // Initialize TNeighborAgentProps
00658         // for each *new* GraphSlamAgent we should add a TNeighborAgentProps instance,
00659         // and initialize its subscribers so that we fetch every new LaserScan and list of
00660         // modified nodes it publishes
00661         {
00662                 for (GraphSlamAgents::_list_type::const_iterator
00663                                 it = nearby_slam_agents.list.begin();
00664                                 it != nearby_slam_agents.list.end();
00665                                 ++it) {
00666 
00667                         const GraphSlamAgent& gsa = *it;
00668 
00669                         // Is the current GraphSlamAgent already registered?
00670                         const auto search = [gsa](const TNeighborAgentProps* neighbor) {
00671                                 return (neighbor->agent == gsa);
00672                         };
00673                         typename neighbors_t::const_iterator neighbor_it = find_if(
00674                                         m_neighbors.begin(),
00675                                         m_neighbors.end(), search);
00676 
00677                         if (neighbor_it == m_neighbors.end()) { // current gsa not found, add it
00678 
00679                                 MRPT_LOG_DEBUG_STREAM("Initializing NeighborAgentProps instance for "
00680                                         << gsa.name.data);
00681                                 m_neighbors.push_back(new TNeighborAgentProps(*this, gsa));
00682                                 TNeighborAgentProps* latest_neighbor = m_neighbors.back();
00683                                 latest_neighbor->setTColor(m_neighbor_colors_manager.getNextTColor());
00684                                 m_neighbor_to_found_initial_tf.insert(make_pair(
00685                                                         latest_neighbor, false));
00686                                 latest_neighbor->setupComm();
00687                         }
00688                 }
00689         }
00690 
00691         this->pubUpdatedNodesList();
00692         this->pubLastRegdIDScan();
00693 
00694         MRPT_END;
00695 } // end of usePublishersBroadcasters
00696 
00697 template<class GRAPH_T>
00698 bool CGraphSlamEngine_MR<GRAPH_T>::pubUpdatedNodesList() {
00699         MRPT_START;
00700         using namespace mrpt_msgs;
00701 
00702         // update the last X NodeIDs + positions; Do it only when a new node is inserted.
00703         // notified of this change anyway after a new node addition
00704         if (this->m_graph_nodes_last_size == this->m_graph.nodes.size()) {
00705                 return false;
00706         }
00707         MRPT_LOG_DEBUG_STREAM("Updating list of node poses");
00708 
00709         // send at most m_num_last_rgd_nodes
00710         typename GRAPH_T::global_poses_t poses_to_send;
00711         int poses_counter = 0;
00712         // fill the NodeIDWithPose_vec msg
00713         NodeIDWithPose_vec ros_nodes;
00714 
00715         // send up to num_last_regd_nodes Nodes - start from end.
00716         for (typename GRAPH_T::global_poses_t::const_reverse_iterator
00717                         cit = this->m_graph.nodes.rbegin();
00718                         (poses_counter <= m_opts.num_last_regd_nodes &&
00719                          cit != this->m_graph.nodes.rend());
00720                         ++cit) {
00721 
00722                 // Do not resend nodes of others, registered in own graph.
00723                 if (cit->second.agent_ID_str != m_conn_manager.getTrimmedNs()) {
00724                         continue; // skip this.
00725                 }
00726 
00727                 NodeIDWithPose curr_node_w_pose;
00728                 // send basics - NodeID, Pose
00729                 curr_node_w_pose.nodeID = cit->first;
00730                 mrpt_bridge::convert(cit->second, curr_node_w_pose.pose);
00731 
00732                 // send mr-fields
00733                 curr_node_w_pose.str_ID.data = cit->second.agent_ID_str;
00734                 curr_node_w_pose.nodeID_loc = cit->second.nodeID_loc;
00735 
00736                 ros_nodes.vec.push_back(curr_node_w_pose);
00737 
00738                 poses_counter++;
00739         }
00740 
00741         m_last_regd_nodes_pub.publish(ros_nodes);
00742 
00743         // update the last known size
00744         m_graph_nodes_last_size = this->m_graph.nodeCount();
00745 
00746         bool res = false;
00747         if (poses_counter) {
00748                 res = true;
00749         }
00750 
00751         return res;
00752         MRPT_END;
00753 } // end of pubUpdatedNodesList
00754 
00755 template<class GRAPH_T>
00756 bool CGraphSlamEngine_MR<GRAPH_T>::pubLastRegdIDScan() {
00757         MRPT_START;
00758         using namespace mrpt_msgs;
00759         using namespace mrpt_bridge;
00760 
00761         // Update the last registered scan + associated nodeID
00762         // Last registered scan always corresponds to the *last* element of the of the
00763         // published NodeIDWithPose_vec that is published above.
00764         //
00765         // - Check if map is empty
00766         // - Have I already published the last laser scan?
00767         if (!this->m_nodes_to_laser_scans2D.empty() &&
00768                         m_nodes_to_laser_scans2D_last_size < this->m_nodes_to_laser_scans2D.size()) {
00769                 // last registered scan
00770                 MRPT_NodeIDWithLaserScan mrpt_last_regd_id_scan =
00771                         *(this->m_nodes_to_laser_scans2D.rbegin());
00772 
00773 
00774                 // if this is a mr-registered nodeID+LS, skip it.
00775                 if (!this->isOwnNodeID(mrpt_last_regd_id_scan.first)) {
00776                         return false;
00777                 }
00778 
00779                 //MRPT_LOG_DEBUG_STREAM
00780                         //<< "Publishing LaserScan of nodeID \""
00781                         //<< mrpt_last_regd_id_scan.first << "\"";
00782                 ASSERT_(mrpt_last_regd_id_scan.second);
00783 
00784                 // convert to ROS msg
00785                 mrpt_msgs::NodeIDWithLaserScan ros_last_regd_id_scan;
00786                 convert(*(mrpt_last_regd_id_scan.second), ros_last_regd_id_scan.scan);
00787                 ros_last_regd_id_scan.nodeID = mrpt_last_regd_id_scan.first;
00788 
00789                 m_last_regd_id_scan_pub.publish(ros_last_regd_id_scan);
00790 
00791                 // update the last known size.
00792                 m_nodes_to_laser_scans2D_last_size =
00793                         this->m_nodes_to_laser_scans2D.size();
00794 
00795                 return true;
00796         }
00797         else {
00798                 return false;
00799         }
00800 
00801 
00802         MRPT_END;
00803 } // end of pubLastRegdIDScan
00804 
00805 
00806 template<class GRAPH_T>
00807 bool CGraphSlamEngine_MR<GRAPH_T>::isOwnNodeID(
00808                 const mrpt::utils::TNodeID nodeID,
00809                 const global_pose_t* pose_out/*=NULL*/) const {
00810         MRPT_START;
00811         using namespace mrpt::graphs::detail;
00812 
00813         // make sure give node is in the graph
00814         typename GRAPH_T::global_poses_t::const_iterator global_pose_search =
00815                 this->m_graph.nodes.find(nodeID);
00816         ASSERTMSG_(global_pose_search != this->m_graph.nodes.end(),
00817                         mrpt::format(
00818                                 "isOwnNodeID called for nodeID \"%lu\" which is not found in the graph",
00819                                 static_cast<unsigned long>(nodeID)));
00820 
00821         // fill pointer to global_pose_t
00822         if (pose_out) {
00823                 pose_out = &global_pose_search->second;
00824         }
00825 
00826         bool res = false;
00827         const TMRSlamNodeAnnotations* node_annots = dynamic_cast<const TMRSlamNodeAnnotations*>(
00828                         &global_pose_search->second);
00829         if ((node_annots && node_annots->agent_ID_str == m_conn_manager.getTrimmedNs()) ||
00830                         (!node_annots)) {
00831                 res = true;
00832         }
00833 
00834         return res;
00835 
00836         MRPT_END;
00837 } // end of isOwnNodeID
00838 
00839 template<class GRAPH_T>
00840 void CGraphSlamEngine_MR<GRAPH_T>::readParams() {
00841         using namespace mrpt::utils;
00842         using namespace mrpt::slam;
00843 
00844         this->readROSParameters();
00845 
00846         // GridMap Alignment
00847         m_alignment_options.loadFromConfigFileName(this->m_config_fname, m_sec_alignment_params);
00848 
00849         // Thu Jun 8 17:02:17 EEST 2017, Nikos Koukis
00850         // other option ends up in segfault.
00851         m_alignment_options.methodSelection = CGridMapAligner::amModifiedRANSAC;
00852 
00853         m_opts.loadFromConfigFileName(this->m_config_fname, m_sec_mr_slam_params);
00854 } // end of readParams
00855 
00856 template<class GRAPH_T>
00857 void CGraphSlamEngine_MR<GRAPH_T>::readROSParameters() {
00858         // call parent method first in case the parent wants to ask for any ROS
00859         // parameters
00860         parent_t::readROSParameters();
00861 
00862 }
00863 
00864 template<class GRAPH_T>
00865 void CGraphSlamEngine_MR<GRAPH_T>::printParams() const {
00866         parent_t::printParams();
00867         m_alignment_options.dumpToConsole();
00868         m_opts.dumpToConsole();
00869 }
00870 
00871 
00872 
00873 template<class GRAPH_T>
00874 void CGraphSlamEngine_MR<GRAPH_T>::setupSubs() { }
00875 
00876 template<class GRAPH_T>
00877 void CGraphSlamEngine_MR<GRAPH_T>::setupPubs() {
00878         using namespace mrpt_msgs;
00879         using namespace sensor_msgs;
00880 
00881         m_list_neighbors_pub = m_nh->advertise<GraphSlamAgents>(
00882                         m_list_neighbors_topic,
00883                         this->m_queue_size,
00884                         /*latch = */ true);
00885 
00886         // last registered laser scan - by default this corresponds to the last
00887         // nodeID of the vector of last registered nodes.
00888         m_last_regd_id_scan_pub = m_nh->advertise<NodeIDWithLaserScan>(
00889                         m_last_regd_id_scan_topic,
00890                         this->m_queue_size,
00891                         /*latch = */ true);
00892 
00893         // last X nodeIDs + positions
00894         m_last_regd_nodes_pub = m_nh->advertise<NodeIDWithPose_vec>(
00895                         m_last_regd_nodes_topic,
00896                         this->m_queue_size,
00897                         /*latch = */ true);
00898 
00899 
00900 
00901 }
00902 
00903 template<class GRAPH_T>
00904 void CGraphSlamEngine_MR<GRAPH_T>::setupSrvs() {
00905         // cm_graph service requests are handled by the custom custom_service_queue CallbackQueue
00906         ros::CallbackQueueInterface* global_queue = m_nh->getCallbackQueue();
00907         m_nh->setCallbackQueue(&this->custom_service_queue);
00908 
00909         m_cm_graph_srvserver = m_nh->advertiseService(
00910                         m_cm_graph_service,
00911                         &CGraphSlamEngine_MR<GRAPH_T>::getCMGraph, this);
00912 
00913         m_nh->setCallbackQueue(global_queue);
00914 }
00915 
00916 template<class GRAPH_T>
00917 bool CGraphSlamEngine_MR<GRAPH_T>::getCMGraph(
00918                 mrpt_msgs::GetCMGraph::Request& req,
00919                 mrpt_msgs::GetCMGraph::Response& res) {
00920         using namespace std;
00921         using namespace mrpt::utils;
00922         using namespace mrpt::math;
00923 
00924         const size_t min_nodeIDs = 2;
00925 
00926         set<TNodeID> nodes_set(req.nodeIDs.begin(), req.nodeIDs.end());
00927         MRPT_LOG_INFO_STREAM("Called the GetCMGraph service for nodeIDs: "
00928                 << getSTLContainerAsString(nodes_set));
00929 
00930         bool ret_val = false;
00931         if (nodes_set.size() < 2) { }
00932         else {
00933                 // fill the given Response with the ROS NetworkOfPoses
00934                 GRAPH_T mrpt_subgraph;
00935                 this->m_graph.extractSubGraph(nodes_set, &mrpt_subgraph,
00936                                 /*root_node = */ INVALID_NODEID,
00937                                 /*auto_expand_set=*/false);
00938                 mrpt_bridge::convert(mrpt_subgraph, res.cm_graph);
00939                 ret_val = true;
00940         }
00941 
00942         return ret_val;
00943 } // end of getCMGraph
00944 
00945 template<class GRAPH_T>
00946 void CGraphSlamEngine_MR<GRAPH_T>::setObjectPropsFromNodeID(
00947                 const mrpt::utils::TNodeID  nodeID,
00948                 mrpt::opengl::CSetOfObjectsPtr& viz_object) {
00949         using namespace mrpt::utils;
00950         MRPT_START;
00951 
00952         // who registered this node?
00953         TNeighborAgentProps* neighbor = NULL;
00954         std::string& agent_ID_str = this->m_graph.nodes.at(nodeID).agent_ID_str;
00955         bool is_not_own = getNeighborByAgentID(agent_ID_str, neighbor);
00956 
00957         TColor obj_color;
00958         if (!is_not_own) { // I registered this.
00959                 // use the standard maps color
00960                 obj_color = this->m_optimized_map_color;
00961         }
00962         else {
00963                 ASSERT_(neighbor);
00964                 obj_color = neighbor->color;
00965         }
00966         viz_object->setColor_u8(obj_color);
00967 
00968         MRPT_END;
00969 }// end of setObjectPropsFromNodeID
00970 
00971 
00972 template<class GRAPH_T>
00973 void CGraphSlamEngine_MR<GRAPH_T>::monitorNodeRegistration(
00974                 bool registered/*=false*/,
00975                 std::string class_name/*="Class"*/) {
00976         MRPT_START;
00977         using namespace mrpt::utils;
00978 
00979         if (m_registered_multiple_nodes) {
00980                 MRPT_LOG_ERROR_STREAM("m_registered_multiple_nodes = TRUE!");
00981                 m_registered_multiple_nodes = !m_registered_multiple_nodes;
00982                 this->m_nodeID_max = this->m_graph.nodeCount()-1;
00983         }
00984         else {
00985                 parent_t::monitorNodeRegistration(registered, class_name);
00986         }
00987 
00988         MRPT_END;
00989 } // end of monitorNodeRegistration
00990 
00991 template<class GRAPH_T>
00992 void CGraphSlamEngine_MR<GRAPH_T>::getRobotEstimatedTrajectory(
00993                 typename GRAPH_T::global_poses_t* graph_poses) const {
00994         MRPT_START;
00995         ASSERT_(graph_poses);
00996 
00997         for (const auto& n : this->m_graph.nodes) {
00998                 if (n.second.agent_ID_str == m_conn_manager.getTrimmedNs()) {
00999                         graph_poses->insert(n);
01000                 }
01001         }
01002 
01003         MRPT_END;
01004 } // end of getRobotEstimatedTrajectory
01005 
01006 template<class GRAPH_T>
01007 void CGraphSlamEngine_MR<GRAPH_T>::
01008 getAllOwnNodes(std::set<mrpt::utils::TNodeID>* nodes_set) const {
01009         ASSERT_(nodes_set);
01010         nodes_set->clear();
01011 
01012         for (const auto& n : this->m_graph.nodes) {
01013                 if (n.second.agent_ID_str == m_conn_manager.getTrimmedNs()) {
01014                         nodes_set->insert(n.first);
01015                 }
01016         }
01017 } // end of getAllOwnNodes
01018 
01019 template<class GRAPH_T>
01020 void CGraphSlamEngine_MR<GRAPH_T>::
01021 getNodeIDsOfEstimatedTrajectory(
01022                 std::set<mrpt::utils::TNodeID>* nodes_set) const { 
01023         ASSERT_(nodes_set);
01024         this->getAllOwnNodes(nodes_set);
01025 } // end of getNodeIDsOfEstimatedTrajectory
01026 
01028 
01029 template<class GRAPH_T>
01030 CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::TNeighborAgentProps(
01031                 CGraphSlamEngine_MR<GRAPH_T>& engine_in,
01032                 const mrpt_msgs::GraphSlamAgent& agent_in):
01033         engine(engine_in),
01034         agent(agent_in),
01035         has_setup_comm(false)
01036 {
01037     using namespace mrpt::utils;
01038 
01039         nh = engine.m_nh;
01040         m_queue_size = engine.m_queue_size;
01041         this->resetFlags();
01042 
01043         // fill the full paths of the topics to subscribe
01044         // ASSUMPTION: agents namespaces start at the root "/"
01045         this->last_regd_nodes_topic = "/" + agent.topic_namespace.data + "/" +
01046                 engine.m_last_regd_nodes_topic;
01047         this->last_regd_id_scan_topic = "/" + agent.topic_namespace.data + "/" +
01048                 engine.m_last_regd_id_scan_topic;
01049         this->cm_graph_service = "/" + agent.topic_namespace.data + "/" +
01050                 engine.m_cm_graph_service;
01051 
01052   engine.logFmt(LVL_DEBUG,
01053       "In constructor of TNeighborAgentProps for topic namespace: %s",
01054       agent.topic_namespace.data.c_str());
01055 
01056         // initialize the occupancy map based on the engine's gridmap properties
01057   gridmap_cached = mrpt::maps::COccupancyGridMap2D::Create();
01058         COccupancyGridMap2DPtr eng_gridmap = engine.m_gridmap_cached;
01059         gridmap_cached->setSize(
01060                         eng_gridmap->getXMin(),
01061                         eng_gridmap->getXMax(),
01062                         eng_gridmap->getYMin(),
01063                         eng_gridmap->getYMax(),
01064                         eng_gridmap->getResolution());
01065 
01066 } // TNeighborAgentProps::TNeighborAgentProps
01067 
01068 template<class GRAPH_T>
01069 CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::~TNeighborAgentProps() { }
01070 
01071 template<class GRAPH_T>
01072 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::setupComm() {
01073         using namespace mrpt::utils;
01074 
01075         this->setupSubs();
01076         this->setupSrvs();
01077 
01078         engine.logFmt(
01079                         LVL_DEBUG,
01080                         "TNeighborAgentProps: Successfully set up subscribers/services "
01081                         "to agent topics for namespace [%s].",
01082                         agent.topic_namespace.data.c_str());
01083 
01084         has_setup_comm = true;
01085 }
01086 
01087 template<class GRAPH_T>
01088 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::setupSrvs() {
01089 
01090         cm_graph_srvclient =
01091                 nh->serviceClient<mrpt_msgs::GetCMGraph>(cm_graph_service);
01092 }
01093 
01094 
01095 template<class GRAPH_T>
01096 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::setupSubs() {
01097         using namespace mrpt_msgs;
01098         using namespace mrpt::utils;
01099 
01100         last_regd_nodes_sub = nh->subscribe<NodeIDWithPose_vec>(
01101                         last_regd_nodes_topic,
01102                         m_queue_size,
01103                         &TNeighborAgentProps::fetchUpdatedNodesList, this);
01104         last_regd_id_scan_sub = nh->subscribe<NodeIDWithLaserScan>(
01105                         last_regd_id_scan_topic,
01106                         m_queue_size,
01107                         &TNeighborAgentProps::fetchLastRegdIDScan, this);
01108 }
01109 
01110 template<class GRAPH_T>
01111 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01112 fetchUpdatedNodesList(
01113                 const mrpt_msgs::NodeIDWithPose_vec::ConstPtr& nodes) {
01114         MRPT_START;
01115         using namespace mrpt_msgs;
01116         using namespace mrpt_bridge;
01117         using namespace std;
01118         using namespace mrpt::utils;
01119 
01120         typedef typename GRAPH_T::constraint_t::type_value pose_t;
01121     engine.logFmt(LVL_DEBUG, "In fetchUpdatedNodesList method.");
01122 
01123         for (NodeIDWithPose_vec::_vec_type::const_iterator
01124                         n_it = nodes->vec.begin();
01125                         n_it != nodes->vec.end();
01126                         ++n_it) {
01127 
01128                 // insert in the set if not already there.
01129                 TNodeID  nodeID = static_cast<TNodeID>(n_it->nodeID);
01130                 std::pair<set<TNodeID>::iterator, bool> res =
01131                         nodeIDs_set.insert(nodeID);
01132                 // if I just inserted this node mark it as not used (in own graph)
01133                 if (res.second) { // insertion took place.
01134                         engine.logFmt(LVL_INFO, "Just fetched a new nodeID: %lu",
01135                                         static_cast<unsigned long>(nodeID));
01136                         nodeID_to_is_integrated.insert(make_pair(n_it->nodeID, false));
01137                 }
01138 
01139                 // update the poses
01140                 pose_t curr_pose;
01141                 // note: use "operator[]" instead of "insert" so that if the key already
01142                 // exists, the corresponding value is changed rather than ignored.
01143                 poses[static_cast<TNodeID>(n_it->nodeID)] =
01144                         convert(n_it->pose, curr_pose);
01145         }
01146   has_new_nodes = true;
01147 
01149         // TODO When using 3 graphSLAM agents GDB Shows that it crashes on
01150         // engine.logFmt lines. Fix this.
01151         //
01152   //engine.logFmt(LVL_DEBUG, // THIS CRASHES - GDB WHERE
01153       //"NodeIDs for topic namespace: %s -> [%s]",
01154       //agent.topic_namespace.data.c_str(),
01155       //mrpt::math::getSTLContainerAsString(vector<TNodeID>(
01156           //nodeIDs_set.begin(), nodeIDs_set.end())).c_str());
01157   // print poses just for verification
01158   //engine.logFmt(LVL_DEBUG, "Poses for topic namespace: %s",
01159       //agent.topic_namespace.data.c_str());
01160   //for (typename GRAPH_T::global_poses_t::const_iterator
01161       //p_it = poses.begin();
01162       //p_it != poses.end();
01163       //++p_it) {
01164     //std::string p_str; p_it->second.asString(p_str);
01165     //engine.logFmt(LVL_DEBUG, "nodeID: %lu | pose: %s",
01166         //static_cast<unsigned long>(p_it->first),
01167         //p_str.c_str());
01168   //}
01169         // TODO - These also seem to crash sometimes
01170         //cout << "Agent information: " << agent << endl;
01171         //cout << "Nodes: " << mrpt::math::getSTLContainerAsString(vector<TNodeID>(nodeIDs_set.begin(), nodeIDs_set.end()));
01172   //print nodeIDs just for verification
01173 
01174   MRPT_END;
01175 } // end of fetchUpdatedNodesList
01176 
01177 template<class GRAPH_T>
01178 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01179 fetchLastRegdIDScan(
01180                 const mrpt_msgs::NodeIDWithLaserScan::ConstPtr& last_regd_id_scan) {
01181         MRPT_START;
01182         using namespace std;
01183         using namespace mrpt::utils;
01184         ASSERT_(last_regd_id_scan);
01185   engine.logFmt(LVL_DEBUG, "In fetchLastRegdIDScan method.");
01186 
01187         // make sure I haven't received any LaserScan for the current nodeID
01188         // TODO
01189         TNodeID curr_node = static_cast<TNodeID>(last_regd_id_scan->nodeID);
01190 
01191         // Pose may not be available due to timing in publishing of the corresponding
01192         // topics. Just keep it in ROS form and then convert them to MRPT form when
01193         // needed.
01194         ros_scans.push_back(*last_regd_id_scan);
01195         has_new_scans = true;
01196 
01197         MRPT_END;
01198 } // end of fetchLastRegdIDScan
01199 
01200 template<class GRAPH_T>
01201 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::getCachedNodes(
01202                 vector_uint* nodeIDs/*=NULL*/,
01203                 std::map<
01204                         mrpt::utils::TNodeID,
01205                         node_props_t>* nodes_params/*=NULL*/,
01206                 bool only_unused/*=true*/) const {
01207         MRPT_START;
01208         using namespace mrpt::obs;
01209         using namespace mrpt::utils;
01210         using namespace mrpt::math;
01211         using namespace std;
01212         using namespace mrpt::poses;
01213 
01214         // at least one of the two args should be given.
01215         ASSERT_(nodeIDs || nodes_params);
01216 
01217         // traverse all nodes
01218         for (std::set<TNodeID>::const_iterator
01219                         n_it = nodeIDs_set.begin();
01220                         n_it != nodeIDs_set.end();
01221                         ++n_it) {
01222 
01223                 // Should I return only the unused ones?
01224                 // If so, if the current nodeID is integrated, skip it.
01225                 if (only_unused && nodeID_to_is_integrated.at(*n_it)) { continue; }
01226 
01227                 // add the node properties
01228                 if (nodes_params) {
01229                         std::pair<TNodeID, node_props_t> params; // current pair to be inserted.
01230                         const pose_t* p = &poses.at(*n_it);
01231 
01232                         params.first = *n_it;
01233                         params.second.pose = *p;
01234                         CObservation2DRangeScanPtr mrpt_scan = CObservation2DRangeScan::Create();
01235       const sensor_msgs::LaserScan* ros_laser_scan =
01236         this->getLaserScanByNodeID(*n_it);
01237 
01238       // if LaserScan not found, skip nodeID altogether.
01239       //
01240       // Its natural to have more poses than LaserScans since on every node
01241       // registration I send a modified list of X node positions and just one
01242       // LaserScan
01243       if (!ros_laser_scan) { continue; }
01244 
01245                         mrpt_bridge::convert(*ros_laser_scan, CPose3D(*p), *mrpt_scan);
01246                         params.second.scan = mrpt_scan;
01247 
01248                         // insert the pair
01249                         nodes_params->insert(params);
01250 
01251                         // debugging message
01252                         //std::stringstream ss;
01253                         //ss << "\ntID: " << nodes_params->rbegin()->first
01254                                 //<< " ==> Props: " << nodes_params->rbegin()->second;
01255                         //engine.logFmt(LVL_DEBUG, "%s", ss.str().c_str());
01256                 }
01257 
01258                 // add the nodeID
01259                 if (nodeIDs) {
01260                         // do not return nodeIDs that don't have valid laserScans
01261                         // this is also checked at the prior if
01262                         if (!nodes_params && !this->getLaserScanByNodeID(*n_it)) {
01263                                 continue;
01264                         }
01265 
01266                         nodeIDs->push_back(*n_it);
01267                 }
01268         }
01269 
01270         MRPT_END;
01271 } // end of TNeighborAgentProps::getCachedNodes
01272 
01273 template<class GRAPH_T>
01274 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::resetFlags() const {
01275   has_new_nodes = false;
01276   has_new_scans = false;
01277 
01278 }
01279 
01280 template<class GRAPH_T>
01281 bool CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01282 hasNewNodesBatch(int new_batch_size) {
01283         MRPT_START;
01284 
01285         auto is_not_integrated = [this](const std::pair<mrpt::utils::TNodeID, bool> pair) {
01286                 return (pair.second == false && getLaserScanByNodeID(pair.first));
01287         };
01288         int not_integrated_num = count_if(
01289                         nodeID_to_is_integrated.begin(),
01290                         nodeID_to_is_integrated.end(),
01291                         is_not_integrated);
01292 
01293         return (not_integrated_num >= new_batch_size);
01294 
01295         MRPT_END;
01296 }
01297 
01298 
01299 template<class GRAPH_T>
01300 const sensor_msgs::LaserScan*
01301 CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01302 getLaserScanByNodeID(
01303                 const mrpt::utils::TNodeID nodeID) const {
01304         MRPT_START;
01305 
01306         // assert that the current nodeID exists in the nodeIDs_set
01307         ASSERT_(nodeIDs_set.find(nodeID) != nodeIDs_set.end());
01308 
01309         for (std::vector<mrpt_msgs::NodeIDWithLaserScan>::const_iterator
01310                         it = ros_scans.begin();
01311                         it != ros_scans.end();
01312                         ++it) {
01313                 if (it->nodeID == nodeID) {
01314                         return &it->scan;
01315                 }
01316         }
01317 
01318         // if out here, LaserScan doesn't exist.
01319   return 0;
01320   MRPT_END;
01321 } // end of TNeighborAgentProps::getLaserScanByNodeID
01322 
01323 template<class GRAPH_T>
01324 void
01325 CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::fillOptPaths(
01326                 const std::set<mrpt::utils::TNodeID>& nodeIDs,
01327                 paths_t* opt_paths) const {
01328         MRPT_START;
01329         using namespace std;
01330         using namespace mrpt::utils;
01331         typedef std::set<TNodeID>::const_iterator set_cit;
01332 
01333         // make sure that all given nodes belong in the nodeIDs_set.
01334         ASSERTMSG_(includes(nodeIDs_set.begin(), nodeIDs_set.end(),
01335                                 nodeIDs.begin(), nodeIDs.end()),
01336                         "nodeIDs is not a strict subset of the current neighbor's nodes");
01337         ASSERT_(opt_paths);
01338 
01339         for (set_cit cit = nodeIDs.begin();
01340                         cit != std::prev(nodeIDs.end());
01341                         ++cit) {
01342 
01343                 for (set_cit cit2 = std::next(cit);
01344                                 cit2 != nodeIDs.end();
01345                                 ++cit2) {
01346 
01347 
01348                         constraint_t c = constraint_t(poses.at(*cit2) - poses.at(*cit));
01349                         c.cov_inv =
01350                                 mrpt::math::CMatrixFixedNumeric<double,
01351                                         constraint_t::state_length,
01352                                         constraint_t::state_length>();
01353                         c.cov_inv.unit();
01354                         c.cov_inv *= 500;
01355 
01356                         opt_paths->push_back(path_t(
01357                                                 /*start=*/ *cit,
01358                                                 /*end=*/ *cit2,
01359                                                 /*constraint=*/ c));
01360 
01361                         engine.logFmt(LVL_DEBUG,
01362                                         "Filling optimal path for nodes: %lu => %lu: %s",
01363                                         static_cast<unsigned long>(*cit),
01364                                         static_cast<unsigned long>(*cit2),
01365                                         opt_paths->back().curr_pose_pdf.getMeanVal().asString().c_str());
01366 
01367                 }
01368         }
01369         MRPT_END;
01370 } // end of TNeighborAgentProps::fillOptPaths
01371 
01372 template<class GRAPH_T>
01373 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01374 computeGridMap() const {
01375         MRPT_START;
01376         using namespace mrpt::poses;
01377         using namespace mrpt::utils;
01378         using namespace mrpt;
01379         using namespace mrpt::math;
01380         using namespace std;
01381 
01382         gridmap_cached->clear();
01383 
01384         vector_uint nodeIDs;
01385         std::map<TNodeID, node_props_t> nodes_params;
01386         // get list of nodes, laser scans
01387         this->getCachedNodes(&nodeIDs, &nodes_params, false);
01388 
01389         // iterate over poses, scans. Add them to the gridmap.
01390         for (typename map<TNodeID, node_props_t>::const_iterator
01391                         it = nodes_params.begin();
01392                         it != nodes_params.end();
01393                         ++it) {
01394                 const CPose3D curr_pose_3d; // do not add the actual pose!
01395                 gridmap_cached->insertObservation(it->second.scan.pointer(), &curr_pose_3d);
01396         }
01397 
01398         MRPT_END;
01399 } // end of TNeighborAgentProps::computeGridMap
01400 
01401 template<class GRAPH_T>
01402 const mrpt::maps::COccupancyGridMap2DPtr&
01403 CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01404 getGridMap() const { 
01405         MRPT_START;
01406         if (hasNewData()) {
01407                 this->computeGridMap();
01408         }
01409 
01410         return gridmap_cached;
01411         MRPT_END;
01412 } // end of TNeighborAgentProps::getGridMap
01413 
01414 template<class GRAPH_T>
01415 void CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::
01416 getGridMap(mrpt::maps::COccupancyGridMap2DPtr& map) const {
01417         MRPT_START;
01418         ASSERT_(map.present());
01419 
01420         if (hasNewData()) {
01421                 this->computeGridMap();
01422         }
01423 
01424         map->copyMapContentFrom(*gridmap_cached);
01425         MRPT_END;
01426 } // end of TNeighborAgentProps::getGridMap
01427 
01428 
01429 template<class GRAPH_T>
01430 bool CGraphSlamEngine_MR<GRAPH_T>::TNeighborAgentProps::hasNewData() const {
01431   return has_new_nodes && has_new_scans;
01432 } // end of hasNewData
01433 
01434 template<class GRAPH_T>
01435 CGraphSlamEngine_MR<GRAPH_T>::TOptions::TOptions(const engine_mr_t& engine_in):
01436         nodes_integration_batch_size(4),
01437         num_last_regd_nodes(10),
01438         conservative_find_initial_tfs_to_neighbors(false),
01439         inter_group_node_count_thresh_minadv(25),
01440         inter_group_node_count_thresh(40),
01441         engine(engine_in)
01442 {
01443 } // end of TOptions::TOptions
01444 
01445 template<class GRAPH_T>
01446 CGraphSlamEngine_MR<GRAPH_T>::TOptions::~TOptions() {
01447 } // end of TOptions::~TOptions
01448 
01449 template<class GRAPH_T>
01450 void CGraphSlamEngine_MR<GRAPH_T>::TOptions::loadFromConfigFile(
01451                 const mrpt::utils::CConfigFileBase& source,
01452                 const std::string& section) {
01453 
01454         MRPT_LOAD_CONFIG_VAR(nodes_integration_batch_size, int, source, section);
01455         MRPT_LOAD_CONFIG_VAR(num_last_regd_nodes, int, source, section);
01456 
01457         MRPT_LOAD_CONFIG_VAR(conservative_find_initial_tfs_to_neighbors, bool, source, section);
01458         ASSERTMSG_(!conservative_find_initial_tfs_to_neighbors,
01459                         "Conservative behavior is not yet implemented.");
01460 
01461 
01462         MRPT_LOAD_CONFIG_VAR(inter_group_node_count_thresh, int, source, section);
01463         // warn user if they choose smaller threshold.
01464         if (inter_group_node_count_thresh < inter_group_node_count_thresh_minadv) {
01465                 engine.logFmt(mrpt::utils::LVL_ERROR,
01466                                 "inter_group_node_count_thresh [%d]"
01467                                 "is set lower than the advised minimum [%d]",
01468                                 inter_group_node_count_thresh,
01469                                 inter_group_node_count_thresh_minadv);
01470 
01471                 mrpt::system::sleep(2000);
01472         }
01473 
01474 
01475 } // end of TOptions::loadFromConfigFile
01476 
01477 template<class GRAPH_T>
01478 void CGraphSlamEngine_MR<GRAPH_T>::TOptions::dumpToTextStream(
01479                 mrpt::utils::CStream& out) const {
01480 
01481         LOADABLEOPTS_DUMP_VAR(nodes_integration_batch_size, int);
01482         LOADABLEOPTS_DUMP_VAR(num_last_regd_nodes, int);
01483         LOADABLEOPTS_DUMP_VAR(conservative_find_initial_tfs_to_neighbors, bool);
01484         LOADABLEOPTS_DUMP_VAR(inter_group_node_count_thresh, int)
01485         LOADABLEOPTS_DUMP_VAR(inter_group_node_count_thresh_minadv, int)
01486 
01487 } // end of TOptions::dumpToTextStream
01488 
01489 
01490 
01491 } } // end of namespaces
01492 
01493 #endif /* end of include guard: CGRAPHSLAMENGINE_MR_IMPL_H */


mrpt_graphslam_2d
Author(s): Nikos Koukis
autogenerated on Sun Sep 17 2017 03:02:04