#include "../00_nav_library/nav_aria_iface.h"
#include "../00_nav_library/nav_geometry.h"
#include "../00_nav_library/nav_robot2lines.h"
#include <iostream>
#include <iomanip>
#include <conio.h>
using namespace std;
class ActionToWallAdvanced : public ArAction
{
public:
ActionToWallAdvanced(double maxSpeed=1000, double stopDistance=600, double stopAccuracyDistance=25, double stopAccuracyAngle=10);
bool haveAchievedGoal() const { return(myHaveAchievedGoal); }
virtual ~ActionToWallAdvanced(void) {};
virtual ArActionDesired *fire(ArActionDesired currentDesired);
virtual void setRobot(ArRobot *robot);
protected:
ArRangeDevice *mySonar;
ArActionDesired myDesired;
double myMaxSpeed;
double myStopDistance;
double myStopAccuracyDistance;
double myStopAccuracyAngle;
bool myHaveAchievedGoal;
};
ActionToWallAdvanced::ActionToWallAdvanced(double maxSpeed, double stopDistance, double stopAccuracyDistance, double stopAccuracyAngle) :
ArAction("ToWall")
{
mySonar = NULL;
myMaxSpeed = maxSpeed;
myStopDistance = stopDistance;
myStopAccuracyDistance = stopAccuracyDistance;
myStopAccuracyAngle = stopAccuracyAngle;
myHaveAchievedGoal = false;
setNextArgument(ArArg("maximum speed", &myMaxSpeed, "Maximum linear speed to go."));
setNextArgument(ArArg("stop distance", &myStopDistance, "Distance to wall at which to stop."));
setNextArgument(ArArg("stop accuracy distance", &myStopAccuracyDistance, "Distance accuracy."));
setNextArgument(ArArg("stop accuracy angle", &myStopAccuracyAngle, "Angle accuracy."));
}
void ActionToWallAdvanced::setRobot(ArRobot *robot)
{
ArAction::setRobot(robot);
mySonar = robot->findRangeDevice("sonar");
if (robot == NULL)
{
ArLog::log(ArLog::Terse, "actionExample: ActionToWallAdvanced: Warning: I found no sonar, deactivating.");
deactivate();
}
}
ArActionDesired *ActionToWallAdvanced::fire(ArActionDesired currentDesired)
{
myDesired.reset();
if (mySonar == NULL)
{
deactivate();
return NULL;
}
static const double Kro = .25;
static const double Ka = 1.00;
static const double Kb = -.375;
myHaveAchievedGoal = false;
double v = myMaxSpeed;
double w = 0;
NAV_Line line_ahead;
NAV_FindCurrentLine(myRobot->getPose(), *mySonar, -60, 60, line_ahead);
if ( line_ahead.isValid() )
{
double dist_to_wall = line_ahead.distance(myRobot->getPose());
double angle_to_wall= ArMath::atan2(line_ahead.getB(), line_ahead.getA());
double robot_angle = myRobot->getTh();
double ro = dist_to_wall - myStopDistance;
double a = angle_to_wall - robot_angle;
if (a<-90) a+=180; else if (a>90) a-=180;
double b = 0;
v = Kro*ro;
w = Ka*a + Kb*b;
if (v>myMaxSpeed) {
v=myMaxSpeed;
} else if (v<-myMaxSpeed) {
v=-myMaxSpeed;
}
#ifdef _DEBUG
cerr << " ro="<<setw(8)<<ro <<" a="<<setw(8)<<a <<" b="<<setw(8)<<b <<" v="<<setw(8)<<v <<" w="<<setw(8)<<w <<endl;
#endif
if (fabs(ro)<=myStopAccuracyDistance && fabs(a)<=myStopAccuracyAngle && fabs(b)<=myStopAccuracyAngle) {
myHaveAchievedGoal = true;
}
}
if (!myHaveAchievedGoal)
{
myDesired.setVel(v);
myDesired.setRotVel(w);
}
return &myDesired;
}
int main(){
NAV_Robot R("localhost", 8101);
if (!R.is_connected()) {
cout << "Cannot connect to the robot or robot simulator, exiting" << endl;
return(0);
}
ArActionStallRecover recover;
ArActionBumpers bumpers;
ArActionAvoidSide avoidside("Avoid Side", 100);
ArActionStop stop;
ActionToWallAdvanced go(2200, 550);
int state = 0;
R.lock();
R.addAction(&recover, 100);
R.addAction(&bumpers, 95);
R.addAction(&avoidside, 80);
R.addAction(&go, 50);
R.addAction(&stop, 10);
R.unlock();
#ifdef _DEBUG
cerr << showpoint << fixed << setprecision(2);
#endif
while( R.is_connected()) {
if (_kbhit()) {
char c=tolower(_getch());
if (c=='q') break;
}
R.lock();
if (state==0) {
if (go.haveAchievedGoal()) {
state=1;
R.remAction(&go);
if (R.getDistanceL10()<R.getDistanceR10()) R.doRotateAngle(-170);
else R.doRotateAngle(170);
#ifdef _DEBUG
cerr << "Wall reached! Turning" << endl;
#endif
} else {
}
} else if (state==1) {
if (R.isCommandDone()) {
R.clearDirectMotion();
state=0;
R.addAction(&go, 50);
#ifdef _DEBUG
cerr << "Turning done! Searching for a new wall" << endl;
#endif
} else {
}
} else {
cerr << "Error: Invalid state!" << endl;
}
#ifdef false
_DEBUG
cerr <<" X="<<setw(6)<< R.getX() <<" Y="<<setw(6)<< R.getY() <<" T="<<setw(8)<< R.getTh()
<<" D10L="<<setw(8)<< R.getDistanceL10()
<<" D10R="<<setw(8)<< R.getDistanceR10()
<< endl;
#endif
R.unlock();
R.Sleep(100);
}
if (R.is_connected()) R.disconnect();
else cerr << "Lost connection, aborting!" << endl;
return(0);
}