actsColorFollowingExample.cpp

Connects to the ACTS program, and uses an ArAction subclass to drive the robot towards the largest detected blob.

00001 
00007 #include "Aria.h"
00008 
00009 
00010 
00011 // Chase is an action that moves the robot toward the largest blob that
00012 // appears in it's current field of view.
00013 class Chase : public ArAction
00014 {
00015   
00016 public:
00017   
00018   // The state of the chase action
00019   enum State {
00020     NO_TARGET,      // There is no target in view
00021     TARGET,         // This is a target in view
00022   };
00023 
00024   // Constructor
00025   Chase(ArACTS_1_2 *acts, ArVCC4 *camera);
00026   
00027   // Destructor
00028   ~Chase(void);
00029   
00030   // The action
00031   ArActionDesired *fire(ArActionDesired currentDesired);
00032 
00033   // Set the ACTS channel that we want to get blob info from
00034   bool setChannel(int channel);
00035 
00036   // Return the current state of this action
00037   State getState(void) { return myState; }
00038 
00039   // Height and width of pixels from frame-grabber
00040   enum {
00041     WIDTH = 160,
00042     HEIGHT = 120
00043   };
00044 
00045 protected:
00046   ArActionDesired myDesired;
00047   ArACTS_1_2 *myActs;
00048   ArVCC4 *myCamera;
00049   ArTime myLastSeen;
00050   State myState;
00051   int myChannel;
00052   int myMaxTime;
00053 };
00054 
00055 
00056 // Constructor: Initialize the chase action
00057 Chase::Chase(ArACTS_1_2 *acts, ArVCC4 *camera) :
00058     ArAction("Chase", "Chases the largest blob.")
00059 {
00060   myActs = acts;
00061   myCamera = camera;
00062   myChannel = 0;
00063   myState = NO_TARGET;
00064   setChannel(1);
00065   myLastSeen.setToNow();
00066   myMaxTime = 1000;
00067 }
00068 
00069 // Destructor
00070 Chase::~Chase(void) {}
00071 
00072 
00073 // The chase action
00074 ArActionDesired *Chase::fire(ArActionDesired currentDesired)
00075 {
00076   ArACTSBlob blob;
00077   ArACTSBlob largestBlob;
00078 
00079   bool flag = false;
00080 
00081   int numberOfBlobs;
00082   int blobArea = 10;
00083 
00084   double xRel, yRel;
00085 
00086   // Reset the desired action
00087   myDesired.reset();
00088   
00089   numberOfBlobs = myActs->getNumBlobs(myChannel);
00090 
00091   // If there are blobs to be seen, set the time to now
00092   if(numberOfBlobs != 0)
00093   {
00094     for(int i = 0; i < numberOfBlobs; i++)
00095     {
00096       myActs->getBlob(myChannel, i + 1, &blob);
00097       if(blob.getArea() > blobArea)
00098       {
00099         flag = true;
00100         blobArea = blob.getArea();
00101         largestBlob = blob;
00102       }
00103     }
00104 
00105     myLastSeen.setToNow();
00106   }
00107 
00108   // If we have not seen a blob in a while...
00109   if (myLastSeen.mSecSince() > myMaxTime)
00110   {
00111     if(myState != NO_TARGET) ArLog::log(ArLog::Normal, "Target Lost");
00112     myState = NO_TARGET;
00113   }
00114   else
00115   {
00116     // If we see a blob and haven't seen one before..
00117     if(myState != TARGET) {
00118       ArLog::log(ArLog::Normal, "Target Aquired");
00119       ArLog::log(ArLog::Normal, "(Using channel %d with %d blobs)", myChannel, numberOfBlobs);
00120     }
00121     myState = TARGET;
00122   }
00123 
00124   if(myState == TARGET && flag == true)
00125   { 
00126     // Determine where the largest blob's center of gravity
00127     // is relative to the center of the camera
00128     xRel = (double)(largestBlob.getXCG() - WIDTH/2.0)  / (double)WIDTH;
00129     yRel = (double)(largestBlob.getYCG() - HEIGHT/2.0) / (double)HEIGHT;
00130       
00131     // Tilt the camera toward the blob
00132     if(!(ArMath::fabs(yRel) < .20))
00133     {
00134       if (-yRel > 0)
00135         myCamera->tiltRel(1);
00136       else
00137         myCamera->tiltRel(-1);
00138     }
00139 
00140     // Set the heading and velocity for the robot
00141     if (ArMath::fabs(xRel) < .10)
00142     {
00143       myDesired.setDeltaHeading(0);
00144     }
00145     else
00146     {
00147       if (ArMath::fabs(-xRel * 10) <= 10)
00148         myDesired.setDeltaHeading(-xRel * 10);
00149       else if (-xRel > 0)
00150         myDesired.setDeltaHeading(10);
00151       else
00152         myDesired.setDeltaHeading(-10);
00153      
00154     }
00155 
00156     myDesired.setVel(200);
00157     return &myDesired;    
00158   }
00159 
00160   // If we have no target, then don't set any action and let lower priority
00161   // actions (e.g. stop) control the robot.
00162   return &myDesired;
00163 }
00164 
00165 // Set the channel that the blob info will be obtained from
00166 bool Chase::setChannel(int channel)
00167 {
00168   if (channel >= 1 && channel <= ArACTS_1_2::NUM_CHANNELS)
00169   {
00170     myChannel = channel;
00171     return true;
00172   }
00173   else
00174     return false;
00175 }
00176 
00177 
00178 
00179 
00180 // Callback to enable/disable the keyboard driving action
00181 void toggleAction(ArAction* action)
00182 {
00183   if(action->isActive()) {
00184     action->deactivate();
00185     ArLog::log(ArLog::Normal, "%s action is now deactivated.", action->getName());
00186   }
00187   else {
00188     action->activate();
00189     ArLog::log(ArLog::Normal, "%s action is now activated.", action->getName());
00190   }
00191 }
00192 
00193 
00194 
00195 // Main function
00196 int main(int argc, char** argv)
00197 {
00198   Aria::init();
00199 
00200   // The robot
00201   ArRobot robot;
00202 
00203   // A key handler to take input from keyboard
00204   ArKeyHandler keyHandler;
00205   Aria::setKeyHandler(&keyHandler);
00206 
00207   // Sonar for basic obstacle avoidance
00208   ArSonarDevice sonar;
00209 
00210   // The camera (Cannon VC-C4)
00211   ArVCC4 vcc4 (&robot);
00212 
00213   // ACTS, for tracking blobs of color
00214   ArACTS_1_2 acts;
00215 
00216   // command line arguments
00217   ArArgumentParser argParser(&argc, argv);
00218   argParser.loadDefaultArguments();
00219   
00220   // The simple way to connect to things (takes arguments from argParser)
00221   ArSimpleConnector simpleConnector(&argParser);
00222 
00223   // Parse the arguments                
00224   if (!Aria::parseArgs())
00225   {    
00226     Aria::logOptions();
00227     keyHandler.restore();
00228     Aria::shutdown();
00229     return 1;
00230   }
00231 
00232   // Robot motion limiter actions (if obstacles are detected by sonar)
00233   ArActionLimiterForwards limiter("speed limiter near", 350, 800, 200);
00234   ArActionLimiterForwards limiterFar("speed limiter far", 400, 1250, 300);
00235   ArActionLimiterBackwards backwardsLimiter;
00236   ArActionConstantVelocity stop("stop", 0);
00237   //ArActionConstantVelocity backup("backup", -200);
00238   
00239 
00240   // The color following action, defined above
00241   Chase chase(&acts, &vcc4);
00242 
00243   // Keyboard teleoperation action
00244   ArActionKeydrive keydriveAction;
00245 
00246   // Use the "a" key to activate/deactivate keydrive mode
00247   keyHandler.addKeyHandler('a', new ArGlobalFunctor1<ArAction*>(&toggleAction, &keydriveAction));
00248 
00249   // Let Aria know about the key handler
00250   Aria::setKeyHandler(&keyHandler);
00251 
00252   // Add the key handler to the robot
00253   robot.attachKeyHandler(&keyHandler);
00254 
00255   // Add the sonar to the robot
00256   robot.addRangeDevice(&sonar);
00257 
00258   // Connect to the robot
00259   if (!simpleConnector.connectRobot(&robot))
00260   {
00261     ArLog::log(ArLog::Terse, "Error: Could not connect to robot... exiting\n");
00262     keyHandler.restore();
00263     Aria::exit(1);
00264   }
00265 
00266   // Open a connection to ACTS
00267   if(!acts.openPort(&robot)) 
00268   {
00269     ArLog::log(ArLog::Terse, "Error: Could not connect to ACTS... exiting.");
00270     keyHandler.restore();
00271     Aria::exit(2);
00272   }
00273 
00274   // Initialize the camera
00275   vcc4.init();
00276 
00277   // Wait a second.....
00278   ArUtil::sleep(1000);
00279 
00280   // Artificially keep the robot from going too fast
00281   robot.setAbsoluteMaxTransVel(400);
00282 
00283   // Enable the motors
00284   robot.comInt(ArCommands::ENABLE, 1);
00285   
00286   // Turn off the amigobot sounds
00287   robot.comInt(ArCommands::SOUNDTOG, 0);
00288 
00289   // Wait....
00290   ArUtil::sleep(200);
00291 
00292   // Add the actions to the robot in descending order of importance.
00293   robot.addAction(&limiter, 7);
00294   robot.addAction(&limiterFar, 6);
00295   robot.addAction(&backwardsLimiter, 5);
00296   robot.addAction(&keydriveAction, 4);
00297   robot.addAction(&chase, 3);
00298   robot.addAction(&stop, 1);
00299 
00300   // Start with keydrive action disabled. Use the 'a' key to turn it on.
00301   keydriveAction.deactivate();
00302 
00303   // Run the robot processing cycle until the connection is lost
00304   ArLog::log(ArLog::Normal, "Running. Train ACTS to detect a color to drive towards an object, or use 'a' key to switch to keyboard driving mode.");
00305   robot.run(true);
00306   
00307   Aria::shutdown();
00308   return 0;
00309 }
00310 

Generated on Fri Jul 31 12:36:37 2009 for Aria by  doxygen 1.4.7