00001 /*!@file Robots/LoBot/LoRoombaVecHist.C Test collision avoidance using ping sonar on roomba */ 00002 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: Farhan Baluch <fbaluch@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/LoRoombaVecHist.C $ 00035 // $Id: LoRoombaVecHist.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 // model manager 00039 #include "Component/ModelManager.H" 00040 #include "Util/log.H" 00041 #include "rutz/shared_ptr.h" 00042 00043 // for images and display 00044 #include "Raster/Raster.H" 00045 #include "Raster/GenericFrame.H" 00046 #include "Image/Image.H" 00047 #include "Image/PixelsTypes.H" 00048 #include "Transport/FrameIstream.H" 00049 #include "Transport/FrameInfo.H" 00050 #include "GUI/XWinManaged.H" 00051 #include "GUI/XWindow.H" 00052 #include "Media/FrameSeries.H" 00053 00054 // Frame grabber 00055 #include "Devices/FrameGrabberConfigurator.H" 00056 #include "Devices/DeviceOpts.H" 00057 #include "Media/FrameSeries.H" 00058 00059 // Devices 00060 #include "Devices/PingSonar.H" 00061 00062 // for color segmentation 00063 #include "Util/Timer.H" 00064 #include "Util/Types.H" 00065 #include "Util/log.H" 00066 #include "Util/sformat.H" 00067 #include <cstdio> 00068 #include <cstdlib> 00069 #include <signal.h> 00070 00071 // for image manipulation 00072 #include "Image/CutPaste.H" // for inplacePaste() 00073 #include "Image/vec2.h" 00074 #include "Image/DrawOps.H" 00075 00076 //for vector fields 00077 #include "Robots/LoBot/control/VectorHistField.H" 00078 00079 #include "Robots/IRobot/Roomba.H" 00080 00081 // number of frames over which framerate info is averaged: 00082 #define NAVG 20 00083 00084 static bool goforever = true; 00085 00086 using namespace geom; 00087 00088 #define MAXVEL 100 00089 #define INPLACEVEL 50 00090 00091 typedef struct robotCmd 00092 { 00093 int motor; 00094 int radius; 00095 00096 } robotCmd; 00097 00098 // ###################################################################### 00099 void terminate(int s) 00100 { LERROR("*** INTERRUPT ***"); goforever = false; } 00101 00102 00103 // ###################################################################### 00104 //! Visualize distance received from sensor 00105 00106 Image<PixRGB<byte> > vizDist(std::vector<int> dists,int divisions) 00107 { 00108 00109 Image<PixRGB<byte> > img(800,800,ZEROS); 00110 int startAng = 0; 00111 int increment = 180/dists.size(); 00112 int beginAng=startAng, endAng=increment; 00113 00114 for(uint s=0;s<dists.size();s++) 00115 { 00116 00117 for(int i=1; i<=divisions;i++) 00118 for (int ang=beginAng;ang<=endAng;ang++) 00119 { 00120 int rad = i*5; 00121 Point2D<int> pt; 00122 pt.i = 200+100*s - (int) (rad*cos(ang*M_PI/180.0)); 00123 pt.j = 400 - (int) (rad*sin(ang*M_PI/180.0)); 00124 00125 if(dists.at(s) <= i*250) 00126 drawPoint(img,pt.i,pt.j,PixRGB<byte>(255,0,0)); 00127 else 00128 drawPoint(img,pt.i,pt.j,PixRGB<byte>(0,0,255)); 00129 00130 writeText(img,Point2D<int>(10+100*s,10), 00131 sformat("%i--%d ",s,dists.at(s)).c_str(), 00132 PixRGB<byte>(255),PixRGB<byte>(0)); 00133 00134 } 00135 beginAng = endAng; 00136 endAng = endAng + increment; 00137 } 00138 00139 return img; 00140 00141 } 00142 00143 00144 00145 // ###################################################################### 00146 //! Convert vectors to motor command 00147 robotCmd vec2motor(geom::vec2f a) 00148 { 00149 //divide our space into 4 quadrants and deal with each one separately 00150 //right now just concerned with angle 00151 //---------// 00152 //| 1 | 2 |// 00153 //|-------|// 00154 //| 3 | 4 |// 00155 //---------// 00156 00157 float ang = (int)a.theta_deg(); 00158 LINFO("ang %f",ang); 00159 int tmpRad; 00160 robotCmd cmd1; 00161 00162 cmd1.radius = 0; 00163 cmd1.motor = 0; 00164 00165 00166 if(ang == 90.0) 00167 { 00168 cmd1.radius = 0; 00169 cmd1.motor = MAXVEL; 00170 } 00171 //turn clockwise if in quadrant 2 00172 if(ang > 90 && ang <=180) 00173 { 00174 LINFO("quadrant--2"); 00175 tmpRad=(int)((ang-181.0) * 2000/90.0); 00176 00177 if(tmpRad >= 0) //i.e. angle is 0 or less we need to turn away 00178 { 00179 cmd1.radius = 23; 00180 cmd1.motor = INPLACEVEL; 00181 } 00182 00183 else 00184 { 00185 cmd1.radius = tmpRad; 00186 cmd1.motor = (int)(MAXVEL/2000)*fabs(tmpRad); //speed propotional to radius 00187 cmd1.motor = 100; 00188 } 00189 00190 } 00191 00192 00193 //turn anti-clockwise if in quadrant 1 00194 if(ang >= 0 && ang <90) 00195 { 00196 LINFO("quadrant--1--ang %f",ang); 00197 tmpRad = 2000-(int)((89.0-ang) * 2000/90.0); 00198 00199 if(tmpRad > 2000) //i.e. we are at 90deg no need to turn 00200 { 00201 cmd1.radius = 0.0; 00202 cmd1.motor = MAXVEL; 00203 } 00204 00205 if(tmpRad <= 0) //i.e. we are at horizontal ang =179 00206 { 00207 cmd1.radius = 23; 00208 cmd1.motor = 100; 00209 } 00210 00211 else 00212 { 00213 cmd1.radius = tmpRad; 00214 cmd1.motor = (int)(MAXVEL/2000)*fabs(tmpRad); //speed propotional to radius 00215 cmd1.motor = 100; 00216 } 00217 00218 } 00219 00220 //turn anti-clockwise in quadrant 3 00221 if(ang < 0 && ang >= -90) 00222 { 00223 LINFO("quadrant--3"); 00224 cmd1.radius = 250; 00225 cmd1.motor = INPLACEVEL; 00226 } 00227 00228 //turn clockwise if in quadrant 4 00229 if(ang < -90 && ang >= -180) 00230 { 00231 LINFO("quadrant--4 , clockwise"); 00232 cmd1.radius = -250; 00233 cmd1.motor = INPLACEVEL; 00234 } 00235 00236 if (cmd1.radius > 2000) 00237 cmd1.radius =2000; 00238 if (cmd1.radius < -2000) 00239 cmd1.radius =-2000; 00240 00241 return cmd1; 00242 } 00243 00244 00245 // ###################################################################### 00246 //! Receive signals from master node and performs requested actions 00247 int main(const int argc, const char **argv) 00248 { 00249 00250 00251 MYLOGVERB = LOG_INFO; 00252 // instantiate a model manager 00253 ModelManager manager( "Avoid Collisions " ); 00254 00255 int itsDim = 30; 00256 int itsSpacing = 15; 00257 00258 //nub::ref<InputFrameSeries> ifs(new InputFrameSeries(manager)); 00259 //manager.addSubComponent(ifs); 00260 00261 manager.setOptionValString(&OPT_FrameGrabberMode, "RGB24"); 00262 manager.setOptionValString(&OPT_FrameGrabberDims, "320x240"); 00263 manager.setOptionValString(&OPT_FrameGrabberFPS, "30"); 00264 00265 nub::soft_ref<PingSonar> pingSonar(new PingSonar(manager,"PingSonar", "PingSonar","/dev/ttyUSB0",3)); 00266 00267 nub::soft_ref<VectorHistField> vectorHistField(new VectorHistField 00268 (manager,"VectorHistField", 00269 "VectorHistField",itsDim,itsDim)); 00270 00271 00272 nub::soft_ref<Roomba> roomba(new Roomba(manager,"Roomba", 00273 "Roomba","/dev/ttyUSB1")); 00274 00275 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00276 manager.addSubComponent(roomba); 00277 manager.addSubComponent(ofs); 00278 manager.addSubComponent(pingSonar); 00279 manager.addSubComponent(vectorHistField); 00280 00281 manager.exportOptions(MC_RECURSE); 00282 00283 // parse command-line 00284 if( manager.parseCommandLine( argc, argv, "", 0, 0 ) == false ) return(1); 00285 00286 // setup signal handling: 00287 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00288 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00289 00290 manager.start(); 00291 00292 LINFO("starting roomba...."); 00293 roomba->sendStart(); 00294 LINFO("setting to full mode...."); 00295 roomba->setMode(2); 00296 00297 00298 roomba->setSpeed(0); 00299 sleep(1); 00300 // timer initialization 00301 Timer tim; 00302 tim.reset(); 00303 00304 Image<PixRGB<byte> > dispImg(itsDim*itsSpacing, itsDim*itsSpacing,ZEROS); 00305 Point2D<int> itsFixedRobotPos(itsDim/2,itsDim-5); 00306 00307 static int dist=0; 00308 static int ang=0; 00309 00310 //create obstacle template field once 00311 float sigma = 5.5; 00312 float amp= 45.0; 00313 Image<geom::vec2f> obsTemplate = vectorHistField->obstacleTemplate(sigma,amp); 00314 00315 //int cnt=0; 00316 // get ready for main loop: 00317 while (goforever) 00318 { 00319 00320 std::vector<int> dists = pingSonar->getDists(); 00321 std::vector<Point2D<float> > sensor; 00322 00323 LINFO("getting dists %d,%d,%d",dists.at(0),dists.at(1),dists.at(2)); 00324 00325 sensor.push_back(Point2D<float> ((float)(dists.at(0)*itsDim/3000),150.0)); 00326 sensor.push_back(Point2D<float> ((float)(dists.at(1)*itsDim/3000),90.0)); 00327 sensor.push_back(Point2D<float> ((float)(dists.at(2)*itsDim/3000),30.0)); 00328 00329 roomba->getDistanceAngle(dist,ang); 00330 LINFO("dist travelled %d, angle turned %d",roomba->getDist(),roomba->getAngle()); 00331 00332 Image<PixRGB<byte> > blobs = vectorHistField->updateField(sensor, Point2D<int>(0,0), ang, dist, Point2D<int> (15,90),obsTemplate); 00333 00334 dispImg = vectorHistField->plotGridField(itsSpacing); 00335 ofs->writeRGB(dispImg,"Output",FrameInfo("output",SRC_POS)); 00336 //ofs->writeRGB(dispImg,sformat("Output%d",cnt++)); 00337 00338 00339 geom::vec2f a; 00340 a = vectorHistField->getVectorAt(itsFixedRobotPos); 00341 00342 robotCmd cmd = vec2motor(a); 00343 //LINFO("motor %d,radius %d", cmd.motor,cmd.radius); 00344 00345 //cmd.motor = 0; 00346 //cmd.radius =0; 00347 try 00348 { 00349 roomba->setSpeed(cmd.motor); 00350 roomba->setRadius(cmd.radius); 00351 } 00352 catch (...) {} 00353 00354 00355 if(tim.getSecs() > 65.0) 00356 goforever=false; 00357 00358 // You can add more commands here. 00359 usleep(100 * 1000); 00360 00361 } 00362 00363 00364 roomba->setSpeed(0); 00365 00366 manager.stop(); 00367 00368 } 00369 00370 00371 00372 // ###################################################################### 00373 /* So things look consistent in everyone's emacs... */ 00374 /* Local Variables: */ 00375 /* indent-tabs-mode: nil */ 00376 /* End: */ 00377