LoLGMDExtricateSimple.C

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/control/LoLGMDExtricateSimple.C
00003    \brief This file defines the non-inline member functions of the
00004    lobot::LGMDExtricateSimple class.
00005 */
00006 
00007 // //////////////////////////////////////////////////////////////////// //
00008 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00009 // by the University of Southern California (USC) and the iLab at USC.  //
00010 // See http://iLab.usc.edu for information about this project.          //
00011 // //////////////////////////////////////////////////////////////////// //
00012 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00013 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00014 // in Visual Environments, and Applications'' by Christof Koch and      //
00015 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00016 // pending; application number 09/912,225 filed July 23, 2001; see      //
00017 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00018 // //////////////////////////////////////////////////////////////////// //
00019 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00022 // redistribute it and/or modify it under the terms of the GNU General  //
00023 // Public License as published by the Free Software Foundation; either  //
00024 // version 2 of the License, or (at your option) any later version.     //
00025 //                                                                      //
00026 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00027 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00028 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00029 // PURPOSE.  See the GNU General Public License for more details.       //
00030 //                                                                      //
00031 // You should have received a copy of the GNU General Public License    //
00032 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00033 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00034 // Boston, MA 02111-1307 USA.                                           //
00035 // //////////////////////////////////////////////////////////////////// //
00036 //
00037 // Primary maintainer for this file: mviswana usc edu
00038 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/control/LoLGMDExtricateSimple.C $
00039 // $Id: LoLGMDExtricateSimple.C 13840 2010-08-27 22:28:12Z mviswana $
00040 //
00041 
00042 //------------------------------ HEADERS --------------------------------
00043 
00044 // lobot headers
00045 #include "Robots/LoBot/control/LoLGMDExtricateSimple.H"
00046 #include "Robots/LoBot/control/LoMetrics.H"
00047 #include "Robots/LoBot/control/LoTurnArbiter.H"
00048 #include "Robots/LoBot/control/LoSpinArbiter.H"
00049 #include "Robots/LoBot/control/LoSpeedArbiter.H"
00050 
00051 #include "Robots/LoBot/LoApp.H"
00052 #include "Robots/LoBot/slam/LoMap.H"
00053 #include "Robots/LoBot/lgmd/LocustModel.H"
00054 
00055 #include "Robots/LoBot/config/LoConfigHelpers.H"
00056 #include "Robots/LoBot/thread/LoUpdateLock.H"
00057 
00058 #include "Robots/LoBot/misc/LoRegistry.H"
00059 #include "Robots/LoBot/util/LoGL.H"
00060 #include "Robots/LoBot/misc/LoVector.H"
00061 #include "Robots/LoBot/util/LoMath.H"
00062 #include "Robots/LoBot/util/LoSTL.H"
00063 #include "Robots/LoBot/misc/singleton.hh"
00064 #include "Robots/LoBot/util/range.hh"
00065 
00066 // OpenGL headers
00067 #ifdef INVT_HAVE_LIBGL
00068 #include <GL/gl.h>
00069 #endif
00070 
00071 // Boost headers
00072 #include <boost/bind.hpp>
00073 
00074 // Standard C++ headers
00075 #include <iomanip>
00076 #include <algorithm>
00077 #include <functional>
00078 #include <vector>
00079 #include <iterator>
00080 #include <utility>
00081 
00082 //----------------------------- NAMESPACE -------------------------------
00083 
00084 namespace lobot {
00085 
00086 //-------------------------- KNOB TWIDDLING -----------------------------
00087 
00088 namespace {
00089 
00090 // Retrieve settings from lgmd_extricate_simple section of config file
00091 template<typename T>
00092 inline T conf(const std::string& key, const T& default_value)
00093 {
00094    return get_conf<T>(LOBE_LGMD_EXTRICATE_SIMPLE, key, default_value) ;
00095 }
00096 
00097 /// This local class encapsulates various parameters that can be used
00098 /// to tweak different aspects of this behaviour.
00099 class Params : public singleton<Params> {
00100    /// If this extricate behaviour were to spin the robot in each and
00101    /// every iteration, it might make the robot zigzag about excessively.
00102    /// Therefore, we have the behaviour check the total range of LGMD
00103    /// spike rates, i.e., max - min, and act only when this range crosses
00104    /// a threshold, i.e., when the range of spiking activity has a
00105    /// significant differential in it. If the range is lower than the
00106    /// above-mentioned threshold, it means all the locusts are
00107    /// experiencing a similar level of spiking and so extrication would
00108    /// simply result in erratic, noisy behaviour.
00109    ///
00110    /// This setting specifies the minimum range across all the LGMD
00111    /// readings that we expect to see before the simple, reactive
00112    /// LGMD-based extrication will kick in. It should be a positive
00113    /// floating point number. Its units are Hertz.
00114    float m_threshold ;
00115 
00116    /// Once the above range threshold has been crossed, the behaviour can
00117    /// simply spin the robot towards the direction corresponding to
00118    /// minimal activity. However, there might be several readings that
00119    /// are the same or reasonably close to the minimum. In this
00120    /// situation, we would like to spin the robot by the least amount.
00121    ///
00122    /// The following setting specifies the maximum spike rate starting at
00123    /// the minimum that we consider "reasonably low." This extricate
00124    /// behaviour then looks at all the "reasonably low" LGMD readings and
00125    /// chooses the one that will result in the minimum amount of spin.
00126    ///
00127    /// The value of this setting should be a floating point number
00128    /// expressed in Hertz.
00129    float m_window ;
00130 
00131    /// Users may specify what speed they would like the extrication to
00132    /// occur.
00133    ///
00134    /// CAUTION: It would be unwise to make this speed too high.
00135    float m_extricate_speed ;
00136 
00137    /// In case the RPM sensor is configured to be off, we will need to
00138    /// specify the extricate "speed" in terms of PWM values as well.
00139    ///
00140    /// NOTE: All speed related behaviours should specify both a speed
00141    /// in m/s and a PWM value.
00142    ///
00143    /// CAUTION: For the extricate behaviour, it would be unwise to
00144    /// make the extrication PWM too high.
00145    int m_extricate_pwm ;
00146 
00147    /// Usually, steering control is effected using the turn arbiter,
00148    /// which veers the robot in different directions while it moves,
00149    /// i.e., smooth car-like turns. However, the lgmd_extricate_tti
00150    /// behaviour also supports spin-style steering, i.e., momentarily
00151    /// stopping the robot and then turning it cw/ccw in-place. This flag
00152    /// turns on spin-style steering. By default, the behaviour uses the
00153    /// normal car-like steering mode.
00154    bool m_spin_style_steering ;
00155 
00156    /// The number of milliseconds between successive iterations of this
00157    /// behaviour.
00158    ///
00159    /// WARNING: The ability to change a behaviour's update frequency is a
00160    /// very powerful feature whose misuse or abuse can wreak havoc! Be
00161    /// sure to use reasonable values for this setting.
00162    int m_update_delay ;
00163 
00164    /// The location and size (within the Robolocust main window) of the
00165    /// goal behaviour's visualization.
00166    typedef Drawable::Geometry Geom ; // just for properly aligning accessors
00167    Geom m_geometry ;
00168 
00169    /// Private constructor because this is a singleton.
00170    Params() ;
00171 
00172    // Boilerplate code to make generic singleton design pattern work
00173    friend class singleton<Params> ;
00174 
00175 public:
00176    /// Accessing the various parameters.
00177    //@{
00178    static float threshold()    {return instance().m_threshold    ;}
00179    static float window()       {return instance().m_window       ;}
00180    static float extricate_speed()    {return instance().m_extricate_speed    ;}
00181    static int   extricate_pwm()      {return instance().m_extricate_pwm      ;}
00182    static bool  spin_style_steering(){return instance().m_spin_style_steering;}
00183    static int   update_delay()       {return instance().m_update_delay       ;}
00184    static Geom  geom()               {return instance().m_geometry           ;}
00185    //@}
00186 } ;
00187 
00188 // Parameters initialization
00189 Params::Params()
00190    : m_threshold(clamp(conf("threshold", 50.0f), 0.1f, 1000.0f)),
00191      m_window(clamp(conf("window", 25.0f), 0.1f, 100.0f)),
00192      m_extricate_speed(clamp(conf("extricate_speed", 0.15f), 0.1f, 0.75f)),
00193      m_extricate_pwm(clamp(conf("extricate_pwm", 25), 10, 50)),
00194      m_spin_style_steering(conf("spin_style_steering", false)),
00195      m_update_delay(clamp(conf("update_delay", 1000), 1, 5000)),
00196      m_geometry(conf<std::string>("geometry", "0 0 10 10"))
00197 {}
00198 
00199 } // end of local anonymous namespace encapsulating above helpers
00200 
00201 //-------------------------- INITIALIZATION -----------------------------
00202 
00203 LGMDExtricateSimple::LGMDExtricateSimple()
00204    : base(Params::update_delay(), LOBE_LGMD_EXTRICATE_SIMPLE, Params::geom())
00205 {
00206    start(LOBE_LGMD_EXTRICATE_SIMPLE) ;
00207 }
00208 
00209 LGMDExtricateSimple::Command::Command()
00210    : drive(0), turn(0)
00211 {}
00212 
00213 void LGMDExtricateSimple::pre_run()
00214 {
00215    if (! App::robot())
00216       throw behavior_error(MOTOR_SYSTEM_MISSING) ;
00217 }
00218 
00219 //---------------------- THE BEHAVIOUR'S ACTION -------------------------
00220 
00221 // Stuff a locust's direction and current LGMD spike rate into an STL pair
00222 static std::pair<float, float> get_locust_data(const LocustModel* L)
00223 {
00224    return std::make_pair(L->direction(), L->get_lgmd()) ;
00225 }
00226 
00227 // Compare locust data according to their directions
00228 static bool
00229 dir_cmp(const std::pair<float, float>& a, const std::pair<float, float>& b)
00230 {
00231    return abs(a.first) < abs(b.first) ;
00232 }
00233 
00234 // Compare locust data according to their LGMD spike rates
00235 static bool
00236 lgmd_cmp(const std::pair<float, float>& a, const std::pair<float, float>& b)
00237 {
00238    return a.second < b.second ;
00239 }
00240 
00241 // This version of the extricate behaviour monitors the LGMD spike rates
00242 // of all the locusts and spins the robot to face the direction
00243 // corresponding to minimal spiking activity.
00244 void LGMDExtricateSimple::action()
00245 {
00246    typedef std::pair<float, float> DLP ; // locust direction-LGMD pair
00247    typedef std::vector<DLP> DLV ;
00248    DLV dlv ;
00249 
00250    // Copy each locust's direction and current LGMD spike rate
00251    UpdateLock::begin_read() ;
00252       const App::LocustModels& L = App::locusts() ;
00253       dlv.reserve(L.size()) ;
00254       std::transform(L.begin(), L.end(), std::back_inserter(dlv),
00255                      get_locust_data) ;
00256    UpdateLock::end_read() ;
00257 
00258    // Sort the locusts according to their spike rates
00259    std::sort(dlv.begin(), dlv.end(), lgmd_cmp) ;
00260 
00261    // Issue extrication commands only if spike rate range is significant,
00262    // i.e., there is enough variation in spiking across all the locusts.
00263    Command C ;
00264    if (dlv.back().second - dlv.front().second >= Params::threshold())
00265    {
00266       // Starting at locust with least spiking activity, find locust
00267       // whose spike rate exceeds acceptable "window" of low readings.
00268       DLV::iterator end = std::find_if(dlv.begin(), dlv.end(),
00269          boost::bind(std::greater<float>(),
00270                      boost::bind(get_second<DLP>, _1),
00271                      dlv.front().second + Params::window())) ;
00272 
00273       // Within the window of spikes acceptable as low, find the one that
00274       // involves least amount of turn from current heading and vote for
00275       // that direction.
00276       DLV::const_iterator min = std::min_element(dlv.begin(), end, dir_cmp) ;
00277       if (Params::spin_style_steering())
00278       {
00279          C.turn = round(min->first) ;
00280          SpinArbiter::instance().
00281             vote(base::name, new SpinArbiter::Vote(C.turn)) ;
00282       }
00283       else
00284       {
00285          const int T = random(TurnArbiter::turn_step(),
00286                               TurnArbiter::turn_max()) ;
00287          switch (quadrant(min->first))
00288          {
00289             case 1:
00290                C.drive =  1 ; C.turn =  T ;
00291                break ;
00292             case 2:
00293                C.drive = -1 ; C.turn = -T ;
00294                break ;
00295             case 3:
00296                C.drive = -1 ; C.turn =  T ;
00297                break ;
00298             case 4:
00299                C.drive =  1 ; C.turn = -T ;
00300                break ;
00301             default: // quadrant() shouldn't return anything outside [1,4]
00302                throw misc_error(LOGIC_ERROR) ;
00303          }
00304          SpeedArbiter::instance().vote(base::name,
00305             new SpeedArbiter::Vote(C.drive * Params::extricate_speed(),
00306                                    C.drive * Params::extricate_pwm())) ;
00307          TurnArbiter::instance().vote(base::name,
00308             new TurnArbiter::Vote(turn_vote_centered_at(C.turn))) ;
00309       }
00310 
00311       // Metrics logging
00312       Metrics::Log log ;
00313       log << std::setw(Metrics::opw()) << std::left << base::name ;
00314       Map* M = App::map() ;
00315       if (M)
00316          log << M->current_pose() ;
00317    }
00318 
00319    // Record stuff for visualization
00320    viz_lock() ;
00321       m_cmd = C ;
00322    viz_unlock() ;
00323 }
00324 
00325 //--------------------------- VISUALIZATION -----------------------------
00326 
00327 #ifdef INVT_HAVE_LIBGL
00328 
00329 // The visualization callback
00330 void LGMDExtricateSimple::render_me()
00331 {
00332    // Make local copies so that extricate thread isn't held up waiting
00333    // for visualization thread to complete.
00334    viz_lock() ;
00335       Command C = m_cmd ;
00336    viz_unlock() ;
00337 
00338    // Draw principal axes (to make it easier to understand what's going
00339    // on with the force vectors and turn command).
00340    unit_view_volume() ;
00341    glColor3f(1, 1, 1) ;
00342    glBegin(GL_LINES) ;
00343       glVertex2i(0, -1) ;
00344       glVertex2i(0,  1) ;
00345       glVertex2i(-1, 0) ;
00346       glVertex2i( 1, 0) ;
00347    glEnd() ;
00348 
00349    // Render the extrication decision's visualization
00350    if (C.drive == 0 && C.turn == 0)
00351       ; // no extrication took place
00352    else
00353    {
00354       Vector v(0.75f * cos(C.turn), 0.75f * sin(C.turn)) ;
00355       if (C.drive == 0) // differential steering
00356          glColor3f(1, 0, 0) ;
00357       else // normal, i.e., car-like, steering
00358       {
00359          v.i *= C.drive ;
00360          glColor3f(1, 1, 1) ;
00361       }
00362       draw_vector(v) ;
00363    }
00364 
00365    // Label the visualization so that it is easy to tell which behaviour
00366    // is being visualized. Also show the magnitudes of the forces.
00367    restore_view_volume() ;
00368    text_view_volume() ;
00369       glColor3f(0, 1, 1) ;
00370       draw_label(3, 12, "LGMD Ext. Sim.") ;
00371    restore_view_volume() ;
00372 }
00373 
00374 #endif
00375 
00376 //----------------------------- CLEAN-UP --------------------------------
00377 
00378 LGMDExtricateSimple::~LGMDExtricateSimple(){}
00379 
00380 //-----------------------------------------------------------------------
00381 
00382 } // end of namespace encapsulating this file's definitions
00383 
00384 /* So things look consistent in everyone's emacs... */
00385 /* Local Variables: */
00386 /* indent-tabs-mode: nil */
00387 /* End: */
Generated on Sun May 8 08:05:44 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3