00001 /** 00002 \file Robots/LoBot/control/LoTurnArbiter.C 00003 \brief This file defines the non-inline member functions of the 00004 lobot::TurnArbiter 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/LoTurnArbiter.C $ 00039 // $Id: LoTurnArbiter.C 13521 2010-06-06 14:23:03Z mviswana $ 00040 // 00041 00042 //------------------------------ HEADERS -------------------------------- 00043 00044 // lobot headers 00045 #include "Robots/LoBot/control/LoTurnArbiter.H" 00046 00047 #include "Robots/LoBot/config/LoConfigHelpers.H" 00048 #include "Robots/LoBot/thread/LoUpdateLock.H" 00049 00050 #include "Robots/LoBot/misc/LoExcept.H" 00051 #include "Robots/LoBot/util/LoGL.H" 00052 #include "Robots/LoBot/util/LoDebug.H" 00053 #include "Robots/LoBot/util/LoSTL.H" 00054 00055 // OpenGL headers 00056 #ifdef INVT_HAVE_LIBGL 00057 #include <GL/gl.h> 00058 #endif 00059 00060 // Standard C++ headers 00061 #include <algorithm> 00062 #include <functional> 00063 #include <iterator> 00064 #include <utility> 00065 00066 //----------------------------- NAMESPACE ------------------------------- 00067 00068 namespace lobot { 00069 00070 //--------------------------- LOCAL HELPERS ----------------------------- 00071 00072 // Retrieve settings from turn_arbiter section of config file 00073 template<typename T> 00074 static inline T conf(const std::string& key, const T& default_value) 00075 { 00076 return get_conf<T>("turn_arbiter", key, default_value) ; 00077 } 00078 00079 //-------------------------- INITIALIZATION ----------------------------- 00080 00081 TurnArbiter::TurnArbiter() 00082 : Arbiter(clamp(conf("update_delay", 500), 1, 1000), 00083 "turn_arbiter", conf<std::string>("geometry", "480 420 140 140")) 00084 { 00085 start("turn_arbiter") ; 00086 } 00087 00088 float TurnArbiter::get_configured_priority(const std::string& behaviour) const 00089 { 00090 return abs(get_conf(behaviour, "turn_priority", 0.0f)) ; 00091 } 00092 00093 //-------------------------- MOTOR COMMANDS ----------------------------- 00094 00095 // Helper to scale all the vote values in a Vote by the given weight 00096 static TurnArbiter::Vote operator*(TurnArbiter::Vote V, float weight) 00097 { 00098 std::transform(V.begin(), V.end(), V.begin(), 00099 std::bind2nd(std::multiplies<float>(), weight)) ; 00100 return V ; 00101 } 00102 00103 // To issue an appropriate motor command, the turn arbiter must first 00104 // combine the votes from all the behaviours, weighting each vote by its 00105 // corresponding behaviour's priority. It then smooths the resulting vote 00106 // using a Gaussian and picks the motor command with the maximum vote 00107 // value. 00108 void TurnArbiter::motor_cmd(const Arbiter::Votes& votes, Robot* robot) 00109 { 00110 Vote result ; 00111 00112 // First, compute weighted sum of all votes 00113 Arbiter::Votes::const_iterator it = votes.begin() ; 00114 for (; it != votes.end(); ++it) 00115 result += 00116 (*dynamic_cast<Vote*>((*it)->vote)) * priority((*it)->behavior_name) ; 00117 //result.dump("TurnArbiter::motor_cmd before smooting") ; 00118 00119 // Then, Gaussian smooth the weighted sum 00120 typedef Vote::VoteMap::value_type DVP ; // direction-vote pair 00121 std::vector<DVP> V(result.m_votes.begin(), result.m_votes.end()) ; 00122 00123 const int N = V.size() ; 00124 const int W = clamp(Params::smoothing_width(), 1, N) ; 00125 const float S = 2 * Params::sigma() * Params::sigma() ; 00126 const float s = 1/(2.506628f /* sqrt(2*pi) */ * Params::sigma()) ; 00127 00128 for (int i = 0; i < N; ++i) 00129 { 00130 float v = 0 ; 00131 for (int j = i - W; j <= i + W; ++j) { 00132 if (j < 0 || j >= N) 00133 continue ; 00134 float d = V[j].first - V[i].first ; 00135 v += V[j].second * exp(-(d*d)/S) * s ; 00136 } 00137 result[V[i].first] = v ; 00138 } 00139 //result.dump("TurnArbiter::motor_cmd after smoothing") ; 00140 00141 result.normalize() ; 00142 //result.dump("TurnArbiter::motor_cmd after normalization") ; 00143 00144 viz_lock() ; 00145 m_vote = result ; // record most recent vote for visualization 00146 //m_vote.dump("TurnArbiter::motor_cmd") ; 00147 viz_unlock() ; 00148 00149 // Finally, pick the command with the maximum votes 00150 Vote::iterator max = std::max_element(result.begin(), result.end()) ; 00151 //LERROR("max vote %g for direction: %d", max.value(), max.direction()) ; 00152 00153 UpdateLock::begin_write() ; 00154 robot->turn(max.direction()) ; 00155 UpdateLock::end_write() ; 00156 } 00157 00158 //------------------------------- VOTES --------------------------------- 00159 00160 // Vote initialization: neutral for all directions 00161 TurnArbiter::Vote::Vote() 00162 { 00163 const int M = turn_max() ; 00164 const int S = turn_step() ; 00165 m_votes[0] = 0 ; 00166 for (int direction = +S; direction <= +M; direction += S) 00167 m_votes[direction] = 0 ; 00168 for (int direction = -S; direction >= -M; direction -= S) 00169 m_votes[direction] = 0 ; 00170 } 00171 00172 // Return the supported turn directions a behaviour can vote on 00173 std::vector<int> TurnArbiter::Vote::get_directions() const 00174 { 00175 std::vector<int> V ; 00176 V.reserve(m_votes.size()) ; 00177 std::transform(m_votes.begin(), m_votes.end(), std::back_inserter(V), 00178 get_first<VoteMap::value_type>) ; 00179 return V ; 00180 } 00181 00182 class abs_diff { 00183 int direction ; 00184 public: 00185 abs_diff(int d) : direction(d) {} 00186 bool operator()(const std::pair<int, float>& a, 00187 const std::pair<int, float>& b) const { 00188 return abs(a.first - direction) < abs(b.first - direction) ; 00189 } 00190 } ; 00191 00192 // Operator to access vote value corresponding to specified turn 00193 // direction. 00194 TurnArbiter::Vote::VoteMap::mapped_type& 00195 TurnArbiter::Vote:: 00196 operator[](int direction) 00197 { 00198 VoteMap::iterator it = m_votes.find(direction) ; 00199 if (it == m_votes.end()) 00200 //throw arbiter_error(UNSUPPORTED_TURN_DIRECTION) ; 00201 it = std::min_element(m_votes.begin(), m_votes.end(), 00202 abs_diff(direction)) ; 00203 return it->second ; 00204 } 00205 00206 // Vote clean-up 00207 TurnArbiter::Vote::~Vote(){} 00208 00209 // Vote iterator start constructor 00210 TurnArbiter::Vote::iterator::iterator(const TurnArbiter::Vote& V) 00211 : m_vote(const_cast<TurnArbiter::Vote&>(V)), 00212 m_iterator(m_vote.m_votes.begin()) 00213 {} 00214 00215 // Vote iterator end constructor 00216 TurnArbiter::Vote::iterator::iterator(const TurnArbiter::Vote& V, bool) 00217 : m_vote(const_cast<TurnArbiter::Vote&>(V)), 00218 m_iterator(m_vote.m_votes.end()) 00219 {} 00220 00221 // Vote iterator copy constructor 00222 TurnArbiter::Vote::iterator::iterator(const TurnArbiter::Vote::iterator& it) 00223 : m_vote(it.m_vote), 00224 m_iterator(it.m_iterator) 00225 {} 00226 00227 // Vote iterator assignment operator 00228 TurnArbiter::Vote::iterator& 00229 TurnArbiter::Vote::iterator::operator=(const TurnArbiter::Vote::iterator& it) 00230 { 00231 if (& it != this) { 00232 m_vote = it.m_vote ; 00233 m_iterator = it.m_iterator ; 00234 } 00235 return *this ; 00236 } 00237 00238 // Vote iterator destructor 00239 TurnArbiter::Vote::iterator::~iterator(){} 00240 00241 // Adding votes 00242 TurnArbiter::Vote& TurnArbiter::Vote::operator+=(const TurnArbiter::Vote& V) 00243 { 00244 std::transform(V.begin(), V.end(), begin(), begin(), std::plus<float>()) ; 00245 return *this ; 00246 } 00247 00248 /* 00249 The following function object is meant to be used with the STL 00250 transform algorithm and scales votes to lie in the range [-1, +1]. It 00251 needs to know the min and max vote values that occur in a vote and then 00252 simply performs a linear interpolation to compute the scaled vote value 00253 like so: 00254 00255 v - m s - (-1) 00256 ----- = -------- 00257 M - m 1 - (-1) 00258 00259 s + 1 v - m 00260 ===> ----- = ----- 00261 2 M - m 00262 00263 ===> s = 2(v - m)/(M - m) - 1 00264 00265 where m = min vote value 00266 M = max vote value 00267 v = unscaled vote value 00268 s = scaled vote value 00269 */ 00270 class scale_vote { 00271 float min, max ; 00272 public: 00273 scale_vote(float m, float M) : min(m), max(M) {} 00274 float operator()(const float& v) const { 00275 return 2 * (v - min)/(max - min) - 1 ; 00276 } 00277 } ; 00278 00279 // Normalizing votes so that all directions' votes are in the [-1, +1] 00280 // range. 00281 void TurnArbiter::Vote::normalize() 00282 { 00283 float min = *std::min_element(begin(), end()) ; 00284 float max = *std::max_element(begin(), end()) ; 00285 normalize(min, max) ; 00286 } 00287 00288 // Normalizing votes so that all directions' votes are in the [-1, +1] 00289 // range. 00290 void TurnArbiter::Vote::normalize(float min, float max) 00291 { 00292 std::transform(begin(), end(), begin(), scale_vote(min, max)) ; 00293 } 00294 00295 // Debug support: dump a vote's direction-value pairs 00296 void TurnArbiter::Vote::dump(const std::string& caller) const 00297 { 00298 lobot::dump(m_votes, caller, "m_votes") ; 00299 } 00300 00301 /* 00302 The following helper function returns a vote for driving in the 00303 specified direction with votes for the other directions falling 00304 linearly away from +1. 00305 00306 To illustrate how this function works, let us say that the supported 00307 steering directions go from -6 degrees (on the right) to +6 degrees 00308 (on the left) in steps of 3 degrees. That is, turn_max is 6 and 00309 turn_step is 3 and, therefore, the supported steering directions are 00310 6, 3, 0, -3, -6. 00311 00312 If we would like to make a medium left turn, i.e., turn direction is 00313 3, then the votes returned by this function will be +1 for 3 and less 00314 than that for the other directions. The amount by which the other 00315 directions' votes will be less depends on the turn_max and turn_step 00316 parameters. In this example, the vote step is 3/6 (step/max) or 0.5. 00317 Thus, the steering direction 3 will get a vote of +1; 6 and 0 will get 00318 1 - 0.5 = 0.5; and -3 will get 1 - 2*0.5 = 0; and -6 will be assigned 00319 1 - 3*.5 = -0.5. That is, the votes will look like so: 00320 00321 6 3 0 -3 -6 00322 0.5 1 0.5 0 -0.5 00323 00324 As we can see, the votes for the directions other than the one at 00325 which they are to be "centered", viz., C, fall away according to the 00326 angular distance between C and that particular direction. The vote for 00327 the direction C is +1 and for the others is something less than 1. 00328 That is, the vote for some direction d is 1 - something. This 00329 something is a function of the angular distance between d and C, i.e., 00330 d - C. 00331 00332 Now, the vote step for consecutive directions is simply s/T, where s 00333 is the turn step and T the turn max. In the above example, the vote 00334 step is 3/6 = 0.5. What this means is that if the vote for some 00335 direction is pegged at v, then the vote for its two surrounding 00336 directions will be v +/- 0.5. 00337 00338 Therefore, if we are d - C degrees away from some turn angle C, we can 00339 divide d - C by the turn step s to get the number of angular steps 00340 between d and C. We then multiply this number by the vote step to get 00341 the total number of vote steps between the directions d and C. 00342 Finally, we subtract that from 1 (the vote for C) to get the vote for 00343 the direction d. 00344 00345 This gives us the following expression for the vote for a steering 00346 angle d: 00347 00348 d - C s 00349 vote[d] = 1 - ----- x --- = 1 - (d - C)/T 00350 s T 00351 00352 But notice that if we were to use the above expression as-is, the 00353 votes for directions whose magnitudes are less than C will be greater 00354 than 1. For example, the vote for direction 0 will be 1 - (0 - 3)/6 = 00355 1 - (-3)/6 = 1 + 0.5 = 1.5! 00356 00357 The problem is that we are really interested in the magnitude of the 00358 difference between d and C and not its sign. In other words, if we 00359 think of (d - C) as an error, then we only want the amount of error 00360 and not the direction in which the error goes. This gives us: 00361 00362 vote[d] = 1 - abs(d - C)/T 00363 */ 00364 TurnArbiter::Vote turn_vote_centered_at(float C) 00365 { 00366 const int T = TurnArbiter::turn_max() ; 00367 00368 TurnArbiter::Vote V ; 00369 TurnArbiter::Vote::iterator it = V.begin() ; 00370 for (; it != V.end(); ++it) 00371 *it = clamp(1 - abs(it.direction() - C)/T, -1.0f, +1.0f) ; 00372 return V ; 00373 } 00374 00375 //--------------------------- VISUALIZATION ----------------------------- 00376 00377 #ifdef INVT_HAVE_LIBGL 00378 00379 void TurnArbiter::render_me() 00380 { 00381 // Copy most recent vote so that turn arbiter thread is not 00382 // unnecessarily held up while the rendering takes place. 00383 viz_lock() ; 00384 Vote V = m_vote ; 00385 viz_unlock() ; 00386 00387 // Render the votes visualization 00388 unit_view_volume() ; 00389 glBegin(GL_LINES) ; 00390 for (Vote::iterator it = V.begin(); it; ++it) 00391 { 00392 float vote = it.value() ; 00393 float direction = it.direction() ; 00394 if (vote < 0) // voted against this direction 00395 { 00396 glColor3f(1, 0, 0) ; 00397 glVertex2i(0, 0) ; 00398 glVertex2f(-vote * cos(direction), -vote * sin(direction)) ; 00399 } 00400 else if (vote > 0) // voted for this direction 00401 { 00402 glColor3f(0, 1, 0) ; 00403 glVertex2i(0, 0) ; 00404 glVertex2f(vote * cos(direction), vote * sin(direction)) ; 00405 } 00406 } 00407 00408 Vote::iterator max = std::max_element(V.begin(), V.end()) ; 00409 if (max.value() > 0) // this is the direction that won 00410 { 00411 glColor3f(1, 1, 1) ; 00412 glLineWidth(2) ; 00413 glVertex2i(0, 0) ; 00414 glVertex2f(cos(max.direction()), sin(max.direction())) ; 00415 } 00416 glEnd() ; 00417 00418 // Label the visualization so that it is easy to tell what is being 00419 // visualized. 00420 restore_view_volume() ; 00421 text_view_volume() ; 00422 glColor3f(0, 1, 1) ; 00423 draw_label(3, 12, "Turn Arbiter") ; 00424 00425 restore_view_volume() ; 00426 } 00427 00428 #endif 00429 00430 //----------------------- TURN ARBITER CLEAN-UP ------------------------- 00431 00432 TurnArbiter::~TurnArbiter(){} 00433 00434 //-------------------------- KNOB TWIDDLING ----------------------------- 00435 00436 // Parameters initialization 00437 TurnArbiter::Params::Params() 00438 : m_turn_max (clamp(conf("turn_max", 20), 5, 60)), 00439 m_turn_step(clamp(conf("turn_step", 1), 1, m_turn_max/2)), 00440 m_smoothing_width(conf("smoothing_window_width", 7)), 00441 m_sigma(clamp(conf("smoothing_sigma", 1.0f), 0.5f, m_turn_max/2.0f)) 00442 {} 00443 00444 // Parameters clean-up 00445 TurnArbiter::Params::~Params(){} 00446 00447 //----------------------------------------------------------------------- 00448 00449 } // end of namespace encapsulating this file's definitions 00450 00451 /* So things look consistent in everyone's emacs... */ 00452 /* Local Variables: */ 00453 /* indent-tabs-mode: nil */ 00454 /* End: */