mapper.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 
00039 #include <topological_map_2d/ros_conversion.h>
00040 #include <pose_graph/constraint_graph.h>
00041 #include <pose_graph/diff_subscriber.h>
00042 #include <pose_graph/graph_db.h>
00043 #include <topological_nav_msgs/SwitchGrid.h>
00044 #include <pcl/ros/conversions.h>
00045 #include <octomap_ros/OctomapROS.h>
00046 #include <pose_graph/graph_search.h>
00047 #include <laser_slam/LocalizedScan.h>
00048 #include <graph_mapping_utils/utils.h>
00049 #include <graph_mapping_msgs/LocalizationDistribution.h>
00050 #include <graph_mapping_msgs/GetPoses.h>
00051 #include <occupancy_grid_utils/ray_tracer.h>
00052 #include <tf/transform_listener.h>
00053 #include <tf/transform_broadcaster.h>
00054 #include <visualization_msgs/MarkerArray.h>
00055 #include <nav_msgs/OccupancyGrid.h>
00056 
00057 
00058 namespace laser_slam_mapper
00059 {
00060 
00061 namespace pg=pose_graph;
00062 namespace gmu=graph_mapping_utils;
00063 namespace mr=mongo_roscpp;
00064 namespace gmm=graph_mapping_msgs;
00065 namespace vm=visualization_msgs;
00066 namespace nm=nav_msgs;
00067 namespace tmap=topological_map_2d;
00068 namespace ls=laser_slam;
00069 namespace gu=occupancy_grid_utils;
00070 namespace gm=geometry_msgs;
00071 namespace msg=topological_nav_msgs;
00072 namespace om=octomap;
00073 namespace omr=octomap;
00074 namespace sm=sensor_msgs;
00075 
00076 using std::map;
00077 using std::set;
00078 using std::string;
00079 using std::pair;
00080 using std::vector;
00081 
00082 using gmu::toString;
00083 
00084 typedef boost::optional<const gmm::ConstraintGraphDiff&> OptionalDiff;
00085 typedef boost::mutex::scoped_lock Lock;
00086 typedef map<unsigned, tf::Pose> NodePoses;
00087 typedef set<unsigned> Nodes;
00088 typedef set<unsigned> Grids;
00089 typedef map<unsigned, unsigned> NodeGridMap;
00090 typedef vector<string> StringVec;
00091 
00092 /************************************************************
00093  * Node class def
00094  ***********************************************************/
00095 
00096 class Mapper
00097 {
00098 public:
00099 
00101   Mapper ();
00102   
00103 private:
00104 
00105   /****************************************
00106    * Entry points
00107    ****************************************/
00108 
00110   void updateLoop (const ros::TimerEvent& e);
00111 
00113   void visualize (const ros::TimerEvent& e);
00114 
00116   void diffCB (OptionalDiff diff, const pg::ConstraintGraph& g);
00117 
00119   void locCB (const gmm::LocalizationDistribution& dist);
00120 
00122   void publishRefTransforms(const ros::TimerEvent& e);
00123 
00125   bool switchGrid (msg::SwitchGrid::Request& req,
00126                    msg::SwitchGrid::Response& resp);
00127 
00128   /****************************************
00129    * Modifying functions
00130    ****************************************/
00131 
00133   void ensureNodeCovered (unsigned n);
00134 
00136   void addGrid (unsigned n);
00137 
00139   void saveGrid (unsigned g);
00140 
00144   void updateEdgeInfo (unsigned g, unsigned g2);
00145 
00148   void updateEdgeInfo (unsigned g);
00149 
00150 
00151   /****************************************
00152    * Non-modifying functions
00153    ****************************************/
00154   
00156   tf::Pose poseOnGrid (unsigned n, unsigned g) const;
00157 
00159   NodePoses optimizePoses (const pg::NodeSet& comp) const;
00160 
00163   unsigned coveredBy (unsigned n, unsigned g, double r) const;
00164 
00167   unsigned coveredBy (unsigned n, const Grids& g, double r) const;
00168 
00170   nm::OccupancyGrid::ConstPtr computeLocalGrid (unsigned g) const;
00171 
00173   om::OcTree computeLocalOctomap (unsigned g) const;
00174 
00176   Nodes nodesOnGrid (unsigned g) const;
00177 
00180   Nodes overlayingNodes (unsigned g) const;
00181 
00183   tf::Pose nodeGridTransform (unsigned n, unsigned g) const;
00184 
00186   Nodes topologicallyCloseNodes (unsigned g, const double r) const;
00187 
00190   Grids currentRelevantGrids () const;
00191   
00192 
00193 
00194   /****************************************
00195    * Ros broadcast
00196    ****************************************/
00197 
00199   void publishGraph ();
00200 
00201   // Save current grid
00202   void saveCurrentGrid ();
00203 
00205   void visualizeGridBoundaries ();
00206 
00208   void visualizeCurrentGrid ();
00209 
00211   void visualizeEdges ();
00212   
00213 
00214   /****************************************
00215    * Parameters
00216    ****************************************/
00217 
00218   // Ros namespace from which we'll read parameters
00219   ros::NodeHandle param_nh_;
00220 
00221   // The side length of a local grid
00222   const double grid_size_;
00223 
00224   // Governs how often new grids are created.  1 will create a new grid for each
00225   // node, while 0 will create a new grid only if node is off existing grids.
00226   const double grid_overlap_;
00227 
00228   // Resolution of local grids
00229   const double resolution_;
00230 
00231   // Frame in which optimized poses are defined
00232   const string ref_frame_;
00233 
00234   // Rate at which graph is updated
00235   const double update_rate_;
00236 
00237   // Radius of robot is used to do additional obstacle clearing if positive
00238   const double robot_radius_;
00239 
00240   /****************************************
00241    * State
00242    ****************************************/
00243 
00244   // The pose graph from graph_slam
00245   pg::ConstraintGraph pose_graph_;
00246   
00247   // The topological map itself
00248   tmap::TopologicalMap tmap_;
00249 
00250   // Does the topological map possibly need to be updated?
00251   bool update_flag_;
00252 
00253   // The most recent localization
00254   boost::optional<gm::PoseStamped> last_loc_;
00255 
00256   // Optimized poses
00257   NodePoses opt_poses_;
00258 
00259   // Pending nodes to be processed
00260   Nodes pending_nodes_;
00261 
00262   // Nodes that have a corresponding grid centered at them
00263   Nodes grid_nodes_;
00264 
00265   // Current grid
00266   boost::optional<unsigned> current_grid_;
00267 
00268   // Map each node to a grid that covers it
00269   NodeGridMap covering_grids_;
00270 
00271   // Counter to generate unique edge ids
00272   unsigned next_edge_id_;
00273 
00274   // Last time a diff was received
00275   ros::Time last_diff_time_;
00276 
00277   // Last time each grid was saved
00278   map<unsigned, ros::Time> grid_save_times_;
00279 
00280 
00281   /****************************************
00282    * Associated objects
00283    ****************************************/
00284 
00285   // Mutable because const operations may need to acquire a lock
00286   mutable boost::mutex mutex_;
00287 
00288   // Node handle for ros communications
00289   ros::NodeHandle nh_;
00290 
00291   // Tf listener
00292   tf::TransformListener tf_;
00293 
00294   // Transform broadcaster for grid frames
00295   tf::TransformBroadcaster tfb_;
00296 
00297   // Stored scans at graph slam nodes
00298   pg::CachedNodeMap<ls::LocalizedScan> scans_;
00299 
00300   // Stored clouds at graph slam nodes
00301   pg::CachedNodeMap<sm::PointCloud2> clouds_;
00302 
00303   // Collection for storing local grids in topo_db
00304   mr::MessageCollection<nm::OccupancyGrid> grids_;
00305 
00306   // Subscription to graph localization
00307   ros::Subscriber loc_sub_;
00308 
00309   // Subscribe to pose graph via diffs
00310   pg::DiffSubscriber diff_sub_;
00311 
00312   // Publish visualization markers
00313   ros::Publisher marker_pub_;
00314 
00315   // Publish local grids
00316   ros::Publisher grid_pub_;
00317 
00318   // Publish graph over ros
00319   ros::Publisher graph_pub_;
00320 
00321   // Publish graph localization over ros
00322   ros::Publisher loc_pub_;
00323 
00324   // Publish octomap for visualization
00325   ros::Publisher octomap_pub_;
00326 
00327   // Service handler for external switch grids requests
00328   ros::ServiceServer switch_grid_srv_;
00329 
00330   // Client to get optimized poses
00331   // Mutable because calling it doesn't change state
00332   mutable ros::ServiceClient get_poses_client_;
00333 
00334   // Timer to call updateLoop
00335   ros::Timer update_timer_;
00336 
00337   // Timer that calls visualize
00338   ros::Timer vis_timer_;
00339 
00340   // Timer to publish transforms
00341   ros::Timer transform_pub_timer_;
00342 
00343   
00344 };
00345 
00346 
00347 /************************************************************
00348  * Initialization
00349  ***********************************************************/
00350 
00351 
00352 StringVec gridIndexes ()
00353 {
00354    StringVec fields;
00355    fields.push_back("id");
00356    return fields;
00357 }
00358 
00359 Mapper::Mapper () :
00360   // Params
00361   param_nh_("~"), 
00362   grid_size_(gmu::getParam(param_nh_, "grid_size", 15.0)),
00363   grid_overlap_(gmu::getParam(param_nh_, "grid_overlap", 0.5)),
00364   resolution_(gmu::getParam(param_nh_, "resolution", 0.025)),
00365   ref_frame_(gmu::getParam<string>(param_nh_, "reference_frame")),
00366   update_rate_(gmu::getParam<double>(param_nh_, "update_rate", 0.4)),
00367   robot_radius_(gmu::getParam<double>(param_nh_, "robot_radius", -1)),
00368 
00369   // State
00370   update_flag_(true), next_edge_id_(1),
00371 
00372   // Other objects
00373   scans_("graph_mapping", "scans"), clouds_("graph_mapping", "clouds"),
00374   grids_("topological_navigation", "grids", gridIndexes()),
00375   loc_sub_(nh_.subscribe("graph_localization", 5, &Mapper::locCB, this)),
00376   diff_sub_(boost::bind(&Mapper::diffCB, this, _1, _2)),
00377   marker_pub_(nh_.advertise<vm::Marker>("visualization_marker", 5)),
00378   grid_pub_(nh_.advertise<nm::OccupancyGrid>("local_grid", 5)),
00379   graph_pub_(nh_.advertise<msg::TopologicalGraph>("topological_graph", 3)),
00380   loc_pub_(nh_.advertise<gm::PoseStamped>("topological_localization", 5)),
00381   octomap_pub_(nh_.advertise<vm::MarkerArray>("visualization_marker_array", 5)),
00382   switch_grid_srv_(nh_.advertiseService("switch_local_grid",
00383                                          &Mapper::switchGrid, this)),
00384   get_poses_client_(nh_.serviceClient<gmm::GetPoses>("get_node_poses")),
00385   update_timer_(nh_.createTimer(gmu::duration(update_rate_),
00386                                 &Mapper::updateLoop, this)),
00387   vis_timer_(nh_.createTimer(ros::Duration(2.0), &Mapper::visualize, this)),
00388   transform_pub_timer_(nh_.createTimer(ros::Duration(0.1),
00389                                        &Mapper::publishRefTransforms, this))
00390 {
00391   ROS_DEBUG_STREAM_NAMED ("init", "Mapper initialization complete");\
00392 }
00393 
00394 
00395 /************************************************************
00396  * Updates
00397  ***********************************************************/
00398 
00399 // Call the mapper service to return optimized poses of a set
00400 // of nodes
00401 NodePoses Mapper::optimizePoses (const pg::NodeSet& comp) const
00402 {
00403   gmm::GetPoses srv;
00404   BOOST_FOREACH (const unsigned n, comp) 
00405     srv.request.nodes.push_back(n);
00406   if (!get_poses_client_.call(srv))
00407     throw std::runtime_error("Service call to optimizer failed");
00408   NodePoses poses;
00409   unsigned i=0;
00410   BOOST_FOREACH (const unsigned n, srv.request.nodes) 
00411     poses[n] = gmu::toPose(srv.response.poses[i++]);
00412   return poses;  
00413 }
00414 
00415 void Mapper::updateLoop (const ros::TimerEvent& e)
00416 {
00417   pg::NodeSet comp;
00418   pg::NodePoseMap opt_poses;
00419   {
00420     Lock l(mutex_);
00421 
00422     // Only update once we have a localization
00423     if (!last_loc_)
00424     {
00425       ROS_INFO_THROTTLE (5.0, "Topological mapper waiting for "
00426                          "initial localization");
00427       return;
00428     }
00429 
00430     // Optimize current graph component
00431     comp = pg::componentContaining(pose_graph_, gmu::refNode(*last_loc_));
00432   }
00433   opt_poses = optimizePoses(comp);
00434 
00435   Lock l(mutex_);
00436   opt_poses_ = opt_poses;
00437   pose_graph_.setOptimizedPoses(opt_poses_);
00438   // Ensure that each pending node has a grid that covers it
00439   BOOST_FOREACH (const unsigned n, pending_nodes_) 
00440   {
00441     if (!gmu::contains(opt_poses_, n))
00442     {
00443       ROS_DEBUG_STREAM_NAMED ("update_int", "No optimized pose yet for " <<
00444                               n << "; skipping it.");
00445       continue;
00446     }
00447     ROS_DEBUG_STREAM_NAMED ("update_int", "Processing pending node " << n);
00448 
00449     const double r = 1-grid_overlap_;
00450     if (!(current_grid_ && coveredBy(n, *current_grid_, r)) &&
00451         !coveredBy(n, grid_nodes_, r))
00452     {
00453       addGrid(n);
00454       updateEdgeInfo(n);
00455       saveGrid(n);
00456       covering_grids_[n] = n;
00457     }
00458     else
00459     {
00460       covering_grids_[n] = coveredBy(n, grid_nodes_, r);
00461     }
00462   }
00463   pending_nodes_.clear();
00464 
00465   // Update info for each grid we currently care about
00466   BOOST_FOREACH (const unsigned g, currentRelevantGrids()) 
00467     updateEdgeInfo (g);
00468 
00469   
00470   // Publish info over ros
00471   publishGraph();
00472   saveCurrentGrid();
00473 
00474   
00475 }
00476 
00477 unsigned Mapper::coveredBy (const unsigned n, const unsigned g,
00478                             const double r) const
00479 {
00480   const tf::Pose& center = gmu::keyValue(opt_poses_, g);
00481   const tf::Pose& pose = gmu::keyValue(opt_poses_, n);
00482   const tf::Pose rel_pose = gmu::relativePose(pose, center);
00483   const double d = grid_size_*r*0.5;
00484   const double rx = rel_pose.getOrigin().x();
00485   const double ry = rel_pose.getOrigin().y();
00486   return (fabs(rx)<d && fabs(ry)<d) ? g : 0;
00487 }
00488 
00489 
00490 unsigned Mapper::coveredBy (const unsigned n, const set<unsigned>& grids,
00491                             const double r) const
00492 {
00493   BOOST_FOREACH (const unsigned g, grids) 
00494   {
00495     if (coveredBy(n, g, r))
00496       return g;
00497   }
00498   return 0;
00499 }
00500 
00501 void Mapper::addGrid (const unsigned n)
00502 {
00503   ROS_DEBUG_STREAM_NAMED ("update", "Adding grid centered at node " << n);
00504   grid_nodes_.insert(n);
00505   msg::TopologicalMapNode info;
00506   info.id = n;
00507   info.y_size = grid_size_;
00508   info.x_size = grid_size_;
00509   info.resolution = resolution_;
00510   tmap_.addNode(info);
00511 }
00512 
00513 
00514 void Mapper::updateEdgeInfo (const unsigned g, const unsigned g2)
00515 {
00516   if (g!=g2 && gmu::contains(grid_nodes_, g2))
00517   {
00518     ROS_DEBUG_NAMED ("update_int", "Processing nearby nodes %u and %u",
00519                      g, g2);
00520     // At this point, g2 is a grid that's close to g.  
00521     pair<tmap::GraphEdge, bool> res =
00522       edge(tmap_.node(g), tmap_.node(g2), tmap_);
00523     if (res.second)
00524     {
00525       // If there's already an edge, just update the transform
00526       // based on the current optimized poses
00527       msg::TopologicalMapEdge& info = tmap_[res.first];
00528       const tf::Pose dest = gmu::keyValue(opt_poses_, info.dest);
00529       const tf::Pose src = gmu::keyValue(opt_poses_, info.src);
00530       tmap_.edgeInfo(tmap_[res.first].id).offset =
00531         gmu::toPose(gmu::relativePose(dest, src));
00532     }
00533     else
00534     {
00535       // Else add an edge if necessary
00536       const tf::Pose dest = gmu::keyValue(opt_poses_, g2);
00537       const tf::Pose src = gmu::keyValue(opt_poses_, g);
00538       const double d2 = dest.getOrigin().distance2(src.getOrigin());
00539       if (d2 < 2*grid_size_*grid_size_)
00540       {
00541         msg::TopologicalMapEdge e;
00542         e.id = next_edge_id_++;
00543         e.src = g;
00544         e.dest = g2;
00545         e.offset = gmu::toPose(gmu::relativePose(dest, src));
00546         tmap_.addEdge(e);
00547         ROS_DEBUG_NAMED("update", "Adding edge from %u to %u", g, g2);
00548       }
00549     }        
00550   }
00551 }
00552 
00553 void Mapper::updateEdgeInfo (const unsigned g)
00554 {
00555   ROS_DEBUG_NAMED ("update_int", "Updating edge info for %u", g);
00556   BOOST_FOREACH (const unsigned n,
00557                  topologicallyCloseNodes(g, grid_size_*1.5))
00558   {
00559     updateEdgeInfo(g, n);
00560   }
00561 }
00562 
00563 
00564 Nodes Mapper::topologicallyCloseNodes (const unsigned g, const double r) const
00565 {
00566   const btVector3 pos = gmu::keyValue(opt_poses_, g).getOrigin();
00567   pg::OptimizedDistancePredicate pred(pose_graph_, pos, r);
00568   return filterNearbyNodes (pose_graph_, g, pred);
00569 }
00570 
00571 Grids Mapper::currentRelevantGrids () const
00572 {
00573   Grids grids;
00574   if (current_grid_)
00575     grids.insert(*current_grid_);
00576   return grids;
00577 }
00578 
00579 
00580 /************************************************************
00581  * Callbacks
00582  ***********************************************************/
00583 
00584 // Take in slam graph localization and publish a PoseStamped
00585 // that represents pose on current local grid; update current grid
00586 // if we're off the edge.
00587 void Mapper::locCB (const gmm::LocalizationDistribution& dist)
00588 {
00589   Lock l(mutex_);
00590   if (dist.samples.size()!=1)
00591     throw std::logic_error("Localization distribution was not deterministic ");
00592   last_loc_ = dist.samples[0];
00593 
00594   const unsigned ref_node = gmu::refNode(*last_loc_);
00595   if (!gmu::contains(opt_poses_, ref_node))
00596   {
00597     ROS_DEBUG_STREAM_NAMED ("localization", "Not updating localization due to"
00598                             " lack of optimized pose for " << ref_node);
00599     return;
00600   }
00601   if (!current_grid_ || !coveredBy(ref_node, *current_grid_, 1-grid_overlap_))
00602   {
00603     if (gmu::contains(covering_grids_, ref_node))
00604     {
00605       current_grid_ = covering_grids_[ref_node];
00606       ROS_DEBUG_STREAM_NAMED ("localization", "On new grid " << *current_grid_);
00607     }
00608   }
00609 
00610   gm::PoseStamped loc;
00611   loc.header.frame_id = tmap::gridFrame(*current_grid_);
00612   loc.header.stamp = dist.stamp;
00613   loc.pose = gmu::transformPose(nodeGridTransform(ref_node, *current_grid_),
00614                                 last_loc_->pose);
00615   loc_pub_.publish(loc);
00616 }
00617 
00618 
00619 // When a diff comes in, incorporate it into the graph.  Also, add all new nodes
00620 // to the pending_nodes_ queue  to be processed in the update loop, and 
00621 void Mapper::diffCB (OptionalDiff diff,
00622                      const pg::ConstraintGraph& g)
00623 {
00624   Lock l(mutex_);
00625   if (diff)
00626   {
00627     BOOST_FOREACH (const gmm::Node& n, diff->new_nodes) 
00628       pending_nodes_.insert(n.id);
00630   }
00631   else
00632   {
00633     BOOST_FOREACH (const unsigned n, g.allNodes()) 
00634       pending_nodes_.insert(n);
00635   }
00636   pose_graph_ = g;
00637 
00638   // Since the incoming graph doesn't have these set
00639   pose_graph_.setOptimizedPoses(opt_poses_); 
00640 
00641   last_diff_time_ = ros::Time::now();
00642 }
00643 
00644 bool Mapper::switchGrid (msg::SwitchGrid::Request& req,
00645                          msg::SwitchGrid::Response& resp)
00646 {
00647   Lock l(mutex_);
00648   ROS_DEBUG_STREAM_NAMED ("localization",
00649                           "Switching to grid " << req.grid);
00650   current_grid_ = req.grid;
00651   return true;
00652 }
00653 
00654 /************************************************************
00655  * Local grids
00656  ***********************************************************/
00657 
00658 
00659 // Not used any more
00660 Nodes Mapper::nodesOnGrid (const unsigned g) const
00661 {
00662   Nodes nodes;
00663   BOOST_FOREACH (const NodePoses::value_type& e, opt_poses_)
00664   {
00665     if (coveredBy(e.first, g, 1.0))
00666       nodes.insert(e.first);
00667   }
00668   return nodes;
00669 }
00670 
00671 Nodes Mapper::overlayingNodes (const unsigned g) const
00672 {
00673   const Nodes potential_nodes = topologicallyCloseNodes(g, grid_size_*1.5);
00674   Nodes nodes;
00675   BOOST_FOREACH (const unsigned n, potential_nodes) 
00676   {
00677     ls::LocalizedScan::ConstPtr scan = scans_.get(n);
00678     const tf::Pose trans = nodeGridTransform(n, g);
00679     const tf::Point b = trans*gmu::toPoint(scan->barycenter);
00680     if ((fabs(b.x()) < grid_size_/2.0) &&
00681         (fabs(b.y()) < grid_size_/2.0))
00682       nodes.insert(n);
00683   }
00684   ROS_DEBUG_STREAM_NAMED ("overlay", "Overlaying grid " << g << " using "
00685                           << toString(nodes) << " (potential nodes were )"
00686                           << toString(potential_nodes));
00687     
00688   return nodes;
00689 }
00690 
00692 tf::Pose Mapper::nodeGridTransform (const unsigned n, const unsigned g) const
00693 {
00694   const tf::Pose& grid_center_pose = gmu::keyValue(opt_poses_, g);
00695   const tf::Pose& node_pose = gmu::keyValue(opt_poses_, n);
00696   return grid_center_pose.inverseTimes(node_pose);
00697 }
00698 
00699 
00700 nm::OccupancyGrid::ConstPtr Mapper::computeLocalGrid (const unsigned g) const
00701 {
00702   ROS_ASSERT_MSG (gmu::contains(grid_nodes_, g), "%u is not a grid node", g);
00703   const std::string frame = tmap::gridFrame(g);
00704   
00706   nm::OccupancyGrid dims;
00707   dims.info.resolution = resolution_;
00708   dims.info.width = grid_size_/resolution_;
00709   dims.info.height = grid_size_/resolution_;
00710   
00711   const double r=grid_size_/2.0;
00712   dims.info.origin.position.x = -r;
00713   dims.info.origin.position.y = -r;
00714   dims.info.origin.orientation.w = 1.0;
00715   dims.header.frame_id = frame;
00716   gu::OverlayClouds overlay = gu::createCloudOverlay(dims, frame);
00717 
00719   BOOST_FOREACH (const unsigned n, overlayingNodes(g))
00720   {
00721     ls::LocalizedScan::ConstPtr stored_scan = scans_.get(n);
00722     gu::LocalizedCloud::Ptr cloud(new gu::LocalizedCloud());
00723     cloud->header.frame_id = frame;
00724     cloud->sensor_pose = gmu::transformPose(nodeGridTransform(n, g),
00725                                             stored_scan->sensor_pose);
00726     cloud->cloud = stored_scan->cloud;
00727     addCloud(&overlay, cloud);
00728   }
00729 
00731   if (robot_radius_ > 0)
00732   {
00733     const tf::Transform world_to_grid = gmu::keyValue(opt_poses_, g).inverse();
00734     BOOST_FOREACH (const unsigned n, nodesOnGrid(g))
00735     {
00736       const tf::Pose node_pose = gmu::keyValue(opt_poses_, n);
00737       const gm::Point pos = gmu::toPoint(world_to_grid*node_pose.getOrigin());
00738       addKnownFreePoint(&overlay, pos, robot_radius_);
00739     }
00740   }
00741 
00742   return getGrid(overlay);                                                     
00743 }
00744 
00745 om::OcTree Mapper::computeLocalOctomap (const unsigned g) const
00746 {
00747   ROS_ASSERT_MSG (gmu::contains(grid_nodes_, g), "%u is not a grid node", g);
00748   const std::string frame = tmap::gridFrame(g);
00749   
00750   // Set up octomap and params
00751   omr::OcTreeROS octomap(resolution_);
00752 
00753   // Add clouds
00754   BOOST_FOREACH (const unsigned n, overlayingNodes(g))
00755   {
00756     ROS_INFO ("Adding cloud for node %u", n);
00757     try
00758     {
00759       sm::PointCloud2::ConstPtr stored_cloud = clouds_.get(n);
00760       pcl::PointCloud<pcl::PointXYZ> cloud;
00761       pcl::fromROSMsg(*stored_cloud, cloud);
00762     
00763       // Set cloud frame, params
00764       const tf::Pose node_pose = nodeGridTransform(n, g);
00765       const btVector3& pos = node_pose.getOrigin();
00766       const pcl::PointXYZ trans(pos.x(), pos.y(), pos.z());
00767       octomap.insertScan(cloud, pcl::PointXYZ(0,0,0), trans,
00768                          node_pose.getRotation());
00769     }
00770     catch (pg::DataNotFoundException& e)
00771     {
00772       ROS_WARN ("Didn't find stored cloud for %u when computing octomap", n);
00773     }
00774   }
00775 
00776   return octomap.octree;
00777 }
00778 
00779 
00780 
00781 /************************************************************
00782  * Ros publication/visualization
00783  ***********************************************************/
00784 
00785 void Mapper::visualize (const ros::TimerEvent&)
00786 {
00787   visualizeGridBoundaries();
00788   visualizeCurrentGrid();
00789   visualizeEdges();
00790 }
00791 
00792 
00793 vm::MarkerArray convertToMarkers (const om::OcTree& octree,
00794                                   const string& frame)
00795 {
00796   vm::MarkerArray m;
00797 
00798   // Get dims
00799   double x, y, minZ, maxZ;
00800   octree.getMetricMin(x, y, minZ);
00801   octree.getMetricMax(y, y, maxZ);
00802 
00803   // each marker is a cube list storing all cubes at a given depth level
00804   m.markers.resize(octree.getTreeDepth());
00805   double lowestRes = octree.getResolution();
00806 
00807   // Loop over leaves and add to appropriate cube list
00808   for (om::OcTree::iterator it = octree.begin(),
00809          end = octree.end(); it != end; ++it)
00810   {
00811     if (octree.isNodeOccupied(*it))
00812     {
00813       // which array to store cubes in?
00814       int idx = int(log2(it.getSize() / lowestRes) +0.5);
00815       assert (idx >= 0 && unsigned(idx) < m.markers.size());
00816 
00817       gm::Point cubeCenter;
00818       cubeCenter.x = it.getX();
00819       cubeCenter.y = it.getY();
00820       cubeCenter.z = it.getZ();
00821       m.markers[idx].points.push_back(cubeCenter);
00822     }
00823   }
00824 
00825   // Set the remaining marker parameters
00826   for (unsigned i= 0; i < m.markers.size(); ++i)
00827   {
00828     double size = lowestRes * pow(2,i);
00829     m.markers[i].header.frame_id = frame;
00830     m.markers[i].header.stamp = ros::Time::now();
00831     m.markers[i].ns = "topological_octomap";
00832     m.markers[i].id = i;
00833     m.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00834     m.markers[i].scale.x = size;
00835     m.markers[i].scale.y = size;
00836     m.markers[i].scale.z = size;
00837     m.markers[i].color.b = m.markers[i].color.a = 1.0;
00838     m.markers[i].action = visualization_msgs::Marker::ADD;
00839   }
00840 
00841   return m;
00842 }
00843 
00844 void Mapper::visualizeCurrentGrid ()
00845 {
00846   if (!last_loc_)
00847     return;
00848 
00849   Lock l(mutex_);
00850   const unsigned n = gmu::refNode(*last_loc_);
00851   if (!gmu::contains(covering_grids_, n))
00852   {
00853     ROS_DEBUG_STREAM_NAMED ("visualization", "Not visualizing current grid "
00854                             " because don't have covering grid for " << n);
00855     return;
00856   }
00857   grid_pub_.publish(computeLocalGrid(*current_grid_));
00858   /*octomap_pub_.publish(convertToMarkers(computeLocalOctomap(*current_grid_),
00859     ref_frame_));*/
00860 }
00861 
00862 void Mapper::visualizeGridBoundaries ()
00863 {
00864   vm::Marker grids;
00865   grids.header.frame_id = ref_frame_;
00866   grids.header.stamp = ros::Time::now();
00867   grids.ns = "topological_map";
00868   grids.type = vm::Marker::LINE_LIST;
00869   grids.action = vm::Marker::ADD;
00870   grids.scale.x = 0.03;
00871   grids.color.r = 1.0;
00872   grids.color.g = 0.6;
00873   grids.color.b = 0.0;
00874   grids.color.a = 1.0;
00875 
00876   BOOST_FOREACH (const unsigned g, grid_nodes_) 
00877   {
00878     const double s = grid_size_*0.5;
00879     const tf::Pose origin = gmu::keyValue(opt_poses_, g);
00880     const int xm[] = {-1, 1, 1, -1};
00881     const int ym[] = {1, 1, -1, -1};
00882     for (int i=0; i<4; i++)
00883     {
00884       const int j = i ? i-1 : 3;
00885       const btVector3 p1(s*xm[j], s*ym[j], 0);
00886       const btVector3 p2(s*xm[i], s*ym[i], 0);
00887       grids.points.push_back(gmu::toPoint(origin*p1));
00888       grids.points.push_back(gmu::toPoint(origin*p2));
00889     }
00890   }
00891   marker_pub_.publish(grids);
00892 }
00893 
00894 void Mapper::visualizeEdges ()
00895 {
00896   vm::Marker edges;
00897   edges.header.frame_id = ref_frame_;
00898   edges.header.stamp = ros::Time::now();
00899   edges.ns = "topological_map_edges";
00900   edges.type = vm::Marker::LINE_LIST;
00901   edges.action = vm::Marker::ADD;
00902   edges.scale.x = 0.03;
00903   edges.color.r = 1.0;
00904   edges.color.g = 0.0;
00905   edges.color.b = 0.0;
00906   edges.color.a = 1.0;
00907   BOOST_FOREACH (const unsigned g, grid_nodes_) 
00908   {
00909     const tf::Pose origin = gmu::keyValue(opt_poses_, g);
00910     BOOST_FOREACH (const tmap::GraphEdge e, out_edges(tmap_.node(g), tmap_)) 
00911     {
00912       if (tmap_[e].src == g)
00913       {
00914         edges.points.push_back(gmu::toPoint(origin.getOrigin()));
00915         edges.points.push_back(gmu::transformPoint(origin,
00916                                                    tmap_[e].offset.position));
00917       }
00918     }
00919   }
00920   marker_pub_.publish(edges);
00921 }
00922 
00923 void Mapper::saveGrid (const unsigned g)
00924 {
00925   typedef mr::MessageWithMetadata<nm::OccupancyGrid>::ConstPtr GridWithMetadata;
00926   ROS_DEBUG_STREAM_NAMED ("grid", "Storing local grid " << g);
00927   nm::OccupancyGrid::ConstPtr grid = computeLocalGrid(g);
00928 
00929   mr::Query q = mr::Query("id", g);
00930   vector<GridWithMetadata> existing = grids_.pullAllResults(q, true);
00931   ROS_DEBUG_NAMED ("grid", "There were %zu existing grids", existing.size());
00932   if (existing.size()>0)
00933   {
00934     const unsigned num_removed = grids_.removeMessages(q);
00935     ROS_WARN_COND_NAMED (num_removed!=existing.size(), "grid",
00936                          "Removed %u grids instead of %zu", num_removed,
00937                          existing.size());
00938   }
00939 
00940   grids_.insert(*grid, mr::Metadata("id", g));
00941   grid_save_times_[g] = ros::Time::now();
00942 }
00943 
00944 void Mapper::publishGraph ()
00945 {
00946   msg::TopologicalGraph::Ptr m;
00947   m = tmap::toMessage(tmap_);
00948   graph_pub_.publish(m);
00949 }
00950 
00951 
00952 void Mapper::publishRefTransforms (const ros::TimerEvent& e)
00953 {
00954   Lock l(mutex_);
00955   BOOST_FOREACH (const unsigned g, grid_nodes_) 
00956   {
00957     tf::StampedTransform tr(gmu::keyValue(opt_poses_, g), ros::Time::now(),
00958                             ref_frame_, tmap::gridFrame(g));
00959     tfb_.sendTransform(tr);
00960   }
00961 }
00962 
00963 void Mapper::saveCurrentGrid ()
00964 {
00965   // Also store/update the current local grid
00966   if (current_grid_) {
00967     if (!gmu::contains(grid_save_times_, *current_grid_) ||
00968         gmu::keyValue(grid_save_times_, *current_grid_) < last_diff_time_) {
00969       saveGrid(*current_grid_);
00970       grid_pub_.publish(computeLocalGrid(*current_grid_));
00971     }
00972   }
00973 }
00974 
00975 
00976 } // namespace
00977 
00978 
00979 
00980 
00981 int main (int argc, char** argv)
00982 {
00983   ros::init(argc, argv, "topological_mapper");
00984   laser_slam_mapper::Mapper node;
00985   ros::spin();
00986   return 0;
00987 }


laser_slam_mapper
Author(s): Bhaskara Marthi
autogenerated on Sun Jan 5 2014 11:39:28