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 <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
00094
00095
00096 class Mapper
00097 {
00098 public:
00099
00101 Mapper ();
00102
00103 private:
00104
00105
00106
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
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
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
00196
00197
00199 void publishGraph ();
00200
00201
00202 void saveCurrentGrid ();
00203
00205 void visualizeGridBoundaries ();
00206
00208 void visualizeCurrentGrid ();
00209
00211 void visualizeEdges ();
00212
00213
00214
00215
00216
00217
00218
00219 ros::NodeHandle param_nh_;
00220
00221
00222 const double grid_size_;
00223
00224
00225
00226 const double grid_overlap_;
00227
00228
00229 const double resolution_;
00230
00231
00232 const string ref_frame_;
00233
00234
00235 const double update_rate_;
00236
00237
00238 const double robot_radius_;
00239
00240
00241
00242
00243
00244
00245 pg::ConstraintGraph pose_graph_;
00246
00247
00248 tmap::TopologicalMap tmap_;
00249
00250
00251 bool update_flag_;
00252
00253
00254 boost::optional<gm::PoseStamped> last_loc_;
00255
00256
00257 NodePoses opt_poses_;
00258
00259
00260 Nodes pending_nodes_;
00261
00262
00263 Nodes grid_nodes_;
00264
00265
00266 boost::optional<unsigned> current_grid_;
00267
00268
00269 NodeGridMap covering_grids_;
00270
00271
00272 unsigned next_edge_id_;
00273
00274
00275 ros::Time last_diff_time_;
00276
00277
00278 map<unsigned, ros::Time> grid_save_times_;
00279
00280
00281
00282
00283
00284
00285
00286 mutable boost::mutex mutex_;
00287
00288
00289 ros::NodeHandle nh_;
00290
00291
00292 tf::TransformListener tf_;
00293
00294
00295 tf::TransformBroadcaster tfb_;
00296
00297
00298 pg::CachedNodeMap<ls::LocalizedScan> scans_;
00299
00300
00301 pg::CachedNodeMap<sm::PointCloud2> clouds_;
00302
00303
00304 mr::MessageCollection<nm::OccupancyGrid> grids_;
00305
00306
00307 ros::Subscriber loc_sub_;
00308
00309
00310 pg::DiffSubscriber diff_sub_;
00311
00312
00313 ros::Publisher marker_pub_;
00314
00315
00316 ros::Publisher grid_pub_;
00317
00318
00319 ros::Publisher graph_pub_;
00320
00321
00322 ros::Publisher loc_pub_;
00323
00324
00325 ros::Publisher octomap_pub_;
00326
00327
00328 ros::ServiceServer switch_grid_srv_;
00329
00330
00331
00332 mutable ros::ServiceClient get_poses_client_;
00333
00334
00335 ros::Timer update_timer_;
00336
00337
00338 ros::Timer vis_timer_;
00339
00340
00341 ros::Timer transform_pub_timer_;
00342
00343
00344 };
00345
00346
00347
00348
00349
00350
00351
00352 StringVec gridIndexes ()
00353 {
00354 StringVec fields;
00355 fields.push_back("id");
00356 return fields;
00357 }
00358
00359 Mapper::Mapper () :
00360
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
00370 update_flag_(true), next_edge_id_(1),
00371
00372
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
00397
00398
00399
00400
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
00423 if (!last_loc_)
00424 {
00425 ROS_INFO_THROTTLE (5.0, "Topological mapper waiting for "
00426 "initial localization");
00427 return;
00428 }
00429
00430
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
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
00466 BOOST_FOREACH (const unsigned g, currentRelevantGrids())
00467 updateEdgeInfo (g);
00468
00469
00470
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
00521 pair<tmap::GraphEdge, bool> res =
00522 edge(tmap_.node(g), tmap_.node(g2), tmap_);
00523 if (res.second)
00524 {
00525
00526
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
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
00582
00583
00584
00585
00586
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
00620
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
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
00656
00657
00658
00659
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
00751 omr::OcTreeROS octomap(resolution_);
00752
00753
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
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
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
00799 double x, y, minZ, maxZ;
00800 octree.getMetricMin(x, y, minZ);
00801 octree.getMetricMax(y, y, maxZ);
00802
00803
00804 m.markers.resize(octree.getTreeDepth());
00805 double lowestRes = octree.getResolution();
00806
00807
00808 for (om::OcTree::iterator it = octree.begin(),
00809 end = octree.end(); it != end; ++it)
00810 {
00811 if (octree.isNodeOccupied(*it))
00812 {
00813
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
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
00859
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
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 }
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 }