sick_ldmrs_print_resolution.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2016, DFKI GmbH
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 DFKI GmbH 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  *      Authors:
00030  *         Martin Günther <martin.guenther@dfki.de>
00031  *         Jochen Sprickerhof <ros@jochen.sprickerhof.de>
00032  *
00033  * Based on LD-MRS example code by SICK AG.
00034  *
00035  */
00036 
00037 #include <ros/ros.h>
00038 
00039 #include <pcl_conversions/pcl_conversions.h>
00040 
00041 #include <sensor_msgs/PointCloud2.h>
00042 #include <sick_ldmrs_msgs/sick_ldmrs_point_type.h>
00043 #include <pcl/point_cloud.h>
00044 
00045 typedef std::vector<std::pair<double, double> > ResolutionMap;
00046 typedef sick_ldmrs_msgs::SICK_LDMRS_Point PointT;
00047 typedef pcl::PointCloud<PointT> PointCloudT;
00048 
00049 #ifndef deg2rad
00050 #define deg2rad 0.01745329251994329576923690768   // (PI / 180.0)
00051 #endif
00052 #ifndef rad2deg
00053 #define rad2deg 57.29577951308232087679815481   // (180.0 / PI)
00054 #endif
00055 
00056 std::string doubleToString(double val,
00057                            int digits_after_decimal_point)
00058 {
00059   std::ostringstream ss;
00060   ss << std::fixed << std::setprecision(digits_after_decimal_point) << val;
00061 
00062   return ss.str();
00063 }
00064 
00065 inline bool almostEqual(double a, double b)
00066 {
00067   return std::abs(a - b) < 1e-6f;
00068 }
00069 
00070 inline double getHAngle(const PointT &p)
00071 {
00072   return atan2(p.y, p.x);
00073 }
00074 
00075 std::string sectorToString(const ResolutionMap& sector)
00076 {
00077   size_t i = 0;
00078   std::ostringstream oss;
00079   oss << std::endl;
00080   for (ResolutionMap::const_iterator s = sector.begin(); s != sector.end(); ++s)
00081   {
00082     oss  << "Sector (" << i << "): start=" << doubleToString(s->first * rad2deg, 3) << " (= " << (int)(round(s->first * rad2deg * 32.0)) << ") res=" << doubleToString(s->second * rad2deg, 3) << std::endl;
00083     i++;
00084   }
00085 
00086   return oss.str();
00087 }
00088 
00089 PointCloudT::const_iterator getNextPointInSameLayer(PointCloudT::const_iterator iter, const PointCloudT::ConstPtr cloud)
00090 {
00091   PointCloudT::const_iterator ret = iter;
00092   for (++iter /*start with the next point*/ ; iter != cloud->end(); ++iter)
00093   {
00094     if (iter->layer == ret->layer)
00095     {
00096       ret = iter;
00097       break;
00098     }
00099   }
00100   return ret;
00101 
00102 }
00103 
00104 PointCloudT::const_iterator getNextPoint(PointCloudT::const_iterator iter, const PointCloudT::ConstPtr cloud)
00105 {
00106   PointCloudT::const_iterator ret = iter;
00107   ++iter;
00108   if (iter != cloud->end())
00109   {
00110     ret = iter;
00111   }
00112   return ret;
00113 
00114 }
00115 
00116 void checkResolution(const PointCloudT::ConstPtr cloud)
00117 {
00118   if (cloud->size() < 10)
00119   {
00120     // do not process on scans with too few scan points
00121     return;
00122   }
00123 
00124   // iterate through all scan points and make a diff of the angles
00125   PointCloudT::const_iterator p;
00126   double angleDiff; // compute differences
00127 
00128   ResolutionMap sectors; // first = start angle, second = resolution
00129 
00130   for (p = cloud->begin(); p != cloud->end(); ++p)
00131   {
00132     PointCloudT::const_iterator p2 = getNextPoint(p, cloud);
00133     PointCloudT::const_iterator p3 = getNextPointInSameLayer(p, cloud);
00134     double interlaced = 1.;
00135     if (almostEqual(getHAngle(*p2), getHAngle(*p3)))
00136     {
00137       // we are close to the border -> only 2 scan layers left
00138       interlaced = 0.5;
00139 
00140     }
00141     angleDiff = std::fabs(getHAngle(*p2) - getHAngle(*p)) * interlaced;
00142 
00143     if (angleDiff > 1e-6f)
00144     {
00145       if (almostEqual(angleDiff, 0.125 * deg2rad)
00146           || almostEqual(angleDiff, 0.25 * deg2rad)
00147           || almostEqual(angleDiff, 0.5 * deg2rad)
00148           || almostEqual(angleDiff, 1.0 * deg2rad))
00149       {
00150         if (sectors.size() == 0)
00151         {
00152           sectors.push_back(std::make_pair(getHAngle(*p), angleDiff));
00153         }
00154         else
00155         {
00156           // we detected a new resolution
00157           if (almostEqual(double(sectors.back().second), angleDiff) == false)
00158           {
00159             sectors.push_back(std::make_pair(getHAngle(*p), angleDiff));
00160           }
00161         }
00162       }
00163     }
00164   }
00165 
00166   // filter out sectors < 3° or with same resolution as next sector
00167   ResolutionMap sectors_filtered;
00168   bool changed = true;
00169   while (changed)
00170   {
00171     changed = false;
00172     for (size_t i = 0; i < sectors.size() - 1; ++i)
00173     {
00174       if (sectors[i].first - sectors[i + 1].first > (3.0 + 1e-6f) * deg2rad &&
00175           !almostEqual(sectors[i].second, sectors[i + 1].second))
00176       {
00177         sectors_filtered.push_back(sectors[i]);
00178       }
00179       else
00180       {
00181         sectors[i + 1].first = sectors[i].first;
00182         changed = true;
00183       }
00184     }
00185     sectors_filtered.push_back(sectors.back());
00186     sectors.swap(sectors_filtered);
00187     sectors_filtered.clear();
00188   }
00189 
00190   std::ostringstream oss;
00191   oss << "Angular resolutions:" << sectorToString(sectors);
00192   ROS_INFO("%s", oss.str().c_str());
00193 }
00194 
00195 void callback(const sensor_msgs::PointCloud2::ConstPtr& pc)
00196 {
00197 
00198   PointCloudT::Ptr cloud = boost::make_shared<PointCloudT>();
00199   pcl::fromROSMsg(*pc, *cloud);
00200 
00201   checkResolution(cloud);
00202 }
00203 
00204 int main(int argc, char **argv)
00205 {
00206   ros::init(argc, argv, "sick_ldmrs_print_resolution");
00207   ros::NodeHandle nh;
00208 
00209   ros::Subscriber sub = nh.subscribe("cloud", 1, callback);
00210 
00211   ros::spin();
00212 
00213   return 0;
00214 }


sick_ldmrs_tools
Author(s): Martin Günther , Jochen Sprickerhof
autogenerated on Mon Aug 14 2017 02:35:43