00001 /** 00002 \file Robots/LoBot/io/LoLaserRangeFinder.C 00003 \brief This file defines the non-inline member functions of the 00004 lobot::LaserRangeFinder 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/io/LoLaserRangeFinder.C $ 00039 // $Id: LoLaserRangeFinder.C 12863 2010-02-19 20:43:51Z mviswana $ 00040 // 00041 00042 //------------------------------ HEADERS -------------------------------- 00043 00044 // lobot headers 00045 #include "Robots/LoBot/io/LoLaserRangeFinder.H" 00046 #include "Robots/LoBot/misc/LoExcept.H" 00047 00048 // Standard C++ headers 00049 #include <algorithm> 00050 00051 #include <ctime> 00052 #include <cstdlib> 00053 00054 //---------------------- ALTERNATIVE DEFINITION ------------------------- 00055 00056 // Un/comment following line when laser range finder is un/available 00057 //#define LOBOT_LRF_DEVMODE 1 00058 00059 // A convenient dummy during development when the laser range finder may 00060 // not always be at hand for testing purposes. 00061 #ifdef LOBOT_LRF_DEVMODE 00062 00063 namespace lobot { 00064 00065 // Constructor 00066 LaserRangeFinder::LaserRangeFinder(const std::string&, int) 00067 : m_bufsiz(0), m_retsiz(0), m_buffer(0), 00068 m_angle_range(-119, 135), 00069 m_distance_range(60, 5600), 00070 m_distances(new int[m_angle_range.size()]) 00071 {} 00072 00073 // A quick function object to generate random integers in the given range 00074 class rand_int { 00075 int min, max ; 00076 public: 00077 rand_int(int i = 0, int x = 100) : min(i - 1), max(x + 1) { 00078 std::srand(std::time(0)) ; 00079 } 00080 int operator()() const { 00081 const float n = static_cast<float>(std::rand())/RAND_MAX ; 00082 return static_cast<int>(min + n * (max - min)) ; 00083 } 00084 } ; 00085 00086 // Dummy API 00087 void LaserRangeFinder::update() 00088 { 00089 std::generate_n(m_distances, m_angle_range.size(), 00090 rand_int(m_distance_range.min(), m_distance_range.max())) ; 00091 } 00092 00093 int LaserRangeFinder::get_distance(int angle) const 00094 { 00095 if (angle < m_angle_range.min() || angle > m_angle_range.max()) 00096 return -1 ; 00097 return m_distances[angle - m_angle_range.min()] ; 00098 } 00099 00100 Image<int> LaserRangeFinder::get_distances() const 00101 { 00102 Image<int> D(m_angle_range.size(), 1, ZEROS) ; 00103 std::copy(m_distances, m_distances + m_angle_range.size(), D.beginw()) ; 00104 return D ; 00105 } 00106 00107 float LaserRangeFinder::average_distance(int min_angle, int max_angle) const 00108 { 00109 const int a = std::max(min_angle - m_angle_range.min(), 0) ; 00110 const int b = std::min(max_angle - m_angle_range.min(), 00111 m_angle_range.size() - 1) ; 00112 if (a == b) // special case for single angle 00113 return m_distances[a] ; 00114 00115 float sum = 0 ; int n = 0 ; 00116 for (int i = a; i <= b; ++i) 00117 if (m_distances[i] > 0) { 00118 sum += m_distances[i] ; 00119 ++n ; 00120 } 00121 return (n > 0) ? sum/n : -1 ; 00122 } 00123 00124 int LaserRangeFinder::max_reading(int min_angle, int max_angle) const 00125 { 00126 const int a = std::max(min_angle - m_angle_range.min(), 0) ; 00127 const int b = std::min(max_angle - m_angle_range.min(), 00128 m_angle_range.size() - 1) ; 00129 if (a == b) // special case for single angle 00130 return m_distances[a] ; 00131 return *(std::max_element(m_distances + a, m_distances + b + 1)) ; 00132 } 00133 00134 // Destructor 00135 LaserRangeFinder::~LaserRangeFinder() 00136 { 00137 delete[] m_distances ; 00138 } 00139 00140 } 00141 00142 #else // not in development mode ==> LRF available ==> use the real thing 00143 00144 //---------------------- ALTERNATIVE DEFINITION ------------------------- 00145 00146 // In case liburg is missing 00147 #ifndef INVT_HAVE_LIBURG 00148 00149 namespace lobot { 00150 00151 // Constructor 00152 LaserRangeFinder::LaserRangeFinder(const std::string&, int) 00153 : m_handle(0), m_bufsiz(0), m_retsiz(0), m_buffer(0), 00154 m_angle_range(0, 0), m_distance_range(-1, -1), m_distances(0) 00155 { 00156 throw missing_libs(MISSING_LIBURG) ; 00157 } 00158 00159 // Empty API 00160 void LaserRangeFinder::update(){} 00161 int LaserRangeFinder::get_distance(int) const {return -1 ;} 00162 Image<int> LaserRangeFinder::get_distances() const {return Image<int>() ;} 00163 float LaserRangeFinder::average_distance(int, int) const {return -1 ;} 00164 int LaserRangeFinder::max_reading(int, int) const {return -1 ;} 00165 00166 // Destructor 00167 LaserRangeFinder::~LaserRangeFinder(){} 00168 00169 } // end of namespace encapsulating above empty definition 00170 00171 #else // liburg available ==> the real McCoy 00172 00173 //-------------------------- FULL DEFINITION ---------------------------- 00174 00175 namespace lobot { 00176 00177 //-------------------------- INITIALIZATION ----------------------------- 00178 00179 LaserRangeFinder::LaserRangeFinder(const std::string& device, int baud_rate) 00180 : m_bufsiz(0), m_retsiz(0), m_buffer(0), 00181 m_angle_range(0, 0), m_distance_range(-1, -1), m_distances(0) 00182 { 00183 if (urg_connect(& m_handle, device.c_str(), baud_rate) < 0) 00184 throw lrf_error(LRF_CONNECTION_FAILURE) ; 00185 00186 m_bufsiz = urg_getDataMax(& m_handle) ; 00187 m_buffer = new long[m_bufsiz] ; 00188 std::fill_n(m_buffer, m_bufsiz, 0) ; 00189 00190 m_angle_range.reset(urg_index2deg(& m_handle, 0), 00191 urg_index2deg(& m_handle, m_bufsiz - 1)) ; 00192 m_distances = new int[m_angle_range.size()] ; 00193 std::fill_n(m_distances, m_angle_range.size(), 0) ; 00194 00195 m_distance_range.reset(static_cast<int>(urg_getDistanceMin(& m_handle)), 00196 static_cast<int>(urg_getDistanceMax(& m_handle))) ; 00197 } 00198 00199 //---------------------- DISTANCE DATA RETRIEVAL ------------------------ 00200 00201 // Buffer latest measurements from device 00202 void LaserRangeFinder::update() 00203 { 00204 if (urg_requestData(& m_handle, URG_GD, URG_FIRST, URG_LAST) < 0) 00205 throw lrf_error(LRF_DATA_RETRIEVAL_FAILURE) ; 00206 00207 m_retsiz = urg_receiveData(& m_handle, m_buffer, m_bufsiz) ; 00208 if (m_retsiz < 0) 00209 throw lrf_error(LRF_DATA_RETRIEVAL_FAILURE) ; 00210 00211 const int m = m_angle_range.min() ; 00212 const int M = m_angle_range.max() ; 00213 for (int angle = m, i = 0; angle <= M; ++angle, ++i) 00214 { 00215 long d = m_buffer[urg_deg2index(const_cast<urg_t*>(& m_handle), angle)] ; 00216 if (d < m_distance_range.min() || d > m_distance_range.max()) 00217 d = -1 ; 00218 m_distances[i] = static_cast<int>(d) ; 00219 } 00220 } 00221 00222 // Return measurement corresponding to given angle 00223 int LaserRangeFinder::get_distance(int angle) const 00224 { 00225 if (angle < m_angle_range.min() || angle > m_angle_range.max()) 00226 return -1 ; 00227 return m_distances[angle - m_angle_range.min()] ; 00228 } 00229 00230 // Return all measurements packed together in an Image<int> 00231 Image<int> LaserRangeFinder::get_distances() const 00232 { 00233 Image<int> D(m_angle_range.size(), 1, NO_INIT) ; 00234 std::copy(m_distances, m_distances + m_angle_range.size(), D.beginw()) ; 00235 return D ; 00236 } 00237 00238 // Return average distance over the given range of angles 00239 float LaserRangeFinder::average_distance(int min_angle, int max_angle) const 00240 { 00241 const int a = std::max(min_angle - m_angle_range.min(), 0) ; 00242 const int b = std::min(max_angle - m_angle_range.min(), 00243 m_angle_range.size() - 1) ; 00244 if (a == b) // special case for single angle 00245 return m_distances[a] ; 00246 00247 float sum = 0 ; int n = 0 ; 00248 for (int i = a; i <= b; ++i) 00249 if (m_distances[i] > 0) { 00250 sum += m_distances[i] ; 00251 ++n ; 00252 } 00253 return (n > 0) ? sum/n : -1 ; 00254 } 00255 00256 // Return maximum distance reading in given angular range 00257 int LaserRangeFinder::max_reading(int min_angle, int max_angle) const 00258 { 00259 const int a = std::max(min_angle - m_angle_range.min(), 0) ; 00260 const int b = std::min(max_angle - m_angle_range.min(), 00261 m_angle_range.size() - 1) ; 00262 if (a == b) // special case for single angle 00263 return m_distances[a] ; 00264 return *(std::max_element(m_distances + a, m_distances + b + 1)) ; 00265 } 00266 00267 //----------------------------- CLEAN-UP -------------------------------- 00268 00269 LaserRangeFinder::~LaserRangeFinder() 00270 { 00271 urg_disconnect(& m_handle) ; 00272 delete[] m_distances ; 00273 delete[] m_buffer ; 00274 } 00275 00276 //----------------------------------------------------------------------- 00277 00278 } // end of namespace encapsulating this file's definitions 00279 00280 #endif // #ifndef INVT_HAVE_LIBURG 00281 #endif // #ifdef LOBOT_LRF_DEVMODE 00282 00283 /* So things look consistent in everyone's emacs... */ 00284 /* Local Variables: */ 00285 /* indent-tabs-mode: nil */ 00286 /* End: */