00001 /*!@file BeoSub/SeaBee.C An autonomous submarine with one ballast*/ 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/SeaBee.C $ 00035 // $Id: SeaBee.C 8521 2007-06-28 17:45:49Z rjpeters $ 00036 // 00037 00038 #include "BeoSub/SeaBee.H" 00039 #include "Devices/HMR3300.H" 00040 //#include "BeoSub/BeoSubBallast.H" 00041 #include "BeoSub/BeoSubIMU.H" 00042 #include "Util/MathFunctions.H" 00043 #include "Devices/FrameGrabberFactory.H" 00044 00045 // ###################################################################### 00046 //! Class definition for BeoSubListener 00047 /*! This is the listener class that is attached to each BeoChip in the 00048 ballast tube of the submarine. This class is just a 00049 pass-through to the function dispatchBeoChipEvent() of class 00050 SeaBee. */ 00051 class BeoSubListener : public BeoChipListener 00052 { 00053 public: 00054 //! Constructor 00055 BeoSubListener(SeaBee *sub) : itsBeoSub(sub) { } 00056 00057 //! destructor 00058 virtual ~BeoSubListener() { } 00059 00060 //! get an event 00061 virtual void event(const BeoChipEventType t, const int valint, 00062 const float valfloat) 00063 { 00064 //LDEBUG("Event: %d val = %d, fval = %f", int(t), valint, valfloat); 00065 itsBeoSub->dispatchBeoChipEvent(t, valint, valfloat); 00066 } 00067 00068 private: 00069 SeaBee *itsBeoSub; //!< pointer to our master 00070 }; 00071 00072 00073 00074 00075 // ###################################################################### 00076 SeaBee::SeaBee(OptionManager& mgr) : 00077 BeoSub(mgr), 00078 // itsIMU(new BeoSubIMU(mgr)), 00079 // itsLeftThrusterServoNum("BeoSubLeftThrusterServoNum", this, 3), 00080 //itsRightThrusterServoNum("BeoSubRightThrusterServoNum", this, 2), 00081 //itsHMR3300(new HMR3300(mgr)), 00082 itsBeo(new BeoChip(mgr, "BeoChip", "BeoChip")) 00083 // itsFballast(new BeoSubBallast(mgr, "Front Ballast", "FrontBallast")), 00084 // itsRballast(new BeoSubBallast(mgr, "Rear Ballast", "RearBallast")), 00085 // itsCameraFront(makeIEEE1394grabber(mgr, "Front Camera", "FrontCamera")), 00086 // itsCameraDown(makeIEEE1394grabber(mgr, "Down Camera", "DownCamera")), 00087 // itsCameraUp(makeIEEE1394grabber(mgr, "Up Camera", "UpCamera")), 00088 // itsDepthSensor(30, 0.99999F), 00089 // itsHeadingSensor(3, 0.99999F), 00090 // itsPitchSensor(3, 0.99999F), 00091 // itsDepthPID(0.001F, 0.0F, 0.1F, 3.0F, 3.0F), 00092 // itsHeadingPID(0.002F, 0.0F, 0.03F, Angle(170.0), Angle(170.0)), 00093 // itsPitchPID(0.001F, 0.0F, 0.1F, Angle(170.0), Angle(170.0)), 00094 // itsRotVelPID(0.3, 0.0001, 0, -500, 500), 00095 // itsDepthPIDon(false), 00096 // itsHeadingPIDon(false), 00097 // itsPitchPIDon(false), 00098 // itsRotVelPIDon(false), 00099 // itsKillSwitchUsed(false), 00100 // itsDiveSetting(0.0F), 00101 // itsPitchSetting(0.0F), 00102 // itsLastHeadingTime(0.0), 00103 // itsLastPitchTime(0.0), 00104 // itsLastDepthTime(0.0), 00105 // #ifdef HAVE_LINUX_PARPORT_H 00106 // lp0(new ParPort(mgr)), 00107 // markerdropper(lp0), 00108 // #endif 00109 // killSwitchDebounceCounter(0) 00110 00111 // itsLeftHThrusterServoNum("BeoSubLeftHThrusterServoNum", this, 4), 00112 // itsRightHThrusterServoNum("BeoSubRightHThrusterServoNum", this, 5), 00113 // itsBeo(new BeoChip(mgr, "BeoChip", "BeoChip")), 00114 // itsDiveSetting(0.0F) 00115 { 00116 00117 00118 //GRAB image from camera to be tested 00119 //gb->setModelParamVal("FrameGrabberFPS", 15.0F); 00120 00121 00122 // itsCameraFront->setModelParamVal("FrameGrabberSubChan", 0); 00123 // itsCameraFront->setModelParamVal("FrameGrabberBrightness", 128); 00124 // itsCameraFront->setModelParamVal("FrameGrabberHue", 180); 00125 // itsCameraFront->setModelParamVal("FrameGrabberNbuf", 2); 00126 00127 /* 00128 itsCameraDown->setModelParamVal("FrameGrabberSubChan", 0); 00129 itsCameraDown->setModelParamVal("FrameGrabberBrightness", 128); 00130 itsCameraDown->setModelParamVal("FrameGrabberHue", 180); 00131 itsCameraDown->setModelParamVal("FrameGrabberNbuf", 2); 00132 00133 itsCameraUp->setModelParamVal("FrameGrabberSubChan", 0); 00134 itsCameraUp->setModelParamVal("FrameGrabberBrightness", 128); 00135 itsCameraUp->setModelParamVal("FrameGrabberHue", 180); 00136 itsCameraUp->setModelParamVal("FrameGrabberNbuf", 2); 00137 */ 00138 00139 // register our babies as subcomponents: 00140 00141 // addSubComponent(itsBeo); 00142 00143 // // reset the BeoChip: 00144 // LINFO("Resetting the BeoChip..."); 00145 // itsBeo->reset(MC_RECURSE); 00146 // usleep(200000); 00147 00148 // // connect our listener to our beochip: 00149 // rutz::shared_ptr<BeoChipListener> b(new BeoSubListener(this)); 00150 // itsBeo->setListener(b); 00151 00152 // // connect our listener to our compass: 00153 // rutz::shared_ptr<HMR3300Listener> bl(new HMRlistener(this)); 00154 // itsHMR3300->setListener(bl); 00155 00156 // rutz::shared_ptr<BeoSubIMUListener> imu(new IMUListener(this)); 00157 // itsIMU->setListener(imu); 00158 00159 // // hook up BeoChips to Ballasts: 00160 // // itsFballast->setBeoChip(itsBeo); 00161 // // itsRballast->setBeoChip(itsBeo); 00162 00163 // // disable RTS/CTS flow control on our BeoChips: 00164 // itsBeo->setModelParamVal("BeoChipUseRTSCTS", false); 00165 00166 // // select default serial ports for everybody: 00167 // itsBeo->setModelParamString("BeoChipDeviceName", "/dev/ttyS1"); 00168 00169 //mgr.loadConfig("camconfig.pmap"); 00170 } 00171 00172 // ###################################################################### 00173 SeaBee::~SeaBee() 00174 { } 00175 00176 void SeaBee::test() { 00177 for (int i=0; i < 5; i++) { 00178 printf("Running Servo %d\n", i); 00179 itsBeo->setServoRaw(i, 255); 00180 sleep(2); 00181 itsBeo->setServoRaw(i, 127); 00182 sleep(2); 00183 itsBeo->setServoRaw(i, 0); 00184 sleep(2); 00185 itsBeo->setServoRaw(i, 127); 00186 } 00187 00188 00189 Raster::waitForKey(); 00190 00191 float x; 00192 while(true) { 00193 00194 x = itsBeo->getAnalog(0); 00195 printf("Pressure Sensor value: %f\n", x); 00196 } 00197 } 00198 00199 // ###################################################################### 00200 void SeaBee::start1() 00201 { 00202 // don't forget to call start1() on our base class! 00203 BeoSub::start1(); 00204 } 00205 00206 // ###################################################################### 00207 void SeaBee::start2() 00208 { 00209 // turn on the analog port capture for the pressure sensor, do not 00210 // capture pulses: 00211 /* itsBeo->captureAnalog(0, true); 00212 itsBeo->captureAnalog(1, false); 00213 itsBeo->capturePulse(0, false); 00214 itsBeo->capturePulse(1, false); 00215 */ 00216 00217 // set all servos to neutral: 00218 for (int i = 0; i < 8; i ++) itsBeo->setServo(i, 0.0F); 00219 00220 // turn on KBD capture for our ballasts: 00221 // itsBeo->captureKeyboard(true); 00222 // itsBeo->debounceKeyboard(false); 00223 00224 00225 // turn the PIDs on: NOTE: first we should dive some... 00226 00227 itsDiveSetting = 0.5F; 00228 00229 // display sign of life: 00230 itsBeo->lcdClear(); 00231 itsBeo->lcdPrintf(3, 0, " iLab and USC rock! "); 00232 00233 // we currently don't have a start2() in our base class, but if we 00234 // add one we should call it here. 00235 } 00236 00237 void SeaBee::stop1() { 00238 //Turn off all PID's 00239 00240 setTransVel(0.0); 00241 00242 //empty both balasts and surface! 00243 // setBallasts(0.0F, 0.0F, true); 00244 00245 } 00246 00247 // ###################################################################### 00248 void SeaBee::advanceRel(const float relDist, const bool stop) 00249 { 00250 float d = relDist * 2.0F; 00251 // turn our heading PID off as it may interfere with our commands of 00252 // the thrusters: 00253 // bool hpid = itsHeadingPIDon; 00254 // useHeadingPID(false); 00255 00256 // just pulse the thrusters: 00257 if (fabsf(d) < 1.0F) 00258 { 00259 setTransVel(d); 00260 sleep(1); 00261 if (stop) 00262 { 00263 setTransVel(-d); 00264 usleep(350000); 00265 } 00266 } 00267 else 00268 { 00269 float forward = 1.0F, reverse = -1.0F; 00270 if (d < 0.0F) { forward = -forward; reverse = -reverse; } 00271 00272 // thrust at full forward: 00273 setTransVel(forward); 00274 00275 // for a time that is proportional to distance. Note: we will 00276 // reach steady-state speed after about 1sec: 00277 usleep(int(fabsf(d) * 1000000)); 00278 00279 if (stop) 00280 { 00281 // now, to stop, thrust full reverse: 00282 setTransVel(reverse); 00283 00284 // for one second: 00285 sleep(1); 00286 } 00287 } 00288 00289 // stop 00290 setTransVel(0); 00291 00292 itsGlobalPosition.x += relDist * cos(itsGlobalHeading.getRadians()); 00293 itsGlobalPosition.y += relDist * sin(itsGlobalHeading.getRadians()); 00294 00295 // useHeadingPID(hpid); 00296 } 00297 00298 void SeaBee::updateThrusters() { 00299 float left = TransVelCommand;// + RotVelCommand; 00300 float right = TransVelCommand;// - RotVelCommand; 00301 00302 if (left > 1) left = 1; 00303 else if (left < -1) left = -1; 00304 00305 if (right > 1) right = 1; 00306 else if (right < -1) right = -1; 00307 00308 thrust(left, right); 00309 } 00310 00311 00312 void SeaBee::setTransVel(const float desired) { 00313 //desiredTransVel = desired; 00314 TransVelCommand = desired; /* open loop for now */ 00315 updateThrusters(); 00316 } 00317 00318 00319 // ###################################################################### 00320 void SeaBee::updateDepth(const float depth) 00321 { 00322 /* 00323 float left = TransVelCommand;// + RotVelCommand; 00324 float right = TransVelCommand;// - RotVelCommand; 00325 00326 if (left > 1) left = 1; 00327 else if (left < -1) left = -1; 00328 00329 if (right > 1) right = 1; 00330 else if (right < -1) right = -1; 00331 00332 thrust(left, right); 00333 */ 00334 00335 00336 // note the time at which the data was received: 00337 /* double t = itsMasterClock.getSecs(); 00338 00339 pthread_mutex_lock(&itsLock); 00340 00341 // update our depth sensor: 00342 itsDepthSensor.newMeasurement(depth); 00343 00344 // inject these values into our current attitude: 00345 itsCurrentAttitude.depth = itsDepthSensor.getValue(); 00346 itsCurrentAttitude.pressureTime = t; 00347 const float tdepth = itsTargetAttitude.depth; 00348 00349 // also update our depth PID and adjust ballasts: 00350 if (itsDepthPIDon && t >= itsLastDepthTime + 0.5) 00351 { 00352 // feed the PID controller: 00353 const float dcmd = itsDepthPID.update(tdepth, itsDepthSensor.getValue()); 00354 00355 // update and limit our dive setting: 00356 itsDiveSetting += dcmd; 00357 if (itsDiveSetting < 0.0F) itsDiveSetting = 0.0F; 00358 else if (itsDiveSetting > 1.0F) itsDiveSetting = 1.0F; 00359 00360 // adjust the ballasts: itsDiveSetting provides the mean, while 00361 // itsPitchSetting provides the deviation: 00362 float f = itsDiveSetting - itsPitchSetting; 00363 float r = itsDiveSetting + itsPitchSetting; 00364 if (f < 0.0F) f = 0.0F; else if (f > 1.0F) f = 1.0F; 00365 if (r < 0.0F) r = 0.0F; else if (r > 1.0F) r = 1.0F; 00366 // setBallasts(f, r); 00367 00368 // remember when we did all this: 00369 itsLastDepthTime = t; 00370 00371 LINFO("dcmd = %f at t=%f", dcmd, t); 00372 } 00373 00374 pthread_mutex_unlock(&itsLock); 00375 */ 00376 00377 } 00378 00379 // ###################################################################### 00380 void SeaBee::thrust(const float leftval, const float rightval) 00381 { 00382 // note: if the value is out of range, the BeoChip will clamp it. 00383 // That's why we read it back from the BeoChip before displaying it: 00384 // itsBeo->setServo(itsLeftHThrusterServoNum.getVal(), leftval); 00385 // itsThrustLeftH = itsBeo->getServo(itsLeftHThrusterServoNum.getVal()); 00386 00387 // itsBeo->setServo(itsRightHThrusterServoNum.getVal(), rightval); 00388 // itsThrustRightH = itsBeo->getServo(itsRightHThrusterServoNum.getVal()); 00389 00390 //LINFO("Th=%-1.2f/%-1.2f", itsThrustLeft, itsThrustRight); 00391 } 00392 00393 void SeaBee::dive(const float leftval, const float rightval) 00394 { 00395 // note: if the value is out of range, the BeoChip will clamp it. 00396 // That's why we read it back from the BeoChip before displaying it: 00397 // itsBeo->setServo(itsLeftVThrusterServoNum.getVal(), leftval); 00398 // itsThrustLeftV = itsBeo->getServo(itsLeftVThrusterServoNum.getVal()); 00399 00400 // itsBeo->setServo(itsRightVThrusterServoNum.getVal(), rightval); 00401 // itsThrustRightV = itsBeo->getServo(itsRightVThrusterServoNum.getVal()); 00402 00403 //LINFO("Th=%-1.2f/%-1.2f", itsThrustLeft, itsThrustRight); 00404 } 00405 00406 // ###################################################################### 00407 void SeaBee::getThrusters(float& leftval, float& rightval) const 00408 { leftval = itsThrustLeftH; rightval = itsThrustRightH; } 00409 00410 00411 00412 // ###################################################################### 00413 void SeaBee::getDiveThrusters(float& leftval, float& rightval) const 00414 { leftval = itsThrustLeftV; rightval = itsThrustRightV; } 00415 00416 // ###################################################################### 00417 void SeaBee::dispatchBeoChipEvent(const BeoChipEventType t, 00418 const int valint, 00419 const float valfloat) 00420 { 00421 // what is this event about and whom is it for? 00422 switch(t) 00423 { 00424 case NONE: // ############################## 00425 LERROR("Unexpected BeoChip NONE event!"); 00426 break; 00427 00428 case PWM0: // ############################## 00429 LERROR("Unexpected BeoChip PWM0 event!"); 00430 break; 00431 00432 case PWM1: // ############################## 00433 LERROR("Unexpected BeoChip PWM1 event!"); 00434 break; 00435 00436 case KBD: // ############################## 00437 LDEBUG("Keyboard: new value %d", valint); 00438 // current diagram is: 00439 // #0 = front full/empty switch 00440 // #1 = front gear encoder 00441 // #2 = rear full/empty switch 00442 // #3 = rear gear encoder 00443 // #4 = kill switch 00444 00445 // let both ballast units know: 00446 // itsFballast->input(valint); 00447 // itsRballast->input(valint); 00448 00449 //check if kill switch is activated 00450 //disabled due to kill-switch/start-switch multi-use - khooyp 00451 //if (valint & 0x10 != 0 && itsKillSwitchUsed) killSwitch(); 00452 break; 00453 00454 case ADC0: // ############################## 00455 { 00456 //LINFO("ADC0 new value = %d", valint); 00457 // the ADC0 is connected to the pressure sensor. Convert to 00458 // meters, with positive going down (so the deeper we are, the 00459 // larger the positive reading). Then update the depth reading: 00460 00461 // A reading of 255 corresponds to 2.5V, given our 2.5V 00462 // reference voltage on the BeoChip's ADC lines: 00463 float depth = (float(valint) * 2.5F) / 255.0F; // in volts 00464 00465 // I here assume that the sensor is an ASDX100A24R: NOTE: a 00466 // 220nF cap is required on the supply line. 00467 00468 // the sensor has a 0.5V offset (i.e., outputs 0.5V when 00469 // pressure is 0): 00470 depth -= 0.5F; 00471 00472 // An ASDX100A24R has a resolution of 0.040V/psi: 00473 depth /= 0.040F; // now in psi 00474 00475 // convert from PSI to meters: at the surface, we have 14.7 00476 // psi (= 1 atmosphere); then it's about 0.44 psi/foot, i.e., 00477 // 1.443 psi/m: 00478 depth = (depth - 14.275F) / 1.443F; 00479 00480 // NOTE: convention in the rest of the code is positive depth 00481 // the more we go down: 00482 updateDepth(depth); 00483 } 00484 break; 00485 00486 case ADC1: // ############################## 00487 LERROR("Unexpected BeoChip ADC1 event!"); 00488 break; 00489 00490 case RESET: // ############################## 00491 LERROR("BeoChip RESET!"); 00492 break; 00493 00494 case ECHOREP: // ############################## 00495 LINFO("BeoChip Echo reply."); 00496 break; 00497 00498 case INOVERFLOW: // ############################## 00499 LERROR("BeoChip input overflow!"); 00500 break; 00501 00502 case SERIALERROR: // ############################## 00503 LERROR("BeoChip serial error!"); 00504 break; 00505 00506 case OUTOVERFLOW: // ############################## 00507 LERROR("BeoChip output overflow!"); 00508 break; 00509 00510 default: // ############################## 00511 LERROR("BeoChip unknown event %d!", int(t)); 00512 break; 00513 } 00514 00515 00516 } 00517 00518 void SeaBee::turnOpen(Angle ang, bool b) { 00519 00520 00521 } 00522 00523 void SeaBee::dropMarker(bool b) { 00524 00525 } 00526 00527 Image<PixRGB <byte> > SeaBee::grabImage(BeoSubCamera bsc) const { 00528 return *(new Image<PixRGB <byte> >); 00529 00530 } 00531 // ###################################################################### 00532 /* So things look consistent in everyone's emacs... */ 00533 /* Local Variables: */ 00534 /* indent-tabs-mode: nil */ 00535 /* End: */