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/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
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
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 }