00001 /*!@file Beobot/beobot-driveStraight-master.C color drive straight - master 00002 adapted from RCBot/driveStraight.C */ 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // 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: Christian Siagian <siagian@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Beobot/beobot-driveStraight-master.C $ 00035 // $Id: beobot-driveStraight-master.C 9412 2008-03-10 23:10:15Z farhan $ 00036 // 00037 00038 #include "Beowulf/Beowulf.H" 00039 #include "Component/ModelManager.H" 00040 #include "Component/OptionManager.H" 00041 #include "Controllers/PID.H" 00042 #include "Devices/FrameGrabberConfigurator.H" 00043 #include "Devices/DeviceOpts.H" 00044 #include "GUI/XWindow.H" 00045 #include "Image/ColorOps.H" 00046 #include "Image/CutPaste.H" 00047 #include "Image/DrawOps.H" 00048 #include "Image/Image.H" 00049 #include "Image/MathOps.H" 00050 #include "Image/Pixels.H" 00051 #include "Image/ShapeOps.H" 00052 #include "RCBot/Motion/MotionEnergy.H" 00053 #include "Raster/Raster.H" 00054 #include "Media/FrameSeries.H" 00055 #include "Transport/FrameIstream.H" 00056 #include "Util/Timer.H" 00057 #include "Util/Types.H" 00058 #include "Util/log.H" 00059 #include <math.h> 00060 #include <signal.h> 00061 00062 #include "Devices/BeoChip.H" 00063 #include "Beobot/BeobotConfig.H" 00064 #include "Controllers/PID.H" 00065 #include "Beobot/BeobotBeoChipListener.H" 00066 00067 // number of frames over which framerate info is averaged: 00068 #define NAVG 20 00069 00070 static bool goforever = true; 00071 BeobotConfig bbc; 00072 00073 // ###################################################################### 00074 void resetBeoChip(nub::soft_ref<BeoChip> b); 00075 00076 // ###################################################################### 00077 void terminate(int s) 00078 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); } 00079 00080 // ###################################################################### 00081 int main(const int argc, const char **argv) 00082 { 00083 MYLOGVERB = LOG_INFO; 00084 00085 // instantiate a model manager: 00086 ModelManager manager("Beobot - Drive Straight"); 00087 00088 // Instantiate our various ModelComponents: 00089 nub::soft_ref<BeoChip> b(new BeoChip(manager)); 00090 manager.addSubComponent(b); 00091 00092 nub::soft_ref<InputFrameSeries> ifs(new InputFrameSeries(manager)); 00093 manager.addSubComponent(ifs); 00094 00095 manager.exportOptions(MC_RECURSE); 00096 00097 // Parse command-line: 00098 if (manager.parseCommandLine(argc, argv, "steer P I D speed P I D", 6, 6) == false) 00099 return(1); 00100 00101 // do post-command-line configs: 00102 00103 // configure the BeoChip 00104 b->setModelParamVal("BeoChipDeviceName", std::string("/dev/ttyS0")); 00105 00106 // let's register our listener: 00107 rutz::shared_ptr<BeobotBeoChipListener> lis(new BeobotBeoChipListener(b)); 00108 rutz::shared_ptr<BeoChipListener> lis2; lis2.dynCastFrom(lis); // cast down 00109 b->setListener(lis2); 00110 00111 int w = ifs->getWidth(), h = ifs->getHeight(); 00112 XWindow winoH(Dims(w, 4*h), 2*w+20, 0, "test-output H"); 00113 XWindow winoV(Dims(w, 4*h), 3*w+30, 0, "test-output V"); 00114 XWindow wini (Dims(w, 4*h), w+10 , 0, "test-input windowL"); 00115 XWindow wini2(Dims(w, 4*h), 0 , 0, "test-input windowC"); 00116 00117 // let's get all our ModelComponent instances started: 00118 manager.start(); 00119 00120 // reset BeoChip 00121 resetBeoChip(b); 00122 00123 // create the motion pyramid 00124 MotionEnergyPyrBuilder<byte> motionPyr(Gaussian5); 00125 00126 // catch signals and redirect them to terminate for clean exit: 00127 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00128 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00129 signal(SIGALRM, terminate); 00130 00131 PID<float> steer_pid(4.0, 0.0, 0.0, -1.0, 1.0); 00132 PID<float> speed_pid(1.6, 0.3, 0.3, -0.6, 0.6); 00133 steer_pid.setPIDPgain(manager.getExtraArgAs<float>(0)); 00134 steer_pid.setPIDIgain(manager.getExtraArgAs<float>(1)); 00135 steer_pid.setPIDDgain(manager.getExtraArgAs<float>(2)); 00136 speed_pid.setPIDPgain(manager.getExtraArgAs<float>(3)); 00137 speed_pid.setPIDIgain(manager.getExtraArgAs<float>(4)); 00138 speed_pid.setPIDDgain(manager.getExtraArgAs<float>(5)); 00139 00140 // timer initialization 00141 Timer tim(1000000); uint64 t[NAVG]; int frame = 0; 00142 // ########## MAIN LOOP: grab, process, display: 00143 while(goforever) 00144 { 00145 tim.reset(); 00146 00147 // grab an image: 00148 ifs->updateNext(); 00149 Image< PixRGB<byte> > ima = ifs->readRGB(); 00150 if(!ima.initialized()) {goforever = false; break;} 00151 wini2.drawImage(ima,0,0); 00152 // Image< PixRGB<byte> > tmp2 = decXY(ima); 00153 // wini2.drawImage(tmp2,0,h); 00154 // tmp2 = decXY(tmp2); 00155 // wini2.drawImage(tmp2,0,h+h/2); 00156 // tmp2 = decXY(tmp2); 00157 // wini2.drawImage(tmp2,0,h+h/2+h/4); 00158 00159 //Image<byte> lum(320,240,ZEROS); 00160 //drawPatch(lum, Point2D<int>(160, int(120-frame*.5)),10, byte(255)); 00161 //drawPatch(lum, Point2D<int>(int(120-frame*.5), 120),10, byte(255)); 00162 Image<byte> lum = luminance(ima); 00163 wini.drawImage(lum,0,0); 00164 // Image<byte> tmp = decXY(lum); 00165 // wini.drawImage(tmp,0,h); 00166 // tmp = decXY(tmp); 00167 // wini.drawImage(tmp,0,h+h/2); 00168 // tmp = decXY(tmp); 00169 // wini.drawImage(tmp,0,h+h/2+h/4); 00170 00171 // build the motion pyramid 00172 // FIX: the second arg is depth of the pyramid 00173 // figure out how to combine each depth info later 00174 motionPyr.updateMotion(lum, 1); // start: 1 00175 ImageSet<float> hpyr = motionPyr.buildHorizontalMotion(); 00176 ImageSet<float> vpyr = motionPyr.buildVerticalMotion(); 00177 00178 // draw the images 00179 int sc = 1; float mn,mx, mn2, mx2; 00180 for(uint i = 0; i < hpyr.size(); i++) 00181 { 00182 Image<float> tmp = hpyr[i]; getMinMax(tmp,mn,mx); 00183 for(uint j = 0; j < i; j++) tmp = intXY(tmp, true); 00184 winoH.drawImage(tmp, 0, h*i); 00185 00186 tmp = vpyr[i]; getMinMax(tmp,mn2,mx2); 00187 for(uint j = 0; j < i; j++) tmp = intXY(tmp,true); 00188 winoV.drawImage(tmp, 0, h*i); 00189 sc *=2; 00190 00191 // LINFO("%4d| m(h): [%7.4f %7.4f %7.4f] m(v): [%7.4f %7.4f %7.4f]", frame, 00192 // mn, mean(hpyr[i]), mx, 00193 // mn2, mean(vpyr[i]), mx2); 00194 } 00195 00196 00197 // ###################################################################### 00198 // Obstacle avoidance 00199 // ###################################################################### 00200 // Image<float> motion = vpyr[0]; 00201 // float motionLeft = 0, motionRight = 0; 00202 // Image<float>::iterator motionPtr = motion.beginw(); 00203 // Image<float>::const_iterator motionPtrStop = motion.end(); 00204 00205 // // find the motion energy on the left and right side 00206 // int inx = 0; 00207 // while (motionPtr != motionPtrStop) { 00208 // int y = inx / motion.getWidth(); 00209 // int x = inx - (y*motion.getWidth()); 00210 00211 // if (y > 1){ 00212 // if (x < (motion.getWidth()/2)) 00213 // motionLeft += fabs(*motionPtr); 00214 // else 00215 // motionRight += fabs(*motionPtr); 00216 // } 00217 // motionPtr++; 00218 // inx++; 00219 // } 00220 00221 // double val = motionRight + motionLeft; 00222 // LINFO("Right: %0.4f Left: %0.4f Total: %0.4f", 00223 // motionRight, motionLeft, val); 00224 00225 // if (val > 20) 00226 // { 00227 // if (motionLeft > motionRight) 00228 // { 00229 // drawLine(lum, Point2D<int>(64,64), Point2D<int>(64+30,64-30), (byte)0, 2); 00230 // b->setServo(bbc.steerServoNum, -1.0); //sc8000->move(1, -1); 00231 // } 00232 // else 00233 // { 00234 // drawLine(lum, Point2D<int>(64,64), Point2D<int>(64-30,64-30), (byte)0, 2); 00235 // b->setServo(bbc.steerServoNum, 1.0); //sc8000->move(1, 1); 00236 // } 00237 // } 00238 // else 00239 // b->setServo(bbc.steerServoNum, 0.0); //sc8000->move(1, 0); 00240 00241 // if (val > 4000) 00242 // { 00243 // LINFO("\n\nSTOP STOP STOP STOP \n"); 00244 // b->setServo(bbc.speedServoNum, 0.0); //sc8000->move(3, 0); 00245 // sleep(2); 00246 // } 00247 // else 00248 // b->setServo(bbc.speedServoNum, -0.270); //sc8000->move(3, -0.270); 00249 00250 // inplaceNormalize(motion, 0.0F, 255.0F); 00251 // winoV.drawImage((Image<byte>)motion, lum.getWidth()+2, 0); 00252 00253 // ###################################################################### 00254 // drive straight 00255 // ###################################################################### 00256 00257 double speed = fabs(mean(vpyr[0])); 00258 double dir = -mean(hpyr[0]); 00259 if(dir > 0.0) LINFO("GO RIGHT"); else LINFO("GO LEFT"); 00260 // Raster::waitForKey(); 00261 00262 // drawLine(lum, Point2D<int>(w/2, h/2), 00263 // Point2D<int>( (int)(w/2 + 75*cos(dir)), 00264 // (int)(h/2 - 75*sin(dir)) ), 00265 // (byte)0, 3); 00266 // window1.drawImage(rescale(lum, 256, 256)); 00267 00268 double st = steer_pid.update(0.0 , dir); 00269 double sp = speed_pid.update(0.175, speed); 00270 if(st > 1.0) st = 1.0; else if (st < -1.0) st = -1.0; 00271 if(sp > 0.6) sp = 0.6; else if (sp < 0.0) sp = 0.0; 00272 LINFO("%4d STEER: %11.7f -> %11.7f SPEED: %11.7f -> %11.7f", frame, 00273 dir , st, speed, sp); 00274 sp = 0.4f; 00275 00276 // execute action command 00277 b->setServo(bbc.steerServoNum, st); 00278 b->setServo(bbc.speedServoNum, sp); 00279 00280 // ###################################################################### 00281 // ###################################################################### 00282 00283 // compute and show framerate over the last NAVG frames: 00284 t[frame % NAVG] = tim.get(); 00285 if (frame % NAVG == 0 && frame > 0) 00286 { 00287 uint64 avg = 0; for (int i = 0; i < NAVG; i ++) avg += t[i]; 00288 float avg2 = 1000000.0 / (float)avg * NAVG; 00289 LINFO("Framerate: %5.2f fps", avg2); 00290 } 00291 frame++; 00292 } 00293 00294 // got interrupted; let's cleanup and exit: 00295 manager.stop(); 00296 return 0; 00297 } 00298 00299 // ###################################################################### 00300 void resetBeoChip(nub::soft_ref<BeoChip> b) 00301 { 00302 // reset the beochip: 00303 LINFO("Resetting BeoChip..."); 00304 b->resetChip(); sleep(1); 00305 00306 // calibrate the servos 00307 b->calibrateServo(bbc.steerServoNum, bbc.steerNeutralVal, 00308 bbc.steerMinVal, bbc.steerMaxVal); 00309 b->calibrateServo(bbc.speedServoNum, bbc.speedNeutralVal, 00310 bbc.speedMinVal, bbc.speedMaxVal); 00311 b->calibrateServo(bbc.gearServoNum, bbc.gearNeutralVal, 00312 bbc.gearMinVal, bbc.gearMaxVal); 00313 00314 // keep the gear at the lowest speed/highest torque 00315 b->setServoRaw(bbc.gearServoNum, bbc.gearMinVal); 00316 00317 // turn on the keyboard 00318 b->debounceKeyboard(true); 00319 b->captureKeyboard(true); 00320 00321 // calibrate the PWMs: 00322 b->calibratePulse(0, 00323 bbc.pwm0NeutralVal, 00324 bbc.pwm0MinVal, 00325 bbc.pwm0MaxVal); 00326 b->calibratePulse(1, 00327 bbc.pwm1NeutralVal, 00328 bbc.pwm1MinVal, 00329 bbc.pwm1MaxVal); 00330 b->capturePulse(0, true); 00331 b->capturePulse(1, true); 00332 00333 // let's play with the LCD: 00334 b->lcdClear(); // 01234567890123456789 00335 b->lcdPrintf(0, 0, "collectFrames: 00000"); 00336 b->lcdPrintf(0, 1, "STEER=XXX SPEED=XXX"); 00337 b->lcdPrintf(0, 2, "PWM0=0000 0000-0000"); 00338 b->lcdPrintf(0, 3, "PWM1=0000 0000-0000"); 00339 } 00340 00341 // ###################################################################### 00342 /* So things look consistent in everyone's emacs... */ 00343 /* Local Variables: */ 00344 /* indent-tabs-mode: nil */ 00345 /* End: */