costmap_3d.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2014-2018, the neonavigation authors
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 copyright holder 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 #include <ros/ros.h>
00031 #include <geometry_msgs/PolygonStamped.h>
00032 #include <nav_msgs/OccupancyGrid.h>
00033 #include <sensor_msgs/PointCloud.h>
00034 
00035 #include <string>
00036 #include <utility>
00037 #include <vector>
00038 
00039 #include <costmap_cspace_msgs/CSpace3D.h>
00040 #include <costmap_cspace_msgs/CSpace3DUpdate.h>
00041 
00042 #include <costmap_cspace/costmap_3d.h>
00043 #include <neonavigation_common/compatibility.h>
00044 
00045 class Costmap3DOFNode
00046 {
00047 protected:
00048   ros::NodeHandle nh_;
00049   ros::NodeHandle pnh_;
00050   ros::Subscriber sub_map_;
00051   std::vector<ros::Subscriber> sub_map_overlay_;
00052   ros::Publisher pub_costmap_;
00053   ros::Publisher pub_costmap_update_;
00054   ros::Publisher pub_footprint_;
00055   ros::Publisher pub_debug_;
00056   ros::Timer timer_footprint_;
00057 
00058   costmap_cspace::Costmap3d::Ptr costmap_;
00059   std::vector<
00060       std::pair<nav_msgs::OccupancyGrid::ConstPtr,
00061                 costmap_cspace::Costmap3dLayerBase::Ptr>> map_buffer_;
00062 
00063   void cbMap(
00064       const nav_msgs::OccupancyGrid::ConstPtr& msg,
00065       const costmap_cspace::Costmap3dLayerBase::Ptr map)
00066   {
00067     if (map->getAngularGrid() <= 0)
00068     {
00069       ROS_ERROR("ang_resolution is not set.");
00070       std::runtime_error("ang_resolution is not set.");
00071     }
00072     ROS_INFO("2D costmap received");
00073 
00074     map->setBaseMap(msg);
00075     ROS_DEBUG("C-Space costmap generated");
00076 
00077     if (map_buffer_.size() > 0)
00078     {
00079       for (auto& map : map_buffer_)
00080         cbMapOverlay(map.first, map.second);
00081       ROS_INFO("%ld buffered costmaps processed", map_buffer_.size());
00082       map_buffer_.clear();
00083     }
00084   }
00085   void cbMapOverlay(
00086       const nav_msgs::OccupancyGrid::ConstPtr& msg,
00087       const costmap_cspace::Costmap3dLayerBase::Ptr map)
00088   {
00089     ROS_DEBUG("Overlay 2D costmap received");
00090 
00091     auto map_msg = map->getMap();
00092     if (map_msg->info.width < 1 ||
00093         map_msg->info.height < 1)
00094     {
00095       map_buffer_.push_back(
00096           std::pair<nav_msgs::OccupancyGrid::ConstPtr,
00097                     costmap_cspace::Costmap3dLayerBase::Ptr>(msg, map));
00098       return;
00099     }
00100 
00101     map->processMapOverlay(msg);
00102     ROS_DEBUG("C-Space costmap updated");
00103   }
00104   bool cbUpdateStatic(
00105       const costmap_cspace::CSpace3DMsg::Ptr map,
00106       const costmap_cspace_msgs::CSpace3DUpdate::Ptr update)
00107   {
00108     publishDebug(*map);
00109     pub_costmap_.publish<costmap_cspace_msgs::CSpace3D>(*map);
00110     return true;
00111   }
00112   bool cbUpdate(
00113       const costmap_cspace::CSpace3DMsg::Ptr map,
00114       const costmap_cspace_msgs::CSpace3DUpdate::Ptr update)
00115   {
00116     publishDebug(*map);
00117     pub_costmap_update_.publish(*update);
00118     return true;
00119   }
00120   void publishDebug(const costmap_cspace_msgs::CSpace3D& map)
00121   {
00122     if (pub_debug_.getNumSubscribers() == 0)
00123       return;
00124     sensor_msgs::PointCloud pc;
00125     pc.header = map.header;
00126     pc.header.stamp = ros::Time::now();
00127     for (size_t yaw = 0; yaw < map.info.angle; yaw++)
00128     {
00129       for (unsigned int i = 0; i < map.info.width * map.info.height; i++)
00130       {
00131         int gx = i % map.info.width;
00132         int gy = i / map.info.width;
00133         if (map.data[i + yaw * map.info.width * map.info.height] < 100)
00134           continue;
00135         geometry_msgs::Point32 p;
00136         p.x = gx * map.info.linear_resolution + map.info.origin.position.x;
00137         p.y = gy * map.info.linear_resolution + map.info.origin.position.y;
00138         p.z = yaw * 0.1;
00139         pc.points.push_back(p);
00140       }
00141     }
00142     pub_debug_.publish(pc);
00143   }
00144   void cbPublishFootprint(const ros::TimerEvent& event, const geometry_msgs::PolygonStamped msg)
00145   {
00146     auto footprint = msg;
00147     footprint.header.stamp = ros::Time::now();
00148     pub_footprint_.publish(footprint);
00149   }
00150 
00151   static costmap_cspace::MapOverlayMode getMapOverlayModeFromString(
00152       const std::string overlay_mode_str)
00153   {
00154     if (overlay_mode_str == "overwrite")
00155     {
00156       return costmap_cspace::MapOverlayMode::OVERWRITE;
00157     }
00158     else if (overlay_mode_str == "max")
00159     {
00160       return costmap_cspace::MapOverlayMode::MAX;
00161     }
00162     ROS_FATAL("Unknown overlay_mode \"%s\"", overlay_mode_str.c_str());
00163     throw std::runtime_error("Unknown overlay_mode.");
00164   };
00165 
00166 public:
00167   Costmap3DOFNode()
00168     : nh_()
00169     , pnh_("~")
00170   {
00171     neonavigation_common::compat::checkCompatMode();
00172     pub_costmap_ = neonavigation_common::compat::advertise<costmap_cspace_msgs::CSpace3D>(
00173         nh_, "costmap",
00174         pnh_, "costmap", 1, true);
00175     pub_costmap_update_ = neonavigation_common::compat::advertise<costmap_cspace_msgs::CSpace3DUpdate>(
00176         nh_, "costmap_update",
00177         pnh_, "costmap_update", 1, true);
00178     pub_footprint_ = pnh_.advertise<geometry_msgs::PolygonStamped>("footprint", 2, true);
00179     pub_debug_ = pnh_.advertise<sensor_msgs::PointCloud>("debug", 1, true);
00180 
00181     int ang_resolution;
00182     pnh_.param("ang_resolution", ang_resolution, 16);
00183 
00184     XmlRpc::XmlRpcValue footprint_xml;
00185     if (!pnh_.hasParam("footprint"))
00186     {
00187       ROS_FATAL("Footprint doesn't specified");
00188       throw std::runtime_error("Footprint doesn't specified.");
00189     }
00190     pnh_.getParam("footprint", footprint_xml);
00191     costmap_cspace::Polygon footprint;
00192     try
00193     {
00194       footprint = costmap_cspace::Polygon(footprint_xml);
00195     }
00196     catch (const std::exception& e)
00197     {
00198       ROS_FATAL("Invalid footprint");
00199       throw e;
00200     }
00201 
00202     costmap_.reset(new costmap_cspace::Costmap3d(ang_resolution));
00203 
00204     auto root_layer = costmap_->addRootLayer<costmap_cspace::Costmap3dLayerFootprint>();
00205     float linear_expand;
00206     float linear_spread;
00207     pnh_.param("linear_expand", linear_expand, 0.2f);
00208     pnh_.param("linear_spread", linear_spread, 0.5f);
00209     root_layer->setExpansion(linear_expand, linear_spread);
00210     root_layer->setFootprint(footprint);
00211 
00212     if (pnh_.hasParam("static_layers"))
00213     {
00214       XmlRpc::XmlRpcValue layers_xml;
00215       pnh_.getParam("static_layers", layers_xml);
00216 
00217       if (layers_xml.getType() != XmlRpc::XmlRpcValue::TypeArray || layers_xml.size() < 1)
00218       {
00219         ROS_FATAL("static_layers parameter must contain at least one layer config.");
00220         ROS_ERROR(
00221             "Migration from old version:\n"
00222             "---  # Old\n"
00223             "static_layers:\n"
00224             "  YOUR_LAYER_NAME:\n"
00225             "    type: LAYER_TYPE\n"
00226             "    parameters: values\n"
00227             "---  # New\n"
00228             "static_layers:\n"
00229             "  - name: YOUR_LAYER_NAME\n"
00230             "    type: LAYER_TYPE\n"
00231             "    parameters: values\n"
00232             "---\n");
00233         throw std::runtime_error("layers parameter must contain at least one layer config.");
00234       }
00235       for (int i = 0; i < layers_xml.size(); ++i)
00236       {
00237         auto layer_xml = std::pair<std::string, XmlRpc::XmlRpcValue>(
00238             layers_xml[i]["name"], layers_xml[i]);
00239         ROS_INFO("New static layer: %s", layer_xml.first.c_str());
00240 
00241         costmap_cspace::MapOverlayMode overlay_mode(costmap_cspace::MapOverlayMode::MAX);
00242         if (layer_xml.second["overlay_mode"].getType() == XmlRpc::XmlRpcValue::TypeString)
00243           overlay_mode = getMapOverlayModeFromString(
00244               layer_xml.second["overlay_mode"]);
00245         else
00246           ROS_WARN("overlay_mode of the static layer is not specified. Using MAX mode.");
00247 
00248         std::string type;
00249         if (layer_xml.second["type"].getType() == XmlRpc::XmlRpcValue::TypeString)
00250           type = std::string(layer_xml.second["type"]);
00251         else
00252         {
00253           ROS_FATAL("Layer type is not specified.");
00254           throw std::runtime_error("Layer type is not specified.");
00255         }
00256 
00257         if (!layer_xml.second.hasMember("footprint"))
00258           layer_xml.second["footprint"] = footprint_xml;
00259 
00260         costmap_cspace::Costmap3dLayerBase::Ptr layer =
00261             costmap_cspace::Costmap3dLayerClassLoader::loadClass(type);
00262         costmap_->addLayer(layer, overlay_mode);
00263         layer->loadConfig(layer_xml.second);
00264 
00265         sub_map_overlay_.push_back(nh_.subscribe<nav_msgs::OccupancyGrid>(
00266             layer_xml.first, 1,
00267             boost::bind(&Costmap3DOFNode::cbMapOverlay, this, _1, layer)));
00268       }
00269     }
00270 
00271     auto static_output_layer = costmap_->addLayer<costmap_cspace::Costmap3dLayerOutput>();
00272     static_output_layer->setHandler(boost::bind(&Costmap3DOFNode::cbUpdateStatic, this, _1, _2));
00273 
00274     sub_map_ = nh_.subscribe<nav_msgs::OccupancyGrid>(
00275         "map", 1,
00276         boost::bind(&Costmap3DOFNode::cbMap, this, _1, root_layer));
00277 
00278     if (pnh_.hasParam("layers"))
00279     {
00280       XmlRpc::XmlRpcValue layers_xml;
00281       pnh_.getParam("layers", layers_xml);
00282 
00283       if (layers_xml.getType() != XmlRpc::XmlRpcValue::TypeArray || layers_xml.size() < 1)
00284       {
00285         ROS_FATAL("layers parameter must contain at least one layer config.");
00286         ROS_ERROR(
00287             "Migration from old version:\n"
00288             "---  # Old\n"
00289             "layers:\n"
00290             "  YOUR_LAYER_NAME:\n"
00291             "    type: LAYER_TYPE\n"
00292             "    parameters: values\n"
00293             "---  # New\n"
00294             "layers:\n"
00295             "  - name: YOUR_LAYER_NAME\n"
00296             "    type: LAYER_TYPE\n"
00297             "    parameters: values\n"
00298             "---\n");
00299         throw std::runtime_error("layers parameter must contain at least one layer config.");
00300       }
00301       for (int i = 0; i < layers_xml.size(); ++i)
00302       {
00303         auto layer_xml = std::pair<std::string, XmlRpc::XmlRpcValue>(
00304             layers_xml[i]["name"], layers_xml[i]);
00305         ROS_INFO("New layer: %s", layer_xml.first.c_str());
00306 
00307         costmap_cspace::MapOverlayMode overlay_mode(costmap_cspace::MapOverlayMode::MAX);
00308         if (layer_xml.second["overlay_mode"].getType() == XmlRpc::XmlRpcValue::TypeString)
00309           overlay_mode = getMapOverlayModeFromString(
00310               layer_xml.second["overlay_mode"]);
00311         else
00312           ROS_WARN("overlay_mode of the layer is not specified. Using MAX mode.");
00313 
00314         std::string type;
00315         if (layer_xml.second["type"].getType() == XmlRpc::XmlRpcValue::TypeString)
00316           type = std::string(layer_xml.second["type"]);
00317         else
00318         {
00319           ROS_FATAL("Layer type is not specified.");
00320           throw std::runtime_error("Layer type is not specified.");
00321         }
00322 
00323         if (!layer_xml.second.hasMember("footprint"))
00324           layer_xml.second["footprint"] = footprint_xml;
00325 
00326         costmap_cspace::Costmap3dLayerBase::Ptr layer =
00327             costmap_cspace::Costmap3dLayerClassLoader::loadClass(type);
00328         costmap_->addLayer(layer, overlay_mode);
00329         layer->loadConfig(layer_xml.second);
00330 
00331         sub_map_overlay_.push_back(nh_.subscribe<nav_msgs::OccupancyGrid>(
00332             layer_xml.first, 1,
00333             boost::bind(&Costmap3DOFNode::cbMapOverlay, this, _1, layer)));
00334       }
00335     }
00336     else
00337     {
00338       // Single layer mode for backward-compatibility
00339       costmap_cspace::MapOverlayMode overlay_mode;
00340       std::string overlay_mode_str;
00341       pnh_.param("overlay_mode", overlay_mode_str, std::string("max"));
00342       if (overlay_mode_str.compare("overwrite") == 0)
00343         overlay_mode = costmap_cspace::MapOverlayMode::OVERWRITE;
00344       else if (overlay_mode_str.compare("max") == 0)
00345         overlay_mode = costmap_cspace::MapOverlayMode::MAX;
00346       else
00347       {
00348         ROS_FATAL("Unknown overlay_mode \"%s\"", overlay_mode_str.c_str());
00349         throw std::runtime_error("Unknown overlay_mode.");
00350       }
00351       ROS_INFO("costmap_3d: %s mode", overlay_mode_str.c_str());
00352 
00353       XmlRpc::XmlRpcValue layer_xml;
00354       layer_xml["footprint"] = footprint_xml;
00355       layer_xml["linear_expand"] = linear_expand;
00356       layer_xml["linear_spread"] = linear_spread;
00357 
00358       auto layer = costmap_->addLayer<costmap_cspace::Costmap3dLayerFootprint>(overlay_mode);
00359       layer->loadConfig(layer_xml);
00360       sub_map_overlay_.push_back(nh_.subscribe<nav_msgs::OccupancyGrid>(
00361           "map_overlay", 1,
00362           boost::bind(&Costmap3DOFNode::cbMapOverlay, this, _1, layer)));
00363     }
00364 
00365     auto update_output_layer = costmap_->addLayer<costmap_cspace::Costmap3dLayerOutput>();
00366     update_output_layer->setHandler(boost::bind(&Costmap3DOFNode::cbUpdate, this, _1, _2));
00367 
00368     const geometry_msgs::PolygonStamped footprint_msg = footprint.toMsg();
00369     timer_footprint_ = nh_.createTimer(
00370         ros::Duration(1.0),
00371         boost::bind(&Costmap3DOFNode::cbPublishFootprint, this, _1, footprint_msg));
00372   }
00373 };
00374 
00375 int main(int argc, char* argv[])
00376 {
00377   ros::init(argc, argv, "costmap_3d");
00378 
00379   Costmap3DOFNode cm;
00380   ros::spin();
00381 
00382   return 0;
00383 }


costmap_cspace
Author(s): Atsushi Watanabe
autogenerated on Sat Jun 22 2019 20:07:13