Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

occupancy_grid.cpp

Go to the documentation of this file.
00001 #include <iostream>
00002 #include <fstream>
00003 #include <algorithm>
00004 #include <queue>
00005 #include "properties.hpp"
00006 #include "occupancy_grid.hpp"
00007 #include "cone_tracing.hpp"
00008 
00009 using namespace Arak;
00010 
00011 OccupancyGrid::OccupancyGrid(const Arak::Util::PropertyMap& props) {
00012   using namespace Arak::Util;
00013   // Set up the grid.
00014   int n = 1;
00015   if (hasp(props, "arak.occupancy_grid.grid_size")) {
00016     parse(getp(props, "arak.occupancy_grid.grid_size"), n);
00017     assert(n > 0);
00018   }
00019   double x, y, width, height;
00020   assert(parse(getp(props, "arak.occupancy_grid.xmin"), x));
00021   assert(parse(getp(props, "arak.occupancy_grid.ymin"), y));
00022   assert(parse(getp(props, "arak.occupancy_grid.width"), width));
00023   assert(parse(getp(props, "arak.occupancy_grid.height"), height));
00024   Geometry::Rectangle r(x, y, x + width, y + height);
00025   double aspect_ratio = width / height;
00026   int rows = std::max(1, int(sqrt(double(n) / aspect_ratio)));
00027   int cols = n / rows;
00028   grid = new EstimatorGrid(r, rows, cols);
00029   for (int i = 0; i < rows; i++)
00030     for (int j = 0; j < cols; j++) {
00031       EstimatorGrid::Cell& cell = grid->getCell(i, j);
00032       OccupancyEstimator* est = new OccupancyEstimator();
00033       cell.add(est);
00034     }
00035   // Process any measurements.
00036   if (hasp(props, "arak.obs_type")) {
00037     const std::string& obs_type = getp(props, "arak.obs_type");    
00038     if (obs_type == "range") {
00039       // Laser data.  Get the parameters.
00040       double maxRange, obstacleWidth, p_given_occ, p_given_free;
00041       assert(parse(getp(props, "arak.range_obs.max_range"), maxRange));
00042       assert(parse(getp(props, "arak.occupancy_grid.obstacle_width"), obstacleWidth));
00043       assert(parse(getp(props, "arak.occupancy_grid.p_given_occ"), p_given_occ));
00044       assert(parse(getp(props, "arak.occupancy_grid.p_given_free"), p_given_free));
00045       // Process the data.
00046       const std::string& datafile_path = 
00047   getp(props, "arak.range_obs.data_file");
00048       std::ifstream in(datafile_path.data());
00049       assert(in.good());
00050       int n;
00051       in >> n;
00052       std::vector<Geometry::Point> impacts;
00053       Geometry::Point source, impact;
00054       in >> source >> impact;
00055       impacts.push_back(impact);
00056       for (int i = 1; i < n; i++) {
00057   Geometry::Point new_source;
00058   in >> new_source >> impact;
00059   if (new_source == source)
00060     impacts.push_back(impact);
00061   else {
00062     laser_scan(source, impacts, maxRange, 
00063          obstacleWidth, p_given_occ, p_given_free);
00064     source = new_source;
00065     impacts.clear();
00066     impacts.push_back(impact);
00067   }
00068       }
00069       laser_scan(source, impacts, maxRange, obstacleWidth, p_given_occ, p_given_free);
00070       /*
00071       for (int i = 0; i < n; i++) {
00072   Geometry::Point p, q;
00073   in >> p >> q;
00074   laser(p, q, maxRange, obstacleWidth, p_given_occ, p_given_free);
00075       }
00076       */
00077     } else if (obs_type == "sonar") {
00078       // Sonar data.  Get the parameters.
00079       double width, maxRange, obstacleWidth;
00080       assert(parse(getp(props, "arak.sonar_obs.width"), width));
00081       assert(parse(getp(props, "arak.sonar_obs.max_range"), maxRange));
00082       assert(parse(getp(props, "arak.occupancy_grid.obstacle_width"), obstacleWidth));
00083       double p_given_occ, p_given_free;
00084       assert(parse(getp(props, "arak.occupancy_grid.p_given_occ"), p_given_occ));
00085       assert(parse(getp(props, "arak.occupancy_grid.p_given_free"), p_given_free));
00086       // Process the data.
00087       const std::string& datafile_path = 
00088   getp(props, "arak.range_obs.data_file");
00089       std::ifstream in(datafile_path.data());
00090       assert(in.good());
00091       int n;
00092       in >> n;
00093       for (int i = 0; i < n; i++) {
00094   Geometry::Point source;
00095   double angle, range;
00096   in >> source >> angle >> range;
00097   sonar(source, angle, range, maxRange, obstacleWidth, width, 
00098         p_given_occ, p_given_free);
00099       }
00100     } else {
00101       std::cerr << "Unrecognized observation type: " 
00102     << obs_type << std::endl;
00103     }
00104   }
00105 }
00106 
00107 OccupancyGrid::~OccupancyGrid() {
00108   for (int i = grid->numRows() - 1; i >= 0; i--) {
00109     for (int j = 0; j < grid->numCols(); j++) {
00110       EstimatorGrid::Cell& cell = grid->getCell(i, j);
00111       delete *(cell.getItemList().begin());
00112     }
00113   }
00114   delete grid;
00115 }
00116 
00117 void OccupancyGrid::laser(const Geometry::Point& source,
00118         const Geometry::Point& impact,
00119         double maxRange,
00120         double obstacleWidth,
00121         double p_given_occ,
00122         double p_given_free) {
00123   // Ignore readings over 50 meters.
00124   if (CGAL::to_double(CGAL::squared_distance(source, impact)) > 
00125       maxRange * maxRange) 
00126     return;
00127   // Compute the max range point.
00128   const Geometry::Vector v = impact - source;
00129   double range = sqrt(CGAL::to_double(v.squared_length()));
00130   const Geometry::Point max = source + v * (maxRange / range);
00131   // Compute the obstacle segment.
00132   Geometry::Segment obstacle(impact, impact + v * (obstacleWidth / range));
00133   // Use a line search from the source to the back of the obstacle.
00134   typedef EstimatorGrid::LineCellIterator Iterator; 
00135   Iterator it(*grid, source, obstacle.target(), Iterator::SEGMENT()), end;
00136   bool free = true;
00137   do {
00138     EstimatorGrid::Cell& cell = *it;
00139     OccupancyEstimator* est = *(cell.getItemList().begin());
00140     // Determine if we have entered the obstacle.
00141     if (free && !cell.has_on_unbounded_side(impact)) free = false;
00142     if (free) {
00143       est->condition(p_given_free);
00144     } else
00145       est->condition(p_given_occ);
00146   } while (++it != end);
00147 }
00148 
00149 void OccupancyGrid::laser_scan(const Geometry::Point& source,
00150              const std::vector<Geometry::Point>& impacts,
00151              double maxRange,
00152              double obstacleWidth,
00153              double p_given_occ,
00154              double p_given_free) {
00155   // std::cerr << "Processing scan with " << impacts.size() << " beams." << std::endl;
00156   // Compute a bounding box containing all cells that should be
00157   // updated by this scan.
00158   double xmin = source.x(), xmax = source.x(), 
00159     ymin = source.y(), ymax = source.y(); 
00160   for (unsigned int i = 0; i < impacts.size(); i++) {
00161     xmin = std::min(xmin, impacts[i].x() - obstacleWidth);
00162     xmax = std::max(xmax, impacts[i].x() + obstacleWidth);
00163     ymin = std::min(ymin, impacts[i].y() - obstacleWidth);
00164     ymax = std::max(ymax, impacts[i].y() + obstacleWidth);
00165   }
00166   // Iterate over these cells.
00167   typedef EstimatorGrid::RectangleCellIterator Iterator; 
00168   Iterator it(*grid, Geometry::Rectangle(xmin, ymin, xmax, ymax)), end;
00169   while (it != end) {
00170     EstimatorGrid::Cell& cell = *it;
00171     OccupancyEstimator* est = *(cell.getItemList().begin());
00172     // Find the center point of the cell.
00173     Geometry::Point center = CGAL::midpoint(cell[0], cell[2]);
00174     // Determine the laser beam closest to this cell (in angle).
00175     unsigned int closest = 0;
00176     double dist = std::numeric_limits<double>::infinity();
00177     for (unsigned int i = 0; i < impacts.size(); i++) {
00178       Geometry::Line line(source, impacts[i]);
00179       Geometry::Point projection = line.projection(center);
00180       double d = sqrt(CGAL::to_double(CGAL::squared_distance(center, projection)));
00181       if (d < dist) {
00182   closest = i;
00183   dist = d;
00184       }
00185     }
00186     // Determine if the angle to the closest beam is close enough.
00187     double angle_to_center = atan2(center.y() - source.y(),
00188            center.x() - source.x());
00189     double beam_angle = atan2(impacts[closest].y() - source.y(),
00190             impacts[closest].x() - source.x());
00191     // std::cerr << "Beam: " << beam_angle << " Center: " << angle_to_center << std::endl;
00192     if ((fabs(angle_to_center - beam_angle) < M_PI / 180.0)  // TODO: parameter
00193   &&
00194   (CGAL::to_double(CGAL::squared_distance(source, impacts[closest])) < 
00195    maxRange * maxRange)) { // ignore max-range readings
00196       // Update this cell with this beam.
00197       double obs_range = 
00198   sqrt(CGAL::to_double(CGAL::squared_distance(impacts[closest], source)));
00199       double center_range = 
00200   sqrt(CGAL::to_double(CGAL::squared_distance(center, source)));
00201       if (fabs(obs_range - center_range) < obstacleWidth / 2.0)
00202   est->condition(p_given_occ);
00203       else if (obs_range > center_range)
00204   est->condition(p_given_free);
00205     }
00206     ++it;
00207   }
00208 }
00209 
00210 void OccupancyGrid::sonar(const Geometry::Point& source,
00211         double angle,
00212         double range,
00213         double maxRange,
00214         double obstacleWidth,
00215         double width,
00216         double p_given_occ,
00217         double p_given_free) {
00218   double minAngle = angle - width / 2.0;
00219   double maxAngle = angle + width / 2.0;
00220   Geometry::Direction min(cos(minAngle), sin(minAngle));
00221   Geometry::Direction max(cos(maxAngle), sin(maxAngle));
00222   range = std::min(range, maxRange);
00223   Geometry::Triangle t = 
00224     outerApprox(source, min, max, Geometry::Kernel::FT(range));
00225   typedef EstimatorGrid::TriangleCellIterator Iterator; 
00226   for (Iterator it = Iterator(*grid, t); it != Iterator(); ++it) {
00227     EstimatorGrid::Cell& cell = *it;
00228     OccupancyEstimator* est = *(cell.getItemList().begin());
00229     // Compute the midpoint (representative) of the cell.
00230     Geometry::Point p = CGAL::midpoint(cell.min(), cell.max());
00231     // Compute the range and angle to this point.
00232     double r = sqrt(CGAL::to_double(CGAL::squared_distance(source, p)));
00233     Geometry::Direction d = (p - source).direction();
00234     // Determine if the point is inside the cone.
00235     if (d.counterclockwise_in_between(min, max)) {
00236       // Determine if the point is before contact, at contact, or
00237       // after contact.
00238       if (r < (range - (obstacleWidth / 2.0))) {
00239   // The point is before contact.
00240   est->condition(p_given_free);
00241       } else if ((range < maxRange) && 
00242      (r <= (range + (obstacleWidth / 2.0)))) {
00243   // The point is at contact.
00244   est->condition(p_given_occ);
00245       }
00246     }
00247   }
00248 }
00249 

Generated on Wed May 25 14:39:17 2005 for Arak by doxygen 1.3.6