nav_grid_publisher.h
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2018, Locus Robotics
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the copyright holder nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
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 // Helper function: needs temp double variables for conversion, then made into floats for Point32
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       // Don't publish an update, publish the full grid if enough time has passed
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       // If the info has changed, force publish the whole grid
00194       saved_info_ = info;
00195       publishNav();
00196       publishOcc();
00197     }
00198     else if (!update_bounds_.isEmpty())
00199     {
00200       // If actual data was updated, publish the updates
00201       publishNavUpdate(update_bounds_);
00202       publishOccUpdate(update_bounds_);
00203     }
00204 
00205     // Publish the update area (or an empty polygon message if there was no update)
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   // Data
00311   nav_grid::NavGrid<NumericType>& data_;
00312   nav_grid::NavGridInfo saved_info_;
00313   bool publish_updates_;
00314 
00315   // Track time
00316   ros::Duration full_publish_cycle_, update_publish_cycle_;
00317   ros::Time last_full_publish_, last_update_publish_, synced_time_stamp_;
00318 
00319   // Track Update Bounds
00320   nav_core2::UIntBounds update_bounds_;
00321 
00322   // Publishers
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 }  // namespace nav_grid_pub_sub
00392 
00393 #endif  // NAV_GRID_PUB_SUB_NAV_GRID_PUBLISHER_H


nav_grid_pub_sub
Author(s):
autogenerated on Wed Jun 26 2019 20:09:52