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
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
00191
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));
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 }