00001 /*!@file Robots/LoBot/LoRoomba.C Test collision avoidance using ping sonar on 00002 roomba */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Farhan Baluch <fbaluch@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/LoRoomba.C $ 00036 // $Id: LoRoomba.C 12962 2010-03-06 02:13:53Z irock $ 00037 // 00038 00039 // model manager 00040 #include "Component/ModelManager.H" 00041 #include "Util/log.H" 00042 #include "rutz/shared_ptr.h" 00043 00044 // for images and display 00045 #include "Raster/Raster.H" 00046 #include "Raster/GenericFrame.H" 00047 #include "Image/Image.H" 00048 #include "Image/PixelsTypes.H" 00049 #include "Transport/FrameIstream.H" 00050 #include "Transport/FrameInfo.H" 00051 #include "GUI/XWinManaged.H" 00052 #include "GUI/XWindow.H" 00053 #include "Media/FrameSeries.H" 00054 00055 // Frame grabber 00056 #include "Devices/FrameGrabberConfigurator.H" 00057 #include "Devices/DeviceOpts.H" 00058 #include "Media/FrameSeries.H" 00059 00060 // Devices 00061 #include "Devices/PingSonar.H" 00062 00063 // for color segmentation 00064 #include "Util/Timer.H" 00065 #include "Util/Types.H" 00066 #include "Util/log.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 // number of frames over which framerate info is averaged: 00077 #define NAVG 20 00078 00079 #if HAVE_LIBSERIAL && HAVE_LIBIROBOT_CREATE 00080 00081 static bool goforever = true; 00082 00083 // for Robot controller 00084 #include <SerialStream.h> 00085 #include <irobot-create.hh> 00086 00087 using namespace iRobot; 00088 using namespace LibSerial; 00089 using namespace geom; 00090 00091 #define MAXVEL 100 00092 #define INPLACEVEL 100 00093 00094 typedef struct robotCmd 00095 { 00096 int motor; 00097 int radius; 00098 00099 } robotCmd; 00100 00101 // ###################################################################### 00102 void terminate(int s) 00103 { LERROR("*** INTERRUPT ***"); goforever = false; exit(1); } 00104 00105 00106 // ###################################################################### 00107 //! Visualize distance received from sensor 00108 00109 Image<PixRGB<byte> > vizDist(std::vector<int> dists,int divisions) 00110 { 00111 00112 Image<PixRGB<byte> > img(800,800,ZEROS); 00113 int startAng = 0; 00114 int increment = 180/dists.size(); 00115 int beginAng=startAng, endAng=increment; 00116 00117 for(uint s=0;s<dists.size();s++) 00118 { 00119 00120 for(int i=1; i<=divisions;i++) 00121 for (int ang=beginAng;ang<=endAng;ang++) 00122 { 00123 int rad = i*5; 00124 Point2D<int> pt; 00125 pt.i = 200+100*s - (int) (rad*cos(ang*M_PI/180.0)); 00126 pt.j = 400 - (int) (rad*sin(ang*M_PI/180.0)); 00127 00128 if(dists.at(s) <= i*250) 00129 drawPoint(img,pt.i,pt.j,PixRGB<byte>(255,0,0)); 00130 else 00131 drawPoint(img,pt.i,pt.j,PixRGB<byte>(0,0,255)); 00132 00133 writeText(img,Point2D<int>(10+100*s,10), 00134 sformat("%i--%d ",s,dists.at(s)).c_str(), 00135 PixRGB<byte>(255),PixRGB<byte>(0)); 00136 00137 } 00138 beginAng = endAng; 00139 endAng = endAng + increment; 00140 } 00141 00142 return img; 00143 00144 } 00145 00146 00147 00148 // ###################################################################### 00149 //! Convert vectors to motor command 00150 robotCmd vec2motor(geom::vec2f a) 00151 { 00152 //divide our space into 4 quadrants and deal with each one separately 00153 //right now just concerned with angle 00154 //---------// 00155 //| 1 | 2 |// 00156 //|-------|// 00157 //| 3 | 4 |// 00158 //---------// 00159 00160 float ang = a.theta_deg(); 00161 int tmpRad; 00162 robotCmd cmd1; 00163 00164 cmd1.radius = 0; 00165 cmd1.motor = 0; 00166 00167 00168 if(ang == 90.0) 00169 { 00170 cmd1.radius = Create::DRIVE_STRAIGHT; 00171 cmd1.motor = MAXVEL; 00172 } 00173 //turn clockwise if in quadrant 2 00174 if(ang > 90 && ang <=180) 00175 { 00176 LINFO("quadrant--2"); 00177 tmpRad=(int)((ang-181.0) * 2000/90.0); 00178 00179 if(tmpRad >= 0) //i.e. angle is 0 or less we need to turn away 00180 { 00181 cmd1.radius = Create::DRIVE_INPLACE_COUNTERCLOCKWISE; 00182 cmd1.motor = INPLACEVEL; 00183 } 00184 00185 else 00186 { 00187 cmd1.radius = tmpRad; 00188 cmd1.motor = (int)(MAXVEL/2000)*fabs(tmpRad); //speed propotional to radius 00189 cmd1.motor = 100; 00190 } 00191 00192 } 00193 00194 00195 //turn anti-clockwise if in quadrant 1 00196 if(ang >= 0 && ang <90) 00197 { 00198 LINFO("quadrant--1"); 00199 tmpRad=2000-(int)((89.0-ang) * 2000/90.0); 00200 00201 if(tmpRad > 2000) //i.e. we are at 90deg no need to turn 00202 { 00203 cmd1.radius = 0.0; 00204 cmd1.motor = MAXVEL; 00205 } 00206 00207 if(tmpRad <= 0) //i.e. we are at horizontal ang =179 00208 { 00209 cmd1.radius = Create::DRIVE_INPLACE_COUNTERCLOCKWISE; 00210 cmd1.motor = 100; 00211 } 00212 00213 00214 else 00215 { 00216 cmd1.radius = tmpRad; 00217 cmd1.motor = (int)(MAXVEL/2000)*fabs(tmpRad); //speed propotional to radius 00218 cmd1.motor = 100; 00219 } 00220 00221 } 00222 00223 //turn anti-clockwise in quadrant 3 00224 if(ang < 0 && ang >= -90) 00225 { 00226 LINFO("quadrant--3"); 00227 cmd1.radius = Create::DRIVE_INPLACE_COUNTERCLOCKWISE; 00228 cmd1.motor = INPLACEVEL; 00229 } 00230 00231 //turn clockwise if in quadrant 4 00232 if(ang < -90 && ang >= -180) 00233 { 00234 LINFO("quadrant--4 , clockwise val = %d",Create::DRIVE_INPLACE_CLOCKWISE); 00235 cmd1.radius = Create::DRIVE_INPLACE_CLOCKWISE; 00236 cmd1.motor = INPLACEVEL; 00237 } 00238 00239 return cmd1; 00240 00241 } 00242 00243 00244 // ###################################################################### 00245 //! Receive signals from master node and performs requested actions 00246 int main(const int argc, const char **argv) 00247 { 00248 00249 00250 MYLOGVERB = LOG_INFO; 00251 00252 // instantiate a model manager 00253 ModelManager manager( "Avoid Collisions " ); 00254 00255 /*nub::ref<InputFrameSeries> ifs(new InputFrameSeries(manager)); 00256 manager.addSubComponent(ifs); 00257 00258 manager.setOptionValString(&OPT_FrameGrabberMode, "RGB24"); 00259 manager.setOptionValString(&OPT_FrameGrabberDims, "320x240"); 00260 manager.setOptionValString(&OPT_FrameGrabberFPS, "30"); 00261 */ 00262 // nub::soft_ref<PingSonar> pingSonar(new PingSonar(manager,"PingSonar", "PingSonar","/dev/ttyUSB0",3)); 00263 00264 nub::ref<OutputFrameSeries> ofs(new OutputFrameSeries(manager)); 00265 manager.addSubComponent(ofs); 00266 // manager.addSubComponent(pingSonar); 00267 manager.exportOptions(MC_RECURSE); 00268 00269 // parse command-line 00270 if( manager.parseCommandLine( argc, argv, "", 0, 0 ) == false ) return(1); 00271 00272 manager.start(); 00273 00274 // initialize the motor controller 00275 SerialStream stream ("/dev/rfcomm5"); 00276 //SerialStream stream ("/dev/ttyUSB0"); 00277 00278 // catch signals and redirect them to terminate for clean exit: 00279 signal(SIGHUP, terminate); signal(SIGINT, terminate); 00280 signal(SIGQUIT, terminate); signal(SIGTERM, terminate); 00281 signal(SIGALRM, terminate); 00282 00283 // instantiate a robot controller 00284 Create robot(stream); 00285 00286 robot.sendBaudCommand(Create::BAUD_57600); 00287 // Swith to full mode. 00288 robot.sendFullCommand(); 00289 00290 // Let's stream some sensors. 00291 Create::sensorPackets_t sensors; 00292 sensors.push_back(Create::SENSOR_ANGLE); 00293 sensors.push_back(Create::SENSOR_DISTANCE); 00294 00295 robot.sendStreamCommand(sensors); 00296 00297 robot.sendDriveCommand (0, Create::DRIVE_STRAIGHT); 00298 //int ledColor = Create::LED_COLOR_GREEN; 00299 robot.sendLedCommand(Create::LED_PLAY, 0, 0); 00300 usleep(20*1000); 00301 00302 // timer initialization 00303 Timer tim; 00304 tim.reset(); 00305 //std::vector<int> dists = pingSonar->getDists(); 00306 00307 Image<PixRGB<byte> > dispImg(500,500,ZEROS); 00308 Point2D<int> startPt(dispImg.getWidth()/2,dispImg.getHeight()-50), endPt; 00309 static int dist=0; 00310 static int ang=0; 00311 00312 // get ready for main loop: 00313 while (!robot.playButton () && goforever) 00314 { 00315 // std::vector<int> dists = pingSonar->getDists(); 00316 00317 // drawPoint(dispImg,endPt.i,endPt.j,PixRGB<byte>(255,0,0)); 00318 00319 // ofs->writeRGB(vizDist(dists,12),"Output",FrameInfo("output",SRC_POS)); 00320 ofs->writeRGB(dispImg,"Output",FrameInfo("output",SRC_POS)); 00321 geom::vec2f a; 00322 00323 float timeInt =5.0F; 00324 if(tim.getSecs() < timeInt) 00325 { 00326 a.set_polar_rad(25.0F,geom::deg2rad(90.0F)); 00327 LINFO("driving 90deg -- vec %f",a.theta_deg()); 00328 } 00329 else if(tim.getSecs() > timeInt && tim.getSecs() <= 2*timeInt) 00330 { 00331 a.set_polar_rad(25.0F,geom::deg2rad(135.0F)); 00332 LINFO("driving 135deg -- vec %f",a.theta_deg()); 00333 } 00334 else if(tim.getSecs() > 2*timeInt && tim.getSecs() <= 3*timeInt) 00335 { 00336 a.set_polar_rad(25.0F,geom::deg2rad(45.0F)); 00337 LINFO("driving 45deg -- vec %f",a.theta_deg()); 00338 } 00339 else if(tim.getSecs() > 3*timeInt && tim.getSecs() < 4*timeInt) 00340 { 00341 LINFO("driving 190deg"); 00342 a.set_polar_rad(25.0F,geom::deg2rad(190.0F)); 00343 LINFO("driving 190deg -- vec %f",a.theta_deg()); 00344 } 00345 00346 robotCmd cmd = vec2motor(a); 00347 00348 LINFO("motor %d,radius %d", cmd.motor,cmd.radius); 00349 int crntDist =robot.distance() ; int crntAng=robot.angle(); 00350 dist += crntDist; 00351 ang += crntAng; 00352 LINFO("dist travelled %d, angle turned %d",dist,ang); 00353 try 00354 { 00355 if(cmd.radius == 0 || cmd.radius ==Create::DRIVE_STRAIGHT) 00356 { 00357 robot.sendDriveCommand (cmd.motor, Create::DRIVE_STRAIGHT); 00358 LINFO("the straight command has val %d", Create::DRIVE_STRAIGHT); 00359 } 00360 else if (cmd.radius == 1 || cmd.radius ==Create::DRIVE_INPLACE_CLOCKWISE) 00361 { 00362 robot.sendDriveCommand (cmd.motor, Create::DRIVE_INPLACE_CLOCKWISE); 00363 LINFO("the clockwise command has val %d", Create::DRIVE_INPLACE_CLOCKWISE); 00364 } 00365 else if (cmd.radius == 2 || cmd.radius ==Create::DRIVE_INPLACE_COUNTERCLOCKWISE) 00366 { 00367 robot.sendDriveCommand (cmd.motor, Create::DRIVE_INPLACE_COUNTERCLOCKWISE); 00368 LINFO("the counter clockwise command has val %d", Create::DRIVE_INPLACE_COUNTERCLOCKWISE); 00369 } 00370 00371 else 00372 robot.sendDriveCommand (cmd.motor, cmd.radius); 00373 00374 } 00375 catch (...) {} 00376 00377 // process robot input 00378 if (robot.bumpLeft () || robot.bumpRight ()) 00379 { 00380 std::cout << "Bump !" << std::endl; 00381 robot.sendPlaySongCommand(2); 00382 robot.sendDriveCommand(50,Create::DRIVE_INPLACE_CLOCKWISE); 00383 } 00384 00385 00386 if (robot.advanceButton ()) 00387 { 00388 00389 } 00390 00391 if(tim.getSecs() > 5*timeInt) 00392 goforever=false; 00393 00394 endPt.i = dispImg.getWidth()/2 - dist*sin(geom::deg2rad(ang)); 00395 endPt.j = (dispImg.getHeight() - 10) - dist*cos(geom::deg2rad(ang)); 00396 00397 00398 // You can add more commands here. 00399 usleep(50 * 1000); 00400 00401 } 00402 00403 robot.sendDriveCommand (0, Create::DRIVE_STRAIGHT); 00404 // Swith to full mode. 00405 robot.sendFullCommand(); 00406 stream.Close(); 00407 manager.stop(); 00408 00409 } 00410 00411 #else 00412 00413 int main(const int argc, const char **argv) 00414 { 00415 //LINFO("I cannot work without LibSerial or libirobot-create"); 00416 return 1; 00417 } 00418 00419 #endif 00420 00421 // ###################################################################### 00422 /* So things look consistent in everyone's emacs... */ 00423 /* Local Variables: */ 00424 /* indent-tabs-mode: nil */ 00425 /* End: */