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 #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
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 }