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
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
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
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
00130 BOOST_FOREACH (const gm::Point& p, transformed_points) {
00131
00132
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
00138
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
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 }