/*--------------------------------------------------------------- perform_TLC Topological Loop Closure: Performs all the required operations to close a loop between two areas which have been determined to be the same. ---------------------------------------------------------------*/ void CHMTSLAM::perform_TLC( CLocalMetricHypothesis &LMH, const CHMHMapNode::TNodeID Ai, // areaInLMH, const CHMHMapNode::TNodeID Ae, // areaLoopClosure, const mrpt::poses::CPose3DPDFGaussian &pose_i_wrt_e ) { MRPT_START ASSERT_(Ai!=Ae) synch::CCriticalSectionLocker locker ( &LMH.m_robotPosesGraph.lock ); printf_debug("[perform_TLC] TLC of areas: %u <-> %u \n",(unsigned)Ai, (unsigned)Ae ); // * Verify a1 \in LMH & a2 \notin LMH // ---------------------------------------------------------------------- ASSERT_( LMH.m_neighbors.count(Ai) == 1); ASSERT_( LMH.m_neighbors.count(Ae) == 0); // * Get the old pose reference of the area which will desapear: // ---------------------------------------------------------------------- TPoseID poseID_Ai_origin; m_map.getNodeByID(Ai)->m_annotations.getElemental( NODE_ANNOTATION_REF_POSEID,poseID_Ai_origin, LMH.m_ID, true); // TPoseID poseID_new_origin; // m_map.getNodeByID(Ae)->m_annotations.getElemental( NODE_ANNOTATION_REF_POSEID,poseID_new_origin, LMH.m_ID, true); // * Make a list Li of pose IDs in Ai, which need a change in coordinates: // ---------------------------------------------------------------------------------------------- //TPoseIDSet Li; //for (map<TPoseID,CHMHMapNode::TNodeID>::const_iterator it=LMH.m_nodeIDmemberships.begin();it!=LMH.m_nodeIDmemberships.end();++it) // if(it->second==Ai) // Li.insert(it->first); // * Change all poses in "Ai" from "p" to " 0 (-) pose1wrt2 (+) (p (-) oldRef )" // ---------------------------------------------------------------------------------------------- // For all the particles //for ( CLocalMetricHypothesis::CParticleList::const_iterator it = LMH.m_particles.begin(); it!=LMH.m_particles.end(); ++it) //{ // // Touch only the affected poseIDs: // for (TPoseIDSet::const_iterator n=Li.begin();n!=Li.end();++n) // { // map<TPoseID,CPose3D>::iterator itPos = it->d->robotPoses.find(*n); // ASSERT_(itPos!=it->d->robotPoses.end()); // itPos->second = Apose_ei + (itPos->second - oldRef); // } //} // Change coords in incr. partitioning as well: //CSimpleMap *SFseq = LMH.m_robotPosesGraph.partitioner.getSequenceOfFrames(); //for (std::map<uint32_t,TPoseID>::const_iterator it=LMH.m_robotPosesGraph.idx2pose.begin();it!=LMH.m_robotPosesGraph.idx2pose.end();++it) //{ // // Only if the pose has been affected: // if (Li.count(it->second)==0) continue; // CPose3DPDFPtr pdf; // CSensoryFramePtr sf; // SFseq->get( it->first, pdf, sf); // // Copy from particles: // CPose3DPDFParticlesPtr pdfParts = CPose3DPDFParticlesPtr(pdf); // LMH.getPoseParticles( it->second, *pdfParts); //} // * Mark all poses in LMH \in Ai as being of "Ae": // ---------------------------------------------------------------------------------------------- for (map<TPoseID,CHMHMapNode::TNodeID>::iterator it=LMH.m_nodeIDmemberships.begin();it!=LMH.m_nodeIDmemberships.end();++it) if(it->second==Ai) it->second=Ae; // * Replace "Ai" by "Ae" in the list of neighbors areas: // ---------------------------------------------------------------------------------------------- LMH.m_neighbors.erase(LMH.m_neighbors.find(Ai)); LMH.m_neighbors.insert(Ae); // * Reflect the change of coordinates in all existing arcs from/to "Ai", which are not part of the LMH (list of neighbors) // "p" to " 0 (-) pose1wrt2 (+) (p (-) oldRef )"... // NOTE: Arcs to "Ai" must be replaced by arcs to "Ae" // ---------------------------------------------------------------------------------------------- { TArcList lstArcs; m_map.getNodeByID(Ai)->getArcs(lstArcs,LMH.m_ID); for(TArcList::iterator arc=lstArcs.begin();arc!=lstArcs.end();++arc) { // TODO ... } } // * The node for "area Ai" must be deleted in the HMAP, and all its arcs. // ---------------------------------------------------------------------------------------------- { TArcList lstArcs; m_map.getNodeByID(Ai)->getArcs(lstArcs); for(TArcList::iterator arc=lstArcs.begin();arc!=lstArcs.end();++arc) arc->clear(); // The "delete" will automatically remove the entry in "m_map". Other smrtpnts will be cleared too. m_map.getNodeByID(Ai).clear(); // The "delete" will automatically remove the entry in "m_map" } // * Merge Ae into the LMH: This includes the change of coordinates to those used now in "Ai" and the rest of neighbors! // ---------------------------------------------------------------------------------------------- CPose3DPDFParticles pdfAiRef; LMH.getPoseParticles(poseID_Ai_origin,pdfAiRef); CPose3D AiRef; pdfAiRef.getMean(AiRef); const CPose3D &Apose_ie = pose_i_wrt_e.mean; //const CPose3D Apose_ei = -Apose_ie; const CPose3D AeRefInLMH = AiRef + Apose_ie; CRobotPosesGraphPtr AePG = m_map.getNodeByID(Ae)->m_annotations.getAs<CRobotPosesGraph>(NODE_ANNOTATION_POSES_GRAPH, LMH.m_ID); // For each pose in Ae: for (CRobotPosesGraph::const_iterator it=AePG->begin();it!=AePG->end();++it) { const TPoseID poseId = it->first; const TPoseInfo &pi = it->second; // Insert the observations into the metric maps: ASSERT_(LMH.m_particles.size() == pi.pdf.size() ); for (size_t i=0;i<pi.pdf.size();i++) { // Transport coordinates: CPose3D &p = *pi.pdf.m_particles[i].d; LMH.m_particles[i].d->robotPoses[poseId] = AeRefInLMH + p; //pi.sf.insertObservationsInto( &LMH.m_particles[i].d->metricMaps, pi.pdf.m_particles[i].d ); } // Add node membership: LMH.m_nodeIDmemberships[poseId] = Ae; // Now, insert the SF LMH.m_SFs[poseId] = pi.sf; // Also add to the list of poses pending to be evaluated by the AA: LMH.m_posesPendingAddPartitioner.push_back(poseId); } // * The current pose of the robot should be in the new coordinate system: // ---------------------------------------------------------------------------------------------- // This is already done since the current pose is just another poseID and it's threaded like the others. // * Rebuild metric maps for consistency: // ---------------------------------------------------------------------------------------------- LMH.rebuildMetricMaps(); // * Update all the data in the node "Ae": // ---------------------------------------------------------------------------------------------- LMH.updateAreaFromLMH(Ae); MRPT_END }
/*--------------------------------------------------------------- updateAreaFromLMH // The corresponding node in the HMT map is updated with the // robot poses & SFs in the LMH. ---------------------------------------------------------------*/ void CLocalMetricHypothesis::updateAreaFromLMH( const CHMHMapNode::TNodeID areaID, bool eraseSFsFromLMH ) { // Build the list with the poses belonging to that area from LMH: // ---------------------------------------------------------------------- TNodeIDList lstPoseIDs; for (map<TPoseID,CHMHMapNode::TNodeID>::const_iterator it=m_nodeIDmemberships.begin();it!=m_nodeIDmemberships.end();++it) if ( it->second==areaID ) lstPoseIDs.insert(it->first); ASSERT_( !lstPoseIDs.empty() ); CHMHMapNodePtr node; { synch::CCriticalSectionLocker ( &m_parent->m_map_cs ); node = m_parent->m_map.getNodeByID( areaID ); ASSERT_(node); ASSERT_(node->m_hypotheses.has( m_ID )); } // end of HMT map cs // The pose to become the origin: TPoseID poseID_origin; node->m_annotations.getElemental( NODE_ANNOTATION_REF_POSEID,poseID_origin, m_ID, true); // 1) The set of robot poses and SFs // In annotation: NODE_ANNOTATION_POSES_GRAPH // --------------------------------------------------------------------- CRobotPosesGraphPtr posesGraph; { CSerializablePtr annot = node->m_annotations.get(NODE_ANNOTATION_POSES_GRAPH,m_ID); if (!annot) { // Add it now: posesGraph = CRobotPosesGraph::Create(); node->m_annotations.setMemoryReference(NODE_ANNOTATION_POSES_GRAPH, posesGraph, m_ID); } else { posesGraph = CRobotPosesGraphPtr(annot); posesGraph->clear(); } } // For each pose in the area: CPose3DPDFParticles pdfOrigin; bool pdfOrigin_ok=false; for (TNodeIDList::const_iterator it=lstPoseIDs.begin();it!=lstPoseIDs.end();++it) { TPoseInfo &poseInfo = (*posesGraph)[*it]; getPoseParticles( *it, poseInfo.pdf ); // Save pose particles // Save the PDF of the origin: if (*it==poseID_origin) { pdfOrigin.copyFrom( poseInfo.pdf ); pdfOrigin_ok = true; } if ( *it != m_currentRobotPose ) // The current robot pose has no SF { std::map<TPoseID,CSensoryFrame>::iterator itSF = m_SFs.find(*it); ASSERT_(itSF!=m_SFs.end()); if (eraseSFsFromLMH) { poseInfo.sf.moveFrom( itSF->second ); // This leaves m_SFs[*it] without observations, but it is being erased just now: m_SFs.erase( itSF ); } else { poseInfo.sf = itSF->second; // Copy observations } } } // Readjust to set the origin pose ID: ASSERT_(pdfOrigin_ok); CPose3DPDFParticles pdfOriginInv; pdfOrigin.inverse(pdfOriginInv); for (CRobotPosesGraph::iterator it=posesGraph->begin();it!=posesGraph->end();++it) { CPose3DPDFParticles::CParticleList::iterator orgIt,pdfIt; ASSERT_( it->second.pdf.size() == pdfOriginInv.size() ); for ( pdfIt=it->second.pdf.m_particles.begin(), orgIt= pdfOriginInv.m_particles.begin();orgIt!=pdfOriginInv.m_particles.end();orgIt++,pdfIt++) *pdfIt->d = *orgIt->d + *pdfIt->d; } // 2) One single metric map built from the most likelily robot poses // In annotation: NODE_ANNOTATION_METRIC_MAPS // --------------------------------------------------------------------- CMultiMetricMapPtr metricMap = node->m_annotations.getAs<CMultiMetricMap>(NODE_ANNOTATION_METRIC_MAPS,m_ID, false); metricMap->clear(); posesGraph->insertIntoMetricMap( *metricMap ); }