Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages | Examples

actionExample.cpp

00001 /*
00002 MobileRobots Advanced Robotics Interface for Applications (ARIA)
00003 Copyright (C) 2004, 2005 ActivMedia Robotics LLC
00004 Copyright (C) 2006, 2007 MobileRobots Inc.
00005 
00006      This program is free software; you can redistribute it and/or modify
00007      it under the terms of the GNU General Public License as published by
00008      the Free Software Foundation; either version 2 of the License, or
00009      (at your option) any later version.
00010 
00011      This program is distributed in the hope that it will be useful,
00012      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014      GNU General Public License for more details.
00015 
00016      You should have received a copy of the GNU General Public License
00017      along with this program; if not, write to the Free Software
00018      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 If you wish to redistribute ARIA under different terms, contact 
00021 MobileRobots for information about a commercial version of ARIA at 
00022 robots@mobilerobots.com or 
00023 MobileRobots Inc, 19 Columbia Drive, Amherst, NH 03031; 800-639-9481
00024 */
00025 
00026 #include "Aria.h"
00027 
00061 /* 
00062  * Action that drives the robot forward, but stops if obstacles are
00063  * detected by sonar. 
00064  */
00065 class ActionGo : public ArAction
00066 {
00067 public:
00068   // constructor, sets myMaxSpeed and myStopDistance
00069   ActionGo(double maxSpeed, double stopDistance);
00070   // destructor. does not need to do anything
00071   virtual ~ActionGo(void) {};
00072   // called by the action resolver to obtain this action's requested behavior
00073   virtual ArActionDesired *fire(ArActionDesired currentDesired);
00074   // store the robot pointer, and it's ArSonarDevice object, or deactivate this action if there is no sonar.
00075   virtual void setRobot(ArRobot *robot);
00076 protected:
00077   // the sonar device object obtained from the robot by setRobot()
00078   ArRangeDevice *mySonar;
00079 
00080 
00081   /* Our current desired action: fire() modifies this object and returns
00082       to the action resolver a pointer to this object.
00083       This object is kept as a class member so that it persists after fire()
00084       returns (otherwise fire() would have to create a new object each invocation,
00085       but would never be able to delete that object).
00086   */
00087   ArActionDesired myDesired;
00088 
00089   double myMaxSpeed;
00090   double myStopDistance;
00091 };
00092 
00093 
00094 /* Action that turns the robot away from obstacles detected by the 
00095  * sonar. */
00096 class ActionTurn : public ArAction
00097 {
00098 public:
00099   // constructor, sets the turnThreshold, and turnAmount
00100   ActionTurn(double turnThreshold, double turnAmount);
00101   // destructor, its just empty, we don't need to do anything
00102   virtual ~ActionTurn(void) {};
00103   // fire, this is what the resolver calls to figure out what this action wants
00104   virtual ArActionDesired *fire(ArActionDesired currentDesired);
00105   // sets the robot pointer, also gets the sonar device, or deactivates this action if there is no sonar.
00106   virtual void setRobot(ArRobot *robot);
00107 protected:
00108   // this is to hold the sonar device form the robot
00109   ArRangeDevice *mySonar;
00110   // what the action wants to do; used by the action resover after fire()
00111   ArActionDesired myDesired;
00112   // distance at which to start turning
00113   double myTurnThreshold;
00114   // amount to turn when turning is needed
00115   double myTurnAmount;
00116   // remember which turn direction we requested, to help keep turns smooth
00117   int myTurning; // -1 == left, 1 == right, 0 == none
00118 };
00119 
00120 /*
00121   Note the use of constructor chaining with 
00122   ArAction(actionName). Also note how it uses setNextArgument, which makes it so that 
00123   other parts of the program could find out what parameters this action has, and possibly modify them.
00124 */
00125 ActionGo::ActionGo(double maxSpeed, double stopDistance) :
00126   ArAction("Go")
00127 {
00128   mySonar = NULL;
00129   myMaxSpeed = maxSpeed;
00130   myStopDistance = stopDistance;
00131   setNextArgument(ArArg("maximum speed", &myMaxSpeed, "Maximum speed to go."));
00132   setNextArgument(ArArg("stop distance", &myStopDistance, "Distance at which to stop."));
00133 }
00134 
00135 /*
00136   Override ArAction::setRobot() to get the sonar device from the robot, or deactivate this action if it is missing.
00137   You must also call ArAction::setRobot() to properly store
00138   the ArRobot pointer in the ArAction base class.
00139 */
00140 void ActionGo::setRobot(ArRobot *robot)
00141 {
00142   ArAction::setRobot(robot);
00143   mySonar = robot->findRangeDevice("sonar");
00144   if (robot == NULL)
00145     {
00146       ArLog::log(ArLog::Terse, "actionExample: ActionGo: Warning: I found no sonar, deactivating.");
00147       deactivate();
00148     }
00149 }
00150 
00151 /*
00152   This fire is the whole point of the action.
00153   currentDesired is the combined desired action from other actions
00154   previously processed by the action resolver.  In this case, we're
00155   not interested in that, we will set our desired 
00156   forward velocity in the myDesired member, and return it.
00157 
00158   Note that myDesired must be a class member, since this method
00159   will return a pointer to myDesired to the caller. If we had
00160   declared the desired action as a local variable in this method,
00161   the pointer we returned would be invalid after this method
00162   returned.
00163 */
00164 ArActionDesired *ActionGo::fire(ArActionDesired currentDesired)
00165 {
00166   double range;
00167   double speed;
00168 
00169   // reset the actionDesired (must be done), to clear
00170   // its previous values.
00171   myDesired.reset();
00172 
00173   // if the sonar is null we can't do anything, so deactivate
00174   if (mySonar == NULL)
00175   {
00176     deactivate();
00177     return NULL;
00178   }
00179   // get the range of the sonar
00180   range = mySonar->currentReadingPolar(-70, 70) - myRobot->getRobotRadius();
00181   // if the range is greater than the stop distance, find some speed to go
00182   if (range > myStopDistance)
00183   {
00184     // just an arbitrary speed based on the range
00185     speed = range * .3;
00186     // if that speed is greater than our max, cap it
00187     if (speed > myMaxSpeed)
00188       speed = myMaxSpeed;
00189     // now set the velocity
00190     myDesired.setVel(speed);
00191   }
00192   // the range was less than the stop distance, so request stop
00193   else
00194   {
00195     myDesired.setVel(0);
00196   }
00197   // return a pointer to the actionDesired to the resolver to make our request
00198   return &myDesired;
00199 }
00200 
00201 
00202 /*
00203   This is the ActionTurn constructor, note the use of constructor chaining 
00204   with the ArAction. also note how it uses setNextArgument, which makes 
00205   it so that other things can see what parameters this action has, and 
00206   set them.  It also initializes the classes variables.
00207 */
00208 ActionTurn::ActionTurn(double turnThreshold, double turnAmount) :
00209   ArAction("Turn")
00210 {
00211   myTurnThreshold = turnThreshold;
00212   myTurnAmount = turnAmount;
00213   setNextArgument(ArArg("turn threshold (mm)", &myTurnThreshold, "The number of mm away from obstacle to begin turnning."));
00214   setNextArgument(ArArg("turn amount (deg)", &myTurnAmount, "The number of degress to turn if turning."));
00215   myTurning = 0;
00216 }
00217 
00218 /*
00219   Sets the myRobot pointer (all setRobot overloaded functions must do this),
00220   finds the sonar device from the robot, and if the sonar isn't there, 
00221   then it deactivates itself.
00222 */
00223 void ActionTurn::setRobot(ArRobot *robot)
00224 {
00225   ArAction::setRobot(robot);
00226   mySonar = robot->findRangeDevice("sonar");
00227   if (mySonar == NULL)
00228   {
00229     ArLog::log(ArLog::Terse, "actionExample: ActionTurn: Warning: I found no sonar, deactivating.");
00230     deactivate(); 
00231   }
00232 }
00233 
00234 /*
00235   This is the guts of the Turn action.
00236 */
00237 ArActionDesired *ActionTurn::fire(ArActionDesired currentDesired)
00238 {
00239   double leftRange, rightRange;
00240   // reset the actionDesired (must be done)
00241   myDesired.reset();
00242   // if the sonar is null we can't do anything, so deactivate
00243   if (mySonar == NULL)
00244   {
00245     deactivate();
00246     return NULL;
00247   }
00248   // Get the left readings and right readings off of the sonar
00249   leftRange = (mySonar->currentReadingPolar(0, 100) - 
00250         myRobot->getRobotRadius());
00251   rightRange = (mySonar->currentReadingPolar(-100, 0) - 
00252         myRobot->getRobotRadius());
00253   // if neither left nor right range is within the turn threshold,
00254   // reset the turning variable and don't turn
00255   if (leftRange > myTurnThreshold && rightRange > myTurnThreshold)
00256   {
00257     myTurning = 0;
00258     myDesired.setDeltaHeading(0);
00259   }
00260   // if we're already turning some direction, keep turning that direction
00261   else if (myTurning)
00262   {
00263     myDesired.setDeltaHeading(myTurnAmount * myTurning);
00264   }
00265   // if we're not turning already, but need to, and left is closer, turn right
00266   // and set the turning variable so we turn the same direction for as long as
00267   // we need to
00268   else if (leftRange < rightRange)
00269   {
00270     myTurning = -1;
00271     myDesired.setDeltaHeading(myTurnAmount * myTurning);
00272   }
00273   // if we're not turning already, but need to, and right is closer, turn left
00274   // and set the turning variable so we turn the same direction for as long as
00275   // we need to
00276   else 
00277   {
00278     myTurning = 1;
00279     myDesired.setDeltaHeading(myTurnAmount * myTurning);
00280   }
00281   // return a pointer to the actionDesired, so resolver knows what to do
00282   return &myDesired;
00283 }
00284 
00285 
00286 
00287 int main(int argc, char** argv)
00288 {
00289   Aria::init();
00290 
00291   ArSimpleConnector conn(&argc, argv);
00292   ArRobot robot;
00293   ArSonarDevice sonar;
00294 
00295   // Create instances of the actions defined above, plus ArActionStallRecover, 
00296   // a predefined action from Aria.
00297   ActionGo go(500, 350);
00298   ActionTurn turn(400, 10);
00299   ArActionStallRecover recover;
00300 
00301     
00302   // Parse all command-line arguments
00303   if(!Aria::parseArgs())
00304   {
00305     Aria::logOptions();
00306     return 1;
00307   }
00308   
00309   // Connect to the robot
00310   if(!conn.connectRobot(&robot))
00311   {
00312     ArLog::log(ArLog::Terse, "actionExample: Could not connect to robot! Exiting.");
00313     return 2;
00314   }
00315 
00316   // Add the range device to the robot. You should add all the range 
00317   // devices and such before you add actions
00318   robot.addRangeDevice(&sonar);
00319 
00320  
00321   // Add our actions in order. The second argument is the priority, 
00322   // with higher priority actions going first, and possibly pre-empting lower
00323   // priority actions.
00324   robot.addAction(&recover, 100);
00325   robot.addAction(&go, 50);
00326   robot.addAction(&turn, 49);
00327 
00328   // Enable the motors, disable amigobot sounds
00329   robot.enableMotors();
00330 
00331   // Run the robot processing cycle.
00332   // 'true' means to return if it loses connection,
00333   // after which we exit the program.
00334   robot.run(true);
00335   
00336   Aria::shutdown();
00337   return 0;
00338 }

Generated on Tue Feb 20 10:51:38 2007 for Aria by  doxygen 1.4.0