00001
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
00036
00037
00038 #include <octomap_server/OctomapServerCombined.h>
00039
00040 namespace octomap{
00041
00042 OctomapServerCombined::OctomapServerCombined(const std::string& filename)
00043 : m_nh(),
00044 m_pointCloudSub(NULL), m_tfPointCloudSub(NULL),
00045 m_octoMap(0.05),
00046 m_maxRange(-1.0),
00047 m_worldFrameId("/map"), m_baseFrameId("base_footprint"),
00048 m_useHeightMap(true),
00049 m_colorFactor(0.8),
00050 m_pointcloudMinZ(-std::numeric_limits<double>::max()),
00051 m_pointcloudMaxZ(std::numeric_limits<double>::max()),
00052 m_occupancyMinZ(-std::numeric_limits<double>::max()),
00053 m_occupancyMaxZ(std::numeric_limits<double>::max()),
00054 m_minSizeX(0.0), m_minSizeY(0.0),
00055 m_filterSpeckles(false), m_filterGroundPlane(true),
00056 m_groundFilterDistance(0.04), m_groundFilterAngle(0.15), m_groundFilterPlaneDistance(0.07)
00057 {
00058 ros::NodeHandle private_nh("~");
00059 private_nh.param("frame_id", m_worldFrameId, m_worldFrameId);
00060 private_nh.param("base_frame_id", m_baseFrameId, m_baseFrameId);
00061 private_nh.param("height_map", m_useHeightMap, m_useHeightMap);
00062 private_nh.param("color_factor", m_colorFactor, m_colorFactor);
00063
00064 private_nh.param("pointcloud_min_z", m_pointcloudMinZ,m_pointcloudMinZ);
00065 private_nh.param("pointcloud_max_z", m_pointcloudMaxZ,m_pointcloudMaxZ);
00066 private_nh.param("occupancy_min_z", m_occupancyMinZ,m_occupancyMinZ);
00067 private_nh.param("occupancy_max_z", m_occupancyMaxZ,m_occupancyMaxZ);
00068 private_nh.param("min_x_size", m_minSizeX,m_minSizeX);
00069 private_nh.param("min_y_size", m_minSizeY,m_minSizeY);
00070
00071 private_nh.param("filter_speckles", m_filterSpeckles, m_filterSpeckles);
00072 private_nh.param("filter_ground", m_filterGroundPlane, m_filterGroundPlane);
00073
00074 private_nh.param("ground_filter/distance", m_groundFilterDistance, m_groundFilterDistance);
00075
00076 private_nh.param("ground_filter/angle", m_groundFilterAngle, m_groundFilterAngle);
00077
00078 private_nh.param("ground_filter/plane_distance", m_groundFilterPlaneDistance, m_groundFilterPlaneDistance);
00079
00080 double res = 0.05;
00081 private_nh.param("resolution", res, res);
00082 m_octoMap.octree.setResolution(res);
00083
00084 private_nh.param("sensor_model/max_range", m_maxRange, m_maxRange);
00085
00086 double probHit = 0.7;
00087 double probMiss = 0.4;
00088 double thresMin = 0.12;
00089 double thresMax = 0.97;
00090 private_nh.param("sensor_model/hit", probHit, probHit);
00091 private_nh.param("sensor_model/miss", probMiss, probMiss);
00092 private_nh.param("sensor_model/min", thresMin, thresMin);
00093 private_nh.param("sensor_model/max", thresMax, thresMax);
00094 m_octoMap.octree.setProbHit(probHit);
00095 m_octoMap.octree.setProbMiss(probMiss);
00096 m_octoMap.octree.setClampingThresMin(thresMin);
00097 m_octoMap.octree.setClampingThresMax(thresMax);
00098
00099 double r, g, b, a;
00100 private_nh.param("color/r", r, 0.0);
00101 private_nh.param("color/g", g, 0.0);
00102 private_nh.param("color/b", b, 1.0);
00103 private_nh.param("color/a", a, 1.0);
00104 m_color.r = r;
00105 m_color.g = g;
00106 m_color.b = b;
00107 m_color.a = a;
00108
00109 bool staticMap = false;
00110 if (filename != "")
00111 staticMap = true;
00112
00113 m_markerPub = m_nh.advertise<visualization_msgs::MarkerArray>("occupied_cells_vis_array", 1, staticMap);
00114 m_binaryMapPub = m_nh.advertise<octomap_ros::OctomapBinary>("octomap_binary", 1, staticMap);
00115 m_pointCloudPub = m_nh.advertise<sensor_msgs::PointCloud2>("octomap_point_cloud_centers", 1, staticMap);
00116 m_collisionObjectPub = m_nh.advertise<mapping_msgs::CollisionObject>("octomap_collision_object", 1, staticMap);
00117 m_mapPub = m_nh.advertise<nav_msgs::OccupancyGrid>("map", 5, staticMap);
00118
00119 m_service = m_nh.advertiseService("octomap_binary", &OctomapServerCombined::serviceCallback, this);
00120
00121
00122 if (staticMap){
00123 if (m_octoMap.octree.readBinary(filename)){
00124 ROS_INFO("Octomap file %s loaded (%zu nodes).", filename.c_str(),m_octoMap.octree.size());
00125
00126 publishAll();
00127 } else{
00128 ROS_ERROR("Could not open requested file %s, exiting.", filename.c_str());
00129 exit(-1);
00130 }
00131 } else {
00132
00133
00134
00135 m_pointCloudSub = new message_filters::Subscriber<sensor_msgs::PointCloud2> (m_nh, "cloud_in", 5);
00136 m_tfPointCloudSub = new tf::MessageFilter<sensor_msgs::PointCloud2> (*m_pointCloudSub, m_tfListener, m_worldFrameId, 5);
00137 m_tfPointCloudSub->registerCallback(boost::bind(&OctomapServerCombined::insertCloudCallback, this, _1));
00138 }
00139
00140
00141
00142 }
00143
00144 OctomapServerCombined::~OctomapServerCombined(){
00145 if (m_tfPointCloudSub)
00146 delete m_tfPointCloudSub;
00147 if (m_pointCloudSub)
00148 delete m_pointCloudSub;
00149
00150 }
00151
00152 void OctomapServerCombined::insertCloudCallback(const sensor_msgs::PointCloud2::ConstPtr& cloud){
00153 ros::WallTime startTime = ros::WallTime::now();
00154
00155
00156
00157
00158
00159 pcl::PointCloud<pcl::PointXYZ> pc;
00160 pcl::fromROSMsg(*cloud, pc);
00161
00162 tf::StampedTransform sensorToWorldTf, sensorToBaseTf, baseToWorldTf;
00163 try {
00164 m_tfListener.waitForTransform(m_worldFrameId, cloud->header.frame_id, cloud->header.stamp, ros::Duration(0.2));
00165
00166 m_tfListener.lookupTransform(m_worldFrameId, cloud->header.frame_id, cloud->header.stamp, sensorToWorldTf);
00167 m_tfListener.lookupTransform(m_baseFrameId, cloud->header.frame_id, cloud->header.stamp, sensorToBaseTf);
00168 m_tfListener.lookupTransform(m_worldFrameId, m_baseFrameId, cloud->header.stamp, baseToWorldTf);
00169 } catch(tf::TransformException& ex){
00170 ROS_ERROR_STREAM( "Transform error: " << ex.what() << ", quitting callback");
00171 return;
00172 }
00173 point3d sensorOrigin = pointTfToOctomap(sensorToWorldTf.getOrigin());
00174 Eigen::Matrix4f sensorToBase, baseToWorld;
00175 pcl_ros::transformAsMatrix(sensorToBaseTf, sensorToBase);
00176 pcl_ros::transformAsMatrix(baseToWorldTf, baseToWorld);
00177
00178
00179 pcl::transformPointCloud(pc, pc, sensorToBase);
00180
00181
00182 pcl::PassThrough<pcl::PointXYZ> pass;
00183 pass.setFilterFieldName("z");
00184 pass.setFilterLimits(m_pointcloudMinZ, m_pointcloudMaxZ);
00185 pass.setInputCloud(pc.makeShared());
00186 pass.filter(pc);
00187
00188 pcl::PointCloud<pcl::PointXYZ> pc_ground;
00189 pcl::PointCloud<pcl::PointXYZ> pc_nonground;
00190 pc_ground.header = pc.header;
00191 pc_nonground.header = pc.header;
00192
00193 if (m_filterGroundPlane){
00194 if (pc.size() < 50){
00195 ROS_WARN("Pointcloud in OctomapServerCombined too small, skipping ground plane extraction");
00196 pc_nonground = pc;
00197 } else {
00198
00199 pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00200 pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00201
00202
00203 pcl::SACSegmentation<pcl::PointXYZ> seg;
00204 seg.setOptimizeCoefficients (true);
00205
00206 seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE);
00207 seg.setMethodType(pcl::SAC_RANSAC);
00208 seg.setMaxIterations(200);
00209 seg.setDistanceThreshold (m_groundFilterDistance);
00210 seg.setAxis(Eigen::Vector3f(0,0,1));
00211 seg.setEpsAngle(m_groundFilterAngle);
00212
00213
00214 pcl::PointCloud<pcl::PointXYZ> cloud_filtered(pc);
00215
00216 pcl::ExtractIndices<pcl::PointXYZ> extract;
00217 bool groundPlaneFound = false;
00218
00219 while(cloud_filtered.size() > 10 && !groundPlaneFound){
00220 seg.setInputCloud(cloud_filtered.makeShared());
00221 seg.segment (*inliers, *coefficients);
00222 if (inliers->indices.size () == 0){
00223 ROS_WARN("No plane found in cloud.");
00224
00225 break;
00226 }
00227
00228 extract.setInputCloud(cloud_filtered.makeShared());
00229 extract.setIndices(inliers);
00230
00231 if (std::abs(coefficients->values.at(3)) < m_groundFilterPlaneDistance){
00232 ROS_DEBUG("Ground plane found: %zu/%zu inliers. Coeff: %f %f %f %f", inliers->indices.size(), cloud_filtered.size(),
00233 coefficients->values.at(0), coefficients->values.at(1), coefficients->values.at(2), coefficients->values.at(3));
00234 extract.setNegative (false);
00235 extract.filter (pc_ground);
00236
00237
00238
00239 if(inliers->indices.size() != cloud_filtered.size()){
00240 extract.setNegative(true);
00241 pcl::PointCloud<pcl::PointXYZ> cloud_out;
00242 extract.filter(cloud_out);
00243 pc_nonground += cloud_out;
00244 cloud_filtered = cloud_out;
00245 }
00246
00247 groundPlaneFound = true;
00248 } else{
00249 ROS_DEBUG("Horizontal plane (not ground) found: %zu/%zu inliers. Coeff: %f %f %f %f", inliers->indices.size(), cloud_filtered.size(),
00250 coefficients->values.at(0), coefficients->values.at(1), coefficients->values.at(2), coefficients->values.at(3));
00251 pcl::PointCloud<pcl::PointXYZ> cloud_out;
00252 extract.setNegative (false);
00253 extract.filter(cloud_out);
00254 pc_nonground +=cloud_out;
00255
00256
00257
00258
00259
00260
00261 if(inliers->indices.size() != cloud_filtered.size()){
00262 extract.setNegative(true);
00263 cloud_out.points.clear();
00264 extract.filter(cloud_out);
00265 cloud_filtered = cloud_out;
00266 } else{
00267 cloud_filtered.points.clear();
00268 }
00269 }
00270
00271 }
00272 if (!groundPlaneFound){
00273 ROS_WARN("No ground plane found in scan");
00274 pc_nonground += cloud_filtered;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284 }
00285 } else {
00286 pc_nonground = pc;
00287 }
00288
00289
00290 pcl::transformPointCloud(pc_ground, pc_ground, baseToWorld);
00291 pcl::transformPointCloud(pc_nonground, pc_nonground, baseToWorld);
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 KeySet free_cells, occupied_cells;
00305
00306 for (pcl::PointCloud<pcl::PointXYZ>::const_iterator it = pc_ground.begin(); it != pc_ground.end(); ++it){
00307 point3d point(it->x, it->y, it->z);
00308
00309 if ((m_maxRange > 0.0) && ((point - sensorOrigin).norm() > m_maxRange) ) {
00310 point = sensorOrigin + (point - sensorOrigin).normalized() * m_maxRange;
00311 }
00312
00313
00314 if (m_octoMap.octree.computeRayKeys(sensorOrigin, point, m_keyRay)){
00315 free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00316 }
00317 }
00318
00319
00320 for (pcl::PointCloud<pcl::PointXYZ>::const_iterator it = pc_nonground.begin(); it != pc_nonground.end(); ++it){
00321 point3d point(it->x, it->y, it->z);
00322
00323 if ((m_maxRange < 0.0) || ((point - sensorOrigin).norm() <= m_maxRange) ) {
00324
00325
00326 if (m_octoMap.octree.computeRayKeys(sensorOrigin, point, m_keyRay)){
00327 free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00328 }
00329
00330 OcTreeKey key;
00331 if (m_octoMap.octree.genKey(point, key)){
00332 occupied_cells.insert(key);
00333 }
00334 } else {
00335 point3d new_end = sensorOrigin + (point - sensorOrigin).normalized() * m_maxRange;
00336 if (m_octoMap.octree.computeRayKeys(sensorOrigin, new_end, m_keyRay)){
00337 free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00338 }
00339 }
00340 }
00341
00342
00343 for(KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ++it){
00344 if (occupied_cells.find(*it) == occupied_cells.end()){
00345 m_octoMap.octree.updateNode(*it, false, true);
00346 }
00347 }
00348
00349
00350 for (KeySet::iterator it = occupied_cells.begin(), end=free_cells.end(); it!= end; it++) {
00351 m_octoMap.octree.updateNode(*it, true, true);
00352 }
00353 m_octoMap.octree.updateInnerOccupancy();
00354 m_octoMap.octree.prune();
00355
00356 double total_elapsed = (ros::WallTime::now() - startTime).toSec();
00357 ROS_DEBUG("Pointcloud insertion in OctomapServer done (%d+%d pts (ground/nonground), %f sec)", int(pc_ground.size()), int(pc_nonground.size()), total_elapsed);
00358
00359 publishAll(cloud->header.stamp);
00360 }
00361
00362
00363 void OctomapServerCombined::publishAll(const ros::Time& rostime){
00364 ros::WallTime startTime = ros::WallTime::now();
00365
00366 if (m_octoMap.octree.size() <= 1){
00367 ROS_WARN("Nothing to publish, octree is empty");
00368 return;
00369 }
00370
00371 bool publishCollisionObject = true;
00372 bool publishMarkerArray = true;
00373 bool publishPointCloud = true;
00374 bool publish2DMap = true;
00375
00376
00377 mapping_msgs::CollisionObject collisionObject;
00378 collisionObject.header.frame_id = m_worldFrameId;
00379 collisionObject.header.stamp = rostime;
00380 collisionObject.id = "map";
00381
00382 geometric_shapes_msgs::Shape shape;
00383 shape.type = geometric_shapes_msgs::Shape::BOX;
00384 shape.dimensions.resize(3);
00385
00386 geometry_msgs::Pose pose;
00387 pose.orientation = tf::createQuaternionMsgFromYaw(0.0);
00388
00389
00390 double minX, minY, minZ, maxX, maxY, maxZ;
00391 m_octoMap.octree.getMetricMin(minX, minY, minZ);
00392 m_octoMap.octree.getMetricMax(maxX, maxY, maxZ);
00393
00394 visualization_msgs::MarkerArray occupiedNodesVis;
00395
00396 occupiedNodesVis.markers.resize(m_octoMap.octree.getTreeDepth());
00397 double lowestRes = m_octoMap.octree.getResolution();
00398
00399
00400 pcl::PointCloud<pcl::PointXYZ> pclCloud;
00401
00402
00403 nav_msgs::OccupancyGrid map;
00404 map.info.resolution = m_octoMap.octree.getResolution();
00405 map.header.frame_id = m_worldFrameId;
00406 map.header.stamp = rostime;
00407
00408 octomap::point3d minPt(minX, minY, minZ);
00409 octomap::point3d maxPt(maxX, maxY, maxZ);
00410 octomap::OcTreeKey minKey, maxKey, curKey;
00411 if (!m_octoMap.octree.genKey(minPt, minKey)){
00412 ROS_ERROR("Could not create min OcTree key at %f %f %f", minPt.x(), minPt.y(), minPt.z());
00413 return;
00414 }
00415 if (!m_octoMap.octree.genKey(maxPt, maxKey)){
00416 ROS_ERROR("Could not create max OcTree key at %f %f %f", maxPt.x(), maxPt.y(), maxPt.z());
00417 return;
00418 }
00419
00420 ROS_DEBUG("MinKey: %d %d %d / MaxKey: %d %d %d", minKey[0], minKey[1], minKey[2], maxKey[0], maxKey[1], maxKey[2]);
00421
00422
00423 double halfPaddedX = 0.5*m_minSizeX;
00424 double halfPaddedY = 0.5*m_minSizeY;
00425 minX = std::min(minX, -halfPaddedX);
00426 maxX = std::max(maxX, halfPaddedX);
00427 minY = std::min(minY, -halfPaddedY);
00428 maxY = std::max(maxY, halfPaddedY);
00429 minPt = octomap::point3d(minX, minY, minZ);
00430 maxPt = octomap::point3d(maxX, maxY, maxZ);
00431
00432 octomap::OcTreeKey paddedMinKey, paddedMaxKey;
00433 if (!m_octoMap.octree.genKey(minPt, paddedMinKey)){
00434 ROS_ERROR("Could not create padded min OcTree key at %f %f %f", minPt.x(), minPt.y(), minPt.z());
00435 return;
00436 }
00437 if (!m_octoMap.octree.genKey(maxPt, paddedMaxKey)){
00438 ROS_ERROR("Could not create padded max OcTree key at %f %f %f", maxPt.x(), maxPt.y(), maxPt.z());
00439 return;
00440 }
00441
00442 ROS_DEBUG("Padded MinKey: %d %d %d / padded MaxKey: %d %d %d", paddedMinKey[0], paddedMinKey[1], paddedMinKey[2], paddedMaxKey[0], paddedMaxKey[1], paddedMaxKey[2]);
00443 assert(paddedMaxKey[0] >= maxKey[0] && paddedMaxKey[1] >= maxKey[1]);
00444
00445 map.info.width = paddedMaxKey[0] - paddedMinKey[0] +1;
00446 map.info.height = paddedMaxKey[1] - paddedMinKey[1] +1;
00447 int mapOriginX = minKey[0] - paddedMinKey[0];
00448 int mapOriginY = minKey[1] - paddedMinKey[1];
00449 assert(mapOriginX >= 0 && mapOriginY >= 0);
00450
00451
00452 octomap::point3d origin;
00453 m_octoMap.octree.genCoords(paddedMinKey, m_octoMap.octree.getTreeDepth(), origin);
00454 map.info.origin.position.x = origin.x() - m_octoMap.octree.getResolution()*0.5;
00455 map.info.origin.position.y = origin.y() - m_octoMap.octree.getResolution()*0.5;
00456
00457
00458 map.data.resize(map.info.width * map.info.height, -1);
00459
00460
00461 for (OcTreeROS::OcTreeType::iterator it = m_octoMap.octree.begin(),
00462 end = m_octoMap.octree.end(); it != end; ++it)
00463 {
00464 if (m_octoMap.octree.isNodeOccupied(*it)){
00465 double z = it.getZ();
00466 if (z > m_occupancyMinZ && z < m_occupancyMaxZ)
00467 {
00468 octomap::OcTreeKey nKey = it.getKey();
00469 octomap::OcTreeKey key;
00470
00471
00472 if (m_filterSpeckles){
00473 bool neighborFound = false;
00474 for (key[2] = nKey[2] - 1; !neighborFound && key[2] <= nKey[2] + 1; ++key[2]){
00475 for (key[1] = nKey[1] - 1; !neighborFound && key[1] <= nKey[1] + 1; ++key[1]){
00476 for (key[0] = nKey[0] - 1; !neighborFound && key[0] <= nKey[0] + 1; ++key[0]){
00477 if (key != nKey){
00478 OcTreeNode* node = m_octoMap.octree.search(key);
00479 if (node && m_octoMap.octree.isNodeOccupied(node)){
00480
00481 neighborFound = true;
00482 }
00483 }
00484 }
00485 }
00486 }
00487
00488 if (!neighborFound){
00489 ROS_DEBUG("Ignoring single speckle at (%f,%f,%f)", it.getX(), it.getY(), it.getZ());
00490 continue;
00491 }
00492 }
00493
00494 double size = it.getSize();
00495 double x = it.getX();
00496 double y = it.getY();
00497
00498
00499 if (publishCollisionObject){
00500 shape.dimensions[0] = shape.dimensions[1] = shape.dimensions[2] = size;
00501 collisionObject.shapes.push_back(shape);
00502 pose.position.x = x;
00503 pose.position.y = y;
00504 pose.position.z = z;
00505 collisionObject.poses.push_back(pose);
00506 }
00507
00508
00509 if (publishMarkerArray){
00510 int idx = int(log2(it.getSize() / lowestRes) +0.5);
00511 assert (idx >= 0 && unsigned(idx) < occupiedNodesVis.markers.size());
00512 geometry_msgs::Point cubeCenter;
00513 cubeCenter.x = x;
00514 cubeCenter.y = y;
00515 cubeCenter.z = z;
00516
00517 occupiedNodesVis.markers[idx].points.push_back(cubeCenter);
00518 if (m_useHeightMap){
00519 double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00520 occupiedNodesVis.markers[idx].colors.push_back(heightMapColor(h));
00521 }
00522 }
00523
00524
00525 if (publishPointCloud)
00526 pclCloud.push_back(pcl::PointXYZ(x, y, z));
00527
00528
00529 if (publish2DMap){
00530 if (it.getDepth() == m_octoMap.octree.getTreeDepth()){
00531 int i = nKey[0] - paddedMinKey[0];
00532 int j = nKey[1] - paddedMinKey[1];
00533 map.data[map.info.width*j + i] = 100;
00534 } else{
00535 int intSize = 1 << (m_octoMap.octree.getTreeDepth() - it.getDepth());
00536 octomap::OcTreeKey minKey=it.getIndexKey();
00537 for(int dx=0; dx < intSize; dx++){
00538 int i = minKey[0]+dx - paddedMinKey[0];
00539 for(int dy=0; dy < intSize; dy++){
00540 int j = minKey[1]+dy - paddedMinKey[1];
00541 map.data[map.info.width*j + i] = 100;
00542 }
00543 }
00544 }
00545 }
00546 }
00547 } else{
00548 if (publish2DMap){
00549 if (it.getDepth() == m_octoMap.octree.getTreeDepth()){
00550 octomap::OcTreeKey nKey = it.getKey();
00551 int i = nKey[0] - paddedMinKey[0];
00552 int j = nKey[1] - paddedMinKey[1];
00553 if (map.data[map.info.width*j + i] == -1){
00554 map.data[map.info.width*j + i] = 0;
00555 }
00556 } else{
00557 int intSize = 1 << (m_octoMap.octree.getTreeDepth() - it.getDepth());
00558 octomap::OcTreeKey minKey=it.getIndexKey();
00559 for(int dx=0; dx < intSize; dx++){
00560 int i = minKey[0]+dx - paddedMinKey[0];
00561 for(int dy=0; dy < intSize; dy++){
00562 int j = minKey[1]+dy - paddedMinKey[1];
00563 if (map.data[map.info.width*j + i] == -1){
00564 map.data[map.info.width*j + i] = 0;
00565 }
00566 }
00567 }
00568 }
00569 }
00570 }
00571 }
00572
00573
00574 if (publishMarkerArray){
00575 for (unsigned i= 0; i < occupiedNodesVis.markers.size(); ++i){
00576 double size = lowestRes * pow(2,i);
00577
00578 occupiedNodesVis.markers[i].header.frame_id = m_worldFrameId;
00579 occupiedNodesVis.markers[i].header.stamp = rostime;
00580 occupiedNodesVis.markers[i].ns = "map";
00581 occupiedNodesVis.markers[i].id = i;
00582 occupiedNodesVis.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00583 occupiedNodesVis.markers[i].scale.x = size;
00584 occupiedNodesVis.markers[i].scale.y = size;
00585 occupiedNodesVis.markers[i].scale.z = size;
00586 occupiedNodesVis.markers[i].color = m_color;
00587
00588
00589 if (occupiedNodesVis.markers[i].points.size() > 0)
00590 occupiedNodesVis.markers[i].action = visualization_msgs::Marker::ADD;
00591 else
00592 occupiedNodesVis.markers[i].action = visualization_msgs::Marker::DELETE;
00593 }
00594
00595
00596 m_markerPub.publish(occupiedNodesVis);
00597 }
00598
00599
00600 if (publishPointCloud){
00601 sensor_msgs::PointCloud2 cloud;
00602 pcl::toROSMsg (pclCloud, cloud);
00603 cloud.header.frame_id = m_worldFrameId;
00604 cloud.header.stamp = rostime;
00605 m_pointCloudPub.publish(cloud);
00606 }
00607
00608 if (publishCollisionObject)
00609 m_collisionObjectPub.publish(collisionObject);
00610
00611 if (publish2DMap)
00612 m_mapPub.publish(map);
00613
00614 double total_elapsed = (ros::WallTime::now() - startTime).toSec();
00615 ROS_DEBUG("Map publishing in OctomapServer took %f sec", total_elapsed);
00616
00617 }
00618
00619
00620 bool OctomapServerCombined::serviceCallback(octomap_ros::GetOctomap::Request &req,
00621 octomap_ros::GetOctomap::Response &res)
00622 {
00623 ROS_INFO("Sending map data on service request");
00624 res.map.header.frame_id = m_worldFrameId;
00625 res.map.header.stamp = ros::Time::now();
00626 octomap::octomapMapToMsgData(m_octoMap.octree, res.map.data);
00627
00628 return true;
00629 }
00630
00631 void OctomapServerCombined::publishMap(const ros::Time& rostime){
00632
00633 octomap_ros::OctomapBinary map;
00634 map.header.frame_id = m_worldFrameId;
00635 map.header.stamp = rostime;
00636
00637 octomap::octomapMapToMsgData(m_octoMap.octree, map.data);
00638
00639 m_binaryMapPub.publish(map);
00640 }
00641
00642 std_msgs::ColorRGBA OctomapServerCombined::heightMapColor(double h) const {
00643
00644 std_msgs::ColorRGBA color;
00645 color.a = 1.0;
00646
00647
00648 double s = 1.0;
00649 double v = 1.0;
00650
00651 h -= floor(h);
00652 h *= 6;
00653 int i;
00654 double m, n, f;
00655
00656 i = floor(h);
00657 f = h - i;
00658 if (!(i & 1))
00659 f = 1 - f;
00660 m = v * (1 - s);
00661 n = v * (1 - s * f);
00662
00663 switch (i) {
00664 case 6:
00665 case 0:
00666 color.r = v; color.g = n; color.b = m;
00667 break;
00668 case 1:
00669 color.r = n; color.g = v; color.b = m;
00670 break;
00671 case 2:
00672 color.r = m; color.g = v; color.b = n;
00673 break;
00674 case 3:
00675 color.r = m; color.g = n; color.b = v;
00676 break;
00677 case 4:
00678 color.r = n; color.g = m; color.b = v;
00679 break;
00680 case 5:
00681 color.r = v; color.g = m; color.b = n;
00682 break;
00683 default:
00684 color.r = 1; color.g = 0.5; color.b = 0.5;
00685 break;
00686 }
00687
00688 return color;
00689 }
00690 }
00691
00692
00693