LoDangerZone.H

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: */
Generated on Sun May 8 08:05:54 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3