00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
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
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
00112 NodeSet processed = nearbyNodes(ref_node, bary, graph, max_link_length_);
00113
00114
00115
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 }