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