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 
00032 
00033 
00034 
00035 #ifndef NAV_GRID_PUB_SUB_NAV_GRID_PUBLISHER_H
00036 #define NAV_GRID_PUB_SUB_NAV_GRID_PUBLISHER_H
00037 
00038 #include <nav_grid_pub_sub/nav_grid_message_utils.h>
00039 #include <nav_grid_pub_sub/occ_grid_message_utils.h>
00040 #include <nav_grid_pub_sub/cost_interpretation.h>
00041 #include <nav_grid_pub_sub/cost_interpretation_tables.h>
00042 #include <ros/ros.h>
00043 #include <nav_grid/nav_grid.h>
00044 #include <nav_grid/coordinate_conversion.h>
00045 #include <nav_core2/bounds.h>
00046 #include <geometry_msgs/PolygonStamped.h>
00047 #include <limits>
00048 #include <string>
00049 #include <vector>
00050 
00051 namespace nav_grid_pub_sub
00052 {
00053 
00054 inline geometry_msgs::Point32 makePoint(const nav_grid::NavGridInfo& info, int x, int y)
00055 {
00056   double point_x = 0.0;
00057   double point_y = 0.0;
00058   gridToWorld(info, x, y, point_x, point_y);
00059   geometry_msgs::Point32 point;
00060   point.x = point_x;
00061   point.y = point_y;
00062   return point;
00063 }
00064 
00105 template<typename NumericType, typename NavGridOfX, typename NavGridOfXUpdate>
00106 class GenericGridPublisher
00107 {
00108 public:
00109   explicit GenericGridPublisher(nav_grid::NavGrid<NumericType>& data) : data_(data) {}
00110 
00127   void init(ros::NodeHandle& nh,
00128             const std::string& nav_grid_topic = "grid",
00129             const std::string& occupancy_grid_topic = "costmap",
00130             const std::string& update_area_topic = "update_area",
00131             bool publish_updates = true,
00132             ros::Duration full_publish_cycle = ros::Duration(0),
00133             ros::Duration update_publish_cycle = ros::Duration(0))
00134   {
00135     full_publish_cycle_ = full_publish_cycle;
00136     update_publish_cycle_ = update_publish_cycle;
00137     last_full_publish_ = ros::Time(0);
00138     last_update_publish_ = ros::Time(0);
00139     publish_updates_ = publish_updates;
00140 
00141     createPublishers<NavGridOfX, NavGridOfXUpdate>(
00142         nh, nav_grid_topic, boost::bind(&GenericGridPublisher::onNewSubscriptionNav, this, _1),
00143         nav_pub_, nav_update_pub_, publish_updates);
00144 
00145     createPublishers<nav_msgs::OccupancyGrid, map_msgs::OccupancyGridUpdate>(
00146         nh, occupancy_grid_topic, boost::bind(&GenericGridPublisher::onNewSubscriptionOcc, this, _1),
00147         occ_pub_, occ_update_pub_, publish_updates);
00148 
00149     if (update_area_topic.length() > 0)
00150     {
00151       update_area_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(update_area_topic, 1);
00152     }
00153   }
00154 
00158   void publish()
00159   {
00160     if (!shouldPublishFull()) return;
00161     last_full_publish_ = ros::Time::now();
00162     synced_time_stamp_ = last_full_publish_;
00163     publishNav();
00164     publishOcc();
00165   }
00166 
00174   void publish(const nav_core2::UIntBounds& bounds)
00175   {
00176     if (!publish_updates_)
00177     {
00178       
00179       publish();
00180       return;
00181     }
00182 
00183     update_bounds_.merge(bounds);
00184 
00185     if (!shouldPublishUpdate()) return;
00186 
00187     const nav_grid::NavGridInfo& info = data_.getInfo();
00188     last_update_publish_ = ros::Time::now();
00189     synced_time_stamp_ = last_update_publish_;
00190 
00191     if (saved_info_ != info)
00192     {
00193       
00194       saved_info_ = info;
00195       publishNav();
00196       publishOcc();
00197     }
00198     else if (!update_bounds_.isEmpty())
00199     {
00200       
00201       publishNavUpdate(update_bounds_);
00202       publishOccUpdate(update_bounds_);
00203     }
00204 
00205     
00206     publishUpdateArea(info, update_bounds_);
00207 
00208     update_bounds_.reset();
00209   }
00210 
00211 
00212 protected:
00213   template<class FullGridType, class UpdateType, class Callback>
00214   void createPublishers(ros::NodeHandle& nh, const std::string& topic, Callback new_subscription_callback,
00215                         ros::Publisher& full_grid_pub, ros::Publisher& update_pub, bool publish_updates)
00216   {
00217     if (topic.length() > 0)
00218     {
00219       full_grid_pub = nh.advertise<FullGridType>(topic, 1, new_subscription_callback);
00220       if (publish_updates)
00221       {
00222         update_pub = nh.advertise<UpdateType>(topic + "_updates", 1);
00223       }
00224     }
00225   }
00226 
00227   virtual nav_msgs::OccupancyGrid toOccupancyGrid(const ros::Time& timestamp) = 0;
00228   virtual map_msgs::OccupancyGridUpdate toOccupancyGridUpdate(const nav_core2::UIntBounds& bounds,
00229                                                               const ros::Time& timestamp) = 0;
00230 
00231   bool shouldPublishHelper(const ros::Time& last_publish, const ros::Duration& cycle) const
00232   {
00233     double cycle_secs = cycle.toSec();
00234     if (cycle_secs < 0.0)
00235     {
00236       return false;
00237     }
00238     else if (cycle_secs == 0.0)
00239     {
00240       return true;
00241     }
00242     else
00243     {
00244       return last_publish + cycle < ros::Time::now();
00245     }
00246   }
00247 
00248   inline bool shouldPublishFull() const
00249   {
00250     return shouldPublishHelper(last_full_publish_, full_publish_cycle_);
00251   }
00252 
00253   inline bool shouldPublishUpdate() const
00254   {
00255     return shouldPublishHelper(last_update_publish_, update_publish_cycle_);
00256   }
00257 
00258   void publishUpdateArea(const nav_grid::NavGridInfo& info, const nav_core2::UIntBounds& bounds)
00259   {
00260     if (update_area_pub_.getNumSubscribers() == 0) return;
00261 
00262     geometry_msgs::PolygonStamped polygon;
00263     polygon.header.frame_id = info.frame_id;
00264     polygon.header.stamp = synced_time_stamp_;
00265 
00266     if (!bounds.isEmpty())
00267     {
00268       polygon.polygon.points.push_back(makePoint(info, bounds.getMinX(), bounds.getMinY()));
00269       polygon.polygon.points.push_back(makePoint(info, bounds.getMaxX(), bounds.getMinY()));
00270       polygon.polygon.points.push_back(makePoint(info, bounds.getMaxX(), bounds.getMaxY()));
00271       polygon.polygon.points.push_back(makePoint(info, bounds.getMinX(), bounds.getMaxY()));
00272     }
00273     update_area_pub_.publish(polygon);
00274   }
00275 
00276   void onNewSubscriptionNav(const ros::SingleSubscriberPublisher& pub)
00277   {
00278     pub.publish(toMsg(data_, ros::Time::now()));
00279   }
00280 
00281   void onNewSubscriptionOcc(const ros::SingleSubscriberPublisher& pub)
00282   {
00283     pub.publish(toOccupancyGrid(ros::Time::now()));
00284   }
00285 
00286   void publishNav()
00287   {
00288     if (nav_pub_.getNumSubscribers() == 0) return;
00289     nav_pub_.publish(toMsg(data_, synced_time_stamp_));
00290   }
00291 
00292   void publishOcc()
00293   {
00294     if (occ_pub_.getNumSubscribers() == 0) return;
00295     occ_pub_.publish(toOccupancyGrid(synced_time_stamp_));
00296   }
00297 
00298   void publishNavUpdate(const nav_core2::UIntBounds& bounds)
00299   {
00300     if (nav_update_pub_.getNumSubscribers() == 0) return;
00301     nav_update_pub_.publish(nav_grid_pub_sub::toUpdate(data_, bounds, synced_time_stamp_));
00302   }
00303 
00304   void publishOccUpdate(const nav_core2::UIntBounds& bounds)
00305   {
00306     if (occ_update_pub_.getNumSubscribers() == 0) return;
00307     occ_update_pub_.publish(toOccupancyGridUpdate(bounds, synced_time_stamp_));
00308   }
00309 
00310   
00311   nav_grid::NavGrid<NumericType>& data_;
00312   nav_grid::NavGridInfo saved_info_;
00313   bool publish_updates_;
00314 
00315   
00316   ros::Duration full_publish_cycle_, update_publish_cycle_;
00317   ros::Time last_full_publish_, last_update_publish_, synced_time_stamp_;
00318 
00319   
00320   nav_core2::UIntBounds update_bounds_;
00321 
00322   
00323   ros::Publisher nav_pub_, nav_update_pub_,
00324                  occ_pub_, occ_update_pub_,
00325                  update_area_pub_;
00326 };
00327 
00334 class NavGridPublisher
00335   : public GenericGridPublisher<unsigned char, nav_2d_msgs::NavGridOfChars, nav_2d_msgs::NavGridOfCharsUpdate>
00336 {
00337 public:
00338   using GenericGridPublisher<unsigned char, nav_2d_msgs::NavGridOfChars, nav_2d_msgs::NavGridOfCharsUpdate>
00339         ::GenericGridPublisher;
00340 
00341   void setCostInterpretation(const std::vector<unsigned char>& cost_interpretation_table)
00342   {
00343     cost_interpretation_table_ = cost_interpretation_table;
00344   }
00345 protected:
00346   nav_msgs::OccupancyGrid toOccupancyGrid(const ros::Time& timestamp) override
00347   {
00348     return nav_grid_pub_sub::toOccupancyGrid(data_, timestamp, cost_interpretation_table_);
00349   }
00350 
00351   map_msgs::OccupancyGridUpdate toOccupancyGridUpdate(const nav_core2::UIntBounds& bounds,
00352                                                       const ros::Time& timestamp) override
00353   {
00354     return nav_grid_pub_sub::toOccupancyGridUpdate(data_, bounds, timestamp, cost_interpretation_table_);
00355   }
00356   std::vector<unsigned char> cost_interpretation_table_ { OCC_GRID_PUBLISHING };
00357 };
00358 
00363 template<typename NumericType>
00364 class ScaleGridPublisher
00365   : public GenericGridPublisher<NumericType, nav_2d_msgs::NavGridOfDoubles, nav_2d_msgs::NavGridOfDoublesUpdate>
00366 {
00367 public:
00368   using GenericGridPublisher<NumericType, nav_2d_msgs::NavGridOfDoubles, nav_2d_msgs::NavGridOfDoublesUpdate>
00369         ::GenericGridPublisher;
00370 
00371   void setIgnoreValue(NumericType ignore_value) { ignore_value_ = ignore_value; }
00372 
00373 protected:
00374   nav_msgs::OccupancyGrid toOccupancyGrid(const ros::Time& timestamp) override
00375   {
00376     nav_grid_pub_sub::getExtremeValues(this->data_, ignore_value_, min_val_, max_val_);
00377     return nav_grid_pub_sub::toOccupancyGrid(this->data_, min_val_, max_val_, ignore_value_, timestamp);
00378   }
00379 
00380   map_msgs::OccupancyGridUpdate toOccupancyGridUpdate(const nav_core2::UIntBounds& bounds,
00381                                                       const ros::Time& timestamp) override
00382   {
00383     return nav_grid_pub_sub::toOccupancyGridUpdate(this->data_, bounds, min_val_, max_val_, ignore_value_, timestamp);
00384   }
00385 
00386   NumericType ignore_value_ { std::numeric_limits<NumericType>::max() };
00387   NumericType min_val_, max_val_;
00388 };
00389 
00390 
00391 }  
00392 
00393 #endif  // NAV_GRID_PUB_SUB_NAV_GRID_PUBLISHER_H