grid_overlay.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
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 Willow Garage, Inc. 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 
00038 #include <occupancy_grid_utils/ray_tracer.h>
00039 #include <ros/assert.h>
00040 #include <tf/transform_datatypes.h>
00041 #include <boost/foreach.hpp>
00042 #include <boost/bind.hpp>
00043 #include <boost/ref.hpp>
00044 #include <boost/optional.hpp>
00045 
00046 namespace occupancy_grid_utils
00047 {
00048 
00049 namespace gm=geometry_msgs;
00050 namespace nm=nav_msgs;
00051 
00052 using boost::bind;
00053 using boost::ref;
00054 using std::vector;
00055 
00056 typedef boost::shared_ptr<nm::OccupancyGrid> GridPtr;
00057 typedef boost::shared_ptr<nm::OccupancyGrid const> GridConstPtr;
00058 
00059 
00060 inline gm::Point transformPt (const btTransform& trans, const gm::Point32& p)
00061 {
00062   const btVector3 pt(p.x, p.y, p.z);
00063   gm::Point transformed;
00064   tf::pointTFToMsg(trans*pt, transformed);
00065   return transformed;
00066 }
00067 
00068 inline double euclideanDistance (const gm::Point& p1, const gm::Point& p2)
00069 {
00070   const double dx=p1.x-p2.x;
00071   const double dy=p1.y-p2.y;
00072   const double dz=p1.z-p2.z;
00073   return sqrt(dx*dx + dy*dy + dz*dz);
00074 }
00075 
00076 
00077 // This is our policy for computing the occupancy of a cell based on hit and pass through counts
00078 inline int8_t determineOccupancy (const unsigned hit_count, const unsigned pass_through_count, 
00079                                   const double occupancy_threshold, const double min_pass_through)
00080 {
00081   int8_t ret;
00082   if (pass_through_count < min_pass_through)
00083     ret=UNKNOWN;
00084   else if (hit_count > pass_through_count*occupancy_threshold)
00085     ret=OCCUPIED;
00086   else 
00087     ret=UNOCCUPIED;
00088   ROS_DEBUG_NAMED ("overlay_get_grid", " Hit count is %u, pass through count is %u, occupancy is %d",
00089                    hit_count, pass_through_count, ret);
00090   return ret;
00091 }
00092 
00093 OverlayClouds createCloudOverlay (const nm::MapMetaData& info, const std::string& frame_id,
00094                                   double occupancy_threshold,
00095                                   double max_distance, double min_pass_through)
00096 {
00097   OverlayClouds overlay;
00098   overlay.info = info;
00099   overlay.frame_id = frame_id;
00100   overlay.occupancy_threshold = occupancy_threshold;
00101   overlay.max_distance = max_distance;
00102   overlay.min_pass_through = min_pass_through;
00103   overlay.hit_counts.resize(info.height*info.width);
00104   overlay.pass_through_counts.resize(info.height*info.width);
00105   ROS_ASSERT(min_pass_through > 0);
00106   return overlay;
00107 }
00108 
00109 
00110 void addCloud (OverlayClouds* overlay, LocalizedCloud::ConstPtr cloud, const int inc)
00111 {
00112   
00113   ROS_ASSERT_MSG(overlay->frame_id==cloud->sensor_pose.header.frame_id,
00114                  "Frame id %s of overlayed cloud didn't match existing one %s",
00115                  cloud->sensor_pose.header.frame_id.c_str(), overlay->frame_id.c_str());
00116   const index_t num_cells = overlay->info.width*overlay->info.height;
00117   ROS_ASSERT(num_cells>0);
00118 
00119   const gm::Point& sensor_pos = cloud->sensor_pose.pose.position;
00120   ROS_DEBUG_NAMED ("overlay", "Ray tracing from %.2f, %.2f", sensor_pos.x, sensor_pos.y);
00121 
00122   // Transform points to world frame
00123   btTransform sensor_to_world;
00124   tf::poseMsgToTF(cloud->sensor_pose.pose, sensor_to_world);
00125   vector<gm::Point> transformed_points(cloud->cloud.points.size());
00126   transform(cloud->cloud.points.begin(), cloud->cloud.points.end(), transformed_points.begin(),
00127             bind(transformPt, ref(sensor_to_world), _1));
00128 
00129   // Iterate over points in this cloud
00130   BOOST_FOREACH (const gm::Point& p, transformed_points) {
00131   
00132     // Skip point unless it's within the distance threshold
00133     if (euclideanDistance(sensor_pos, p) < overlay->max_distance) {
00134       ROS_DEBUG_NAMED ("overlay_counts", " Ray tracing to point %.2f, %.2f", p.x, p.y);
00135       boost::optional<index_t> last_ind;
00136 
00137       // Inner loop: raytrace along the line and update counts
00138       // We allow both the sensor pose and the target to be off the grid
00139       BOOST_FOREACH (const Cell& c, rayTrace(overlay->info, sensor_pos, p, true, true)) {
00140         last_ind = cellIndex(overlay->info, c);
00141         overlay->pass_through_counts[*last_ind] += inc;
00142         ROS_ASSERT(overlay->pass_through_counts[*last_ind]>=0);
00143         ROS_DEBUG_NAMED ("overlay_counts", "  Pass-through counts for %d, %d are now %u", c.x, c.y, 
00144                          overlay->pass_through_counts[*last_ind]);
00145       }
00146 
00147       if (last_ind) {
00148         // If the last cell equals the point (i.e., point is not off the grid), update hit counts
00149         const Cell last_cell = indexCell(overlay->info, *last_ind);
00150         if (last_cell == pointCell(overlay->info, p)) {
00151           overlay->hit_counts[*last_ind] += inc;
00152           ROS_ASSERT(overlay->hit_counts[*last_ind]>=0);
00153           ROS_DEBUG_NAMED ("overlay_counts", "  Hit counts for %d, %d are now %u", last_cell.x, last_cell.y, 
00154                            overlay->hit_counts[*last_ind]);
00155         }
00156         else
00157           ROS_ASSERT (!withinBounds(overlay->info, pointCell(overlay->info, p)));
00158       }
00159     }
00160   }
00161   ROS_DEBUG_NAMED ("overlay", "Done ray tracing from %.2f, %.2f", sensor_pos.x, sensor_pos.y);
00162 }
00163 
00164 
00165 void addCloud (OverlayClouds* overlay, LocalizedCloud::ConstPtr cloud)
00166 {
00167   addCloud(overlay, cloud, 1);
00168 }
00169 
00170 void removeCloud (OverlayClouds* overlay, LocalizedCloud::ConstPtr cloud)
00171 {
00172   addCloud(overlay, cloud, -1);
00173 }
00174 
00175 
00176 
00177 GridPtr getGrid (const OverlayClouds& overlay) 
00178 {
00179   GridPtr grid(new nm::OccupancyGrid());
00180   grid->info = overlay.info;
00181   grid->header.frame_id = overlay.frame_id;
00182   ROS_DEBUG_STREAM_NAMED ("overlay_get_grid", "Getting overlaid grid with geometry " << overlay.info);
00183   grid->data.resize(overlay.info.width*overlay.info.height);
00184   transform(overlay.hit_counts.begin(), overlay.hit_counts.end(), overlay.pass_through_counts.begin(), 
00185             grid->data.begin(), bind(determineOccupancy, _1, _2, overlay.occupancy_threshold,
00186                                      overlay.min_pass_through));
00187   return grid;
00188 }
00189 
00190 void resetCounts (OverlayClouds* overlay)
00191 {
00192   fill(overlay->hit_counts.begin(), overlay->hit_counts.end(), 0);
00193   fill(overlay->pass_through_counts.begin(), overlay->pass_through_counts.end(), 0);
00194 }
00195 
00196 nm::MapMetaData gridInfo (const OverlayClouds& overlay) 
00197 {
00198   return overlay.info;
00199 }
00200 
00201 } // namespace occupancy_grid_utils


occupancy_grid_utils
Author(s): Bhaskara Marthi
autogenerated on Tue Jan 7 2014 11:17:09