loop_scan_matcher.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  */
00030 
00031 #include <graph_slam/loop_scan_matcher.h>
00032 #include <pose_graph/geometry.h>
00033 #include <pose_graph/utils.h>
00034 #include <pose_graph/transforms.h>
00035 #include <boost/foreach.hpp>
00036 #include <ros/ros.h>
00037 
00038 namespace graph_slam
00039 {
00040 
00041 namespace gm=geometry_msgs;
00042 namespace ksm=karto_scan_matcher;
00043 using namespace pose_graph;
00044 
00045 using std::vector;
00046 
00047 LoopScanMatcher::LoopScanMatcher (const gm::Pose2D& laser_offset, const double max_link_length,
00048                                   const unsigned min_chain_length, const double min_response,
00049                                   const bool use_covariances) :
00050   ScanManager(laser_offset), max_link_length_(max_link_length),
00051   min_chain_length_(min_chain_length), min_response_(min_response),
00052   use_covariances_(use_covariances)
00053 {
00054   ROS_DEBUG_STREAM_NAMED ("init", "Initializing loop scan matcher with max link length " <<
00055                           max_link_length_ << ", min chain length " << min_chain_length_ <<
00056                           ", min response " << min_response_);
00057 }
00058 
00059 NodeConstraintVector LoopScanMatcher::getConstraints (const PoseGraph& graph, const NodeId ref_node,
00060                                                       const Pose& init_pose_estimate, const LaserPtr scan) const
00061 {
00062 
00063   // Initialize the matcher based on scan parameters if necessary
00064   if (!matcher_) {
00065     ksm::DoubleVector resolutions, sizes;
00066     
00067     sizes.push_back(5.0);
00068     resolutions.push_back(0.05);
00069 
00070     sizes.push_back(0.3);
00071     resolutions.push_back(0.01);
00072     
00073     matcher_.reset(new ksm::KartoScanMatcher(*scan, laser_offset_, sizes, resolutions));
00074     matcher_->setPenalizeDistance(false); 
00075   }
00076     
00077   const gm::Point b = computeBarycenterInBaseFrame(scan);
00078   ChainVec candidates = possibleLoopClosures(graph, ref_node, pointInReferenceFrame(b, init_pose_estimate), scan);
00079 
00080   NodeConstraintVector constraints;
00081   BOOST_FOREACH (const Chain& chain, candidates) {
00082     NodeSet nodes(chain.begin(), chain.end());
00083     ksm::ScanMatchResult result = scanMatchNodes(matcher_, init_pose_estimate, scan, nodes);
00084     ROS_DEBUG_STREAM_NAMED ("loop_closure", "Loop closure response against chain " <<
00085                             toString(chain) << " was " << result.response);
00086     if (result.response >= min_response_) {
00087       Eigen3::Matrix3f prec2d = result.cov.inverse();
00088       const PrecisionMatrix prec = getPrecisionMatrix(result, use_covariances_);
00089       const gm::Point opt_barycenter = pointInReferenceFrame(b, convertToPose(result.pose));
00090       constraints.push_back(scanChainConstraint(opt_barycenter, result.pose, prec, chain));
00091       ROS_DEBUG_STREAM_NAMED ("loop_closure", "Adding loop constraint with pose " <<
00092                               toString(result.pose) << " and precision " << prec);
00093     }
00094   }
00095 
00096   return constraints;
00097 }
00098 
00099 // Either n is further than distance from pose, or it doesn't have an optimized pose
00100 bool LoopScanMatcher::furtherThan (const double max_distance, const Point& p, const NodeId n) const
00101 {
00102   boost::optional<gm::Point> p2 = nodeBarycenter(n);
00103   return (!p2 || euclideanDistance(p, *p2) > max_distance);
00104 }
00105 
00106 ChainVec LoopScanMatcher::possibleLoopClosures (const PoseGraph& graph, const NodeId ref_node,
00107                                                 const gm::Point& bary, const LaserPtr scan) const
00108 {
00109   ChainVec chains;
00110 
00111   // We mark all nearby linked nodes as processed, so we'll never consider chains that include them
00112   NodeSet processed = nearbyNodes(ref_node, bary, graph, max_link_length_);
00113 
00114   // Identify the set of nodes whose barycenter (based on current optimized pose) is within a radius of
00115   // the current scan's barycenter
00116   const NodeSet all_nodes = graph.allNodes();
00117   NodeSet candidate_nodes;
00118   remove_copy_if(all_nodes.begin(), all_nodes.end(), inserter(candidate_nodes, candidate_nodes.begin()),
00119                  bind(&LoopScanMatcher::furtherThan, this, max_link_length_, bary, _1));
00120 
00121   ROS_DEBUG_STREAM_NAMED ("loop_closure", "Looking for possible loop closures.  Barycenter is " << 
00122                           toString(bary) << " and nearby linked nodes are " << toString(processed) <<
00123                           " and candidate nodes are " << toString(candidate_nodes));
00124 
00125   BOOST_FOREACH (const NodeId seed, candidate_nodes) {
00126     if (!contains(processed, seed)) {
00127       const Chain candidate = getChain(seed, candidate_nodes, processed);
00128       if (candidate.size() >= min_chain_length_) {
00129         addChain(candidate, &chains, &processed);
00130       }
00131     }
00132   } 
00133 
00134   return chains;
00135 }
00136 
00137 
00138 
00139 } // namespace graph_slam


graph_slam
Author(s): Bhaskara Marthi
autogenerated on Tue Jan 7 2014 11:17:21