#include <stdlib.h>
#include <stream.h>
#include <strings.h>
#include <math.h>
extern "C"
{
#include "../Nclient.h"
}
// state indices
int SONAR_BASE = 17;
int SONAR_MAX = 32;
int IR_BASE = 1;
int IR_MAX = 16;
// range limit
int IR_LIMIT = 14;
int TICK = 8;
int getShortestIndexIR(int, int);
int getShortestIndexIR();
int getShortestIndexSonar(int, int);
int getShortestIndexSonar();
void findWall(int);
bool followWall(int,unsigned int);
long bumpMask();
void iCorner(int);
int dist(int X, int Y);
int angTo(int X, int Y);
void bug1(int,int,int);
void bug2(int,int,int);
enum algol {WALL, BUG1, BUG2};
// integer distance computation
int dist(int X, int Y) {
int dx = (X-State[34]);
int dy = (Y-State[35]);
int d = sqrt(dx*dx+dy*dy);
return d;
}
// integer angle determination (*10 so fits units)
int angTo(int X, int Y) {
int dx = (X-State[34]);
int dy = (Y-State[35]);
double ang = atan2(dy,dx);
ang = (ang/(2*M_PI)*360);
int comp_ang = (ang*10.0);
cerr << "Angle computed to be " << comp_ang <<
endl;
return comp_ang;
}
// usage: bug port distance algol goalX goalY
int main(int argc, char** argv)
{
bool keepRunning = true;
int returnval;
algol alg = WALL;
int DESIRED_DISTANCE = 8;
int goalX = 0;
int goalY = 0;
if(argc > 1) { // they gave port or help
if(!strcmp("-?",argv[1]) || !strcmp("-h",argv[1]))
{
cout << argv[0] << " port
distance algol" << endl;
exit(0);
}
SERV_TCP_PORT = atoi(argv[1]);
}
if(argc > 2) { // they gave distance
DESIRED_DISTANCE = atoi(argv[2]);
}
if(argc > 3) { // they gave algolrithm
if(argc > 5) { // they gave goal co-ords
goalX = atoi(argv[4]);
goalY = atoi(argv[5]);
}
if(!strcasecmp(argv[3],"bug1")) {
alg = BUG1;
}
else if(!strcasecmp(argv[3],"bug2")) {
alg = BUG2;
}
}
// lets connect to the robot. if we don't, exit.
returnval = connect_robot(1);
if(returnval)
{
cout<<"We've made a connection"<<endl;
}
else
{
cout<<"The robot doesn't want
to talk to you. GO AWAY!"<<endl;
exit(0);
}
// zero the robot
zr();
// updates the state mask to all be 1, we'll look at everything.
for (int i = 0; i < 42; i++)
{
Smask[i] = 1;
}
ct();
gs();
if(alg == WALL) {
findWall(DESIRED_DISTANCE);
// turn alongside wall so wall following code works
better
int index = getShortestIndexSonar();
while(index != 13)
{
vm(0,350,350);
gs();
index = getShortestIndexSonar();
}
followWall(DESIRED_DISTANCE,-1);
}
else if(alg == BUG1) {
cout << "Going to (" << goalX <<
"," << goalY << ")\n";
bug1(goalX,goalY, DESIRED_DISTANCE);
}
else if(alg == BUG2) {
cout << "Going to (" << goalX <<
"," << goalY << ")\n";
bug2(goalX,goalY, DESIRED_DISTANCE);
}
// disconnect from the robot before exiting... this will
keep him
// from being mad at us next time.
disconnect_robot(1);
return 0;
}
// This function turns the robot towards the goal and moves till it
hits
// an obstacle. Then it follows the obstacle around until it
finds the
// S-line again
void bug2(int goalX, int goalY, int DESIRED_DISTANCE) {
int s_ang; // slope of S-line
while(1) {
//align with S-line
int ang = angTo(goalX,goalY);
s_ang = ang;
cerr << "Angle to be set to " << ang
<< endl;
int rot = ang - State[36];
pr(0,rot,rot);
while((State[36] - ang) > 20 || (ang - State[36])
> 20) {
gs();
}
// drive till near an obstacle or goal
gs();
int front_dist = (State[1] + State[16] + State[2])/3;
int goal_dist = dist(goalX,goalY);
while(front_dist > DESIRED_DISTANCE && goal_dist
> (10*DESIRED_DISTANCE)) {
vm(200,0,0);
gs();
front_dist = (State[1] + State[16] +
State[2])/3;
goal_dist = dist(goalX,goalY);
}
if(goal_dist <= (10*DESIRED_DISTANCE)) break;
// go around obstacle
// turn alongside wall so wall following code works
better
int index = getShortestIndexSonar();
while(index != 13)
{
vm(0,350,350);
gs();
index = getShortestIndexSonar();
}
// get away from initial point
int iX = State[34];
int iY = State[35];
int oD = dist(goalX,goalY); // record distance
of contact point
while(dist(iX,iY) < (30*DESIRED_DISTANCE)) {
followWall(DESIRED_DISTANCE,TICK);
gs();
}
// follow till you hit sline (give or take
five degrees)
int c_ang = angTo(goalX,goalY);
while(c_ang - ang > 50 || ang - c_ang > 50 || dist(goalX,goalY)
> (oD+20)) {
followWall(DESIRED_DISTANCE,TICK);
gs();
c_ang = angTo(goalX,goalY);
}
}
}
// This function turns the robot towards the goal and moves till it
hits
// an obstacle. Then it circumnavigates it, recording the closest
point.
// Then it goes back to it and relaunches itself towards the start
point
void bug1(int goalX, int goalY, int DESIRED_DISTANCE) {
int iX, iY; // initial X and Y positions to circumnavigate obstacle
while(1) {
// align with S-line
gs();
int ang = angTo(goalX,goalY);
cerr << "Angle to be set to " << ang
<< endl;
int rot = ang - State[36];
pr(0,rot,rot);
while((State[36] - ang) > 20 || (ang - State[36])
> 20) {
gs();
}
// drive till near an obstacle or goal
gs();
int front_dist = (State[1] + State[16] + State[2])/3;
int goal_dist = dist(goalX,goalY);
while(front_dist > DESIRED_DISTANCE && goal_dist
> (10*DESIRED_DISTANCE)) {
vm(200,0,0);
gs();
front_dist = (State[1] + State[16] +
State[2])/3;
goal_dist = dist(goalX,goalY);
}
if(goal_dist < (10*DESIRED_DISTANCE)) break;
// go around obstacle
iX = State[34];
iY = State[35];
int bestX = iX;
int bestY = iY;
int bestD = dist(goalX,goalY);
// turn alongside wall so wall following code works
better
int index = getShortestIndexSonar();
while(index != 13)
{
vm(0,350,350);
gs();
index = getShortestIndexSonar();
}
// get away from initial point
while(dist(iX,iY) < (30*DESIRED_DISTANCE)) {
followWall(DESIRED_DISTANCE,TICK);
int D = dist(goalX,goalY);
if(D < bestD) {
bestD = D;
bestX = State[34];
bestY = State[35];
}
gs();
}
// now, get back to initial point
while(dist(iX,iY) > (20*DESIRED_DISTANCE)) {
followWall(DESIRED_DISTANCE,TICK);
int D = dist(goalX,goalY);
if(D < bestD) {
bestD = D;
bestX = State[34];
bestY = State[35];
}
gs();
}
cout << "Back where we started!\n";
// now go to the best point
while(dist(bestX,bestY) > (20*DESIRED_DISTANCE))
{
followWall(DESIRED_DISTANCE,TICK);
gs();
}
}
}
// this function gets run when the robot is far from walls. it
will search
// out the closest wall and get DESIRED_DISTANCE away from it.
// the function uses PID control to get to the desired distance
void findWall(int DESIRED_DISTANCE)
{
long error = 0;
long errorLast;
long errorSum = 0;
double Kp = .7;
double Kd = .35;
double Ki = .15;
int tv = 0;
int rv = 0;
// this points the robot towards the nearest wall
int index = getShortestIndexSonar();
while(index != 1)
{
rv = 350;
vm(tv,rv,rv);
gs();
index = getShortestIndexSonar();
}
rv = 0;
gs();
error = State[getShortestIndexIR()] - DESIRED_DISTANCE;
errorLast = error;
// This does the PID control to get to desired distance
while(error != 0 || errorLast != 0)
{
errorLast = error;
error = State[getShortestIndexIR()]
- DESIRED_DISTANCE;
errorSum = errorSum + error;
// handling for integral windup
if(errorSum > 250)
{
errorSum = 250;
}
if(errorSum < -250)
{
errorSum = -250;
}
// if you hit a wall, back up, else use
the PID computed velocity
if(State[33] & bumpMask() != 0)
{
tv = -5;
}
else
{
tv = Kp*error
+ Kd*(error - errorLast) + Ki*errorSum;
}
vm(tv,rv,rv);
gs();
}
}
// function assumes you start within IR range
// it attempts to follow a wall by tackling a few special cases
// the ticks limit is for the bug algorithms
// uses PD control to maintain distance from wall
bool followWall(int DESIRED_DISTANCE, unsigned int tick_limit)
{
static bool turn_corner = false;
unsigned int ticks = 0;
int tv = 0;
int rv = 0;
int error = 0;
int errorLast = 0;
double Kp = 4;
double Kd = 3;
while(ticks < tick_limit) {
gs();
int dist_front = (State[1] + State[16] + State[2])/3;
int dist_fr = State[getShortestIndexIR(14,16)];
int dist_right = State[getShortestIndexIR(12,14)];
int closest_sensor = getShortestIndexIR();
int dist_near = State[closest_sensor];
errorLast = error;
error = DESIRED_DISTANCE - dist_right;
// Nothing to the front, forge ahead and try to match
distance
if(dist_front > IR_LIMIT && dist_right <=
DESIRED_DISTANCE + 1) {
if(dist_near < DESIRED_DISTANCE/2)
{
tv = 50;
}
else {
tv = 200;
}
rv = Kp*error + Kd*(error-errorLast);
}
// Something to the front, curve to the left
else if(dist_front <= IR_LIMIT) {
if(dist_near >= DESIRED_DISTANCE) {
// wall approaching, gently curve
tv = 50;
rv = 100;
}
else if(dist_near > DESIRED_DISTANCE/2)
{ // closer than we should be, but not an emergency
tv = 40;
rv = 150;
}
else { // AGGGHHH!
tv = 20;
rv = 200;
}
}
// Nothing at all curve to the right
else {
if(dist_near > IR_LIMIT) {
tv = 100;
rv = -350;
}
else { // something is still in
range, be gentler
tv = 80;
rv = -200;
}
}
vm(tv,rv,rv);
++ticks;
}
return true;
}
// this returns which sonar has the closest obstacle in front of it.
// it returns a number from 1 to 16, instead of the index into State
// takes bounds
int getShortestIndexSonar() { return getShortestIndexSonar(SONAR_BASE,SONAR_MAX);
}
int getShortestIndexSonar(int lowBound, int highBound)
{
gs();
long closestValue = State[lowBound];
int index = lowBound;
for (int i = lowBound; i <= highBound; i++)
{
if(State[i] < closestValue)
{
closestValue
= State[i];
index = i;
}
}
return (index - SONAR_BASE + 1);
}
// this returns which sonar has the closest obstacle in front of it.
// it returns a number from 1 to 16, instead of the index into State
// takes bounds
int getShortestIndexIR() { return getShortestIndexIR(IR_BASE,IR_MAX);
}
int getShortestIndexIR(int lowBound, int highBound)
{
gs();
long closestValue = State[lowBound];
int index = lowBound;
for (int i = lowBound; i <= highBound; i++)
{
if(State[i] < closestValue)
{
closestValue
= State[i];
index = i;
}
}
return (index);
}
// this function returns a mask for the bump sensors. the mask
can be
// ANDed with the State long for bump sensors to look at only the bump
// sensors in the front half of the robot.
long bumpMask()
{
long ret = 0;
if(State[36] < 180) ret
= 0x000f803f;
else if(State[36] < 360) ret = 0x000f007f;
else if(State[36] < 540) ret = 0x000e00ff;
else if(State[36] < 720) ret = 0x000c01ff;
else if(State[36] < 900) ret = 0x000803ff;
else if(State[36] < 1080) ret = 0x000007ff;
else if(State[36] < 1260) ret = 0x00000ffe;
else if(State[36] < 1440) ret = 0x00001ffc;
else if(State[36] < 1620) ret = 0x00003ff8;
else if(State[36] < 1800) ret = 0x00007ff0;
else if(State[36] < 1980) ret = 0x0000ffe0;
else if(State[36] < 2160) ret = 0x0001ffc0;
else if(State[36] < 2340) ret = 0x0003ff80;
else if(State[36] < 2520) ret = 0x0007ff00;
else if(State[36] < 2700) ret = 0x000ffe00;
else if(State[36] < 2880) ret = 0x000ffc01;
else if(State[36] < 3060) ret = 0x000ff803;
else if(State[36] < 3240) ret = 0x000ff007;
else if(State[36] < 3420) ret = 0x000fe00f;
else
ret = 0x000fc01f;
return ret;
}
// this handles inside corners. The robot will approach the wall
and stop
// when it is 15 away. Then it will turn 90 degrees counterclockwise.
// there is a delay function, because the ws() command would not compile.
// so it gives a decent amount of time for the motors to move.
void iCorner(int DESIRED_DISTANCE)
{
while(State[1] != DESIRED_DISTANCE)
{
vm(50*(State[1] - DESIRED_DISTANCE)/(15-DESIRED_DISTANCE),0,0);
gs();
}
vm(0,0,0);
gs();
pr(0,900,900);
for(int i = 0 ; i < 25 ; i++)
{
gs();
}
return;
}