00001 /** 00002 \file Robots/LoBot/control/LoDangerZone.H 00003 \brief An object for monitoring lobot's danger zone. 00004 00005 This file defines a class that reads the danger zone settings from the 00006 Robolocust config file and implements an update method that the main 00007 thread can use to keep the current state of the danger zone in sync 00008 with the laser range finder measurements. Other threads, viz., the 00009 Robolocust behaviours, can read the current danger zone state and take 00010 appropriate action using the different state access APIs implemented 00011 by the danger zone object. 00012 */ 00013 00014 // //////////////////////////////////////////////////////////////////// // 00015 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00016 // by the University of Southern California (USC) and the iLab at USC. // 00017 // See http://iLab.usc.edu for information about this project. // 00018 // //////////////////////////////////////////////////////////////////// // 00019 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00020 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00021 // in Visual Environments, and Applications'' by Christof Koch and // 00022 // Laurent Itti, California Institute of Technology, 2001 (patent // 00023 // pending; application number 09/912,225 filed July 23, 2001; see // 00024 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00025 // //////////////////////////////////////////////////////////////////// // 00026 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00027 // // 00028 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00029 // redistribute it and/or modify it under the terms of the GNU General // 00030 // Public License as published by the Free Software Foundation; either // 00031 // version 2 of the License, or (at your option) any later version. // 00032 // // 00033 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00034 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00035 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00036 // PURPOSE. See the GNU General Public License for more details. // 00037 // // 00038 // You should have received a copy of the GNU General Public License // 00039 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00040 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00041 // Boston, MA 02111-1307 USA. // 00042 // //////////////////////////////////////////////////////////////////// // 00043 // 00044 // Primary maintainer for this file: mviswana usc edu 00045 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/io/LoDangerZone.H $ 00046 // $Id: LoDangerZone.H 13037 2010-03-23 01:00:53Z mviswana $ 00047 // 00048 00049 #ifndef LOBOT_DANGER_ZONE_DOT_H 00050 #define LOBOT_DANGER_ZONE_DOT_H 00051 00052 //------------------------------ HEADERS -------------------------------- 00053 00054 // lobot headers 00055 #include "Robots/LoBot/io/LoLRFData.H" 00056 #include "Robots/LoBot/io/LoLaserRangeFinder.H" 00057 00058 #include "Robots/LoBot/misc/singleton.hh" 00059 #include "Robots/LoBot/util/range.hh" 00060 00061 // Standard C++ headers 00062 #include <string> 00063 #include <vector> 00064 00065 //----------------------------- NAMESPACE ------------------------------- 00066 00067 namespace lobot { 00068 00069 //------------------------- CLASS DEFINITION ---------------------------- 00070 00071 /** 00072 \class lobot::DangerZone 00073 \brief An object for monitoring the robot's danger zone. 00074 00075 This class provides an API for keeping track of the robot's danger 00076 zone. The Robolocust danger zone works by dividing the laser range 00077 finder's FOV into several angular blocks. Each block has three 00078 fundamental settings: 00079 00080 - extents 00081 - distance 00082 - threshold 00083 00084 The extents define the block's angular range. A blocks's distance 00085 setting specifies the minimum distance between the robot and 00086 obstacles. A block's threshold setting specifies the minimum number of 00087 LRF distance measurements that must be less than its distance setting 00088 for the block to be actually considered as being "penetrated" or 00089 "active." 00090 00091 For example, let us say we have a danger zone block with extents [-30, 00092 30], distance 350 and threshold 20. This means that when we have >= 20 00093 LRF readings that are <= 350mm in the angular range -30 degrees to +30 00094 degrees, an obstacle has penetrated this particular portion of the 00095 robot's danger zone and, thus, activated this block. 00096 00097 The danger zone settings are specified in the Robolocust config file. 00098 00099 The main thread is supposed to update the danger zone object after 00100 calling the laser range finder object's update() method. 00101 00102 Other threads, viz., the behaviours that need to monitor the danger 00103 zone, may use the lobot::DangerZone state access APIs to ascertain the 00104 current conditions of the danger zone and take appropriate action. 00105 00106 As it does for updating other objects, the main thread must use 00107 lobot::UpdateLock's write lock when updating the danger zone. Other 00108 threads must use lobot::UpdateLock's read lock when accessing the 00109 danger zone's current state. 00110 */ 00111 class DangerZone : public singleton<DangerZone> { 00112 // Prevent copy and assignment 00113 DangerZone(const DangerZone&) ; 00114 DangerZone& operator=(const DangerZone&) ; 00115 00116 // Boilerplate code to make the generic singleton design pattern work 00117 friend class singleton<DangerZone> ; 00118 00119 /// The danger zone works by dividing the laser range finder's FOV 00120 /// into several user-specified angular blocks. Each such block is 00121 /// associated with a user-specified distance and a threshold. When 00122 /// the LRF reports a distance measurement in a block less than that 00123 /// block's danger zone, that reading is added to a list of danger 00124 /// zone readings for that block. When the number of danger zone 00125 /// readings for block exceeds its threshold, that block is considered 00126 /// "active" or "penetrated." 00127 /// 00128 /// This inner class holds together angular blocks and their 00129 /// correspondinng danger zone specifications, thresholds, danger zone 00130 /// readings, etc. 00131 public: 00132 class Block { 00133 /// The angular extents of the block. These extents are read from 00134 /// the config file. 00135 range<int> m_extents ; 00136 00137 /// The user-specified minimum acceptable distance measurement for 00138 /// this block. When the LRF reports a distance less than the value 00139 /// of the danger zone, that reading will get recorded as a danger 00140 /// zone reading. 00141 int m_danger_zone ; 00142 00143 /// The user-specified minimum number of danger zone readings for 00144 /// this block. Danger zone readings less than this number will not 00145 /// activate the block. 00146 int m_threshold ; 00147 00148 /// The danger zone readings for this block. This data structure is 00149 /// cleared and updated as part of the main thread's update cycle 00150 /// (i.e., it is not a static setting read from the config file). 00151 //@{ 00152 public: 00153 typedef LRFData::Reading Reading ; 00154 typedef std::vector<Reading> Readings ; 00155 private: 00156 Readings m_danger_zone_readings ; 00157 //@} 00158 00159 /// Private constructors because only the DangerZone object can 00160 /// create new danger zone blocks. 00161 //@{ 00162 Block(const range<int>& extents, int danger_zone, int threshold) ; 00163 Block(int start_angle, int end_angle, int danger_zone, int threshold) ; 00164 //@} 00165 00166 /// Add a danger zone reading to the block. 00167 void add(const Reading& R) {m_danger_zone_readings.push_back(R) ;} 00168 00169 /// Clear the block's danger zone readings. 00170 void clear() {m_danger_zone_readings.clear() ;} 00171 00172 /// Helper function object to update a block. 00173 //@{ 00174 class update { 00175 const LRFData& lrf ; 00176 public: 00177 update(const LRFData&) ; 00178 void operator()(const Block&) const ; 00179 } ; 00180 friend class update ; 00181 //@} 00182 00183 // The outer class, viz., lobot::DangerZone, has special privileges 00184 // with danger zone blocks. 00185 friend class DangerZone ; 00186 00187 public: 00188 /// Retrieving the angular block's extents, danger zone and 00189 /// threshold settings. 00190 //@{ 00191 int start() const {return m_extents.min() ;} 00192 int end() const {return m_extents.max() ;} 00193 int size() const {return m_extents.size() ;} 00194 const range<int>& extents() const {return m_extents ;} 00195 00196 int danger_zone() const {return m_danger_zone ;} 00197 int threshold() const {return m_threshold ;} 00198 //@} 00199 00200 /// How many danger zone readings does this block currently have? 00201 int danger_level() const {return m_danger_zone_readings.size() ;} 00202 00203 /// Has this block of the danger zone been penetrated by an 00204 /// obstacle? 00205 bool penetrated() const {return danger_level() >= threshold() ;} 00206 00207 /// Iterators for going through the current danger zone readings. 00208 //@{ 00209 Readings::const_iterator danger_begin() const { 00210 return m_danger_zone_readings.begin() ; 00211 } 00212 Readings::const_iterator danger_end() const { 00213 return m_danger_zone_readings.end() ; 00214 } 00215 //@} 00216 00217 /// Debug support 00218 void dump(const std::string& caller) const ; 00219 } ; 00220 00221 /// The Robolocust danger zone consists of several blocks. 00222 //@{ 00223 typedef std::vector<Block> Blocks ; 00224 private: 00225 Blocks m_blocks ; 00226 //@} 00227 00228 /// How many blocks does the danger zone have? 00229 public: 00230 static int num_blocks() {return instance().m_blocks.size() ;} 00231 00232 /// Once the danger zone settings have been loaded from the config 00233 /// file, we find the max danger zone and store that for later use 00234 /// (e.g., some behaviours need this value for rendering purposes). 00235 /// Since the danger zone settings are constants, finding and storing 00236 /// this value avoids having to repeatedly find it each time it is 00237 /// needed. 00238 private: 00239 float m_max ; 00240 public: 00241 static float max() {return instance().m_max ;} 00242 00243 /// Obviously, for this whole danger zone thing to work, we also need 00244 /// an LRF object from where we can get distance measurements. The 00245 /// main thread should specify this. 00246 private: 00247 static const LaserRangeFinder* m_lrf ; 00248 public: 00249 static void use(const LaserRangeFinder* lrf) {m_lrf = lrf ;} 00250 00251 /// Everytime we update the danger zone, we record the LRF 00252 /// measurements that resulted in the current danger zone state. 00253 private: 00254 LRFData* m_lrf_data ; 00255 00256 /// A private constructor because this class is a singleton. 00257 DangerZone() ; 00258 00259 public: 00260 /// This method updates the danger zone using the current laser range 00261 /// finder measurements. It is meant to be called only by the main 00262 /// thread, which should use lobot::UpdateLock's write lock when 00263 /// calling this function. 00264 static void update() ; 00265 00266 /// A convenience function to check if any block in the danger zone 00267 /// has been penetrated or not. 00268 /// 00269 /// NOTE: Client should use lobot::UpdateLock's read lock when calling 00270 /// this function. 00271 static bool penetrated() ; 00272 00273 /// Iterators for walking through the list of danger zone blocks. 00274 /// 00275 /// NOTE: Client should use lobot::UpdateLock's read lock when calling 00276 /// thess functions. 00277 //@{ 00278 static Blocks::const_iterator begin() {return instance().m_blocks.begin() ;} 00279 static Blocks::const_iterator end() {return instance().m_blocks.end() ;} 00280 //@} 00281 00282 /// Retrieving the LRF measurements snapshot corresponding to the 00283 /// current danger zone state. 00284 /// 00285 /// NOTE: Client should use lobot::UpdateLock's read lock when calling 00286 /// this function. 00287 static const LRFData& lrf_data() {return *instance().m_lrf_data ;} 00288 00289 /// Clean-up. 00290 ~DangerZone() ; 00291 } ; 00292 00293 //----------------------------------------------------------------------- 00294 00295 } // end of namespace encapsulating this file's definitions 00296 00297 #endif 00298 00299 /* So things look consistent in everyone's emacs... */ 00300 /* Local Variables: */ 00301 /* indent-tabs-mode: nil */ 00302 /* End: */