LoForward.C

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/control/LoForward.C
00003    \brief This file defines the non-inline member functions of the
00004    lobot::Forward 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/LoForward.C $
00039 // $Id: LoForward.C 13521 2010-06-06 14:23:03Z mviswana $
00040 //
00041 
00042 //------------------------------ HEADERS --------------------------------
00043 
00044 // lobot headers
00045 #include "Robots/LoBot/control/LoForward.H"
00046 
00047 #include "Robots/LoBot/LoApp.H"
00048 #include "Robots/LoBot/config/LoConfigHelpers.H"
00049 #include "Robots/LoBot/thread/LoUpdateLock.H"
00050 
00051 #include "Robots/LoBot/misc/LoExcept.H"
00052 #include "Robots/LoBot/misc/LoRegistry.H"
00053 #include "Robots/LoBot/util/LoGL.H"
00054 #include "Robots/LoBot/util/LoMath.H"
00055 
00056 // OpenGL headers
00057 #ifdef INVT_HAVE_LIBGL
00058 #include <GL/gl.h>
00059 #endif
00060 
00061 // Standard C++ headers
00062 #include <iomanip>
00063 #include <sstream>
00064 #include <algorithm>
00065 #include <limits>
00066 
00067 //----------------------------- NAMESPACE -------------------------------
00068 
00069 namespace lobot {
00070 
00071 //--------------------------- LOCAL HELPERS -----------------------------
00072 
00073 // Retrieve settings from forward section of config file
00074 template<typename T>
00075 static inline T conf(const std::string& key, const T& default_value)
00076 {
00077    return get_conf<T>(LOBE_FORWARD, key, default_value) ;
00078 }
00079 
00080 // Overload of above function for retrieving ranges
00081 template<typename T>
00082 static inline range<T>
00083 conf(const std::string& key, const range<T>& default_value)
00084 {
00085    return get_conf<T>(LOBE_FORWARD, key, default_value) ;
00086 }
00087 
00088 //-------------------------- INITIALIZATION -----------------------------
00089 
00090 Forward::Forward()
00091    : base(clamp(conf("update_delay", 1000), 100, 2500),
00092           LOBE_FORWARD, conf<std::string>("geometry", "480 0 140 140")),
00093      m_min_distance(0, -1)
00094 {
00095    start(LOBE_FORWARD) ;
00096 }
00097 
00098 void Forward::pre_run()
00099 {
00100    if (Params::adaptive_mode())
00101    {
00102       if (! App::lrf())
00103          throw behavior_error(LASER_RANGE_FINDER_MISSING) ;
00104    }
00105    //else: in fixed mode, don't need the LRF
00106 }
00107 
00108 //---------------------- THE BEHAVIOUR'S ACTION -------------------------
00109 
00110 // Depending on how it's configured, the forward driving behaviour will
00111 // either vote to drive at a fixed speed or, in adaptive mode, at a speed
00112 // based on distance readings from the LRF.
00113 void Forward::action()
00114 {
00115    // Steering decision is always to drive straight ahead
00116    // Speed, however, is decided based on operational mode
00117    TurnArbiter::Vote* T = new TurnArbiter::Vote(turn_vote_centered_at(0)) ;
00118    SpeedInfo S = Params::adaptive_mode() ? adaptive_speed() : fixed_speed() ;
00119 
00120    // First, record votes and other info for visualization before
00121    // turning them over to the arbiters. Otherwise, it is possible the
00122    // votes might get deleted by the arbiter threads, which would cause
00123    // a segfault here when this thread attempts to dereference those
00124    // pointers.
00125    viz_lock() ;
00126       m_turn_vote    = *T ;
00127       m_speed_vote   = *S.second ;
00128       m_min_distance = S.first ;
00129    viz_unlock() ;
00130 
00131    // Cast the turn and speed votes
00132     TurnArbiter::instance().vote(base::name, T) ;
00133    SpeedArbiter::instance().vote(base::name, S.second) ;
00134 }
00135 
00136 // In fixed mode, simply return a speed vote using the cruising params
00137 Forward::SpeedInfo Forward::fixed_speed() const
00138 {
00139    return SpeedInfo(LRFData::Reading(0, -1),
00140                     new SpeedArbiter::Vote(Params::cruising_speed(),
00141                                            Params::cruising_pwm())) ;
00142 }
00143 
00144 // In adaptive mode, regulate speed based on distance to closest obstacle
00145 Forward::SpeedInfo Forward::adaptive_speed() const
00146 {
00147    // Make local copy of LRF data to avoid holding update lock for too long
00148    UpdateLock::begin_read() ;
00149       LRFData lrf(App::lrf()) ;
00150    UpdateLock::end_read() ;
00151 
00152    // Find minimum average distance in configured FOV.
00153    //
00154    // NOTE: We multiply the average distance for each angle we consider
00155    // by the cosine of that angle in order to project that "distance
00156    // vector" onto the vector corresponding to straight ahead (i.e., zero
00157    // degree heading).
00158    const range<int> fov = Params::fov() ;
00159    const int step = Params::averaging_block() ;
00160 
00161    LRFData::Reading min(std::numeric_limits<int>::min(),
00162                         std::numeric_limits<int>::max()) ;
00163    for (int angle = fov.min(); angle <= fov.max(); angle += step)
00164    {
00165       const int m = clamp(angle - step/2, lrf.min_angle(), angle - 1) ;
00166       const int M = clamp(angle + step/2, angle + 1, lrf.max_angle()) ;
00167       const int d = round(lrf.average_distance(m, M)) ;
00168       if (d <= 0) // all bad readings in [angle - step/2, angle + step/2]?!?
00169          continue ;
00170       if (d < min.distance())
00171          min = LRFData::Reading(angle, d) ;
00172    }
00173 
00174    // Compute speed and PWM corresponding to min distance using linear
00175    // interpolation.
00176    const range<float> S = Params::speed_range() ;
00177    const range<int>   P = Params::pwm_range() ;
00178    const range<int>   D = Params::distance_range() ;
00179 
00180    if (min.distance() == std::numeric_limits<int>::max()) // all bad readings?
00181       return SpeedInfo(LRFData::Reading(180, -1),
00182                        new SpeedArbiter::Vote(S.min(), P.min())) ;
00183 
00184    const float d =
00185       static_cast<float>(min.distance() - D.min())/(D.max() - D.min()) ;
00186    const float s = clamp(S.min() + d * (S.max() - S.min()),
00187                          S.min(), S.max()) ;
00188    const int   p = clamp(P.min() + round(d * (P.max() - P.min())),
00189                          P.min(), P.max()) ;
00190    //LERROR("min distance = [%4d @ %4d], speed vote = %6.3f",
00191           //min.distance(), min.angle(), s) ;
00192    return SpeedInfo(min, new SpeedArbiter::Vote(s, p)) ;
00193 }
00194 
00195 //--------------------------- VISUALIZATION -----------------------------
00196 
00197 #ifdef INVT_HAVE_LIBGL
00198 
00199 // Helper to convert the minimum distance reading into a string label
00200 static std::string dist(int d)
00201 {
00202    std::ostringstream label ;
00203    label << d << " mm" ;
00204    return label.str() ;
00205 }
00206 
00207 // Helper to convert the chosen speed value a string label
00208 static std::string speed(float s)
00209 {
00210    using namespace std ;
00211 
00212    std::ostringstream label ;
00213    label << setw(6) << fixed << setprecision(3) << s << " m/s" ;
00214    return label.str() ;
00215 }
00216 
00217 void Forward::render_me()
00218 {
00219    // Make local copy so that forward behaviour's thread isn't held up
00220    // waiting for visualization thread to complete.
00221    viz_lock() ;
00222        TurnArbiter::Vote V = m_turn_vote ;
00223       SpeedArbiter::Vote S = m_speed_vote ;
00224       LRFData::Reading   D = m_min_distance ;
00225    viz_unlock() ;
00226 
00227    unit_view_volume() ;
00228    glBegin(GL_LINES) ;
00229       // Render the turn vote's visualization
00230       for (TurnArbiter::Vote::iterator it = V.begin(); it; ++it)
00231       {
00232          float vote = it.value() ;
00233          float direction = it.direction() ;
00234          if (vote < 0) // voted against this direction
00235          {
00236             glColor3f(1, 0, 0) ;
00237             glVertex2i(0, 0) ;
00238             glVertex2f(-vote * cos(direction), -vote * sin(direction)) ;
00239          }
00240          else if (vote > 0) // voted for this direction
00241          {
00242             glColor3f(0, 1, 0) ;
00243             glVertex2i(0, 0) ;
00244             glVertex2f(vote * cos(direction), vote * sin(direction)) ;
00245          }
00246       }
00247 
00248       // Render distance reading's direction corresponding to speed vote
00249       if (Params::adaptive_mode()) {
00250          glColor3f(1, 1, 1) ;
00251          glVertex2i(0, 0) ;
00252          glVertex2f(0.75f * cos(D.angle()), 0.75f * sin(D.angle())) ;
00253       }
00254    glEnd() ;
00255 
00256    // Label the visualization so that it is easy to tell which behaviour
00257    // is being visualized. Also label the speed value and, if applicable,
00258    // the distance reading that resulted in the chosen speed.
00259    restore_view_volume() ;
00260    text_view_volume() ;
00261    glColor3f(0, 1, 1) ;
00262    draw_label(3, 12, "Forward") ;
00263    if (Params::adaptive_mode())
00264       draw_label(3, m_geometry.height - 16, dist(D.distance()).c_str()) ;
00265    draw_label(3,  m_geometry.height - 4, speed(S.speed()).c_str()) ;
00266 
00267    restore_view_volume() ;
00268 }
00269 
00270 #endif
00271 
00272 //----------------------------- CLEAN-UP --------------------------------
00273 
00274 Forward::~Forward(){}
00275 
00276 //-------------------------- KNOB TWIDDLING -----------------------------
00277 
00278 // Parameters initialization
00279 Forward::Params::Params()
00280    : m_cruising_speed(clamp(conf("cruising_speed", 0.5f), 0.1f, 10.0f)),
00281      m_cruising_pwm(clamp(conf("cruising_pwm", 30), 15, 100)),
00282      m_adaptive_mode(conf("adaptive_mode", false)),
00283      m_fov(clamp(conf("fov", range<int>(-60, 60)), range<int>(-90, 90))),
00284      m_averaging_block(clamp(conf("averaging_block", 10), 1, 20)),
00285      m_speed_range(clamp(conf("speed_range", range<float>(0.1f, 0.5f)),
00286                          range<float>(0.05f, 0.5f))),
00287      m_pwm_range(clamp(conf("pwm_range", range<int>(25, 100)),
00288                        range<int>(10, 100))),
00289      m_distance_range(clamp(conf("distance_range", range<int>(250, 2500)),
00290                             range<int>(100, 5000)))
00291 {}
00292 
00293 // Parameters clean-up
00294 Forward::Params::~Params(){}
00295 
00296 //-----------------------------------------------------------------------
00297 
00298 } // end of namespace encapsulating this file's definitions
00299 
00300 /* So things look consistent in everyone's emacs... */
00301 /* Local Variables: */
00302 /* indent-tabs-mode: nil */
00303 /* End: */
Generated on Sun May 8 08:41:22 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3