00001 /** 00002 \file Robots/LoBot/control/LoSurvey.H 00003 \brief A cartographic behaviour, i.e., a behaviour that builds the 00004 obstacle map used by Robolocust. 00005 00006 This file defines a class that implements a map-making behaviour. This 00007 behaviour uses a SLAM algorithm to build a map and record the robot's 00008 trajectory within this map. 00009 */ 00010 00011 // //////////////////////////////////////////////////////////////////// // 00012 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00013 // by the University of Southern California (USC) and the iLab at USC. // 00014 // See http://iLab.usc.edu for information about this project. // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00017 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00018 // in Visual Environments, and Applications'' by Christof Koch and // 00019 // Laurent Itti, California Institute of Technology, 2001 (patent // 00020 // pending; application number 09/912,225 filed July 23, 2001; see // 00021 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00022 // //////////////////////////////////////////////////////////////////// // 00023 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00024 // // 00025 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00026 // redistribute it and/or modify it under the terms of the GNU General // 00027 // Public License as published by the Free Software Foundation; either // 00028 // version 2 of the License, or (at your option) any later version. // 00029 // // 00030 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00031 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00032 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00033 // PURPOSE. See the GNU General Public License for more details. // 00034 // // 00035 // You should have received a copy of the GNU General Public License // 00036 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00037 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00038 // Boston, MA 02111-1307 USA. // 00039 // //////////////////////////////////////////////////////////////////// // 00040 // 00041 // Primary maintainer for this file: mviswana usc edu 00042 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/control/LoSurvey.H $ 00043 // $Id: LoSurvey.H 13523 2010-06-07 00:22:03Z mviswana $ 00044 // 00045 00046 #ifndef LOBOT_SURVEY_BEHAVIOUR_DOT_H 00047 #define LOBOT_SURVEY_BEHAVIOUR_DOT_H 00048 00049 //------------------------------ HEADERS -------------------------------- 00050 00051 // lobot headers 00052 #include "Robots/LoBot/control/LoBehavior.H" 00053 00054 #include "Robots/LoBot/slam/LoFastSLAM.H" 00055 #include "Robots/LoBot/slam/LoOdometry.H" 00056 00057 #include "Robots/LoBot/io/LoRobot.H" 00058 #include "Robots/LoBot/thread/LoCondition.H" 00059 #include "Robots/LoBot/misc/factory.hh" 00060 00061 // Standard C++ headers 00062 #include <memory> 00063 00064 //----------------------------- NAMESPACE ------------------------------- 00065 00066 namespace lobot { 00067 00068 //------------------------- CLASS DEFINITION ---------------------------- 00069 00070 /** 00071 \class lobot::Survey 00072 00073 \brief A behaviour for updating the Robolocust occupancy grid. 00074 00075 This class implements a behaviour that uses a SLAM algorithm to build 00076 an occupancy map of lobot's environment and record its trajectory 00077 within this map. 00078 00079 NOTE: This behaviour does not vote for any motor actions. 00080 */ 00081 class Survey : public Behavior { 00082 // Prevent copy and assignment 00083 Survey(const Survey&) ; 00084 Survey& operator=(const Survey&) ; 00085 00086 // Handy type to have around in a derived class 00087 typedef Behavior base ; 00088 00089 // Boilerplate code to make the generic factory design pattern work 00090 friend class subfactory<Survey, base> ; 00091 typedef register_factory<Survey, base> my_factory ; 00092 static my_factory register_me ; 00093 00094 /// The survey behaviour uses a SLAM algorithm to build a map of the 00095 /// robot's surroundings and keep track of its trajectory. 00096 std::auto_ptr<FastSLAM> m_slam ; 00097 00098 /// Since SLAM updates can be fairly intense and take a while to 00099 /// complete, this class uses a flag to keep track of when SLAM is in 00100 /// progress and when it is not. This is necessitated by the fact that 00101 /// odometric updates take place in the main thread. If SLAM is 00102 /// currently in progress, then the low-level odometric updates should 00103 /// be accumulated till the SLAM update is done. After the SLAM update 00104 /// is complete, it can be retriggered with the accumulated odometry. 00105 bool m_slam_busy ; 00106 00107 /// This data member keeps track of the low-level odometry. It 00108 /// accumulates the low-level odometry packets. When the SLAM 00109 /// algorithm is ready for its next iteration, the Survey behaviour 00110 /// will pass the accumulated odometry to the SLAM module and reset 00111 /// this variable so that it can start accumulating odometry again. 00112 Odometry m_odometry ; 00113 00114 /// As mentioned above, since SLAM updates can take a while, we must 00115 /// accumulate low-level odometry until the SLAM algorithm is ready to 00116 /// run its next iteration. The m_odometry data member is used to 00117 /// accumulate odometry. When the SLAM module is ready, the contents 00118 /// of m_odometry will be copied to this data member, viz., ut, and 00119 /// m_odometry will be reset so it can start accumulating odometry 00120 /// afresh. 00121 /// 00122 /// NOTE: This data member is named ut to denote the latest control 00123 /// input u at time t to the SLAM algorithm. 00124 Odometry ut ; 00125 00126 /// Low-level odometric updates occur in the main thread whereas SLAM 00127 /// takes place in the survey behaviour's thread. To ensure that the 00128 /// SLAM algorithm is invoked with minimal amounts of odometric 00129 /// accumulation, we use a condition variable to signal the survey 00130 /// behaviour's thread whenever the main thread receives a low-level 00131 /// odometry packet. 00132 Condition m_odometry_cond ; 00133 00134 /// The lobot::Condition class requires a function or function object 00135 /// to be passed to its waiting and signaling methods. This inner 00136 /// helper class is used to implement a function object that can be 00137 /// used in conjunction with lobot::Condition. 00138 /// 00139 /// This class takes two type parameters: 00140 /// 00141 /// F -- function or function object implementing the predicate 00142 /// required by lobot::Condition 00143 /// R -- the return type for F; usually bool 00144 /// 00145 /// On instantiation, the cond_helper should be given a reference to 00146 /// the Survey object and a function or function object that will 00147 /// implement the desired condition variable test. When its function 00148 /// call operator is invoked, cond_helper will in turn call F, passing 00149 /// it the Survey object, and will return to lobot::Condition whatever 00150 /// F returns. 00151 /// 00152 /// Thus, this helper class acts as an intermediary and a binder. In 00153 /// its role as an intermediary, it transmits/forwards 00154 /// lobot::Condition's predicate call to F and F's return value to 00155 /// lobot::Condition. In its role as a binder, it binds the Survey 00156 /// object to F, since any meaninful synchronization actions between 00157 /// the main and survey behaviour threads will require a Survey object 00158 /// whereas the generic lobot::Condition interface calls functions 00159 /// without any arguments. 00160 template<typename F, typename R = bool> 00161 class cond_helper { 00162 Survey& survey ; 00163 F pred ; 00164 public: 00165 cond_helper(Survey&, F) ; 00166 R operator()() {return pred(survey) ;} 00167 } ; 00168 00169 // The cond_helper needs access to the Survey class's innards to 00170 // properly keep track of odometry, the SLAM algorithm's state, etc. 00171 template<typename F, typename R> friend class cond_helper ; 00172 00173 /// This inner class acts as a predicate for signaling the Survey 00174 /// behaviour's thread when new odometry is available. If the SLAM 00175 /// algorithm is currently busy, it will take care of accumulating the 00176 /// odometry. Otherwise, it will check if the odometric thresholds set 00177 /// by the user have been crossed and, if so, will return true to 00178 /// trigger the SLAM update. 00179 class odometry_helper { 00180 int distance, angle ; 00181 public: 00182 odometry_helper(int dist, int ang) ; 00183 bool operator()(Survey&) ; 00184 } ; 00185 00186 /// This inner class acts as a predicate for blocking the Survey 00187 /// behaviour's thread until the configured odometric thresholds have 00188 /// been crossed. Once this condition is met, the Survey behaviour 00189 /// will trigger the next SLAM update. Before the update is triggered, 00190 /// the SLAM algorithm will be marked busy. 00191 struct threshold_helper { 00192 bool operator()(Survey&) ; 00193 } ; 00194 00195 /// This inner class acts as a function object for resetting the state 00196 /// of the SLAM module. When this flag is cleared, the main thread's 00197 /// odometric accumulation will cease and the Survey behaviour will be 00198 /// signaled to trigger the next SLAM update. 00199 struct reset_helper { 00200 void operator()(Survey&) ; 00201 } ; 00202 00203 /// Since it can be cumbersome to directly instantiate the cond_helper 00204 /// template, we use these helper functions to return the desired 00205 /// object with all the correct types and parameters. 00206 //@{ 00207 cond_helper<odometry_helper> odometry_update(int dist, int ang) { 00208 return cond_helper<odometry_helper>(*this, odometry_helper(dist, ang)) ; 00209 } 00210 00211 cond_helper<threshold_helper> threshold_check() { 00212 return cond_helper<threshold_helper>(*this, threshold_helper()) ; 00213 } 00214 00215 cond_helper<reset_helper, void> reset_slam_busy_flag() { 00216 return cond_helper<reset_helper, void>(*this, reset_helper()) ; 00217 } 00218 //@} 00219 00220 /// A private constructor because behaviours are instantiated with an 00221 /// object factory and not directly by clients. 00222 Survey() ; 00223 00224 /// Most behaviours rely on the base class to implement the action 00225 /// processing loop in lobot::Behavior::run(). By default, that 00226 /// function checks the lobot::Shutdown signal and calls the virtual 00227 /// action() method in a loop. Successive iterations are separated by 00228 /// a short sleep. 00229 /// 00230 /// However, for the survey behaviour, we need to override the base 00231 /// class's main loop because a sleep-based loop is inappropriate. If 00232 /// we were to rely on the default run function, then we could 00233 /// potentially accumulate quite a bit of odometry before performing a 00234 /// SLAM update. In general, we would like to invoke the SLAM 00235 /// algorithm with minimal odometric accumulation so that the map and 00236 /// pose get updated with small, incremental motions rather than in 00237 /// relatively large jumps. 00238 /// 00239 /// Therefore, this class needs to provide its own implementation of 00240 /// the run function. 00241 void run() ; 00242 00243 /// Some things to do before commencing regular action processing. 00244 void pre_run() ; 00245 00246 /// This is the callback function for the low-level updates of the 00247 /// robot's odometry. 00248 static void sensor_hook(const Robot::Sensors&, unsigned long client_data) ; 00249 00250 /// This function keeps track of the robot's low-level odometry. It 00251 /// executes in the context of the main thread. Thus, to let the 00252 /// survey behaviour know that new odometry is available, it uses the 00253 /// condition variable m_odometry_cond to signal the survey 00254 /// behaviour's thread. 00255 void accumulate(int distance, int angle) ; 00256 00257 /// This method triggers the SLAM update using the latest control and 00258 /// sensor inputs. It is called by the run function, which takes care 00259 /// of the necessary signaling/synchronization with the main thread. 00260 void action() ; 00261 00262 /// Visualization support: functions for rendering the FastSLAM 00263 /// algorithm's particles on the application-wide map so we can see 00264 /// how FastSLAM is working... 00265 //@{ 00266 static void render_particles(unsigned long client_data) ; 00267 void render_particles() ; 00268 //@} 00269 00270 /// Clean-up. 00271 ~Survey() ; 00272 } ; 00273 00274 //------------------- TEMPLATE FUNCTION DEFINITIONS --------------------- 00275 00276 // Constructor for the Survey behaviour's odometry condition variable's 00277 // helper function object. 00278 template<typename F, typename R> 00279 Survey::cond_helper<F,R>::cond_helper(Survey& s, F f) 00280 : survey(s), pred(f) 00281 {} 00282 00283 //----------------------------------------------------------------------- 00284 00285 } // end of namespace encapsulating this file's definitions 00286 00287 #endif 00288 00289 /* So things look consistent in everyone's emacs... */ 00290 /* Local Variables: */ 00291 /* indent-tabs-mode: nil */ 00292 /* End: */