octomap_server_contact_nodelet.cpp
Go to the documentation of this file.
00001 // -*- mode: c++ -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2015, JSK Lab
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/o2r other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the JSK Lab nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *********************************************************************/
00035 
00036 #define BOOST_PARAMETER_MAX_ARITY 7
00037 #include "jsk_pcl_ros/octomap_server_contact.h"
00038 #include <algorithm>
00039 
00040 using namespace octomap;
00041 using octomap_msgs::Octomap;
00042 
00043 namespace jsk_pcl_ros
00044 {
00045   OctomapServerContact::OctomapServerContact(const ros::NodeHandle &privateNh)
00046   : OctomapServer(privateNh),
00047     DiagnosticNodelet("OctomapServerContact"),
00048     m_octreeContact(NULL),
00049     m_publishUnknownSpace(false),
00050     m_publishFrontierSpace(false),
00051     m_offsetVisualizeUnknown(0),
00052     m_maxRangeProximity(0.05),
00053     m_occupancyMinX(-std::numeric_limits<double>::max()),
00054     m_occupancyMaxX(std::numeric_limits<double>::max()),
00055     m_occupancyMinY(-std::numeric_limits<double>::max()),
00056     m_occupancyMaxY(std::numeric_limits<double>::max()),
00057     m_useContactSurface(true)
00058   {
00059     delete m_octree;
00060     m_octree = NULL;
00061     m_octree = new OcTreeContact(m_res);
00062     m_octreeContact = dynamic_cast<OcTreeContact*>(m_octree);
00063     if (!m_octreeContact) {
00064       ROS_ERROR("Could not convert OcTreeContact from OcTree");
00065       assert(m_octreeContact);
00066     }
00067 
00068     m_useHeightMap = false;
00069 
00070     privateNh.param("publish_unknown_space", m_publishUnknownSpace, m_publishUnknownSpace);
00071     privateNh.param("offset_vis_unknown", m_offsetVisualizeUnknown, m_offsetVisualizeUnknown);
00072     privateNh.param("sensor_model/max_range_proximity", m_maxRangeProximity, m_maxRangeProximity);
00073     privateNh.param("publish_frontier_space", m_publishFrontierSpace, m_publishFrontierSpace);
00074 
00075     privateNh.param("occupancy_min_x", m_occupancyMinX,m_occupancyMinX);
00076     privateNh.param("occupancy_max_x", m_occupancyMaxX,m_occupancyMaxX);
00077     privateNh.param("occupancy_min_y", m_occupancyMinY,m_occupancyMinY);
00078     privateNh.param("occupancy_max_y", m_occupancyMaxY,m_occupancyMaxY);
00079 
00080     privateNh.param("use_contact_surface", m_useContactSurface,m_useContactSurface);
00081 
00082     double r, g, b, a;
00083     privateNh.param("color_unknown/r", r, 0.5);
00084     privateNh.param("color_unknown/g", g, 0.5);
00085     privateNh.param("color_unknown/b", b, 0.7);
00086     privateNh.param("color_unknown/a", a, 1.0);
00087     m_colorUnknown.r = r;
00088     m_colorUnknown.g = g;
00089     m_colorUnknown.b = b;
00090     m_colorUnknown.a = a;
00091     privateNh.param("color_frontier/r", r, 1.0);
00092     privateNh.param("color_frontier/g", g, 0.0);
00093     privateNh.param("color_frontier/b", b, 0.0);
00094     privateNh.param("color_frontier/a", a, 1.0);
00095     m_colorFrontier.r = r;
00096     m_colorFrontier.g = g;
00097     m_colorFrontier.b = b;
00098     m_colorFrontier.a = a;
00099 
00100     m_unknownPointCloudPub = m_nh.advertise<sensor_msgs::PointCloud2>("octomap_unknown_point_cloud_centers", 1, m_latchedTopics);
00101     m_umarkerPub = m_nh.advertise<visualization_msgs::MarkerArray>("unknown_cells_vis_array", 1, m_latchedTopics);
00102 
00103     m_pointProximitySub = new message_filters::Subscriber<sensor_msgs::PointCloud2> (m_nh, "proximity_in", 5);
00104     m_tfPointProximitySub = new tf::MessageFilter<sensor_msgs::PointCloud2> (*m_pointProximitySub, m_tfListener, m_worldFrameId, 5);
00105     m_tfPointProximitySub->registerCallback(boost::bind(&OctomapServerContact::insertProximityCallback, this, _1));
00106 
00107     m_frontierPointCloudPub = m_nh.advertise<sensor_msgs::PointCloud2>("octomap_frontier_point_cloud_centers", 1, m_latchedTopics);
00108     m_fromarkerPub = m_nh.advertise<visualization_msgs::MarkerArray>("frontier_cells_vis_array", 1, m_latchedTopics);
00109 
00110     m_contactSensorSub.subscribe(m_nh, "contact_sensors_in", 2);
00111     m_tfContactSensorSub.reset(new tf::MessageFilter<jsk_recognition_msgs::ContactSensorArray> (
00112                                  m_contactSensorSub, m_tfListener, m_worldFrameId, 2));
00113     m_tfContactSensorSub->registerCallback(boost::bind(&OctomapServerContact::insertContactSensorCallback, this, _1));
00114 
00115     initContactSensor(privateNh);
00116   }
00117 
00118   OctomapServerContact::~OctomapServerContact() {
00119   }
00120 
00121   void OctomapServerContact::initContactSensor(const ros::NodeHandle &privateNh) {
00122     double defaultPadding, defaultScale;
00123     privateNh.param<double>("self_see_defaultPadding", defaultPadding, .01);
00124     privateNh.param<double>("self_see_defaultScale", defaultScale, 1.0);
00125     std::vector<robot_self_filter::LinkInfo> links;
00126 
00127     if (!privateNh.hasParam("self_see_links")) {
00128       ROS_WARN("No links specified for self filtering.");
00129     }
00130     else {
00131       XmlRpc::XmlRpcValue sslVals;;
00132       privateNh.getParam("self_see_links", sslVals);
00133       if (sslVals.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00134         ROS_WARN("Self see links need to be an array");
00135       }
00136       else {
00137         if (sslVals.size() == 0) {
00138           ROS_WARN("No values in self see links array");
00139         }
00140         else {
00141           for (int i = 0; i < sslVals.size(); i++) {
00142             robot_self_filter::LinkInfo li;
00143             if (sslVals[i].getType() != XmlRpc::XmlRpcValue::TypeStruct) {
00144               ROS_WARN("Self see links entry %d is not a structure.  Stopping processing of self see links",i);
00145               break;
00146             }
00147             if (!sslVals[i].hasMember("name")) {
00148               ROS_WARN("Self see links entry %d has no name.  Stopping processing of self see links",i);
00149               break;
00150             }
00151             li.name = std::string(sslVals[i]["name"]);
00152             if (!sslVals[i].hasMember("padding")) {
00153               ROS_DEBUG("Self see links entry %d has no padding.  Assuming default padding of %g",i,defaultPadding);
00154               li.padding = defaultPadding;
00155             }
00156             else {
00157               li.padding = sslVals[i]["padding"];
00158             }
00159             if (!sslVals[i].hasMember("scale")) {
00160               ROS_DEBUG("Self see links entry %d has no scale.  Assuming default scale of %g",i,defaultScale);
00161               li.scale = defaultScale;
00162             }
00163             else {
00164               li.scale = sslVals[i]["scale"];
00165             }
00166             links.push_back(li);
00167           }
00168         }
00169       }
00170     }
00171     m_selfMask = boost::shared_ptr<robot_self_filter::SelfMaskNamedLink>(new robot_self_filter::SelfMaskNamedLink(m_tfListener, links));
00172   }
00173 
00174   void OctomapServerContact::insertProximityCallback(const sensor_msgs::PointCloud2::ConstPtr& cloud) {
00175     // ROS_INFO("insertProximityCallback is called");
00176 
00177     ros::WallTime startTime = ros::WallTime::now();
00178 
00179     //
00180     // ground filtering in base frame
00181     //
00182     PCLPointCloud pc; // input cloud for filtering and ground-detection
00183     pcl::fromROSMsg(*cloud, pc);
00184 
00185     tf::StampedTransform sensorToWorldTf;
00186     try {
00187       m_tfListener.lookupTransform(m_worldFrameId, cloud->header.frame_id, cloud->header.stamp, sensorToWorldTf);
00188     } catch(tf::TransformException& ex){
00189       ROS_ERROR_STREAM( "Transform error of sensor data: " << ex.what() << ", quitting callback");
00190       return;
00191     }
00192 
00193     Eigen::Matrix4f sensorToWorld;
00194     pcl_ros::transformAsMatrix(sensorToWorldTf, sensorToWorld);
00195 
00196     // directly transform to map frame:
00197     pcl::transformPointCloud(pc, pc, sensorToWorld);
00198 
00199     pc.header = pc.header;
00200 
00201     insertScanProximity(sensorToWorldTf.getOrigin(), pc);
00202 
00203     double total_elapsed = (ros::WallTime::now() - startTime).toSec();
00204     ROS_DEBUG("Pointcloud insertion in OctomapServer done (%zu pts, %f sec)", pc.size(), total_elapsed);
00205 
00206     publishAll(cloud->header.stamp);
00207   }
00208 
00209   void OctomapServerContact::insertScanProximity(const tf::Point& sensorOriginTf, const PCLPointCloud& pc) {
00210     point3d sensorOrigin = pointTfToOctomap(sensorOriginTf);
00211 
00212     if (!m_octree->coordToKeyChecked(sensorOrigin, m_updateBBXMin)
00213         || !m_octree->coordToKeyChecked(sensorOrigin, m_updateBBXMax))
00214       {
00215         ROS_ERROR_STREAM("Could not generate Key for origin "<<sensorOrigin);
00216       }
00217 
00218 #ifdef COLOR_OCTOMAP_SERVER
00219     unsigned char* colors = new unsigned char[3];
00220 #endif
00221 
00222     // instead of direct scan insertion, compute update to filter ground:
00223     KeySet free_cells, occupied_cells;
00224 
00225     // all other points: free on ray, occupied on endpoint:
00226     for (PCLPointCloud::const_iterator it = pc.begin(); it != pc.end(); ++it) {
00227       point3d point(it->x, it->y, it->z);
00228       // maxrange check
00229       if ((m_maxRangeProximity < 0.0) || ((point - sensorOrigin).norm() <= m_maxRangeProximity) ) {
00230 
00231         // free cells
00232         if (m_octree->computeRayKeys(sensorOrigin, point, m_keyRay)){
00233           free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00234         }
00235         // occupied endpoint
00236         OcTreeKey key;
00237         if (m_octree->coordToKeyChecked(point, key)){
00238           occupied_cells.insert(key);
00239 
00240           updateMinKey(key, m_updateBBXMin);
00241           updateMaxKey(key, m_updateBBXMax);
00242 
00243 #ifdef COLOR_OCTOMAP_SERVER // NB: Only read and interpret color if it's an occupied node
00244           const int rgb = *reinterpret_cast<const int*>(&(it->rgb)); // TODO: there are other ways to encode color than this one
00245           colors[0] = ((rgb >> 16) & 0xff);
00246           colors[1] = ((rgb >> 8) & 0xff);
00247           colors[2] = (rgb & 0xff);
00248           m_octree->averageNodeColor(it->x, it->y, it->z, colors[0], colors[1], colors[2]);
00249 #endif
00250         }
00251       } else {// ray longer than maxrange:;
00252         point3d new_end = sensorOrigin + (point - sensorOrigin).normalized() * m_maxRangeProximity;
00253         if (m_octree->computeRayKeys(sensorOrigin, new_end, m_keyRay)){
00254           free_cells.insert(m_keyRay.begin(), m_keyRay.end());
00255 
00256           octomap::OcTreeKey endKey;
00257           if (m_octree->coordToKeyChecked(new_end, endKey)){
00258             updateMinKey(endKey, m_updateBBXMin);
00259             updateMaxKey(endKey, m_updateBBXMax);
00260           } else{
00261             ROS_ERROR_STREAM("Could not generate Key for endpoint "<<new_end);
00262           }
00263         }
00264       }
00265     }
00266 
00267     // mark free cells only if not seen occupied in this cloud
00268     for(KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ++it){
00269       if (occupied_cells.find(*it) == occupied_cells.end()){
00270         m_octree->updateNode(*it, false);
00271       }
00272     }
00273 
00274     // now mark all occupied cells:
00275     for (KeySet::iterator it = occupied_cells.begin(), end=occupied_cells.end(); it!= end; it++) {
00276       m_octree->updateNode(*it, true);
00277     }
00278 
00279     // TODO: eval lazy+updateInner vs. proper insertion
00280     // non-lazy by default (updateInnerOccupancy() too slow for large maps)
00281     //m_octree->updateInnerOccupancy();
00282     octomap::point3d minPt, maxPt;
00283     ROS_DEBUG_STREAM("Bounding box keys (before): " << m_updateBBXMin[0] << " " <<m_updateBBXMin[1] << " " << m_updateBBXMin[2] << " / " <<m_updateBBXMax[0] << " "<<m_updateBBXMax[1] << " "<< m_updateBBXMax[2]);
00284 
00285     // TODO: snap max / min keys to larger voxels by m_maxTreeDepth
00286     //   if (m_maxTreeDepth < 16)
00287     //   {
00288     //      OcTreeKey tmpMin = getIndexKey(m_updateBBXMin, m_maxTreeDepth); // this should give us the first key at depth m_maxTreeDepth that is smaller or equal to m_updateBBXMin (i.e. lower left in 2D grid coordinates)
00289     //      OcTreeKey tmpMax = getIndexKey(m_updateBBXMax, m_maxTreeDepth); // see above, now add something to find upper right
00290     //      tmpMax[0]+= m_octree->getNodeSize( m_maxTreeDepth ) - 1;
00291     //      tmpMax[1]+= m_octree->getNodeSize( m_maxTreeDepth ) - 1;
00292     //      tmpMax[2]+= m_octree->getNodeSize( m_maxTreeDepth ) - 1;
00293     //      m_updateBBXMin = tmpMin;
00294     //      m_updateBBXMax = tmpMax;
00295     //   }
00296 
00297     // TODO: we could also limit the bbx to be within the map bounds here (see publishing check)
00298     minPt = m_octree->keyToCoord(m_updateBBXMin);
00299     maxPt = m_octree->keyToCoord(m_updateBBXMax);
00300     ROS_DEBUG_STREAM("Updated area bounding box: "<< minPt << " - "<<maxPt);
00301     ROS_DEBUG_STREAM("Bounding box keys (after): " << m_updateBBXMin[0] << " " <<m_updateBBXMin[1] << " " << m_updateBBXMin[2] << " / " <<m_updateBBXMax[0] << " "<<m_updateBBXMax[1] << " "<< m_updateBBXMax[2]);
00302 
00303     if (m_compressMap)
00304       m_octree->prune();
00305   }
00306 
00307   void OctomapServerContact::insertContactSensor(const jsk_recognition_msgs::ContactSensorArray::ConstPtr& msg) {
00308     std::vector<jsk_recognition_msgs::ContactSensor> datas = msg->datas;
00309 
00310     // setup tf transformation between octomap and each link
00311     {
00312       std_msgs::Header tmpHeader;
00313       tmpHeader.frame_id = m_worldFrameId;
00314       tmpHeader.stamp = msg->header.stamp;
00315       if(!m_selfMask->assumeFrame(tmpHeader)) {
00316         ROS_ERROR_STREAM("failed tf transformation in insertContactSensor");
00317         return;
00318       }
00319     }
00320 
00321     // clamp min and max points  cf. https://github.com/OctoMap/octomap/issues/146
00322     point3d pmin_raw( m_occupancyMinX, m_occupancyMinY, m_occupancyMinZ );
00323     point3d pmax_raw( m_occupancyMaxX, m_occupancyMaxY, m_occupancyMaxZ );
00324     point3d pmin = m_octree->keyToCoord(m_octree->coordToKey(pmin_raw));
00325     point3d pmax = m_octree->keyToCoord(m_octree->coordToKey(pmax_raw));
00326     float diff[3];
00327     unsigned int steps[3];
00328     double resolution = m_octreeContact->getResolution();
00329     for (int i = 0; i < 3; ++i) {
00330       diff[i] = pmax(i) - pmin(i);
00331       steps[i] = floor(diff[i] / resolution);
00332       // std::cout << "bbx " << i << " size: " << diff[i] << " " << steps[i] << " steps\n";
00333     }
00334 
00335     // loop for grids of octomap
00336     if (m_useContactSurface) {
00337       std::vector< std::vector<bool> > containFlag(datas.size(), std::vector<bool>(8));
00338       point3d p = pmin;
00339       for (unsigned int x = 0; x < steps[0]; ++x) {
00340         p.x() += resolution;
00341         for (unsigned int y = 0; y < steps[1]; ++y) {
00342           p.y() += resolution;
00343           for (unsigned int z = 0; z < steps[2]; ++z) {
00344             // std::cout << "querying p=" << p << std::endl;
00345             p.z() += resolution;
00346             // loop for vertices of each gird
00347             point3d vertexOffset(-resolution/2.0, -resolution/2.0, -resolution/2.0);
00348             point3d vertex;
00349             for (int i = 0; i < 2; i++) {
00350               if (i == 1) { vertexOffset.z() += resolution; }
00351               for (int j = 0; j < 2; j++) {
00352                 if (j == 1) { vertexOffset.y() += resolution; }
00353                 for (int k = 0; k < 2; k++) {
00354                   if (k == 1) { vertexOffset.x() += resolution; }
00355                   vertex = p + vertexOffset;
00356                   // std::cout << "vertex = " << vertex << std::endl;
00357                   // loop for each body link
00358                   for (int l=0; l<datas.size(); l++) {
00359                     if (m_selfMask->getMaskContainmentforNamedLink(vertex(0), vertex(1), vertex(2), datas[l].link_name) == robot_self_filter::INSIDE) {
00360                       // std::cout << "inside vertex = " << vertex << std::endl;
00361                       containFlag[l][i+j*2+k*4] = true;
00362                     }
00363                     else {
00364                       containFlag[l][i+j*2+k*4] = false;
00365                     }
00366                   }
00367                 }
00368                 vertexOffset.x() -= resolution;
00369               }
00370               vertexOffset.y() -= resolution;
00371             }
00372 
00373             // update probability of grid
00374             std::vector<bool> containFlagLinkSum(8, false);
00375             std::vector<bool> containFlagVerticesSum(datas.size(), false);
00376             std::vector<bool> containFlagVerticesProd(datas.size(), true);
00377             bool insideFlag = false;
00378             bool surfaceFlag = false;
00379             for (int l = 0; l < datas.size(); l++) {
00380               for (int i = 0; i < 8; i++) {
00381                 if (containFlag[l][i]) {
00382                   containFlagLinkSum[i] = true;
00383                   containFlagVerticesSum[l] = true;
00384                 }
00385                 else {
00386                   containFlagVerticesProd[l] = false;
00387                 }
00388               }
00389             }
00390             insideFlag = (std::find(containFlagLinkSum.begin(), containFlagLinkSum.end(), false) == containFlagLinkSum.end()); // when all elements is true
00391             for (int l = 0; l < datas.size(); l++) {
00392               if (containFlagVerticesSum[l] && !(containFlagVerticesProd[l]) ) {
00393                 if (datas[l].contact) {
00394                   surfaceFlag = true;
00395                 }
00396               }
00397             }
00398             if (insideFlag) { // inside
00399               octomap::OcTreeKey pKey;
00400               if (m_octreeContact->coordToKeyChecked(p, pKey)) {
00401                 m_octreeContact->updateNode(pKey, m_octreeContact->getProbMissContactSensorLog());
00402                 // std::cout << "find inside grid and find key. p = " << vertex << std::endl;
00403               }
00404             }
00405             else if (surfaceFlag) { // surface
00406               octomap::OcTreeKey pKey;
00407               if (m_octreeContact->coordToKeyChecked(p, pKey)) {
00408                 m_octreeContact->updateNode(pKey, m_octreeContact->getProbHitContactSensorLog());
00409                 // std::cout << "find surface grid and find key. p = " << vertex << std::endl;
00410               }
00411             }
00412           }
00413           p.z() = pmin.z();
00414         }
00415         p.y() = pmin.y();
00416       }
00417     }
00418     else {
00419       point3d vertexOffset(-resolution/2.0, -resolution/2.0, -resolution/2.0);
00420 #pragma omp parallel for
00421       for (unsigned int cnt = 0; cnt < steps[0] * steps[1] * steps[2]; ++cnt) {
00422         // get grid center
00423         point3d p;
00424         {
00425           unsigned int id[3];
00426           id[0] = cnt / (steps[1] * steps[2]);
00427           id[1] = (cnt % (steps[1] * steps[2])) / steps[2];
00428           id[2] = (cnt % (steps[1] * steps[2])) % steps[2];
00429           p.x() = pmin(0) + resolution * id[0];
00430           p.y() = pmin(1) + resolution * id[1];
00431           p.z() = pmin(2) + resolution * id[2];
00432         }
00433         point3d vertex;
00434         vertex = p + vertexOffset;
00435         // loop for each body link
00436         for (int l=0; l<datas.size(); l++) {
00437           if (m_selfMask->getMaskContainmentforNamedLink(vertex(0), vertex(1), vertex(2), datas[l].link_name) == robot_self_filter::INSIDE) {
00438             octomap::OcTreeKey pKey;
00439             if (m_octreeContact->coordToKeyChecked(p, pKey)) {
00440 #pragma omp critical
00441               m_octreeContact->updateNode(pKey, m_octreeContact->getProbMissContactSensorLog());
00442             }
00443             break;
00444           }
00445         }
00446       }
00447     }
00448     m_octreeContact->updateInnerOccupancy();
00449   }
00450 
00451   void OctomapServerContact::insertContactSensorCallback(const jsk_recognition_msgs::ContactSensorArray::ConstPtr& msg) {
00452     NODELET_INFO("insert contact sensor");
00453     insertContactSensor(msg);
00454 
00455     publishAll(msg->header.stamp);
00456   }
00457 
00458   void OctomapServerContact::publishAll(const ros::Time& rostime) {
00459     ros::WallTime startTime = ros::WallTime::now();
00460     size_t octomapSize = m_octreeContact->size();
00461     // TODO: estimate num occ. voxels for size of arrays (reserve)
00462     if (octomapSize <= 1) {
00463       ROS_WARN("Nothing to publish, octree is empty");
00464       return;
00465     }
00466 
00467     bool publishFreeMarkerArray = m_publishFreeSpace && (m_latchedTopics || m_fmarkerPub.getNumSubscribers() > 0);
00468     bool publishUnknownMarkerArray = m_publishUnknownSpace && (m_latchedTopics || m_umarkerPub.getNumSubscribers() > 0);
00469     bool publishFrontierMarkerArray = m_publishFrontierSpace && (m_latchedTopics || m_fromarkerPub.getNumSubscribers() > 0);
00470     bool publishMarkerArray = (m_latchedTopics || m_markerPub.getNumSubscribers() > 0);
00471     bool publishPointCloud = (m_latchedTopics || m_pointCloudPub.getNumSubscribers() > 0);
00472     bool publishBinaryMap = (m_latchedTopics || m_binaryMapPub.getNumSubscribers() > 0);
00473     bool publishFullMap = (m_latchedTopics || m_fullMapPub.getNumSubscribers() > 0);
00474     m_publish2DMap = (m_latchedTopics || m_mapPub.getNumSubscribers() > 0);
00475 
00476     // init markers for free space:
00477     visualization_msgs::MarkerArray freeNodesVis;
00478     // each array stores all cubes of a different size, one for each depth level:
00479     freeNodesVis.markers.resize(m_treeDepth+1);
00480 
00481     geometry_msgs::Pose pose;
00482     pose.orientation = tf::createQuaternionMsgFromYaw(0.0);
00483 
00484     // init markers:
00485     visualization_msgs::MarkerArray occupiedNodesVis;
00486     // each array stores all cubes of a different size, one for each depth level:
00487     occupiedNodesVis.markers.resize(m_treeDepth+1);
00488 
00489     // init pointcloud:
00490     pcl::PointCloud<pcl::PointXYZ> pclCloud;
00491 
00492     // call pre-traversal hook:
00493     handlePreNodeTraversal(rostime);
00494 
00495     // now, traverse all leafs in the tree:
00496     for (OcTree::iterator it = m_octreeContact->begin(m_maxTreeDepth), end = m_octreeContact->end(); it != end; ++it) {
00497       bool inUpdateBBX = isInUpdateBBX(it);
00498 
00499       // call general hook:
00500       handleNode(it);
00501       if (inUpdateBBX) {
00502         handleNodeInBBX(it);
00503       }
00504 
00505       if (m_octreeContact->isNodeOccupied(*it)) {
00506         double x = it.getX();
00507         double y = it.getY();
00508         double z = it.getZ();
00509         if (x > m_occupancyMinX && x < m_occupancyMaxX && y > m_occupancyMinY && y < m_occupancyMaxY && z > m_occupancyMinZ && z < m_occupancyMaxZ) {
00510           double size = it.getSize();
00511           double x = it.getX();
00512           double y = it.getY();
00513 
00514           // Ignore speckles in the map:
00515           if (m_filterSpeckles && (it.getDepth() == m_treeDepth +1) && isSpeckleNode(it.getKey())) {
00516             ROS_DEBUG("Ignoring single speckle at (%f,%f,%f)", x, y, z);
00517             continue;
00518           } // else: current octree node is no speckle, send it out
00519 
00520           handleOccupiedNode(it);
00521           if (inUpdateBBX) {
00522             handleOccupiedNodeInBBX(it);
00523           }
00524 
00525           //create marker:
00526           if (publishMarkerArray) {
00527             unsigned idx = it.getDepth();
00528             assert(idx < occupiedNodesVis.markers.size());
00529 
00530             geometry_msgs::Point cubeCenter;
00531             cubeCenter.x = x;
00532             cubeCenter.y = y;
00533             cubeCenter.z = z;
00534 
00535             occupiedNodesVis.markers[idx].points.push_back(cubeCenter);
00536             if (m_useHeightMap) {
00537               double minX, minY, minZ, maxX, maxY, maxZ;
00538               m_octreeContact->getMetricMin(minX, minY, minZ);
00539               m_octreeContact->getMetricMax(maxX, maxY, maxZ);
00540 
00541               double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00542               occupiedNodesVis.markers[idx].colors.push_back(heightMapColor(h));
00543             }
00544           }
00545 
00546           // insert into pointcloud:
00547           if (publishPointCloud) {
00548             pclCloud.push_back(pcl::PointXYZ(x, y, z));
00549           }
00550 
00551         }
00552       } else { // node not occupied => mark as free in 2D map if unknown so far
00553         double x = it.getX();
00554         double y = it.getY();
00555         double z = it.getZ();
00556         if (x > m_occupancyMinX && x < m_occupancyMaxX && y > m_occupancyMinY && y < m_occupancyMaxY && z > m_occupancyMinZ && z < m_occupancyMaxZ) {
00557           handleFreeNode(it);
00558           if (inUpdateBBX)
00559             handleFreeNodeInBBX(it);
00560 
00561           if (m_publishFreeSpace) {
00562             double x = it.getX();
00563             double y = it.getY();
00564 
00565             //create marker for free space:
00566             if (publishFreeMarkerArray) {
00567               unsigned idx = it.getDepth();
00568               assert(idx < freeNodesVis.markers.size());
00569 
00570               geometry_msgs::Point cubeCenter;
00571               cubeCenter.x = x;
00572               cubeCenter.y = y;
00573               cubeCenter.z = z;
00574 
00575               freeNodesVis.markers[idx].points.push_back(cubeCenter);
00576             }
00577           }
00578         }
00579       }
00580     }
00581 
00582     // call post-traversal hook:
00583     handlePostNodeTraversal(rostime);
00584 
00585     // finish MarkerArray:
00586     if (publishMarkerArray) {
00587       for (unsigned i = 0; i < occupiedNodesVis.markers.size(); ++i) {
00588         double size = m_octreeContact->getNodeSize(i);
00589 
00590         occupiedNodesVis.markers[i].header.frame_id = m_worldFrameId;
00591         occupiedNodesVis.markers[i].header.stamp = rostime;
00592         occupiedNodesVis.markers[i].ns = m_worldFrameId;
00593         occupiedNodesVis.markers[i].id = i;
00594         occupiedNodesVis.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00595         occupiedNodesVis.markers[i].scale.x = size;
00596         occupiedNodesVis.markers[i].scale.y = size;
00597         occupiedNodesVis.markers[i].scale.z = size;
00598         occupiedNodesVis.markers[i].color = m_color;
00599 
00600 
00601         if (occupiedNodesVis.markers[i].points.size() > 0) {
00602           occupiedNodesVis.markers[i].action = visualization_msgs::Marker::ADD;
00603         }
00604         else {
00605           occupiedNodesVis.markers[i].action = visualization_msgs::Marker::DELETE;
00606         }
00607       }
00608 
00609       m_markerPub.publish(occupiedNodesVis);
00610     }
00611 
00612 
00613     // finish FreeMarkerArray:
00614     if (publishFreeMarkerArray) {
00615       for (unsigned i = 0; i < freeNodesVis.markers.size(); ++i) {
00616         double size = m_octreeContact->getNodeSize(i);
00617 
00618         freeNodesVis.markers[i].header.frame_id = m_worldFrameId;
00619         freeNodesVis.markers[i].header.stamp = rostime;
00620         freeNodesVis.markers[i].ns = m_worldFrameId;
00621         freeNodesVis.markers[i].id = i;
00622         freeNodesVis.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00623         freeNodesVis.markers[i].scale.x = size;
00624         freeNodesVis.markers[i].scale.y = size;
00625         freeNodesVis.markers[i].scale.z = size;
00626         freeNodesVis.markers[i].color = m_colorFree;
00627 
00628 
00629         if (freeNodesVis.markers[i].points.size() > 0) {
00630           freeNodesVis.markers[i].action = visualization_msgs::Marker::ADD;
00631         }
00632         else {
00633           freeNodesVis.markers[i].action = visualization_msgs::Marker::DELETE;
00634         }
00635       }
00636 
00637       m_fmarkerPub.publish(freeNodesVis);
00638     }
00639 
00640 
00641     // publish unknown grid as marker
00642     if (publishUnknownMarkerArray) {
00643       visualization_msgs::MarkerArray unknownNodesVis;
00644       unknownNodesVis.markers.resize(1);
00645 
00646       point3d_list unknownLeaves;
00647       double offset = m_offsetVisualizeUnknown;
00648       point3d pMin(m_occupancyMinX + offset, m_occupancyMinY + offset, m_occupancyMinZ + offset);
00649       point3d pMax(m_occupancyMaxX - offset, m_occupancyMaxY - offset, m_occupancyMaxZ - offset);
00650 
00651       m_octreeContact->getUnknownLeafCenters(unknownLeaves, pMin, pMax);
00652       pcl::PointCloud<pcl::PointXYZ> unknownCloud;
00653 
00654       for (point3d_list::iterator it = unknownLeaves.begin(); it != unknownLeaves.end(); it++) {
00655         float x = (*it).x();
00656         float y = (*it).y();
00657         float z = (*it).z();
00658         unknownCloud.push_back(pcl::PointXYZ(x, y, z));
00659 
00660         geometry_msgs::Point cubeCenter;
00661         cubeCenter.x = x;
00662         cubeCenter.y = y;
00663         cubeCenter.z = z;
00664         if (m_useHeightMap) {
00665           double minX, minY, minZ, maxX, maxY, maxZ;
00666           m_octreeContact->getMetricMin(minX, minY, minZ);
00667           m_octreeContact->getMetricMax(maxX, maxY, maxZ);
00668           double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00669           unknownNodesVis.markers[0].colors.push_back(heightMapColor(h));
00670         }
00671         unknownNodesVis.markers[0].points.push_back(cubeCenter);
00672       }
00673 
00674       double size = m_octreeContact->getNodeSize(m_maxTreeDepth);
00675       unknownNodesVis.markers[0].header.frame_id = m_worldFrameId;
00676       unknownNodesVis.markers[0].header.stamp = rostime;
00677       unknownNodesVis.markers[0].ns = m_worldFrameId;
00678       unknownNodesVis.markers[0].id = 0;
00679       unknownNodesVis.markers[0].type = visualization_msgs::Marker::CUBE_LIST;
00680       unknownNodesVis.markers[0].scale.x = size;
00681       unknownNodesVis.markers[0].scale.y = size;
00682       unknownNodesVis.markers[0].scale.z = size;
00683       unknownNodesVis.markers[0].color = m_colorUnknown;
00684 
00685       if (unknownNodesVis.markers[0].points.size() > 0) {
00686         unknownNodesVis.markers[0].action = visualization_msgs::Marker::ADD;
00687       }
00688       else {
00689         unknownNodesVis.markers[0].action = visualization_msgs::Marker::DELETE;
00690       }
00691       m_umarkerPub.publish(unknownNodesVis);
00692 
00693       // publish unknown grid as pointcloud
00694       sensor_msgs::PointCloud2 unknownRosCloud;
00695       pcl::toROSMsg (unknownCloud, unknownRosCloud);
00696       unknownRosCloud.header.frame_id = m_worldFrameId;
00697       unknownRosCloud.header.stamp = rostime;
00698       m_unknownPointCloudPub.publish(unknownRosCloud);
00699 
00700       // publish frontier grid as marker
00701       if (publishFrontierMarkerArray) {
00702         visualization_msgs::MarkerArray frontierNodesVis;
00703         frontierNodesVis.markers.resize(1);
00704         pcl::PointCloud<pcl::PointXYZ> frontierCloud;
00705         double resolution = m_octreeContact->getResolution();
00706         // how many resolution-size grids are in one edge
00707         int x_num = int(((m_occupancyMaxX - m_occupancyMinX) / resolution));
00708         int y_num = int(((m_occupancyMaxY - m_occupancyMinY) / resolution));
00709         int z_num = int(((m_occupancyMaxZ - m_occupancyMinZ) / resolution));
00710         std::vector< std::vector< std::vector<int> > > check_unknown(x_num, std::vector< std::vector<int> >(y_num, std::vector<int>(z_num)));
00711         std::vector< std::vector< std::vector<int> > > check_occupied(x_num, std::vector< std::vector<int> >(y_num, std::vector<int>(z_num)));
00712         std::vector< std::vector< std::vector<int> > > check_frontier(x_num, std::vector< std::vector<int> >(y_num, std::vector<int>(z_num)));
00713 
00714         for (int i = 0; i < x_num; i++) {
00715           for (int j = 0; j < y_num; j++) {
00716             for (int k = 0; k < z_num; k++) {
00717               check_unknown[i][j][k] = 0;
00718               check_occupied[i][j][k] = 0;
00719               check_frontier[i][j][k] = 0;
00720             }
00721           }
00722         }
00723 
00724         // for all unknown grids, store its information to array
00725         for (point3d_list::iterator it_unknown = unknownLeaves.begin();
00726              it_unknown != unknownLeaves.end();
00727              it_unknown++) {
00728           // get center of unknown grids
00729           double x_unknown = it_unknown->x();
00730           double y_unknown = it_unknown->y();
00731           double z_unknown = it_unknown->z();
00732           int x_index = int(std::round((x_unknown - m_occupancyMinX) / resolution - 1));
00733           int y_index = int(std::round((y_unknown - m_occupancyMinY) / resolution - 1));
00734           int z_index = int(std::round((z_unknown - m_occupancyMinZ) / resolution - 1));
00735           check_unknown[x_index][y_index][z_index] = 1;
00736         }
00737 
00738         // for all occupied grids, store its information to array
00739         for (int idx = 0; idx < occupiedNodesVis.markers.size(); idx++) {
00740           double size_occupied = occupiedNodesVis.markers[idx].scale.x;
00741           for (int id = 0; id < occupiedNodesVis.markers[idx].points.size(); id++) {
00742             double x_occupied = occupiedNodesVis.markers[idx].points[id].x;
00743             double y_occupied = occupiedNodesVis.markers[idx].points[id].y;
00744             double z_occupied = occupiedNodesVis.markers[idx].points[id].z;
00745             int x_min_index = std::round((x_occupied - (size_occupied / 2.0) - m_occupancyMinX) / resolution);
00746             int y_min_index = std::round((y_occupied - (size_occupied / 2.0) - m_occupancyMinY) / resolution);
00747             int z_min_index = std::round((z_occupied - (size_occupied / 2.0) - m_occupancyMinZ) / resolution);
00748             for (int i = x_min_index; i < x_min_index + int(size_occupied/resolution); i++) {
00749               for (int j = y_min_index; j < y_min_index + int(size_occupied/resolution); j++) {
00750                 for (int k = z_min_index; k < z_min_index + int(size_occupied/resolution); k++) {
00751                   check_occupied[i][j][k] = 1;
00752                 }
00753               }
00754             }
00755           }
00756         }
00757 
00758         // for all grids except occupied and unknown, (NOTE there are grids which are not free, nor occupied, nor unknown)
00759         // check whether they are frontier, namely, adjecent to unknown grids
00760         // NOTE all unknown grids are displaced half from the other grids
00761         geometry_msgs::Point cubeCenter;
00762         for (int i = 0; i < x_num; i++) {
00763           for (int j = 0; j < y_num; j++) {
00764             for (int k = 0; k < z_num-1; k++) {
00765               for (int l = -1; l <= 1; l++) {
00766                 if ( i+l < 0 || x_num <= i+l ) continue;
00767                 for (int m = -1; m <= 1; m++) {
00768                   if ( j+m < 0 || y_num <= j+m ) continue;
00769                   for (int n = -1; n <= 1; n++) {
00770                     if (  k+n < 0 || z_num <= k+n ) continue;
00771                     if (l == 0 && m == 0 && n== 0) continue;
00772                     if (check_unknown[i+l][j+m][k+n] == 1 && check_unknown[i][j][k] == 0 && check_occupied[i][j][k] == 0 && check_frontier[i][j][k] == 0) {
00773                       check_frontier[i][j][k] = 1;
00774                       cubeCenter.x = (i+0.5)*resolution + m_occupancyMinX;
00775                       cubeCenter.y = (j+0.5)*resolution + m_occupancyMinY;
00776                       cubeCenter.z = (k+0.5)*resolution + m_occupancyMinZ;
00777                       if (m_useHeightMap) {
00778                         double minX, minY, minZ, maxX, maxY, maxZ;
00779                         m_octreeContact->getMetricMin(minX, minY, minZ);
00780                         m_octreeContact->getMetricMax(maxX, maxY, maxZ);
00781                         double h = (1.0 - std::min(std::max((cubeCenter.z-minZ)/ (maxZ - minZ), 0.0), 1.0)) *m_colorFactor;
00782                         frontierNodesVis.markers[0].colors.push_back(heightMapColor(h));
00783                       }
00784                       frontierNodesVis.markers[0].points.push_back(cubeCenter);
00785                     }
00786                   }
00787                 }
00788               }
00789             }
00790           }
00791         }
00792 
00793         // publish frontier grid as marker
00794         double size = m_octreeContact->getNodeSize(m_maxTreeDepth);
00795         frontierNodesVis.markers[0].header.frame_id = m_worldFrameId;
00796         frontierNodesVis.markers[0].header.stamp = rostime;
00797         frontierNodesVis.markers[0].ns = m_worldFrameId;
00798         frontierNodesVis.markers[0].id = 0;
00799         frontierNodesVis.markers[0].type = visualization_msgs::Marker::CUBE_LIST;
00800         frontierNodesVis.markers[0].scale.x = size;
00801         frontierNodesVis.markers[0].scale.y = size;
00802         frontierNodesVis.markers[0].scale.z = size;
00803         frontierNodesVis.markers[0].color = m_colorFrontier;
00804 
00805         if (frontierNodesVis.markers[0].points.size() > 0) {
00806           frontierNodesVis.markers[0].action = visualization_msgs::Marker::ADD;
00807         }
00808         else {
00809           frontierNodesVis.markers[0].action = visualization_msgs::Marker::DELETE;
00810         }
00811 
00812         m_fromarkerPub.publish(frontierNodesVis);
00813 
00814         // publish frontier grid as pointcloud
00815         sensor_msgs::PointCloud2 frontierRosCloud;
00816         pcl::toROSMsg (frontierCloud, frontierRosCloud);
00817         frontierRosCloud.header.frame_id = m_worldFrameId;
00818         frontierRosCloud.header.stamp = rostime;
00819         m_frontierPointCloudPub.publish(frontierRosCloud);
00820       }
00821     }
00822 
00823     // finish pointcloud:
00824     if (publishPointCloud) {
00825       sensor_msgs::PointCloud2 cloud;
00826       pcl::toROSMsg (pclCloud, cloud);
00827       cloud.header.frame_id = m_worldFrameId;
00828       cloud.header.stamp = rostime;
00829       m_pointCloudPub.publish(cloud);
00830     }
00831 
00832     if (publishBinaryMap) {
00833       publishBinaryOctoMap(rostime);
00834     }
00835 
00836     if (publishFullMap) {
00837       publishFullOctoMap(rostime);
00838     }
00839 
00840     double totalElapsed = (ros::WallTime::now() - startTime).toSec();
00841     ROS_DEBUG("Map publishing in OctomapServer took %f sec", totalElapsed);
00842   }
00843 
00844   void OctomapServerContact::onInit(void)
00845   {
00846     DiagnosticNodelet::onInit();
00847     onInitPostProcess();
00848   }
00849 }
00850 
00851 #include <pluginlib/class_list_macros.h>
00852 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::OctomapServerContact, nodelet::Nodelet);


jsk_pcl_ros
Author(s): Yohei Kakiuchi
autogenerated on Tue Jul 2 2019 19:41:43