00001 /** 00002 \file Robots/LoBot/slam/LoSlamParams.H 00003 \brief A helper class to hold the different SLAM parameters. 00004 00005 This file defines a helper class that holds the different SLAM 00006 parameters together in one place that can be used by the different 00007 bits and pieces that implement Robolocust's SLAM subsystem. 00008 */ 00009 00010 // //////////////////////////////////////////////////////////////////// // 00011 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00012 // by the University of Southern California (USC) and the iLab at USC. // 00013 // See http://iLab.usc.edu for information about this project. // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00016 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00017 // in Visual Environments, and Applications'' by Christof Koch and // 00018 // Laurent Itti, California Institute of Technology, 2001 (patent // 00019 // pending; application number 09/912,225 filed July 23, 2001; see // 00020 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00021 // //////////////////////////////////////////////////////////////////// // 00022 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00023 // // 00024 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00025 // redistribute it and/or modify it under the terms of the GNU General // 00026 // Public License as published by the Free Software Foundation; either // 00027 // version 2 of the License, or (at your option) any later version. // 00028 // // 00029 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00030 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00031 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00032 // PURPOSE. See the GNU General Public License for more details. // 00033 // // 00034 // You should have received a copy of the GNU General Public License // 00035 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00036 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00037 // Boston, MA 02111-1307 USA. // 00038 // //////////////////////////////////////////////////////////////////// // 00039 // 00040 // Primary maintainer for this file: mviswana usc edu 00041 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/slam/LoSlamParams.H $ 00042 // $Id: LoSlamParams.H 13575 2010-06-17 01:42:18Z mviswana $ 00043 // 00044 00045 #ifndef LOBOT_SLAM_PARAMS_DOT_H 00046 #define LOBOT_SLAM_PARAMS_DOT_H 00047 00048 //------------------------------ HEADERS -------------------------------- 00049 00050 // lobot headers 00051 #include "Robots/LoBot/ui/LoDrawable.H" 00052 #include "Robots/LoBot/misc/singleton.hh" 00053 #include "Robots/LoBot/util/range.hh" 00054 #include "Robots/LoBot/util/triple.hh" 00055 00056 // Standard C++ headers 00057 #include <string> 00058 #include <utility> 00059 00060 //----------------------------- NAMESPACE ------------------------------- 00061 00062 namespace lobot { 00063 00064 //------------------------- CLASS DEFINITION ---------------------------- 00065 00066 /** 00067 \class lobot::SlamParams 00068 \brief A helper class for holding the various SLAM related parameters. 00069 00070 The settings for Robolocust's SLAM subsystem are spread over a couple 00071 of different sections of the config file. This class helps put them 00072 all in one place so that all the SLAM related modules can access these 00073 parameters from one place instead of having to duplicate code or 00074 introduce unweildy module dependencies. 00075 */ 00076 class SlamParams : public singleton<SlamParams> { 00077 /// Robolocust uses an occupancy grid for its map. Each cell in this 00078 /// grid holds a probability indicating the confidence level regarding 00079 /// the presence of an obstacle at that particular position in the 00080 /// map. 00081 /// 00082 /// To make the map cover a reasonably substantial physical area while 00083 /// simultaneously minimizing the amount of memory required to hold 00084 /// the grid, we need to discretize the physical space of the robot's 00085 /// environment. Thus, each cell in the grid will represent a small 00086 /// square area of the environment. 00087 /// 00088 /// This setting specifies the size of the above-mentioned square (in 00089 /// mm). 00090 float m_cell_size ; 00091 00092 /// The map's extents are specified using [left, right, bottom, top] 00093 /// values. These extents are in the physical environment's coordinate 00094 /// system (i.e., mm). 00095 float m_extents[4] ; 00096 00097 /// The above parameters dictate the size of the map's grid. These two 00098 /// data members are used to store the grid's dimensions. 00099 int m_width, m_height ; 00100 00101 /// This member holds the length of the map's diagonal. It is useful 00102 /// for the probabilistic beam model applied by the FastSLAM algorithm 00103 /// to the laser range finder measurements. 00104 float m_max_distance ; 00105 00106 /// This member variable holds the x and y scale factors for 00107 /// converting real/physical coordinates to grid coordinates and vice 00108 /// versa. 00109 std::pair<float, float> m_scale ; 00110 00111 /// The robot's pose w.r.t. the map is specified using an (x, y) 00112 /// position and an angle indicating the direction in which it is 00113 /// "looking." This setting specifies the robot's initial pose. 00114 triple<float, float, float> m_initial_pose ; 00115 00116 /// When the robot moves, it will experience some amount of 00117 /// translational and rotational slip. This parameter captures these 00118 /// errors and they are used in the prediction step of the FastSLAM 00119 /// algorithm. 00120 /// 00121 /// The value of this setting is expected to be a triple of floating 00122 /// point numbers. The first two numbers specify the amount of 00123 /// translational error (in mm) to expect in the x and y directions 00124 /// respectively. The third number specifies the amount of rotational 00125 /// error in degrees. 00126 /// 00127 /// NOTE: Ideally, these parameters will be empirically determined via 00128 /// either manual experiments designed to characterize and quantify 00129 /// systematic odometric errors or via some automated learning 00130 /// approach based on sample data. 00131 triple<float, float, float> m_errors ; 00132 00133 /// The FastSLAM algorithm is a Rao-Blackwellized particle filter. 00134 /// This setting allows us to configure the number of particles to 00135 /// use. 00136 int m_num_particles ; 00137 00138 /// In order to cut down on the amount of processing required by the 00139 /// FastSLAM algorithm and also to preserve particle diversity, 00140 /// Robolocust will only resample the particle population when the 00141 /// variance of the particle weights becomes high (thus indicating a 00142 /// lot of spread and high uncertainty in the state estimate). 00143 /// 00144 /// To make the actual determination as to when to resample, 00145 /// Robolocust computes the effective sample size by taking the 00146 /// reciprocal of the sum of the squares of all the weights. When the 00147 /// effective sample size (ESS) drops below some threshold, the 00148 /// particle filter's resampling step will kick in. 00149 /// 00150 /// The following setting specifies the effective sample size 00151 /// threshold. Usually, a good value to use for it would be half the 00152 /// number of particles. However, to disable the ESS check, you may 00153 /// set this to zero or to a value greater than the number of 00154 /// particles. In that case, resampling will take place after each and 00155 /// every iteration of the SLAM update. 00156 int m_ess_threshold ; 00157 00158 /// During resampling, it might be a good idea to introduce some 00159 /// random particles just in case the filter has arrived at an 00160 /// incorrect state estimate. However, we don't want to insert random 00161 /// particles all the time. 00162 /// 00163 /// Therefore, Robolocust tracks the averages of the particle weights 00164 /// and inserts random particles only when the short-term average 00165 /// performs poorly w.r.t. the long-term average. An exponential 00166 /// filter is used to smooth the short and long-term particle weight 00167 /// averages to ensure that momentary glitches don't get misconstrued 00168 /// as incorrect state estimates. 00169 /// 00170 /// The following setting specifies the values of the exponential 00171 /// decays to use for filtering the short and long-term averages. 00172 /// These values are plugged into a running average formula for 00173 /// computing the averages. The long-term average's decay parameter 00174 /// must be much less than that of the short-term average. 00175 /// 00176 /// This setting expects to be given two numbers. The first is the 00177 /// decay parameter for the short-term average and the second is the 00178 /// decay parameter for the long-term average. Both numbers must lie 00179 /// between zero and one. 00180 std::pair<float, float> m_alpha ; 00181 00182 /// As we know, in a particle filter, each particle makes a guess 00183 /// about the current state. These guesses are, of course, not 00184 /// entirely random; rather they are the result of probabilistic 00185 /// motion and sensor models. Good guesses, i.e., ones that match the 00186 /// sensor data, get more weight while poor ones are assigned lower 00187 /// weights and get filtered out. The overall state of the robot can 00188 /// then be gleaned by analyzing the particle population's density. 00189 /// 00190 /// There are many ways to perform particle density analysis. The one 00191 /// used by Robolocust's FastSLAM implementation works in the 00192 /// following manner: 00193 /// 00194 /// 1. First, find the particle with maximum weight 00195 /// 2. Then, find K particles whose states most closely match that 00196 /// of the above particle 00197 /// 3. Compute the current state as the average of these K states 00198 /// 00199 /// The following setting specifies the value to use for K. It is 00200 /// specified as a percentage of the total number of particles. To use 00201 /// just the particle with max weight and not bother with computing 00202 /// the average of the top K particles, set this value to a negative 00203 /// number. 00204 int m_k ; 00205 00206 /// Like all Bayesian filters, the FastSLAM algorithm has a prediction 00207 /// step, wherein the latest control command is used to predict a new 00208 /// state, and a correction step, wherein the latest sensor data is 00209 /// used to correct the state prediction. Since a laser range finder 00210 /// serves as lobot's primary sensing modality, the Robolocust 00211 /// implementation of FastSLAM employs a probabilistic beam model in 00212 /// its correction step. This beam model involves ray casting, a 00213 /// computationally intense operation. To cut down on the number of 00214 /// rays to be cast, we can configure Robolocust to consider only some 00215 /// of the distance measurements returned by the laser range finder. 00216 /// 00217 /// The following setting allows us to do that. It is expected to be a 00218 /// triple of integers. The first two numbers specify the starting and 00219 /// ending angles to consider (e.g., from -90 to +90 degrees). The 00220 /// third number is a step size. Thus, for example, if the beam_specs 00221 /// setting is "-90 90 15," then the FastSLAM algorithm will only 00222 /// consider the laser range finder readings corresponding to -90, 00223 /// -75, -60, -45, -30, -15, 0, 15, 30, 45, 60, 75 and 90 degrees, 00224 /// which makes for a total of 13 ray casting operations instead of 00225 /// (potentially) > 180. 00226 /// 00227 /// NOTE: Limiting the field of view of the laser range finder speeds 00228 /// up the FastSLAM algorithm but at the expense of map accuracy. 00229 triple<int, int, int> m_beam_specs ; 00230 00231 /// The probabilistic beam model mentioned above works by computing 00232 /// the expected range reading from the current state estimate (i.e., 00233 /// robot pose and occupancy map) and then seeing how well the actual 00234 /// distance measurements match the expected ones. We expect particles 00235 /// with good state estimates to match the actual sensor data better 00236 /// than those with poor estimates. Thus, good particles will get 00237 /// higher weights and the particle filter will pick those particles 00238 /// while culling the poor ones from the particle population. 00239 /// 00240 /// To rate the state estimates made by different particles, we run 00241 /// the actual range reading through the formula for a normal 00242 /// distribution centered at the expected range. This will produce a 00243 /// number that we can use for the particle weight. The following 00244 /// setting specifies the standard deviation for the above-mentioned 00245 /// application of the normal distribution formula. It is a distance 00246 /// (in mm). 00247 /// 00248 /// The value of this setting should reflect the amount of error we 00249 /// are willing to tolerate between the estimated range readings and 00250 /// the actual ones. It should also take into account the 00251 /// discretization parameters of the occupancy map. 00252 float m_beam_model_sigma ; 00253 00254 /// The beam model described above computes the likelihood of a single 00255 /// distance measurement. Since the laser range finder returns 00256 /// multiple distance readings, we have to multiply the individual 00257 /// beam probabilities to obtain the final/total measurement 00258 /// likelihood. 00259 /// 00260 /// Unfortunately, as each beam's probability is a number between zero 00261 /// and one, multiplying the individual probabilities together will 00262 /// very rapidly result in extremely small numbers: of the order of 00263 /// ten raised to -50. This causes floating point instabilities. 00264 /// 00265 /// To work around this problem, we multiply individual beam 00266 /// probabilities by a large constant and multiply the resulting 00267 /// numbers instead of the original [0,1] likelihoods. The following 00268 /// setting specifies the value of the above-mentioned large constant. 00269 float m_beam_model_fudge ; 00270 00271 /// For the beam model described above to work, we need to specify the 00272 /// minimum and maximum range readings the laser range finder can 00273 /// produce. Although the robot can determine this directly from the 00274 /// device itself, depending on the environment and on other factors, 00275 /// we may want the FastSLAM algorithm to consider a range different 00276 /// from the device's actual range. This setting allows us to do that. 00277 /// Its value should be two floating point numbers. The first one 00278 /// specifies the beam's minimum range (in mm) and the second one its 00279 /// maximum range (again in mm). 00280 range<float> m_beam_range ; 00281 00282 /// In addition to the expected measurement computation, the 00283 /// probabilistic beam model should also consider various other 00284 /// factors that come into play and corrupt sensor data. Instead of 00285 /// explicitly modeling these other things, we simply lump all of them 00286 /// into a uniform distribution based on the range of distance 00287 /// readings returned by the LRF. Since this value is a constant, we 00288 /// can compute and store it with the parameters structure. 00289 float m_prob_rnd ; 00290 00291 /// During the map update step, the SLAM algorithm uses each distance 00292 /// measurement to determine which cells in the occupancy grid are 00293 /// occupied. Since the grid is a discretized version of the world, 00294 /// there will, naturally, be discrepancies between the actual 00295 /// distance reading and the same range in grid coordinates. 00296 /// 00297 /// This setting specifies the amount of discrepancy that should be 00298 /// tolerated. As an example of how this works, let's say that the 00299 /// value of this setting is set to 100mm and that we get a reading 00300 /// (in some direction) of 622mm. Then, depending on the map's 00301 /// discretization parameters, as the algorithm traces the distance 00302 /// measurement within the occupancy grid in order to find the cell at 00303 /// which the measurement ends, it will accept a cell that is within 00304 /// 100mm of 622, i.e., from 522 to 722mm. 00305 float m_occ_range_error ; 00306 00307 /// This setting specifies the minimum probability value a cell in the 00308 /// occupancy grid should have for it to be considered as being 00309 /// occupied. Cells with probabilities lower than this threshold will 00310 /// be considered as free space. 00311 /// 00312 /// This parameter's value should be a floating point number between 00313 /// zero and one. 00314 /// 00315 /// NOTE: Internally, this number gets converted to its equivalent 00316 /// log-odds form and the threshold check is then performed in 00317 /// "log-odds space." 00318 float m_occ_threshold ; 00319 00320 /// As the robot moves around and senses its environment, its internal 00321 /// grid update and query algorithms will not always reliably hit the 00322 /// same cell over and over (due, for example, to sensor and actuator 00323 /// noise). Therefore, when we update a cell (x,y) in the occupancy 00324 /// grid, we should also update its immediate neighbours to ensure 00325 /// that subsequent queries near (x,y) are not entirely off the mark. 00326 /// 00327 /// The following setting specifies a weighting factor to use when 00328 /// updating a cell. This factor will applied to the cell in question 00329 /// and the remaining weight will be applied to its immediate 00330 /// neighbours. To illustrate how this works, let us say the update 00331 /// weight is set to 0.75. Then, when the robot updates a cell (x,y), 00332 /// it will apply 75% of the update delta (see the "occupancy_deltas" 00333 /// setting defined above) to (x,y) and divide the remaining 25% of 00334 /// the delta value equally between the remaining 8 cells in the 00335 /// immediate neighbourhood of (x,y). If (x,y) is in one of the 00336 /// corners of the map, the remaining 25% will be divided equally 00337 /// between the 3 neighbouring cells; if (x,y) is on an edge boundary 00338 /// other than a corner, the remaining 25% will be divided equally 00339 /// between the 5 immediate neighbours. 00340 /// 00341 /// As can be gleaned from the above discussion, the value of this 00342 /// setting should be a floating point number in the range [0,1]. 00343 /// 00344 /// NOTE: Although it is referred to as the "update" weight, this 00345 /// parameter is also used when querying the map for occupancy 00346 /// likelihoods. Thus, when the robot wants to check the occupancy 00347 /// likelihood of some location (x,y), this weighting factor (e.g., 00348 /// 75%) will be applied to the actual value stored in that cell and 00349 /// the remaining weight (25%) will be divided equally between the 00350 /// immediate neighbours of (x,y) to produce a weighted sum for the 00351 /// final occupancy value retrieved from the grid. 00352 float m_update_weight ; 00353 00354 /// Since odometry tends to be more error-prone than a laser range 00355 /// finder, Robolocust can be configured to use a scan matching 00356 /// algorithm to correct the raw odometry and use the corrected values 00357 /// to compute pose updates in the filter's prediction step. The 00358 /// following flag can be used to turn scan matching on or off 00359 /// (default is off). 00360 bool m_match_scans ; 00361 00362 /// Although SLAM is designed to learn a map and localize the robot at 00363 /// the same time, we can configure the Robolocust system to only 00364 /// perform localization given a known map. The following setting 00365 /// specifies a file name for a map. The robot will read this map 00366 /// during initialization and then localize itself w.r.t. this map 00367 /// using the Monte Carlo Localization component of the SLAM 00368 /// algorithm. 00369 /// 00370 /// The map file is expected to be a plain text file containing 00371 /// coordinates of obstacles. Each obstacle is specified using four 00372 /// coordinates. The first two coordinates specify the location of the 00373 /// lower left corner of a rectangle where the obstacle "begins" and 00374 /// the next two are for the upper right corner where the obstacle 00375 /// "ends." 00376 /// 00377 /// The coordinates are all expressed in the map's real/physical 00378 /// coordinate system. 00379 /// 00380 /// NOTE: This setting is actually part of the survey behaviour. 00381 std::string m_map_file ; 00382 00383 /// This member holds the geometry specs for the map's visualization. 00384 Drawable::Geometry m_geometry ; 00385 00386 /// Private constructor because this class is a singleton. 00387 SlamParams() ; 00388 friend class singleton<SlamParams> ; // boilerplate 00389 00390 public: 00391 /// This function returns the size of each cell of the occupancy grid, 00392 /// i.e., the amount of actual physical area each cell in the grid 00393 /// takes up. 00394 /// 00395 /// NOTE: Each cell in the occupancy grid is a square. This function 00396 /// returns the length of a side of the square. 00397 static float map_cell_size() {return instance().m_cell_size ;} 00398 00399 /// This function returns extents of the map in physical coordinates. 00400 static void map_extents(float* L, float* R, float* B, float* T) ; 00401 00402 /// This function returns the map extents via an array of four 00403 /// numbers ordered like so: left, right, bottom, top. The extents are 00404 /// in physical coordnates. 00405 static void map_extents(float ext[4]) ; 00406 00407 /// This function returns a pointer to the internal array holding the 00408 /// map extents. This is a convenience function. Clients should not 00409 /// misuse the returned pointer. 00410 static const float* map_extents() {return instance().m_extents ;} 00411 00412 /// These function return the size of the occupancy grid, i.e., the 00413 /// number of cells in the horizontal and vertical directions. This 00414 /// number is derived from the map discretization as specified in the 00415 /// config file. 00416 //@{ 00417 static int map_width() {return instance().m_width ;} 00418 static int map_height() {return instance().m_height ;} 00419 //@} 00420 00421 /// This function returns the max distance that can be traversed 00422 /// within the map. 00423 static float max_map_distance() {return instance().m_max_distance ;} 00424 00425 /// These functions return the scale factors for converting 00426 /// real/physical coordinates to grid coordinates and vice versa. 00427 //@{ 00428 static float Sx() {return instance().m_scale.first ;} 00429 static float Sy() {return instance().m_scale.second ;} 00430 //@} 00431 00432 /// This function returns the robot's initial pose as configured by 00433 /// the user. 00434 static const triple<float, float, float>& initial_pose() { 00435 return instance().m_initial_pose ; 00436 } 00437 00438 /// These functions return the translational and rotational errors for 00439 /// the robot's motion as specified by the user. 00440 //@{ 00441 static float x_error() {return instance().m_errors.first ;} 00442 static float y_error() {return instance().m_errors.second ;} 00443 static float t_error() {return instance().m_errors.third ;} 00444 //@} 00445 00446 /// This function returns the number of particles to be used by the 00447 /// FastSLAM algorithm. 00448 static int num_particles() {return instance().m_num_particles ;} 00449 00450 /// This function returns the threshold value for the effective sample 00451 /// size test, which determines when the particle filter will resample 00452 /// its particle population. 00453 static int ess_threshold() {return instance().m_ess_threshold ;} 00454 00455 /// These functions return the decay parameters for the short and 00456 /// long-term averages used to determine the appropriate time and 00457 /// number of random particles to be inserted. 00458 //@{ 00459 static float alpha_fast() {return instance().m_alpha.first ;} 00460 static float alpha_slow() {return instance().m_alpha.second ;} 00461 //@} 00462 00463 /// This function returns the number of particles that should most 00464 /// closely match the particle with max weight when deciding the 00465 /// current best hypothesis regarding the robot's pose and environment 00466 /// map. 00467 static int num_matches() {return instance().m_k ;} 00468 00469 /// These functions return various parameters used by the 00470 /// probabilistic beam model. 00471 //@{ 00472 static int beam_start() {return instance().m_beam_specs.first ;} 00473 static int beam_end() {return instance().m_beam_specs.second;} 00474 static int beam_step() {return instance().m_beam_specs.third ;} 00475 static float beam_sigma() {return instance().m_beam_model_sigma ;} 00476 static float beam_fudge() {return instance().m_beam_model_fudge ;} 00477 static range<float> beam_range() {return instance().m_beam_range ;} 00478 static float beam_prob_rnd() {return instance().m_prob_rnd ;} 00479 static float beam_occ_range_error() {return instance().m_occ_range_error ;} 00480 //@} 00481 00482 /// This function returns the minimum occupancy likelihood 00483 /// corresponding to the "occupied" state. 00484 static float occ_threshold() {return instance().m_occ_threshold ;} 00485 00486 /// This function returns the amount of "spread" associated with 00487 /// checking or setting a cell's likelihood across its immediate 00488 /// neighbours. 00489 static float update_weight() {return instance().m_update_weight ;} 00490 00491 /// This function returns true if scan matching is enabled; false 00492 /// otherwise. 00493 static bool match_scans() {return instance().m_match_scans ;} 00494 00495 /// If SLAM is configured to perform localization only, i.e., no 00496 /// mapping, then the user will be expected to specify a file name 00497 /// containing the known map to be used for localization. This 00498 /// function returns the map file name. 00499 static std::string map_file() {return instance().m_map_file ;} 00500 00501 /// This function returns true if SLAM is configured to perform 00502 /// localization only. In this mode, the user must supply a known map 00503 /// and only the Monte Carlo Localization component of the SLAM 00504 /// algorithm will be used. This mode is useful for testing the 00505 /// localization part of SLAM in isolation from the mapping part. 00506 static bool localization_mode() {return ! instance().m_map_file.empty() ;} 00507 00508 /// This function returns true if SLAM is configured to perform both 00509 /// localization and mapping. This is the usual operational mode for a 00510 /// SLAM algorithm. 00511 static bool slam_mode() {return ! localization_mode() ;} 00512 00513 /// This function returns the geometry of the map's UI drawable. It is 00514 /// useful when figuring out transformations for map related rendering 00515 /// operations. 00516 static Drawable::Geometry map_geometry() {return instance().m_geometry ;} 00517 } ; 00518 00519 //----------------------------------------------------------------------- 00520 00521 } // end of namespace encapsulating this file's definitions 00522 00523 #endif 00524 00525 /* So things look consistent in everyone's emacs... */ 00526 /* Local Variables: */ 00527 /* indent-tabs-mode: nil */ 00528 /* End: */