sequential_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/sequential_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 SequentialScanMatcher::SequentialScanMatcher (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), running_nodes_(50)
00053 {
00054   ROS_DEBUG_STREAM_NAMED ("init", "Initializing sequential scan matcher with max link length " <<
00055                           max_link_length_ << ", min chain length " << min_chain_length_ <<
00056                           ", min response " << min_response_);
00057 }
00058 
00059 bool alreadyHaveConstraintToTarget (const NodeConstraint& constraint, const NodeConstraintVector& constraints)
00060 {
00061   bool found = false;
00062   BOOST_FOREACH (const NodeConstraint& c, constraints) {
00063     if (c.target == constraint.target) {
00064       found = true;
00065       break;
00066     }
00067   }
00068   return found;
00069 }
00070 
00071 
00072 
00073 NodeConstraintVector SequentialScanMatcher::getConstraints (const PoseGraph& graph, const NodeId ref_node,
00074                                                             const Pose& initial_pose_estimate,
00075                                                             const LaserPtr scan) const
00076 {
00077   // Initialize the matcher based on the parameters of \a scan if necessary
00078   if (!matcher_)
00079     matcher_.reset(new ksm::KartoScanMatcher(*scan, laser_offset_, 0.3, 0.01));
00080 
00081   const gm::Point b = computeBarycenterInBaseFrame(scan);
00082   NodeConstraintVector constraints;
00083   
00084   if (running_nodes_.size() > 0) {
00085     ROS_ASSERT (*(--running_nodes_.end()) == ref_node);
00086 
00087     // Update the initial estimate based on scan matching
00088     NodeSet nodes;
00089     BOOST_FOREACH (const NodeId& n, running_nodes_)
00090       nodes.insert(n);
00091     const ksm::ScanMatchResult res = scanMatchNodes(matcher_, initial_pose_estimate, scan, nodes);
00092     const Pose corrected_pose = convertToPose(res.pose);
00093     const PrecisionMatrix prec = getPrecisionMatrix(res, use_covariances_);
00094     const Eigen3::Affine3d trans = relativeTransform(corrected_pose, optimizedPose(ref_node));
00095     const NodeConstraint constraint(ref_node, makeConstraint(trans, prec));
00096     ROS_DEBUG_STREAM_NAMED ("running_nodes", "Updating localization based on " << running_nodes_.size() <<
00097                             " nodes from " << toString2D(initial_pose_estimate) << " to " <<
00098                             toString2D(corrected_pose) << "; added constraint to " << constraint.target <<
00099                             " with precision " << toString(constraint.constraint.precision));
00100     constraints.push_back(constraint);
00101 
00102     vector<Chain> chains = candidateChains(graph, ref_node, pointInReferenceFrame(b, corrected_pose), scan);
00103 
00104     for (unsigned i=0; i<chains.size(); i++) {
00105       NodeSet nodes(chains[i].begin(), chains[i].end());
00106       ksm::ScanMatchResult result = scanMatchNodes(matcher_, corrected_pose, scan, nodes);
00107       if (result.response >= min_response_ || i==0) {
00108         const PrecisionMatrix prec = getPrecisionMatrix(result, use_covariances_);
00109         const gm::Point opt_frame_barycenter = pointInReferenceFrame(b, convertToPose(result.pose));
00110         NodeConstraint constraint = scanChainConstraint(opt_frame_barycenter, result.pose, prec, chains[i]);
00111         if (!alreadyHaveConstraintToTarget(constraint, constraints))
00112           constraints.push_back(constraint);
00113       
00114         ROS_DEBUG_STREAM_NAMED ("scan_odom", "Initial corrected estimate to scan matching was " <<
00115                                 toString2D(corrected_pose) << " and scan-matched estimate is "
00116                                 << toString(result.pose) << " to node " << constraint.target <<
00117                                 " with precision " << toString(constraint.constraint.precision));
00118                      
00119       }
00120     }
00121   }
00122   return constraints;
00123 }
00124 
00125 
00126 ChainVec SequentialScanMatcher::candidateChains (const PoseGraph& g, const NodeId ref_node, 
00127                                                  const gm::Point& barycenter, LaserPtr scan) const
00128 {
00129   vector<Chain> chains;
00130   NodeSet processed;
00131   
00132   ROS_DEBUG_STREAM_NAMED ("scan_odom_chains", "Getting chains near " << barycenter 
00133                           << " starting at " << ref_node);
00134 
00135   NodeSet nodes = nearbyNodes(ref_node, barycenter, g, max_link_length_);
00136 
00137   Chain running_chain(running_nodes_.begin(), running_nodes_.end());
00138   addChain(running_chain, &chains, &processed);
00139 
00140   BOOST_FOREACH (const NodeId seed, nodes) {
00141     if (!contains(processed, seed)) {
00142       Chain candidate = getChain(seed, nodes, processed);
00143       if (candidate.size() >= min_chain_length_) 
00144         addChain(candidate, &chains, &processed);
00145     }
00146   }
00147   return chains;
00148 }
00149 
00150 
00151 void SequentialScanMatcher::addRunningNode (const NodeId& n)
00152 {
00153   running_nodes_.push_back(n);
00154 }
00155 
00156 
00157 } // namespace graph_slam


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