00001 /*!@file BeoSub/BeoSubAction.C Helper class for BeoSub motor actions */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/BeoSubAction.C $ 00035 // $Id: BeoSubAction.C 4663 2005-06-23 17:47:28Z rjpeters $ 00036 // 00037 00038 #include "BeoSub/BeoSubAction.H" 00039 #include "BeoSub/BeoSub.H" 00040 #include <cmath> 00041 00042 // ###################################################################### 00043 // ########## BeoSubAction member functions 00044 // ###################################################################### 00045 BeoSubAction::BeoSubAction(BeoSub *bs, const bool pulseWidthControl) : 00046 itsBeoSub(bs), itsDeadBand(10.0f), pulseWidthControl(pulseWidthControl) 00047 { } 00048 00049 // ###################################################################### 00050 BeoSubAction::~BeoSubAction() 00051 { } 00052 00053 // ###################################################################### 00054 bool BeoSubAction::execute(const float target, const bool stabil, const int itsMaxIter) 00055 { 00056 00057 if(pulseWidthControl){ 00058 return pulseWidthExecute(target, stabil, itsMaxIter); 00059 } 00060 int iter = 0; 00061 itsErrIndex = 0; 00062 itsErrorHistory[itsErrIndex] = difference(getPosition(), target); 00063 00064 00065 while(iter < itsMaxIter) 00066 { 00067 float pos = getPosition(); 00068 //difference between current pos and target pos 00069 itsErrorHistory[(itsErrIndex+1)%20] = difference(pos, target); 00070 //difference between current error and error in the previous iteration 00071 float errDiff = itsErrorHistory[(itsErrIndex+1)%20] - itsErrorHistory[itsErrIndex]; 00072 00073 LDEBUG("pos = %f, target = %f", pos, target); 00074 LDEBUG("Current error = %f, Previous Error = %f, errDiff = %f", itsErrorHistory[(itsErrIndex+1)%20], itsErrorHistory[itsErrIndex], errDiff); 00075 00076 // have we achieved the target position? 00077 if (fabsf(difference(pos, target)) < itsDeadBand) return true; // done 00078 00079 //calculate the total error for integral control 00080 float totalErr = 0; // total error over last 20 iterations 00081 for(int i = 0; i < 20; i ++) 00082 totalErr += itsErrorHistory[i]; 00083 00084 LDEBUG("Total error = %f", totalErr); 00085 00086 //calculating number of pulses based on PID control 00087 u = itsGainP*itsErrorHistory[(itsErrIndex+1)%20] 00088 + itsGainD*errDiff 00089 + itsGainI*totalErr; 00090 LDEBUG("u = %f", u); 00091 int numOfPulses; 00092 if(fabsf(u) > 8 ) 00093 numOfPulses = 8; 00094 else 00095 numOfPulses = int(fabsf(u)); 00096 // activate according to difference between current and target pos: 00097 for(float i = 0; i < numOfPulses; i++){ 00098 activate(u > 0); 00099 // if desired, stabilize a bit: 00100 if (stabil) stabilize(); 00101 } 00102 00103 iter ++; 00104 itsErrIndex = (itsErrIndex +1)%20; 00105 usleep(50000); 00106 } 00107 00108 LINFO("Max number (%d) of iterations reached -- GIVING UP", itsMaxIter); 00109 return false; 00110 } 00111 00112 00113 // ###################################################################### 00114 bool BeoSubAction::pulseWidthExecute(const float target, const bool stabil, const int itsMaxIter) 00115 { 00116 int iter = 0; 00117 itsErrIndex = 0; 00118 itsErrorHistory[itsErrIndex] = difference(getPosition(), target); 00119 00120 00121 while(iter < itsMaxIter) 00122 { 00123 float pos = getPosition(); 00124 //difference between current pos and target pos 00125 itsErrorHistory[(itsErrIndex+1)%20] = difference(pos, target); 00126 //difference between current error and error in the previous iteration 00127 float errDiff = itsErrorHistory[(itsErrIndex+1)%20] - itsErrorHistory[itsErrIndex]; 00128 00129 LDEBUG("Pulse Width: pos = %f, target = %f", pos, target); 00130 LDEBUG("Pulse Width: Current error = %f, Previous Error = %f, errDiff = %f", itsErrorHistory[(itsErrIndex+1)%20], itsErrorHistory[itsErrIndex], errDiff); 00131 00132 // have we achieved the target position? 00133 if (fabsf(difference(pos, target)) < itsDeadBand) return true; // done 00134 00135 //calculate the total error for integral control 00136 float totalErr = 0; // total error over last 20 iterations 00137 for(int i = 0; i < 20; i ++) 00138 totalErr += itsErrorHistory[i]; 00139 00140 LDEBUG("Pulse Width: Total error = %f", totalErr); 00141 00142 //calculating number of pulses based on PID control 00143 u = itsGainP*itsErrorHistory[(itsErrIndex+1)%20] 00144 + itsGainD*errDiff 00145 + itsGainI*totalErr; 00146 LDEBUG("u = %f", u); 00147 if(turnOnTime < 0) 00148 turnOnTime ++; 00149 00150 if(turnOnTime == 0){ 00151 turnOnTime = int(fabsf(u)); 00152 turnOnMotor(u > 0); 00153 } 00154 00155 if(turnOnTime > 0){ 00156 turnOnTime --; 00157 if(turnOnTime == 0) 00158 turnOffMotor(u > 0); 00159 turnOnTime = -3; 00160 } 00161 00162 // if desired, stabilize a bit: 00163 if (stabil) stabilize(pulseWidthControl); 00164 iter ++; 00165 itsErrIndex = (itsErrIndex +1)%20; 00166 usleep(50000); 00167 } 00168 00169 LINFO("Max number (%d) of iterations reached -- GIVING UP", itsMaxIter); 00170 return false; 00171 } 00172 00173 00174 // ###################################################################### 00175 // ########## BeoSubActionDive member functions 00176 // ###################################################################### 00177 BeoSubActionDive::BeoSubActionDive(BeoSub *bs, const bool pulseWidthControl) : 00178 BeoSubAction(bs, pulseWidthControl) 00179 { 00180 itsDeadBand = 5.0f; //FIXME: what are the units??? 00181 00182 if(pulseWidthControl){ 00183 itsGainP = 10.0f/5; 00184 itsGainD = 0; 00185 itsGainI = 0.01f/1; 00186 }else{ 00187 itsGainP = 13.0f/5; 00188 itsGainD = 0; 00189 itsGainI = 0.01f/1; 00190 } 00191 // get current heading in case we want to stabilize it: 00192 itsHeading = itsBeoSub->getHeading(); 00193 } 00194 00195 // ###################################################################### 00196 BeoSubActionDive::~BeoSubActionDive() 00197 { } 00198 00199 // ###################################################################### 00200 bool BeoSubActionDive::activate(const bool incr) 00201 { 00202 // one pulse on vertical thruster 00203 itsBeoSub->pulseMotor(BSM_UPDOWN, !incr); 00204 return true; 00205 } 00206 00207 // ###################################################################### 00208 bool BeoSubActionDive::turnOnMotor(const bool incr){ 00209 itsBeoSub->turnOnMotor(BSM_UPDOWN, !incr); 00210 return true; 00211 } 00212 00213 // ###################################################################### 00214 bool BeoSubActionDive::turnOffMotor(const bool incr){ 00215 itsBeoSub->turnOffMotor(BSM_UPDOWN); 00216 return true; 00217 } 00218 00219 // ###################################################################### 00220 float BeoSubActionDive::getPosition() const 00221 { return itsBeoSub->getDepth(); } 00222 00223 // ###################################################################### 00224 bool BeoSubActionDive::stabilize(const bool pulseWidthControl) 00225 { 00226 BeoSubActionTurn t(itsBeoSub, pulseWidthControl); 00227 00228 return t.execute(itsHeading, false, 1); 00229 } 00230 00231 // ###################################################################### 00232 float BeoSubActionDive::difference(float pos, float target) 00233 { 00234 return pos - target; 00235 } 00236 00237 00238 // ###################################################################### 00239 // ########## BeoSubActionTurn member functions 00240 // ###################################################################### 00241 BeoSubActionTurn::BeoSubActionTurn(BeoSub *bs, const bool pulseWidthControl) : 00242 BeoSubAction(bs, pulseWidthControl) 00243 { 00244 itsDeadBand = 10.0f; //FIXME: what are the units??? 00245 00246 if(pulseWidthControl){ 00247 itsGainP = 5.0f/20; 00248 itsGainD = 0; 00249 itsGainI = 0.01f/5; 00250 } 00251 else{ 00252 itsGainP = 5.0f/20; 00253 itsGainD = 0; 00254 itsGainI = 0.01f/5; 00255 } 00256 // get current depth in case we want to stabilize it: 00257 itsDepth = itsBeoSub->getDepth(); 00258 } 00259 00260 // ###################################################################### 00261 BeoSubActionTurn::~BeoSubActionTurn() 00262 { } 00263 00264 // ###################################################################### 00265 bool BeoSubActionTurn::activate(const bool incr) 00266 { 00267 // one pulse on lateral thrusters 00268 itsBeoSub->pulseMotor(BSM_LEFTRIGHT, incr); 00269 return true; 00270 } 00271 // ###################################################################### 00272 bool BeoSubActionTurn::turnOnMotor(const bool incr){ 00273 itsBeoSub->turnOnMotor(BSM_UPDOWN, !incr); 00274 return true; 00275 } 00276 00277 // ###################################################################### 00278 bool BeoSubActionTurn::turnOffMotor(const bool incr){ 00279 itsBeoSub->turnOffMotor(BSM_UPDOWN); 00280 return true; 00281 } 00282 00283 // ###################################################################### 00284 float BeoSubActionTurn::getPosition() const 00285 { return itsBeoSub->getHeading(); } 00286 00287 // ###################################################################### 00288 bool BeoSubActionTurn::stabilize(const bool pulseWidthControl) 00289 { 00290 BeoSubActionDive d(itsBeoSub, pulseWidthControl); 00291 return d.execute(itsDepth, false, 1); 00292 } 00293 00294 // ###################################################################### 00295 float BeoSubActionTurn::difference(float pos, float target) 00296 { 00297 //assuming turning clockwise is positive 00298 if(fabsf(pos - target) > 180){ 00299 if(pos > target) 00300 return target + 360 - pos; 00301 else 00302 return pos + 360 - target; 00303 } 00304 else 00305 return (pos - target); 00306 00307 } 00308 00309 // ###################################################################### 00310 /* So things look consistent in everyone's emacs... */ 00311 /* Local Variables: */ 00312 /* indent-tabs-mode: nil */ 00313 /* End: */