00001 /*!@file BeoSub/BeoSubOneBal.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/BeoSubOneBal.C $ 00035 // $Id: BeoSubOneBal.C 7880 2007-02-09 02:34:07Z itti $ 00036 // 00037 00038 #include "BeoSub/BeoSubOneBal.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 BeoSubOneBal. */ 00051 class BeoSubListener : public BeoChipListener 00052 { 00053 public: 00054 //! Constructor 00055 BeoSubListener(BeoSubOneBal *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 BeoSubOneBal *itsBeoSub; //!< pointer to our master 00070 }; 00071 00072 // ###################################################################### 00073 // here a listener for the compass: 00074 class HMRlistener : public HMR3300Listener { 00075 public: 00076 //! Constructor 00077 HMRlistener(BeoSubOneBal *sub) : itsBeoSub(sub) { } 00078 00079 //! Destructor 00080 virtual ~HMRlistener() {}; 00081 00082 //! New data was received 00083 virtual void newData(const Angle heading, const Angle pitch, 00084 const Angle roll) 00085 { 00086 //LDEBUG("<Heading=%f Pitch=%f Roll=%f>", heading.getVal(), 00087 // pitch.getVal(), roll.getVal()); 00088 itsBeoSub->updateCompass(heading, pitch, roll); 00089 } 00090 00091 private: 00092 BeoSubOneBal *itsBeoSub; 00093 }; 00094 00095 // here a listener for the compass: 00096 class IMUListener : public BeoSubIMUListener { 00097 public: 00098 //! Constructor 00099 IMUListener(BeoSubOneBal *sub) : itsBeoSub(sub) { } 00100 //! Destructor 00101 virtual ~IMUListener() {}; 00102 00103 //! New data was received 00104 virtual void newData(const float xa, const float ya, const float za, 00105 const Angle xv, const Angle yv, const Angle zv) 00106 { 00107 itsBeoSub->updateIMU(xa, ya, za, xv, yv, zv); 00108 } 00109 private: 00110 BeoSubOneBal *itsBeoSub; 00111 }; 00112 00113 00114 /* 00115 // ###################################################################### 00116 // here a listener for the compass: 00117 class IMUlistener : public BeoSubIMUListener { 00118 public: 00119 //! Destructor 00120 virtual ~HMRlistener() {}; 00121 00122 //! New data was received 00123 virtual void newData(const float xa, const float ya, const float za, 00124 const Angle xv, const Angle yv, const Angle zv) 00125 { 00126 } 00127 00128 private: 00129 BeoSubOneBal *itsBeoSub; 00130 }; 00131 */ 00132 00133 00134 00135 // ###################################################################### 00136 BeoSubOneBal::BeoSubOneBal(OptionManager& mgr) : 00137 BeoSub(mgr), 00138 itsIMU(new BeoSubIMU(mgr)), 00139 itsLeftThrusterServoNum("BeoSubLeftThrusterServoNum", this, 3), 00140 itsRightThrusterServoNum("BeoSubRightThrusterServoNum", this, 2), 00141 itsHMR3300(new HMR3300(mgr)), 00142 itsBeo(new BeoChip(mgr, "BeoChip", "BeoChip")), 00143 itsFballast(new BeoSubBallast(mgr, "Front Ballast", "FrontBallast")), 00144 itsRballast(new BeoSubBallast(mgr, "Rear Ballast", "RearBallast")), 00145 itsCameraFront(makeIEEE1394grabber(mgr, "Front Camera", "FrontCamera")), 00146 itsCameraDown(makeIEEE1394grabber(mgr, "Down Camera", "DownCamera")), 00147 itsCameraUp(makeIEEE1394grabber(mgr, "Up Camera", "UpCamera")), 00148 itsDepthSensor(30, 0.99999F), 00149 itsHeadingSensor(3, 0.99999F), 00150 itsPitchSensor(3, 0.99999F), 00151 itsDepthPID(0.001F, 0.0F, 0.1F, 3.0F, 3.0F), 00152 itsHeadingPID(0.002F, 0.0F, 0.03F, Angle(170.0), Angle(170.0)), 00153 itsPitchPID(0.001F, 0.0F, 0.1F, Angle(170.0), Angle(170.0)), 00154 itsRotVelPID(0.3, 0.0001, 0, -500, 500), 00155 itsDepthPIDon(false), 00156 itsHeadingPIDon(false), 00157 itsPitchPIDon(false), 00158 itsRotVelPIDon(false), 00159 itsKillSwitchUsed(false), 00160 itsDiveSetting(0.0F), 00161 itsPitchSetting(0.0F), 00162 itsLastHeadingTime(0.0), 00163 itsLastPitchTime(0.0), 00164 itsLastDepthTime(0.0), 00165 #ifdef HAVE_LINUX_PARPORT_H 00166 lp0(new ParPort(mgr)), 00167 markerdropper(lp0), 00168 #endif 00169 killSwitchDebounceCounter(0) 00170 00171 { 00172 // register our babies as subcomponents: 00173 addSubComponent(itsHMR3300); 00174 addSubComponent(itsIMU); 00175 addSubComponent(itsBeo); 00176 addSubComponent(itsCameraDown); 00177 addSubComponent(itsCameraFront); 00178 addSubComponent(itsCameraUp); 00179 addSubComponent(itsFballast); 00180 addSubComponent(itsRballast); 00181 #ifdef HAVE_LINUX_PARPORT_H 00182 addSubComponent(lp0); 00183 #endif 00184 00185 // reset the BeoChip: 00186 LINFO("Resetting the BeoChip..."); 00187 itsBeo->reset(MC_RECURSE); 00188 usleep(200000); 00189 00190 // connect our listener to our beochip: 00191 rutz::shared_ptr<BeoChipListener> b(new BeoSubListener(this)); 00192 itsBeo->setListener(b); 00193 00194 // connect our listener to our compass: 00195 rutz::shared_ptr<HMR3300Listener> bl(new HMRlistener(this)); 00196 itsHMR3300->setListener(bl); 00197 00198 rutz::shared_ptr<BeoSubIMUListener> imu(new IMUListener(this)); 00199 itsIMU->setListener(imu); 00200 00201 // hook up BeoChips to Ballasts: 00202 itsFballast->setBeoChip(itsBeo); 00203 itsRballast->setBeoChip(itsBeo); 00204 00205 // disable RTS/CTS flow control on our BeoChips: 00206 itsBeo->setModelParamVal("BeoChipUseRTSCTS", false); 00207 00208 // select default serial ports for everybody: 00209 itsHMR3300->setModelParamString("HMR3300SerialPortDevName", 00210 "/dev/ttyS0", MC_RECURSE); 00211 itsBeo->setModelParamString("BeoChipDeviceName", "/dev/ttyS2"); 00212 itsIMU->setModelParamString("IMUSerialPortDevName", "/dev/ttyS3", 00213 MC_RECURSE); 00214 00215 // set the I/O for our ballasts: 00216 itsRballast->setModelParamVal("RearBallastOutRed", 1); 00217 itsRballast->setModelParamVal("RearBallastOutWhite", 0); 00218 itsRballast->setModelParamVal("RearBallastInYellow", 1); 00219 itsRballast->setModelParamVal("RearBallastInWhite", 0); 00220 00221 itsFballast->setModelParamVal("FrontBallastOutRed", 3); 00222 itsFballast->setModelParamVal("FrontBallastOutWhite", 2); 00223 itsFballast->setModelParamVal("FrontBallastInYellow", 3); 00224 itsFballast->setModelParamVal("FrontBallastInWhite", 2); 00225 //mgr.loadConfig("camconfig.pmap"); 00226 } 00227 00228 // ###################################################################### 00229 BeoSubOneBal::~BeoSubOneBal() 00230 { } 00231 00232 // ###################################################################### 00233 void BeoSubOneBal::start1() 00234 { 00235 // select firewire subchannels for our cameras: 00236 itsCameraDown->setModelParamVal("FrameGrabberSubChan", int(BEOSUBCAMDOWN)); 00237 itsCameraFront->setModelParamVal("FrameGrabberSubChan", int(BEOSUBCAMFRONT)); 00238 itsCameraUp->setModelParamVal("FrameGrabberSubChan", int(BEOSUBCAMUP)); 00239 00240 //NOTE that the stuff below is certainly necessary, but DOES NOT WORK in current form. FIX! 00241 /* 00242 itsCameraFront->setModelParamVal("FrameGrabberExposure", 511); 00243 itsCameraFront->setModelParamVal("FramGrabberGain", 87); 00244 itsCameraFront->setModelParamVal("FrameGrabberNbuf", 10); 00245 itsCameraFront->setModelParamVal("FrameGrabberSaturation", 90); 00246 itsCameraFront->setModelParamVal("FrameGrabberWhiteBalSU", 95); 00247 itsCameraFront->setModelParamVal("FrameGrabberWhiteBalRV", 87); 00248 00249 itsCameraDown->setModelParamVal("FrameGrabberExposure", 511); 00250 itsCameraDown->setModelParamVal("FramGrabberGain", 87); 00251 itsCameraDown->setModelParamVal("FrameGrabberNbuf", 10); 00252 itsCameraDown->setModelParamVal("FrameGrabberSaturation", 90); 00253 itsCameraDown->setModelParamVal("FrameGrabberWhiteBalSU", 95); 00254 itsCameraDown->setModelParamVal("FrameGrabberWhiteBalRV", 87); 00255 00256 itsCameraUp->setModelParamVal("FrameGrabberExposure", 511); 00257 itsCameraUp->setModelParamVal("FramGrabberGain", 87); 00258 itsCameraUp->setModelParamVal("FrameGrabberNbuf", 10); 00259 itsCameraUp->setModelParamVal("FrameGrabberSaturation", 90); 00260 itsCameraUp->setModelParamVal("FrameGrabberWhiteBalSU", 95); 00261 itsCameraUp->setModelParamVal("FrameGrabberWhiteBalRV", 87); 00262 */ 00263 // don't forget to call start1() on our base class! 00264 BeoSub::start1(); 00265 } 00266 00267 // ###################################################################### 00268 void BeoSubOneBal::start2() 00269 { 00270 // turn on the analog port capture for the pressure sensor, do not 00271 // capture pulses: 00272 itsBeo->captureAnalog(0, true); 00273 itsBeo->captureAnalog(1, false); 00274 itsBeo->capturePulse(0, false); 00275 itsBeo->capturePulse(1, false); 00276 00277 // set all servos to neutral: 00278 for (int i = 0; i < 8; i ++) itsBeo->setServo(i, 0.0F); 00279 00280 // turn on KBD capture for our ballasts: 00281 itsBeo->captureKeyboard(true); 00282 itsBeo->debounceKeyboard(false); 00283 00284 // initialize all ballasts at once: 00285 CLINFO("filling ballasts..."); 00286 setBallasts(1.0F, 1.0F, false); sleep(4); 00287 CLINFO("emptying ballasts..."); 00288 setBallasts(0.0F, 0.0F, true); 00289 00290 // turn the PIDs on: NOTE: first we should dive some... 00291 //itsHeadingPIDon = true; 00292 //setBallasts(0.5F, 0.5F, true); 00293 //itsPitchPIDon = true; 00294 itsDiveSetting = 0.5F; 00295 00296 // display sign of life: 00297 itsBeo->lcdClear(); 00298 itsBeo->lcdPrintf(3, 0, " iLab and USC rock! "); 00299 00300 // we currently don't have a start2() in our base class, but if we 00301 // add one we should call it here. 00302 } 00303 00304 void BeoSubOneBal::stop1() { 00305 //Turn off all PID's 00306 useDepthPID(false); 00307 useHeadingPID(false); 00308 usePitchPID(false); 00309 useRotVelPID(false); 00310 setRotVel(0.0); 00311 setTransVel(0.0); 00312 00313 //empty both balasts and surface! 00314 setBallasts(0.0F, 0.0F, true); 00315 00316 } 00317 00318 // ###################################################################### 00319 void BeoSubOneBal::advanceRel(const float relDist, const bool stop) 00320 { 00321 float d = relDist * 2.0F; 00322 // turn our heading PID off as it may interfere with our commands of 00323 // the thrusters: 00324 bool hpid = itsHeadingPIDon; 00325 useHeadingPID(false); 00326 00327 // just pulse the thrusters: 00328 if (fabsf(d) < 1.0F) 00329 { 00330 setTransVel(d); 00331 sleep(1); 00332 if (stop) 00333 { 00334 setTransVel(-d); 00335 usleep(350000); 00336 } 00337 } 00338 else 00339 { 00340 float forward = 1.0F, reverse = -1.0F; 00341 if (d < 0.0F) { forward = -forward; reverse = -reverse; } 00342 00343 // thrust at full forward: 00344 setTransVel(forward); 00345 00346 // for a time that is proportional to distance. Note: we will 00347 // reach steady-state speed after about 1sec: 00348 usleep(int(fabsf(d) * 1000000)); 00349 00350 if (stop) 00351 { 00352 // now, to stop, thrust full reverse: 00353 setTransVel(reverse); 00354 00355 // for one second: 00356 sleep(1); 00357 } 00358 } 00359 00360 // stop 00361 setTransVel(0); 00362 00363 itsGlobalPosition.x += relDist * cos(itsGlobalHeading.getRadians()); 00364 itsGlobalPosition.y += relDist * sin(itsGlobalHeading.getRadians()); 00365 00366 useHeadingPID(hpid); 00367 } 00368 00369 // ###################################################################### 00370 void BeoSubOneBal::turnOpen(const Angle openHeading, const bool stop){ 00371 bool hpid = itsHeadingPIDon; 00372 useHeadingPID(false); 00373 00374 /* for now, we'll always turn at 15 degrees/sec */ 00375 float value = openHeading.getVal(); 00376 float turnrate; 00377 if(value > 0) { 00378 turnrate = 15; 00379 } else { 00380 turnrate = -15; 00381 } 00382 00383 setRotVel(turnrate); 00384 usleep((long)((value/turnrate)*1e6)); 00385 setRotVel(0.0); 00386 itsGlobalHeading += openHeading; 00387 useHeadingPID(hpid); 00388 } 00389 00390 // ###################################################################### 00391 void BeoSubOneBal::strafeRel(const float relDist) 00392 {/* 00393 bool hpid = itsHeadingPIDon; 00394 useHeadingPID(false); 00395 BeoSub::strafeRel(relDist); 00396 useHeadingPID(hpid);*/ 00397 turnRel(90); 00398 advanceRel(relDist); 00399 turnRel(-90); 00400 } 00401 00402 void BeoSubOneBal::updateThrusters() { 00403 float left = TransVelCommand + RotVelCommand; 00404 float right = TransVelCommand - RotVelCommand; 00405 00406 if (left > 1) left = 1; 00407 else if (left < -1) left = -1; 00408 00409 if (right > 1) right = 1; 00410 else if (right < -1) right = -1; 00411 00412 thrust(left, right); 00413 } 00414 00415 void BeoSubOneBal::updateRotVelPID(const Angle current) { 00416 if(itsRotVelPIDon) { 00417 //LINFO("%5.2f %5.2f", (PIDRotVel-current).getVal(), RotVelCommand); 00418 RotVelCommand = itsRotVelPID.update(PIDRotVel, current).getVal(); 00419 updateThrusters(); 00420 } 00421 } 00422 00423 void BeoSubOneBal::setRotVel(const Angle desired) { 00424 if(itsRotVelPIDon) { 00425 PIDRotVel = desired; 00426 } else { 00427 RotVelCommand = desired.getVal(); 00428 updateThrusters(); 00429 } 00430 } 00431 00432 void BeoSubOneBal::setTransVel(const float desired) { 00433 //desiredTransVel = desired; 00434 TransVelCommand = desired; /* open loop for now */ 00435 updateThrusters(); 00436 } 00437 00438 void BeoSubOneBal::updateIMU(const float xa, const float ya, const float za, 00439 const Angle xv, const Angle yv, const Angle zv) 00440 { 00441 //LINFO("%5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f", xa, ya, za, xv.getVal(), yv.getVal(), zv.getVal(), itsCurrentAttitude.heading.getVal(), itsCurrentAttitude.pitch.getVal(), itsCurrentAttitude.roll.getVal()); 00442 updateRotVelPID(zv); /* ignore roll/pitch interaction for now */ 00443 } 00444 00445 // ###################################################################### 00446 void BeoSubOneBal::updateCompass(const Angle heading, const Angle pitch, 00447 const Angle roll) 00448 { 00449 // note the time at which the data was received: 00450 double t = itsMasterClock.getSecs(); 00451 00452 pthread_mutex_lock(&itsLock); 00453 00454 // update our heading and pitch sensors: 00455 itsHeadingSensor.newMeasurement(heading); 00456 itsPitchSensor.newMeasurement(pitch); 00457 00458 // inject these values into our current attitude: 00459 itsCurrentAttitude.heading = itsHeadingSensor.getValue(); 00460 itsCurrentAttitude.pitch = itsPitchSensor.getValue(); 00461 itsCurrentAttitude.roll = roll; 00462 itsCurrentAttitude.compassTime = t; 00463 00464 00465 // also update our heading PID and thrust accordingly: 00466 // only update every once in a while (in seconds): 00467 if (itsHeadingPIDon && t >= itsLastHeadingTime + 0.5) 00468 { 00469 // feed the PID controller: 00470 const float hcmd = 00471 itsHeadingPID.update(itsTargetAttitude.heading, 00472 itsHeadingSensor.getValue()).getVal(); 00473 setRotVel(hcmd); 00474 00475 // remember when we did all this: 00476 itsLastHeadingTime = t; 00477 00478 LINFO("hcmd = %f at t = %f", hcmd, t); 00479 } 00480 00481 // also update our pitch PID and adjust ballasts accordingly: 00482 if (itsPitchPIDon && t >= itsLastPitchTime + 0.5) 00483 { 00484 // feed the PID controller: 00485 const float pcmd = 00486 itsPitchPID.update(itsTargetAttitude.pitch, 00487 itsPitchSensor.getValue()).getVal(); 00488 00489 // update and limit our pitch setting: This setting should be 00490 // subtracted from the front ballast and added to the rear 00491 // ballast, relative to level: 00492 itsPitchSetting += pcmd; 00493 if (itsPitchSetting > 0.25F) itsPitchSetting = 0.25F; 00494 if (itsPitchSetting < -0.25F) itsPitchSetting = -0.25F; 00495 00496 // adjust the ballasts: itsDiveSetting provides the mean, while 00497 // itsPitchSetting provides the deviation: 00498 float f = itsDiveSetting - itsPitchSetting; 00499 float r = itsDiveSetting + itsPitchSetting; 00500 if (f < 0.0F) f = 0.0F; else if (f > 1.0F) f = 1.0F; 00501 if (r < 0.0F) r = 0.0F; else if (r > 1.0F) r = 1.0F; 00502 setBallasts(f, r); 00503 00504 // remember when we did all this: 00505 itsLastPitchTime = t; 00506 00507 LINFO("pcmd = %f at t = %f", pcmd, t); 00508 } 00509 00510 pthread_mutex_unlock(&itsLock); 00511 } 00512 00513 // ###################################################################### 00514 void BeoSubOneBal::updateDepth(const float depth) 00515 { 00516 // note the time at which the data was received: 00517 double t = itsMasterClock.getSecs(); 00518 00519 pthread_mutex_lock(&itsLock); 00520 00521 // update our depth sensor: 00522 itsDepthSensor.newMeasurement(depth); 00523 00524 // inject these values into our current attitude: 00525 itsCurrentAttitude.depth = itsDepthSensor.getValue(); 00526 itsCurrentAttitude.pressureTime = t; 00527 const float tdepth = itsTargetAttitude.depth; 00528 00529 // also update our depth PID and adjust ballasts: 00530 if (itsDepthPIDon && t >= itsLastDepthTime + 0.5) 00531 { 00532 // feed the PID controller: 00533 const float dcmd = itsDepthPID.update(tdepth, itsDepthSensor.getValue()); 00534 00535 // update and limit our dive setting: 00536 itsDiveSetting += dcmd; 00537 if (itsDiveSetting < 0.0F) itsDiveSetting = 0.0F; 00538 else if (itsDiveSetting > 1.0F) itsDiveSetting = 1.0F; 00539 00540 // adjust the ballasts: itsDiveSetting provides the mean, while 00541 // itsPitchSetting provides the deviation: 00542 float f = itsDiveSetting - itsPitchSetting; 00543 float r = itsDiveSetting + itsPitchSetting; 00544 if (f < 0.0F) f = 0.0F; else if (f > 1.0F) f = 1.0F; 00545 if (r < 0.0F) r = 0.0F; else if (r > 1.0F) r = 1.0F; 00546 setBallasts(f, r); 00547 00548 // remember when we did all this: 00549 itsLastDepthTime = t; 00550 00551 LINFO("dcmd = %f at t=%f", dcmd, t); 00552 } 00553 00554 pthread_mutex_unlock(&itsLock); 00555 } 00556 00557 // ###################################################################### 00558 void BeoSubOneBal::thrust(const float leftval, const float rightval) 00559 { 00560 // note: if the value is out of range, the BeoChip will clamp it. 00561 // That's why we read it back from the BeoChip before displaying it: 00562 itsBeo->setServo(itsLeftThrusterServoNum.getVal(), leftval); 00563 itsThrustLeft = itsBeo->getServo(itsLeftThrusterServoNum.getVal()); 00564 00565 itsBeo->setServo(itsRightThrusterServoNum.getVal(), rightval); 00566 itsThrustRight = itsBeo->getServo(itsRightThrusterServoNum.getVal()); 00567 00568 //LINFO("Th=%-1.2f/%-1.2f", itsThrustLeft, itsThrustRight); 00569 } 00570 00571 // ###################################################################### 00572 void BeoSubOneBal::getThrusters(float& leftval, float& rightval) const 00573 { leftval = itsThrustLeft; rightval = itsThrustRight; } 00574 00575 // ###################################################################### 00576 void BeoSubOneBal::setFrontBallast(const float val, const bool blocking) 00577 { itsFballast->set(val, blocking); } 00578 00579 // ###################################################################### 00580 void BeoSubOneBal::setRearBallast(const float val, const bool blocking) 00581 { itsRballast->set(val, blocking); } 00582 00583 // ###################################################################### 00584 void BeoSubOneBal::setBallasts(const float f, const float r, 00585 const bool blocking) 00586 { 00587 // move all ballasts simultaneously rather than sequentially: 00588 itsFballast->set(f, false); 00589 itsRballast->set(r, false); 00590 00591 if (blocking) 00592 { 00593 const double timeout = itsMasterClock.getSecs() + 20.0; 00594 while(itsMasterClock.getSecs() < timeout) 00595 { 00596 if (itsFballast->moving() == false && 00597 itsRballast->moving() == false) break; 00598 usleep(100000); 00599 } 00600 if (itsMasterClock.getSecs() >= timeout) 00601 LERROR("Timeout on blocking setBallasts -- IGNORED"); 00602 } 00603 } 00604 00605 // ###################################################################### 00606 float BeoSubOneBal::getFrontBallast() const 00607 { return itsFballast->get(); } 00608 00609 // ###################################################################### 00610 float BeoSubOneBal::getRearBallast() const 00611 { return itsRballast->get(); } 00612 00613 // ###################################################################### 00614 void BeoSubOneBal::getBallasts(float& f, float& r) const 00615 { f = itsFballast->get(); r = itsRballast->get(); } 00616 00617 // ###################################################################### 00618 void BeoSubOneBal::dropMarker(const bool blocking) 00619 { 00620 #ifndef HAVE_LINUX_PARPORT_H 00621 LFATAL("<linux/parport.h> must be installed to use this function"); 00622 #else 00623 markerdropper.Step(150, 65000); 00624 #endif 00625 } 00626 00627 // ###################################################################### 00628 void BeoSubOneBal::killSwitch() 00629 { 00630 //Turn off all PID's 00631 useDepthPID(false); 00632 useHeadingPID(false); 00633 usePitchPID(false); 00634 useRotVelPID(false); 00635 setRotVel(0.0); 00636 setTransVel(0.0); 00637 00638 //empty both balasts and surface! 00639 setBallasts(0.0F, 0.0F, true); 00640 00641 LFATAL("Kill switch pulled!"); 00642 } 00643 00644 // ###################################################################### 00645 void BeoSubOneBal::dispatchBeoChipEvent(const BeoChipEventType t, 00646 const int valint, 00647 const float valfloat) 00648 { 00649 // what is this event about and whom is it for? 00650 switch(t) 00651 { 00652 case NONE: // ############################## 00653 LERROR("Unexpected BeoChip NONE event!"); 00654 break; 00655 00656 case PWM0: // ############################## 00657 LERROR("Unexpected BeoChip PWM0 event!"); 00658 break; 00659 00660 case PWM1: // ############################## 00661 LERROR("Unexpected BeoChip PWM1 event!"); 00662 break; 00663 00664 case KBD: // ############################## 00665 LDEBUG("Keyboard: new value %d", valint); 00666 // current diagram is: 00667 // #0 = front full/empty switch 00668 // #1 = front gear encoder 00669 // #2 = rear full/empty switch 00670 // #3 = rear gear encoder 00671 // #4 = kill switch 00672 00673 // let both ballast units know: 00674 itsFballast->input(valint); 00675 itsRballast->input(valint); 00676 00677 //check if kill switch is activated 00678 //disabled due to kill-switch/start-switch multi-use - khooyp 00679 //if (valint & 0x10 != 0 && itsKillSwitchUsed) killSwitch(); 00680 break; 00681 00682 case ADC0: // ############################## 00683 { 00684 //LINFO("ADC0 new value = %d", valint); 00685 // the ADC0 is connected to the pressure sensor. Convert to 00686 // meters, with positive going down (so the deeper we are, the 00687 // larger the positive reading). Then update the depth reading: 00688 00689 // A reading of 255 corresponds to 2.5V, given our 2.5V 00690 // reference voltage on the BeoChip's ADC lines: 00691 float depth = (float(valint) * 2.5F) / 255.0F; // in volts 00692 00693 // I here assume that the sensor is an ASDX100A24R: NOTE: a 00694 // 220nF cap is required on the supply line. 00695 00696 // the sensor has a 0.5V offset (i.e., outputs 0.5V when 00697 // pressure is 0): 00698 depth -= 0.5F; 00699 00700 // An ASDX100A24R has a resolution of 0.040V/psi: 00701 depth /= 0.040F; // now in psi 00702 00703 // convert from PSI to meters: at the surface, we have 14.7 00704 // psi (= 1 atmosphere); then it's about 0.44 psi/foot, i.e., 00705 // 1.443 psi/m: 00706 depth = (depth - 14.275F) / 1.443F; 00707 00708 // NOTE: convention in the rest of the code is positive depth 00709 // the more we go down: 00710 updateDepth(depth); 00711 } 00712 break; 00713 00714 case ADC1: // ############################## 00715 LERROR("Unexpected BeoChip ADC1 event!"); 00716 break; 00717 00718 case RESET: // ############################## 00719 LERROR("BeoChip RESET!"); 00720 break; 00721 00722 case ECHOREP: // ############################## 00723 LINFO("BeoChip Echo reply."); 00724 break; 00725 00726 case INOVERFLOW: // ############################## 00727 LERROR("BeoChip input overflow!"); 00728 break; 00729 00730 case SERIALERROR: // ############################## 00731 LERROR("BeoChip serial error!"); 00732 break; 00733 00734 case OUTOVERFLOW: // ############################## 00735 LERROR("BeoChip output overflow!"); 00736 break; 00737 00738 default: // ############################## 00739 LERROR("BeoChip unknown event %d!", int(t)); 00740 break; 00741 } 00742 00743 /* in addition, we also poll the kill switch on the parallel port */ 00744 if(isKilled()) { 00745 killSwitchDebounceCounter++; 00746 if(killSwitchDebounceCounter > 50) { 00747 killSwitch(); 00748 } 00749 //LINFO("killSwitchDebounce at %i\n", killSwitchDebounceCounter); 00750 } else { 00751 if(killSwitchDebounceCounter > 0) { 00752 LINFO("killSwitchDebounce reset\n"); 00753 } 00754 killSwitchDebounceCounter = 0; 00755 } 00756 } 00757 00758 // ###################################################################### 00759 Image< PixRGB<byte> > 00760 BeoSubOneBal::grabImage(const enum BeoSubCamera cam) const 00761 { 00762 if (cam == BEOSUBCAMFRONT) return itsCameraFront->readRGB(); 00763 if (cam == BEOSUBCAMDOWN) return itsCameraDown->readRGB(); 00764 if (cam == BEOSUBCAMUP) return itsCameraUp->readRGB(); 00765 LERROR("Wrong camera %d -- RETURNING EMPTY IMAGE", int(cam)); 00766 return Image< PixRGB<byte> >(); 00767 } 00768 00769 // ###################################################################### 00770 void BeoSubOneBal::useDepthPID(const bool useit) 00771 { itsDepthPIDon = useit; } 00772 00773 // ###################################################################### 00774 void BeoSubOneBal::useHeadingPID(const bool useit) 00775 { itsHeadingPIDon = useit; } 00776 00777 // ###################################################################### 00778 void BeoSubOneBal::usePitchPID(const bool useit) 00779 { itsPitchPIDon = useit; } 00780 00781 void BeoSubOneBal::useRotVelPID(const bool useit) 00782 { itsRotVelPIDon = useit; } 00783 00784 // ###################################################################### 00785 void BeoSubOneBal::useKillSwitch(const bool useit) 00786 { itsKillSwitchUsed = useit; } 00787 00788 // ###################################################################### 00789 bool BeoSubOneBal::isKilled() 00790 { 00791 #ifndef HAVE_LINUX_PARPORT_H 00792 LFATAL("<linux/parport.h> must be installed to use this function"); 00793 return true; // can't happen, but placate compiler 00794 #else 00795 unsigned char status; 00796 status = lp0->ReadStatus(); 00797 return (status & PARPORT_STATUS_BUSY) || !(status & PARPORT_STATUS_ACK); 00798 #endif 00799 } 00800 00801 // ###################################################################### 00802 void BeoSubOneBal::setDepthPgain(float p) 00803 { itsDepthPID.setPIDPgain(p); } 00804 00805 // ###################################################################### 00806 void BeoSubOneBal::setDepthIgain(float i) 00807 { itsDepthPID.setPIDIgain(i); } 00808 00809 // ###################################################################### 00810 void BeoSubOneBal::setDepthDgain(float d) 00811 { itsDepthPID.setPIDDgain(d); } 00812 00813 // ###################################################################### 00814 void BeoSubOneBal::setHeadingPgain(float p) 00815 { itsHeadingPID.setPIDPgain(p); } 00816 00817 // ###################################################################### 00818 void BeoSubOneBal::setHeadingIgain(float i) 00819 { itsHeadingPID.setPIDIgain(i); } 00820 00821 // ###################################################################### 00822 void BeoSubOneBal::setHeadingDgain(float d) 00823 { itsHeadingPID.setPIDDgain(d); } 00824 00825 // ###################################################################### 00826 void BeoSubOneBal::setPitchPgain(float p) 00827 { itsPitchPID.setPIDPgain(p); } 00828 00829 // ###################################################################### 00830 void BeoSubOneBal::setPitchIgain(float i) 00831 { itsPitchPID.setPIDIgain(i); } 00832 00833 // ###################################################################### 00834 void BeoSubOneBal::setPitchDgain(float d) 00835 { itsPitchPID.setPIDDgain(d); } 00836 00837 // ###################################################################### 00838 void BeoSubOneBal::setRotVelPgain(float p) 00839 { itsRotVelPID.setPIDPgain(p); } 00840 00841 // ###################################################################### 00842 void BeoSubOneBal::setRotVelIgain(float i) 00843 { itsRotVelPID.setPIDIgain(i); } 00844 00845 // ###################################################################### 00846 void BeoSubOneBal::setRotVelDgain(float d) 00847 { itsRotVelPID.setPIDDgain(d); } 00848 // ###################################################################### 00849 /* So things look consistent in everyone's emacs... */ 00850 /* Local Variables: */ 00851 /* indent-tabs-mode: nil */ 00852 /* End: */