An example program demonstrating how to make and use new actions.This example program creates two new actions, Go and Turn. Go will drive the robot forward safely, while Turn will avoid obstacles detected by the sonar by turning. This program also adds a predefined action from Aria which tries to recover from stalls (hit something and can't move forward) by backing and turning.
Each of these actions have the normal constructor and destructor, note that the constructors use constructor chaining to create their ArAction part correctly. Each action then also implements the essential virtual method, fire(). This fire function is called by the action resolver, and returns values that, in combination with other actions' desired behavior, determine the driving commands sent to the robot.
Also note that each of these actions override the setRobot function; these implementations obtain the sonar device from the robot in addition to doing the needed caching of the robot pointer. This is what you should do if you care about the presence or absence of a particular sensor. If you don't care about any particular sensor you could just use one of the checkRangeDevice... methods in ArRobot (there are four of them). Also note that these are very naive actions, they are simply an example of how to use actions.
See the Actions Actions section of the Aria reference manual overview for more details about actions.
Note that actions must take a small amount of time to execute, to avoid delaying the robot synchronization cycle.
#include "Aria.h"
{
public:
ActionGo(double maxSpeed, double stopDistance);
virtual ~ActionGo(void) {};
protected:
double myMaxSpeed;
double myStopDistance;
};
{
public:
ActionTurn(double turnThreshold, double turnAmount);
virtual ~ActionTurn(void) {};
virtual void setRobot(
ArRobot *robot);
protected:
double myTurnThreshold;
double myTurnAmount;
int myTurning;
};
ActionGo::ActionGo(double maxSpeed, double stopDistance) :
{
mySonar = NULL;
myMaxSpeed = maxSpeed;
myStopDistance = stopDistance;
setNextArgument(
ArArg(
"maximum speed", &myMaxSpeed,
"Maximum speed to go."));
setNextArgument(
ArArg(
"stop distance", &myStopDistance,
"Distance at which to stop."));
}
void ActionGo::setRobot(
ArRobot *robot)
{
if (robot == NULL)
{
deactivate();
}
}
{
double range;
double speed;
if (mySonar == NULL)
{
deactivate();
return NULL;
}
range = mySonar->currentReadingPolar(-70, 70) - myRobot->getRobotRadius();
if (range > myStopDistance)
{
speed = range * .3;
if (speed > myMaxSpeed)
speed = myMaxSpeed;
myDesired.setVel(speed);
}
else
{
myDesired.setVel(0);
}
return &myDesired;
}
ActionTurn::ActionTurn(double turnThreshold, double turnAmount) :
{
myTurnThreshold = turnThreshold;
myTurnAmount = turnAmount;
setNextArgument(
ArArg(
"turn threshold (mm)", &myTurnThreshold,
"The number of mm away from obstacle to begin turnning."));
setNextArgument(
ArArg(
"turn amount (deg)", &myTurnAmount,
"The number of degress to turn if turning."));
myTurning = 0;
}
void ActionTurn::setRobot(
ArRobot *robot)
{
if (mySonar == NULL)
{
deactivate();
}
}
{
double leftRange, rightRange;
if (mySonar == NULL)
{
deactivate();
return NULL;
}
leftRange = (mySonar->currentReadingPolar(0, 100) -
myRobot->getRobotRadius());
rightRange = (mySonar->currentReadingPolar(-100, 0) -
myRobot->getRobotRadius());
if (leftRange > myTurnThreshold && rightRange > myTurnThreshold)
{
myTurning = 0;
myDesired.setDeltaHeading(0);
}
else if (myTurning)
{
myDesired.setDeltaHeading(myTurnAmount * myTurning);
}
else if (leftRange < rightRange)
{
myTurning = -1;
myDesired.setDeltaHeading(myTurnAmount * myTurning);
}
else
{
myTurning = 1;
myDesired.setDeltaHeading(myTurnAmount * myTurning);
}
return &myDesired;
}
int main(int argc, char** argv)
{
ActionGo go(500, 350);
ActionTurn turn(400, 10);
{
return 1;
}
{
return 2;
}
}