scan_manager.cpp
Go to the documentation of this file.
00001 /* Copyright (c) 2008, Willow Garage, Inc.
00002  * All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *
00007  *     * Redistributions of source code must retain the above copyright
00008  *       notice, this list of conditions and the following disclaimer.
00009  *     * Redistributions in binary form must reproduce the above copyright
00010  *       notice, this list of conditions and the following disclaimer in the
00011  *       documentation and/or other materials provided with the distribution.
00012  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00013  *       contributors may be used to endorse or promote products derived from
00014  *       this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00020  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00021  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00022  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00025  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026  * POSSIBILITY OF SUCH DAMAGE.
00027  *
00028  */
00029 
00030 
00039 #include <graph_slam/scan_manager.h>
00040 #include <pose_graph/geometry.h>
00041 #include <pose_graph/utils.h>
00042 #include <pose_graph/transforms.h>
00043 #include <boost/foreach.hpp>
00044 #include <queue>
00045 
00046 namespace graph_slam
00047 {
00048 
00049 namespace gm=geometry_msgs;
00050 namespace ksm=karto_scan_matcher;
00051 namespace sm=sensor_msgs;
00052 using namespace pose_graph;
00053 
00054 using std::vector;
00055 using boost::optional;
00056 
00057 typedef NodeSequenceMap::value_type SequenceLink;
00058 typedef NodeSequenceMap::left_map::const_iterator LeftIter;
00059 typedef NodeSequenceMap::right_map::const_iterator RightIter;
00060 
00061 const double RADIAN_TO_METER_MULT = 1.0;
00062 
00063 ScanManager::ScanManager (const gm::Pose2D& offset) : laser_offset_(offset)
00064 {}
00065 
00066 void ScanManager::addNode (const NodeId n, const LaserPtr scan)
00067 {
00068   ROS_ASSERT (!contains(scans_, n) && !contains(barycenters_, n));
00069   ROS_DEBUG_NAMED ("scan_manager", "Adding node %lu", n.getId());
00070   scans_[n] = scan;
00071 
00072   barycenters_[n] = computeBarycenterInBaseFrame(scan);
00073   
00074   if (last_node_) {
00075     node_sequence_.insert(SequenceLink(*last_node_, n));
00076     ROS_DEBUG_NAMED ("scan_manager", " added sequence link from %lu", last_node_->getId());
00077   }
00078   last_node_ = n;
00079 }
00080     
00081 void ScanManager::resetLastNode ()
00082 {
00083   last_node_ = optional<NodeId>();
00084   ROS_DEBUG_STREAM_NAMED ("scan_manager", "Resetting last node");
00085 }
00086 
00087 
00088 optional<NodeId> ScanManager::lastNode () const
00089 {
00090   return last_node_;
00091 }
00092 
00093 ksm::ScanWithPose makeScanWithPose (const NodePoseMap& optimized_poses, const NodeScanMap scans_,
00094                                     const NodeId n)
00095 {
00096   return ksm::ScanWithPose(*keyValue(scans_, n), projectToPose2D(keyValue(optimized_poses, n)));
00097 }
00098 
00099 
00100 template <typename NodeContainer>
00101 vector<ksm::ScanWithPose> ScanManager::makeRefScans (const NodeContainer& nodes) const
00102 {
00103   vector<ksm::ScanWithPose> loc_scans(nodes.size());
00104   transform(nodes.begin(), nodes.end(), loc_scans.begin(),
00105             bind(makeScanWithPose, *optimized_poses_, scans_, _1));
00106   return loc_scans;
00107 }
00108 
00109 
00110 
00111 
00112 Chain ScanManager::getChain (const NodeId seed, const NodeSet& nodes, const NodeSet& processed) const
00113 {
00114   ROS_ASSERT_MSG (contains(nodes, seed), "Node set does not contain %lu", seed.getId());
00115   ROS_ASSERT_MSG (!contains(processed, seed), "%lu was already processed", seed.getId());
00116   const Chain forward_chain = onewayChain(node_sequence_.left, seed, nodes, processed);
00117   const Chain backward_chain = onewayChain(node_sequence_.right, seed, nodes, processed);
00118 
00119   Chain chain(forward_chain.size()+backward_chain.size()-1);
00120   copy(backward_chain.rbegin(), backward_chain.rend(), chain.begin());
00121   copy(forward_chain.begin()+1, forward_chain.end(), chain.begin() + backward_chain.size());
00122 
00123   return chain;
00124 }
00125 
00126 gm::Point ScanManager::computeBarycenterInBaseFrame (const LaserPtr scan) const
00127 {
00128   const gm::Point offset_center = computeBarycenter(*scan);
00129   const Affine3d offset_transform = poseToWorldTransform(convertToPose(laser_offset_));
00130   return transformPoint(offset_transform, offset_center);
00131 }
00132 
00133 
00134 optional<gm::Point> ScanManager::nodeBarycenter (const NodeId n) const
00135 {
00136   if (contains(*optimized_poses_, n) && contains(barycenters_, n)) 
00137     return optional<gm::Point>(nodeBarycenter(n, keyValue(*optimized_poses_, n)));
00138   else
00139     return optional<gm::Point>();
00140 }
00141 
00142 gm::Point ScanManager::nodeBarycenter (const NodeId n, const gm::Pose& pose) const
00143 {
00144   return pointInReferenceFrame(keyValue(barycenters_, n), pose);
00145 }
00146 
00147 
00148 NodeSet ScanManager::nearbyNodes (const NodeId n, const Point& center, const PoseGraph& g,
00149     const double max_distance) const
00150 {
00151   NodeSet nodes;
00152   
00153   std::queue<NodeId> q;
00154   q.push(n);
00155   ROS_DEBUG_STREAM_NAMED ("scan_manager_nearby_nodes", "Looking for nodes within " << max_distance
00156                           << " of " << n << " at " << toString(center));
00157 
00158   while (!q.empty()) {
00159     const NodeId current = q.front();
00160     optional<gm::Point> current_center = nodeBarycenter(current);
00161     q.pop();
00162     if (!current_center) {
00163       ROS_DEBUG_STREAM_NAMED ("scan_manager_nearby_nodes", "No barycenter found for " << current);
00164       continue;
00165     }
00166 
00167     if (!contains(nodes, current) && 
00168         euclideanDistance(*current_center, center) < max_distance) {
00169       nodes.insert(current);
00170       ROS_DEBUG_STREAM_NAMED ("scan_manager_nearby_nodes", "Adding nearby node " <<
00171                               current << " at " << toString(*current_center));
00172       BOOST_FOREACH (const NodeId n2, g.neighbors(current))
00173         q.push(n2);
00174     }
00175   }
00176 
00177   return nodes;
00178 }
00179 
00180 NodeConstraint ScanManager::scanChainConstraint (const gm::Point& barycenter, const gm::Pose2D& pose,
00181                                                  const pg::PrecisionMatrix& prec,
00182                                                  const Chain& chain) const
00183 {
00184   const NodeId closest = closestNode(barycenter, chain);
00185   const Pose2D closest_pose = projectToPose2D(keyValue(*optimized_poses_, closest));
00186   return NodeConstraint(closest, makeConstraint(relativeTransform(pose, closest_pose), prec));
00187 }
00188 
00189 
00190 // Used for finding closest node to a pose
00191 // Note that we just ignore nodes without an optimized pose (rather than asserting)
00192 bool closerTo (const gm::Pose2D& pose, const NodePoseMap& optimized_poses,
00193                const NodeId n1, const NodeId n2)
00194 {
00195   if (!contains(optimized_poses, n1)) {
00196     ROS_WARN_STREAM ("Node " << n1 << " didn't have an optimized pose; ignoring.");
00197     return false;
00198   }
00199   else if (!contains(optimized_poses, n2)) {
00200     ROS_WARN_STREAM ("Node " << n2 << " didn't have an optimized pose; ignoring.");
00201     return true;
00202   }
00203   else {
00204     const gm::Pose2D p1 = projectToPose2D(keyValue(optimized_poses, n1));
00205     const gm::Pose2D p2 = projectToPose2D(keyValue(optimized_poses, n2));
00206     const double d1=euclideanDistance(pose, p1, RADIAN_TO_METER_MULT);
00207     const double d2=euclideanDistance(pose, p2, RADIAN_TO_METER_MULT);
00208     return d1<d2;
00209   }
00210 }
00211 
00212 
00213 NodeId ScanManager::closestNode (const gm::Point& barycenter, const Chain& chain) const
00214 {
00215   optional<NodeId> closest;
00216   double min_distance = -42;
00217 
00218   BOOST_FOREACH (const NodeId n, chain) {
00219     if (contains(*optimized_poses_, n) && contains(barycenters_, n)) {
00220       const double dist = euclideanDistance(*nodeBarycenter(n), barycenter);
00221       if (!closest || min_distance > dist) {
00222         closest = n;
00223         min_distance = dist;
00224       }
00225     }
00226   }
00227   ROS_ASSERT_MSG(min_distance > -0.1, "Couldn't find closest node to point");
00228   return *closest;
00229 }
00230 
00231 NodeId ScanManager::closestNode (const gm::Pose2D& pose, const NodeSet& nodes) const
00232 {
00233   NodeSet::const_iterator pos = min_element (nodes.begin(), nodes.end(), 
00234                                              bind(closerTo, pose, *optimized_poses_, _1, _2));
00235   ROS_ASSERT (pos!=nodes.end());
00236   return *pos;
00237 }
00238 
00239 geometry_msgs::Pose ScanManager::optimizedPose (const NodeId n) const
00240 {
00241   return keyValue(*optimized_poses_, n);
00242 }
00243 
00244 ksm::ScanMatchResult ScanManager::scanMatchNodes (KartoMatcherPtr matcher,
00245                                                   const gm::Pose& init_pose_estimate, 
00246                                                   const LaserPtr scan, const NodeSet& nodes) const
00247 {
00248   
00249   return matcher->scanMatch(*scan, projectToPose2D(init_pose_estimate), makeRefScans(nodes));
00250 }
00251 
00252 PrecisionMatrix getPrecisionMatrix (const ksm::ScanMatchResult& res, const bool use_covariances)
00253 {
00254   PrecisionMatrix prec;
00255   const Eigen3::Matrix3f prec2D = res.cov.inverse();
00256   ROS_ASSERT (prec2D(0,1) == prec2D(1,0)); // validate my assumption
00257   if (use_covariances)
00258     prec = makePrecisionMatrix(prec2D(0,0), prec2D(1,1), prec2D(0,1), prec2D(2,2));
00259   else
00260     prec = makePrecisionMatrix(1, 1, 1);
00261   return prec;
00262 }
00263 
00264 void addChain (const Chain& chain, vector<Chain>* chains, NodeSet* processed)
00265 {
00266   ROS_DEBUG_NAMED ("scan_odom_chains", "Adding chain starting at %lu with %zu nodes",
00267                    chain[0].getId(), chain.size());
00268   chains->push_back(chain);
00269   BOOST_FOREACH (const NodeId n, chain) {
00270     processed->insert(n);
00271   }
00272 }
00273 
00274 
00275 
00276 void ScanManager::setOptimizedPoses (const NodePoseMap& optimized_poses) const 
00277 {
00278   optimized_poses_ = optimized_poses;
00279 }
00280 
00281 void ScanManager::unsetOptimizedPoses () const
00282 {
00283   optimized_poses_ = optional<NodePoseMap>();
00284 }
00285 
00286 WithOptimizedPoses::WithOptimizedPoses (const ScanManager* matcher, const NodePoseMap& poses) :
00287   matcher(matcher)
00288 {
00289   matcher->setOptimizedPoses(poses);
00290 }
00291 
00292 WithOptimizedPoses::~WithOptimizedPoses ()
00293 {
00294   matcher->unsetOptimizedPoses();
00295 }
00296 
00297   
00298 
00299 
00300 }


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