/*-------------------------------------------------------------------------- | Filename: map-socbot.c (based on map-eve.c; | map-eve.c is derived from drive.c) | | Author: Nicholas Tay, UWA 1998 | Changes: Thomas Braunl, UWA 2000 | T. Y. Ng, UWA Dec, 2001 | Modified: W. Chen, UWA Feb, 2002 | | Description: Map Generation for the Eyebot embedded in soccer robot. | Note: This program currently only works for soccer robot #2 | ----------------------------------------------------------------------- */ #include "eyebot.h" #include <stdio.h> #include <math.h> #include <stdlib.h> typedef struct { int x1; int y1; int x2; int y2; } Segment; /* Representation of XSegments - stores line-segments */ #define GRID_WIDTH 80 /* The width of each cell */ #define GRID_DIMENSIONS 80 /* The dimension of the Grid */ #define GRID_CENTER 40 /* Half the GRID_DIMENSIONS */ #define PSD_MAX 210 /* Maximum PSD reliable range including OFFSET */ #define PSD_LIMIT 400 #define OFFSET_RIGHT 0 /* (original=38) Offset value for Right PSD */ #define OFFSET_LEFT 0 /* (original=38) Offset value for Left PSD */ #define OFFSET_FRONT 0 /* (original=0) Offset value for Front PSD */ #ifndef ROBOT_RADIUS #define ROBOT_RADIUS 80 /* (original=75) Chosen radius for soccer robot that is rectanglar in shape */ #endif #define CLEAR 0 /* Sets a cell to "clear" */ #define BLOCKED 1 /* Sets a cell to "blocked" */ #define NOT_BORDER 3 /* Sets a cell to "not map border" */ #define BLOCKED_UNEXP 4 /* Sets a cell to "blocked but unexplored" */ #define MAP_BORDER 5 /* Sets a cell to "map border" */ #define CLEAR_UNEXP 6 /* Sets a cell to "clear but unexplored" */ #define V_LIN 7.0 #define T_LIN 0.3 #define V_ROT 10.0 #define T_ROT 0.1 #define IS_EXPLORED -1 #define NOT_CLOSE 0 #define IS_CLOSE 1 #define NUM_PSD 3 #define LEFT_MIN 60 /* 60mm is the min working distance of left psd */ #define FRONT_MIN 70 /* 70mm is the min working distance of front psd */ #define RIGHT_MIN 60 /* 60mm is the min working distance of right psd */ #define FRONT_GAP 90 #define FOLLOW_GAP 85 /* for left or right boundary following routine */ #define ADJUST_LIMIT 100 #define LEFT_PSD 0 #define FRONT_PSD 1 #define RIGHT_PSD 2 /* new-1:--------------------= front_too_close =-------------------- */ /** Checks if front of robot is too close to an obstacle using front psd. @param vw_ The VW handle @param front_psd The front psd sensor @return TRUE if it is too close FALSE otherwise */ int front_too_close(VWHandle vw_, PSDHandle front_psd) { int ref, front, value = FALSE; ref = PSDGet(front_psd) - OFFSET_FRONT; VWSetSpeed(vw_, -0.10, 0.0);/* move backwards; -0.10 chosen arbitarily */ OSWait(1/*20*/); /* wait for 20/100 seconds, 20 chosen arbitarily */ VWSetSpeed(vw_, 0.0, 0.0); /* stop robot */ front = PSDGet(front_psd) - OFFSET_FRONT; if(front < ref || front == FRONT_MIN) value = TRUE; /* too close */ /*LCDPutString("front_too_close\n"); */ return value; } /* new-2:---------------------= stop_forward =---------------------- */ /** Stops the robot moving forwards. @param vw_ The VW handle */ void stop_forward(VWHandle vw_) { VWSetSpeed(vw_, -0.2, 0.0);/* -0.2 chosen arbitarily */ VWSetSpeed(vw_, 0.0, 0.0); } /* new-3:---------------------= move_backward =---------------------- */ /** Moves the robot backwards using front psd. @param vw_ The VW handle @param front_psd The front psd sensor */ void move_backward(VWHandle vw_, PSDHandle front_psd) { int temp_dist; do{ VWSetSpeed(vw_, -0.10, 0.0);/* move backwards; -0.10 chosen arbitarily */ temp_dist = PSDGet(front_psd) - OFFSET_FRONT; /*LCDPutString("move_backward\n");*/ }while(temp_dist < 120);/* 120 chosen arbitarily */ VWSetSpeed(vw_, 0.0, 0.0); } /* 1--------------------------= VEHStop =--------------------------- */ /** Stops the robot. @param vw_ The VW handle */ void VEHStop(VWHandle vw_) { VWSetSpeed(vw_, 0.0, 0.0); } /* 2--------------------------= MAP_Check =------------------------- */ /** Checks adjacent cells for a match in (value_). @param map_ The map grid @param pos_ The index of the grid @param value_ The value of the cell that the routine tries to match @return TRUE, If a match is found; FALSE otherwise @see Display_MAP */ int MAP_Check(char *map_, int pos_, int value_) { int i, j, temp = FALSE; for(i = -1; i < 2; i++) for(j = -1; j < 2; j++) /* Evaluates neighbouring cells to determine a match */ if(map_[pos_ - i * GRID_DIMENSIONS + j] == value_) temp = TRUE; return temp; } /* 3-----------------------= MAP_Segment =-------------------------- */ /** Obtains the equivalent map position for the robot position. @param vals_ The position of the robot @return map position */ int MAP_Segment(float vals_) { return (int)(vals_ * 1000.0 + GRID_WIDTH * GRID_CENTER + 100); } /* 4-------------------------= MAP_Pos =---------------------------- */ /** Obtains the array index for a particular grid cell. Given a particular robot position, returns the cell that represents the robot position. @param temp Current position of the robot @param dist Distance received from the PSD sensor @param offset_ The angle offset (Depends on which PSD used) @param x The array index @param y The array index @see MAP_Locate MAP_Location */ void MAP_Pos(PositionType temp, int dist, float offset_, int *x, int *y) { float a, b; a = temp.x + (float)dist*cos(temp.phi + offset_) / 1000.0; b = temp.y + (float)dist*sin(temp.phi + offset_) / 1000.0; *x = ((int)(a * 1000.0) / GRID_WIDTH) + GRID_CENTER; *y = ((int)(-b * 1000.0) / GRID_WIDTH) + GRID_CENTER; if(a < 0) *x -= 1; if(b > 0) *y -= 1; } /* 5-----------------------= MAP_Angle =---------------------------- */ /** Finds the difference between two radians. The order of the radians is important, as the function returns a positive difference. @param x_ The first radians @param y_ The second radians @return The angle difference in radians. The angle is positive */ radians MAP_Angle(radians x_, radians y_) { if(x_ < 0) x_ += 2.0 * M_PI; if(y_ < 0) y_ += 2.0 * M_PI; if(y_ < x_) y_ += 2.0 * M_PI; return (y_ - x_); } /* 6-------------------------= MAP_Location =----------------------- */ /** Obtains the location of a cell in the grid in terms of its robot position. Performs the reverse function of "MAP_Pos". The robot position returned is the center of the cell. @param target The position (PositionType) of the cell @param index_ The cell array index @see MAP_Pos */ void MAP_Location(PositionType *target_, int index_) { int x, y; y = index_ / GRID_DIMENSIONS; x = index_ % GRID_DIMENSIONS; target_->x = ((float)x - (float)GRID_CENTER + 0.5) * (float)GRID_WIDTH / 1000.0; target_->y = ((float)y - (float)GRID_CENTER + 0.5) * (float)GRID_WIDTH / -1000.0; } /* 7----------------------= MAP_Position =--------------------------- */ /** VWGetPosition equivalent. Obtains the position of the robot. However, this function updates the robot position to the grid map. @param vw_ The VW handle for the robot @param pos The position (PositionType) of the robot @param map_ The grid for storage @return The position of the robot */ int MAP_Position(VWHandle vw_, PositionType *pos_, char *map_) { int i = 0, j = 0, a, b; VWGetPosition(vw_, pos_); /* Obtain robot position */ MAP_Pos(*pos_, 0, 0.0, &i, &j); /* Updating the Grid Map */ if((map_[j * GRID_DIMENSIONS + i] != BLOCKED /*1*/) && (map_[j * GRID_DIMENSIONS + i] != MAP_BORDER /*5*/)) map_[j * GRID_DIMENSIONS + i] = CLEAR; /*0;*/ /* Updates its neighbouring cells to "clear" (0) if they were initially defined as "clear but unexplored" (6) */ for(a = -1; a < 2; a++) for (b = -1; b < 2; b++) if(map_[(j + a) * GRID_DIMENSIONS + i + b] == CLEAR_UNEXP /*6*/) map_[(j + a) * GRID_DIMENSIONS + i + b] = CLEAR; /*0;*/ return j * GRID_DIMENSIONS + i; } /* 8------------------------= MAP_Dist =---------------------------- */ /** Obtains the distance to the nearest obstacle using the right PSD sensor. Records the obstacle and all spaces between the obstacle and the robot into the grid. Also checks the left PSD sensor for obstacles. @param vw_ The VW Handle @param psd_ The right PSD sensor @param psdLeft The left PSD sensor @param map_ The grid for storage @return The distance to the obstacle using the right PSD sensor */ int MAP_Dist (VWHandle vw_, PSDHandle psd_, PSDHandle psdLeft, char *map_) { int i, j, k, x = 0, y = 0, obstacle_, dist; PositionType pos_n_; /* Checks Left PSD Sensors */ dist = PSDGet(psdLeft) - OFFSET_LEFT; VWGetPosition(vw_, &pos_n_); if(dist < PSD_MAX){ /* An Obstacle is detected */ /* Marks the cell containing the obstacle as "blocked but unexplored"(4) */ MAP_Pos(pos_n_, dist + ROBOT_RADIUS, M_PI/2.0, &x, &y); if((x >= 0) && (x < GRID_DIMENSIONS) && (y >= 0) && (y < GRID_DIMENSIONS)) if((map_[y * GRID_DIMENSIONS + x] != CLEAR/*0*/) && (map_[y * GRID_DIMENSIONS + x] != BLOCKED)) if(!MAP_Check(&map_[0], y * GRID_DIMENSIONS + x, BLOCKED /*1*/)) map_[y * GRID_DIMENSIONS + x] = BLOCKED_UNEXP; /*4;*/ /* Set the cell beside the robot as "clear"(0) */ if(dist > GRID_WIDTH /*80*/){ MAP_Pos(pos_n_, ROBOT_RADIUS, M_PI/2.0, &x, &y); if((x >= 0) && (x < GRID_DIMENSIONS) && (y >= 0) && (y < GRID_DIMENSIONS)) map_[y * GRID_DIMENSIONS + x] = CLEAR; /*0;*/ } } else { /* Left Sensors did not detect an obstacle within out given range */ /* Sets the cell at the limit of PSD range to "clear but unexplored" (6) */ MAP_Pos(pos_n_, ROBOT_RADIUS + PSD_MAX, M_PI/2.0, &x, &y); if((x >= 0) && (x < GRID_DIMENSIONS) && (y >= 0) && (y < GRID_DIMENSIONS)) if((map_[y * GRID_DIMENSIONS + x] != CLEAR) && (map_[y * GRID_DIMENSIONS + x] != BLOCKED)) if(!MAP_Check(&map_[0], y * GRID_DIMENSIONS + x, BLOCKED /*1*/)) if(!MAP_Check(&map_[0], y * GRID_DIMENSIONS + x, CLEAR /*0*/)) map_[y * GRID_DIMENSIONS + x] = CLEAR_UNEXP; /*6;*/ } /* Checks Right PSD Sensor */ obstacle_ = PSDGet(psd_) - OFFSET_RIGHT; VWGetPosition(vw_, &pos_n_); if(obstacle_ < PSD_MAX){ /* An obstacle is detected */ dist = obstacle_; for(k = 0; k < 5; k++){ MAP_Pos(pos_n_, dist + ROBOT_RADIUS, -M_PI/2.0, &x, &y); if((x >= 0) && (x < GRID_DIMENSIONS) && (y >= 0) && (y < GRID_DIMENSIONS)){ /* The cell containing the obstacle is marked as "blocked" (1) */ if(dist == obstacle_){ if(map_[y * GRID_DIMENSIONS + x] != MAP_BORDER/*5*/) map_[y * GRID_DIMENSIONS + x] = BLOCKED; /*1;*/ /* Neighbouring cells which are unexplored (4) or (6) are cleared */ for(i = -2; i < 3; i++) for(j = -2; j < 3; j++) if((((y + i) * GRID_DIMENSIONS + x + j) > 0) && ((y + i) * GRID_DIMENSIONS + x + j) < (GRID_DIMENSIONS * GRID_DIMENSIONS)) if((map_[(y + i) * GRID_DIMENSIONS + x + j] == BLOCKED_UNEXP/*4*/) || (map_[(y + i) * GRID_DIMENSIONS + x + j] == CLEAR_UNEXP/*6*/)) map_[(y + i) * GRID_DIMENSIONS + x + j] = NOT_BORDER;//3 is not cleared (0) } /* Sets cells between the robot and obstacle as "clear" (0) */ else if((map_[y * GRID_DIMENSIONS + x] != BLOCKED/*1*/) && (map_[y * GRID_DIMENSIONS + x] != MAP_BORDER/*5*/)) map_[y * GRID_DIMENSIONS + x] = CLEAR; /*0;*/ } dist -= obstacle_ / 4; } } return obstacle_; /* Returns Right PSD Distance */ } /* 9-----------------------= MAP_Orient =--------------------------- */ /** Obtains the orientation required for the robot to face the target position. This routine is required for Path Navigation. @param vw_ The VW handle @param current The current position of the robot @param pos_n The target destination for the robot @return The orientation required for the robot (radians) @see MAP_Navigation MAP_Target */ float MAP_Orient(VWHandle vw_, PositionType current, PositionType pos_n) { float angle = 0; /* Using the robot's position, determines the desired orientation * the robot must face to reach the destination */ if(current.x == pos_n.x){ if(pos_n.y >= current.y) return M_PI / 2.0; else return -M_PI / 2.0; } angle = atan((pos_n.y - current.y) / fabs(pos_n.x - current.x)); if(pos_n.x < current.x) angle = M_PI - angle; return angle; } /* 10---------------------= MAP_Navigation =------------------------ */ /** Performs a robot navigation routine to reach a destination. Includes code for obstacle avoidance and boundary following. Adapted from the DistBug architecture. @param vw_ The VW handle @param psd_x The PSD Handles for the left, front and right PSDs @param target The target cell in the grid @param map_ The grid map used for storage @see Wall_Follow_Right MAP_Target MAP_Orient MAP_Location */ void MAP_Navigation (VWHandle vw_, PSDHandle * psd_x, int target, char *map_) { PositionType dest_n, pos_n_, stored; SpeedType stopped_; int i, j, dist_ = 0, prev_ = 0, x1, x2, y1, y2, looped = 0; MAP_Location(&dest_n, target); VWGetPosition(vw_, &stored); LCDPutString("Navigate_target\n"); do{ /* Rotate robot until it faces the correct orientation to target */ VWSetSpeed(vw_, 0, 0.2); /* 0.2- magic number */ //LCDPutString("Left rotation\n"); VWGetPosition(vw_, &pos_n_); }while(MAP_Angle(pos_n_.phi, MAP_Orient(vw_, pos_n_, dest_n)) > 0.03);/* 0.03- magic number */ VEHStop(vw_); do{ /* Begins navigation trajectory */ VWSetSpeed(vw_, 0.13, 0); /* 0.13- magic number */ MAP_Position(vw_, &pos_n_, &map_[0]); VWGetSpeed(vw_, &stopped_); /* Condition to eliminate the target destination * if the destination is unreachable (ie. no path exists ). */ if(looped != 0) if((fabs(pos_n_.x - stored.x) <= 0.15) && (fabs(pos_n_.y - stored.y) <= 0.15)){ /* 0.15- magic number */ map_[target] = CLEAR; /*0;*/ return; } if((fabs(pos_n_.x - dest_n.x) + fabs(pos_n_.y - dest_n.y)) < (fabs(stored.x - dest_n.x) + fabs(stored.y - dest_n.y))){ VWGetPosition(vw_, &stored); looped = 0; } if((fabs(pos_n_.x - stored.x) > 0.15) && (fabs(pos_n_.y - stored.y) > 0.15)) looped = 1; /* new-4: no obstacle in front or right of robot but its left is close to wall(s) */ if((PSDGet(psd_x[0]) - OFFSET_LEFT) < 100 && (PSDGet(psd_x[1]) - OFFSET_FRONT) > 100 && (PSDGet(psd_x[2]) - OFFSET_RIGHT) > 100 ){ // 100 chosen arbitarily stop_forward(vw_); VWSetSpeed(vw_, 0.0, -0.2); // rotate robot clockwise; -0.2 chosen arbitarily while((PSDGet(psd_x[0]) - OFFSET_LEFT) < 90 /*100*/){ /*LCDPutString("L_close_Not_F/R\n");*/ } VEHStop(vw_); } /* new-5: no obstacle in front or left of robot but its right is close to wall(s) */ if((PSDGet(psd_x[0]) - OFFSET_LEFT) > 100 && (PSDGet(psd_x[1]) - OFFSET_FRONT) > 100 && (PSDGet(psd_x[2]) - OFFSET_RIGHT) < 100 ){ // 100 chosen arbitarily stop_forward(vw_); VWSetSpeed(vw_, 0.0, 0.2); // rotate robot anti-clockwise; 0.2 chosen arbitarily while((PSDGet(psd_x[2]) - OFFSET_RIGHT) < 90 /*100*/){ /*LCDPutString("R_close_Not_L/F\n");*/ } VEHStop(vw_); } /* An obstacle is detected obstructing the robot's path in front of robot */ if(((PSDGet(psd_x[1]) - OFFSET_FRONT) < 100/*80*/) || ((stopped_.v < 0.05) && (stopped_.w == 0))){ /*LCDPutString("An obstacle\n"); */ stop_forward(vw_);/* stop moving forwards */ if((dist_=PSDGet(psd_x[0]) - OFFSET_LEFT) < (PSDGet(psd_x[2]) - OFFSET_RIGHT)){ /* The left side of the robot is closer to the obstacle, * thus perform Boundary-Following using the left PSD Sensors */ VWSetSpeed(vw_, 0, -0.2);/* -0.2- magic number */ do{ /* Rotate the robot so that the robot is parallel to the left wall */ prev_ = dist_; OSWait(1); dist_ = PSDGet(psd_x[0]) - OFFSET_LEFT; }while (prev_ >= dist_); VEHStop(vw_); MAP_Position(vw_, &pos_n_, &map_[0]); /* Perform left boundary-following */ while((MAP_Angle(pos_n_.phi, MAP_Orient(vw_, pos_n_, dest_n)) > 0.05) && (MAP_Angle(MAP_Orient(vw_, pos_n_, dest_n),pos_n_.phi) > 0.05) && (fabs(pos_n_.x - dest_n.x) + fabs(pos_n_.y - dest_n.y) > 0.16)){/* 0.16- magic number */ dist_ = PSDGet(psd_x[0]) - OFFSET_LEFT; MAP_Pos(pos_n_, ROBOT_RADIUS, 0, &x1, &y1); MAP_Pos(pos_n_, GRID_WIDTH + ROBOT_RADIUS, 0, &x2, &y2); VWGetSpeed(vw_, &stopped_); /* Condition for robot stalled (collision) */ if((stopped_.v < 0.05) && (stopped_.w == 0)){ /* 0.05- magic number */ stop_forward(vw_); VWSetSpeed(vw_, 0, -0.30); /* -0.30- magic number */ } /* Condition for boundary conditions (reach limits of grid map) */ else if((map_[y1 * GRID_DIMENSIONS + x1] == MAP_BORDER/*5*/) || (map_[y2 * GRID_DIMENSIONS + x2] == MAP_BORDER/*5*/)){ stop_forward(vw_); VWSetSpeed(vw_, 0, -0.3); } /* Obstacle is detected in front of robot - rotates right to avoid */ else if((PSDGet(psd_x[1]) - OFFSET_FRONT) < 100/*80*/){/* 80 chosen arbitarily */ /*VEHStop(vw_);*/ stop_forward(vw_); /* LCDPutString("L_elseif_fnt<100\n");*/ VWDriveTurn(vw_, -M_PI/4.0, 0.4); /* 0.4- magic number */ while(!VWDriveDone(vw_)) prev_ = PSDGet(psd_x[0]) - OFFSET_LEFT; while((dist_ = PSDGet(psd_x[0]) - OFFSET_LEFT) <= prev_){ VWSetSpeed(vw_, 0, -0.30); prev_ = dist_; } } else{ MAP_Pos(pos_n_, ROBOT_RADIUS, 0, &x1, &y1); MAP_Pos(pos_n_, GRID_WIDTH + ROBOT_RADIUS, 0, &x2, &y2); /* Condition for boundary limits to the left of robot - * must proceed in the same direction */ if((map_[y1 * GRID_DIMENSIONS + x1] == MAP_BORDER /*5*/) || (map_[y2 * GRID_DIMENSIONS + x2] == MAP_BORDER /*5*/)){ VWSetSpeed(vw_, 0.15, 0); /* 0.15- magic number */ } /* Possible collision with obstacle - collision avoidance routine */ else if((PSDGet(psd_x[0]) - OFFSET_LEFT) < 100 /*80*/){/* 80 chosen arbitarily */ stop_forward(vw_); VWSetSpeed(vw_, 0, -0.2); /* -0.2- magic number */ /* LCDPutString("Left<100\n"); */ } /* Robot lost the obstacle (outward corner). * Curve left to maintain contact with the boundary */ else if((PSDGet(psd_x[0]) - OFFSET_LEFT) > 138){/* 38 + 100 = 138 */ VWSetSpeed(vw_, 0.05, 0.55); /* 0.05 & 0.55- magic numbers */ dist_ = prev_; /* LCDPutString("else_curve_L\n"); */ } /* Veering close to obstacle, adjust trajectory */ else if(dist_ > prev_){ VWSetSpeed(vw_, 0.15, 0.2); /* LCDPutString("else_veer_close\n");*/ } /* Veering away from obstacle, adjust trajectory */ else if(dist_ < prev_){ VWSetSpeed(vw_, 0.15, -0.2); /* LCDPutString("else_veer_away\n"); */ } /* Robot should maintain trajectory - moving parallel */ else{ VWSetSpeed(vw_, 0.15, 0); /* LCDPutString("move parallel\n"); */ } } prev_ = dist_; MAP_Position(vw_, &pos_n_, &map_[0]); } } else{ /* The right side of the robot is closer to the wall - * enact a Boundary-Following routine using the right sensors */ VWSetSpeed(vw_, 0, 0.2); do{ /* Rotates robot so that robot is parallel to right wall */ prev_ = dist_; OSWait(1); dist_ = PSDGet(psd_x[2]) - OFFSET_RIGHT; }while (prev_ >= dist_); VEHStop(vw_); MAP_Position(vw_, &pos_n_, &map_[0]); /* Begin right wall-following routine */ while((MAP_Angle(pos_n_.phi, MAP_Orient(vw_, pos_n_, dest_n)) > 0.05) && (MAP_Angle(MAP_Orient(vw_, pos_n_, dest_n),pos_n_.phi) > 0.05) && (fabs(pos_n_.x - dest_n.x) + fabs(pos_n_.y - dest_n.y) > 0.16)){ dist_ = PSDGet(psd_x[2]) - OFFSET_RIGHT; MAP_Pos(pos_n_, ROBOT_RADIUS, 0, &x1, &y1); MAP_Pos(pos_n_, GRID_WIDTH + ROBOT_RADIUS, 0, &x2, &y2); VWGetSpeed(vw_, &stopped_); /* Condition for robot stalled (collision) */ if((stopped_.v < 0.05) && (stopped_.w == 0)){ stop_forward(vw_); VWSetSpeed(vw_, 0, 0.3); } /* Condition for reaching boundary limits */ else if((map_[y1 * GRID_DIMENSIONS + x1] == MAP_BORDER /*5*/) || (map_[y2 * GRID_DIMENSIONS + x2] == MAP_BORDER /*5*/)){ stop_forward(vw_); VWSetSpeed(vw_, 0, 0.3); } /* Condition for obstacle in front of robot - rotate left to avoid */ else if((PSDGet(psd_x[1]) - OFFSET_FRONT) < 100/*80*/){/* 80 chosen arbitarily */ /*VEHStop(vw_);*/ stop_forward(vw_); /*LCDPutString("R_elseif_fnt<100\n");*/ VWDriveTurn(vw_, M_PI/4.0, 0.4); while(!VWDriveDone(vw_)) prev_ = PSDGet(psd_x[2]) - OFFSET_RIGHT; while((dist_ = PSDGet(psd_x[2]) - OFFSET_RIGHT) <= prev_){ VWSetSpeed(vw_, 0, 0.30); prev_ = dist_; } } else{ MAP_Pos(pos_n_, ROBOT_RADIUS, -M_PI/2.0, &x1, &y1); MAP_Pos(pos_n_, GRID_WIDTH + ROBOT_RADIUS, -M_PI/2.0, &x2, &y2); /* Condition for boundary limits reached */ if((map_[y1 * GRID_DIMENSIONS + x1] == MAP_BORDER /*5*/) || (map_[y2 * GRID_DIMENSIONS + x2] == MAP_BORDER /*5*/)) VWSetSpeed(vw_, 0.15, 0); /* an obstacle close to right of robot - enact collision avoidance routine */ else if((PSDGet(psd_x[2]) - OFFSET_RIGHT) < 100/*80*/){/* 80 chosen arbitarily */ stop_forward(vw_); VWSetSpeed(vw_, 0, 0.2); } /* No obstacle detected (outward corner) - * robot must turn right to relocate obstacle */ else if((PSDGet(psd_x[2]) - OFFSET_RIGHT) > 138){/* 38 + 100 = 138 */ VWSetSpeed(vw_, 0.05, -0.55); dist_ = prev_; } /* Veering close to obstacle, adjust trajectory */ else if(dist_ > prev_) VWSetSpeed(vw_, 0.15, -0.2); /* Veering away from obstacle, adjust trajectory */ else if(dist_ < prev_) VWSetSpeed(vw_, 0.15, 0.2); /* Robot moving parallel to obstacle - maintain trajectory */ else VWSetSpeed(vw_, 0.15, 0); } prev_ = dist_; MAP_Position(vw_, &pos_n_, &map_[0]); } } } }while(fabs(pos_n_.x - dest_n.x) + fabs(pos_n_.y - dest_n.y) > 0.16); //VEHStop(vw_); stop_forward(vw_); for(i = -1; i < 2; i++) for(j = -1; j < 2; j++) if(map_[target + GRID_DIMENSIONS * i + j] == CLEAR_UNEXP /*6*/) map_[target + GRID_DIMENSIONS * i + j] = CLEAR; /*0;*/ if(map_[target] == BLOCKED_UNEXP /*4*/) map_[target] = NOT_BORDER; /*3;*/ LCDPutString("end_Navigation\n"); } /* 11----------------------= MAP_Locate =--------------------------- */ /** Locates the nearest unexplored obstacle to the robot. And proceeds to that obstacle. The maximum range of operation is the limits to the PSD set by PSD_MAX. @param vw_ The VW Handle @param x_ The PSD Handle for the front PSD sensor @param map_ The address of the occupation grid system */ int MAP_Locate (VWHandle vw_, PSDHandle x_, char *map_) { int mindist_ = PSD_MAX, obstacle_, p_x, p_y, x = 0, y = 0; radians angle_ = 0; PositionType pos_n_, stop_; SpeedType stopped_; LCDPutString("Locate_obstacle\n"); VEHStop(vw_); /* clear previous speed setting */ OSWait(1); /* wait for a while */ VWDriveTurn(vw_, 2.0 * M_PI, 0.5); /* 0.5- magic number */ LCDPutString("Full circle\n"); while (!VWDriveDone(vw_)){ /* Rotates around a full circle, locating obstacles */ MAP_Position(vw_, &pos_n_, &map_[0]); MAP_Pos(pos_n_, 0, 0, &p_x, &p_y); /* LCDPutString("F_circ_turning\n"); */ /*obstacle_ = PSDGet(x_) - OFFSET_FRONT;*/ if((obstacle_ = PSDGet(x_) - OFFSET_FRONT) < 80){/* 80 chosen arbitarily */ obstacle_ = 70; /*30; original=35; magic number */ /* LCDPutString("Obstacle=70\n"); */ } if(obstacle_ < PSD_MAX){ /* Obstacle detected */ MAP_Pos(pos_n_, obstacle_ + ROBOT_RADIUS, 0, &x, &y); /* Ensure obstacle is not previously explored */ if((x >= 0) && (x < GRID_DIMENSIONS) && (y >= 0) && (y < GRID_DIMENSIONS)) if((map_[y*GRID_DIMENSIONS+x] != CLEAR /*0*/) && (map_[y*GRID_DIMENSIONS+x] != BLOCKED /*1*/)) if(!MAP_Check(&map_[0], y * GRID_DIMENSIONS + x, BLOCKED /*1*/)){ map_[y * GRID_DIMENSIONS + x] = BLOCKED_UNEXP; /*4;*/ if(obstacle_ < mindist_){ mindist_ = obstacle_; angle_ = pos_n_.phi; /* LCDPutString("F_circ_notExpl\n"); */ } } } /* Mark map according for the sensor detecting no obstacles */ else if(obstacle_ >= PSD_MAX){ MAP_Pos(pos_n_, PSD_MAX + ROBOT_RADIUS, 0, &x, &y); if((x >= 0) && (x < GRID_DIMENSIONS) && (y >= 0) && (y < GRID_DIMENSIONS)) if((map_[y*GRID_DIMENSIONS+x] != CLEAR/*0*/) && (map_[y*GRID_DIMENSIONS+x] != BLOCKED/*1*/)) if(!MAP_Check(&map_[0], y * GRID_DIMENSIONS + x, BLOCKED/*1*/)) map_[y * GRID_DIMENSIONS + x] = CLEAR_UNEXP; /*6;*/ } } VEHStop(vw_); LCDPutString("end_Full_circle\n"); if(mindist_ == PSD_MAX) return NOT_CLOSE; /* 0; */ MAP_Position(vw_, &stop_, &map_[0]); VEHStop(vw_); /* clear previous speed setting */ OSWait(1); /* wait for a while */ VWDriveTurn(vw_, -MAP_Angle(angle_, stop_.phi), M_PI / 3.0); while(!VWDriveDone(vw_)); /* LCDPutString("turn_rate=PI/3\n"); */ VEHStop(vw_); OSWait(1); /* wait for a while */ /* Drive robot to the nearest detected obstacle */ /* =first move robot away from detected obstacle if it too close= */ if(front_too_close(vw_, x_)){ move_backward(vw_, x_); VEHStop(vw_); OSWait(1); /* wait for a while */ } //LCDPutString("Drive towards\n"); /* =then drive robot towards the detected obstacle= */ VWSetSpeed(vw_, 0.10, 0); /* 0.10- magic number */ do{ MAP_Position(vw_, &stop_, &map_[0]); VWGetSpeed(vw_, &stopped_); }while((PSDGet(x_) - OFFSET_FRONT) > FRONT_GAP/*90*/ ); /* 90 chosen arbitarily */ stop_forward(vw_); OSWait(1); /* wait for a while */ return IS_CLOSE; /*1;*/ } /* 12-------------------- Wall_Follow_Right ------------------------ */ /** A boundary-following algorithm that tracks the right side of the robot. @param vw_ The VW Handle @param psd_ The addresses of the Right, Front and Left PSD sensors @param map The address for the occupation grids @param segs The address for the configuration space @param count The counter for the number of line-segments @see MAP_Navigation */ void Wall_Follow_Right (VWHandle vw_, PSDHandle * psd_, char *map_, Segment * segs_, int *count_) { int dist_ = 0, prev_ = -1, looped_ = 0, val_ = 0, turn_ = 0; int x1, y1, x2, y2; radians orient_ = 0; SpeedType stopped_; PositionType pos_n_, start_; /* Rotate robot so that it is approximately parallel to obstacle */ VWDriveTurn(vw_, M_PI / 2.0, 0.4); /* 0.4- magic number */ while(!VWDriveDone(vw_)) val_ = MAP_Dist(vw_, psd_[2], psd_[0], &map_[0]); VEHStop(vw_); VWSetSpeed(vw_, 0.2, 0); /* 0.2- magic number */ MAP_Position(vw_, &pos_n_, &map_[0]); MAP_Position(vw_, &start_, &map_[0]); if(*count_ < GRID_DIMENSIONS*10){ /* Store configuration space map */ segs_[*count_].x1 = (int) (MAP_Segment(start_.x) + (val_ + ROBOT_RADIUS) * cos(start_.phi - M_PI/2.0)); segs_[*count_].y1 = (int) (MAP_Segment(start_.y) + (val_ + ROBOT_RADIUS) * sin(start_.phi - M_PI/2.0)); } /* Wall-Following Routine */ while((looped_ == 0) || ((fabs(start_.x - pos_n_.x) > 0.1) || (fabs(start_.y - pos_n_.y) > 0.1))){ /*0.1- magic number*/ MAP_Pos(pos_n_, ROBOT_RADIUS, 0, &x1, &y1); MAP_Pos(pos_n_, GRID_WIDTH + ROBOT_RADIUS, 0, &x2, &y2); VWGetSpeed(vw_, &stopped_); dist_ = MAP_Dist(vw_, psd_[2], psd_[0], &map_[0]); /* Condition for robot stall (collision) */ if((stopped_.v < 0.025) && (stopped_.w == 0)) /* 0.025- magic number */ VWSetSpeed(vw_, 0, 0.3); /* 0.3- magic number */ /* Condition for grid boundary limit reached */ else if((map_[y1 * GRID_DIMENSIONS + x1] == MAP_BORDER/*5*/) || (map_[y2 * GRID_DIMENSIONS + x2] == MAP_BORDER/*5*/)){ VWSetSpeed(vw_, 0, 0.4); /* 0.4- magic number */ /* Store configuration space map */ if((turn_ == 0) && (*count_ < 10*GRID_DIMENSIONS)){ segs_[*count_].x2 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + dist_) * cos(pos_n_.phi - M_PI/2.0) + turn_ * ROBOT_RADIUS * cos(pos_n_.phi)); segs_[*count_].y2 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + dist_) * sin(pos_n_.phi - M_PI/2.0) + turn_ * ROBOT_RADIUS * sin(pos_n_.phi)); *count_ += 1; } turn_ = 1; } /* Obstacle detected in front of robot - enact left turn to avoid collision */ else if((PSDGet(psd_[1]) - OFFSET_FRONT) <= FRONT_GAP/*GRID_WIDTH*/){ /*VEHStop(vw_);*/ stop_forward(vw_); VWSetSpeed(vw_, 0, 0.30); orient_ = pos_n_.phi - M_PI / 5.0; /* Rotation until robot reaches corner of the boundary */ while((dist_ = MAP_Dist(vw_, psd_[2], psd_[0], &map_[0])) >= prev_){ prev_ = dist_; if((dist_ <= 120) && (turn_ == 0) && (*count_ < GRID_DIMENSIONS*10)){/*120- magic number*/ MAP_Position(vw_, &pos_n_, &map_[0]); /* Condition to store configuration space map */ if(MAP_Angle(orient_, pos_n_.phi) >= (M_PI / 12.0)){ orient_ = pos_n_.phi; segs_[*count_].x2 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + dist_) * cos(pos_n_.phi - M_PI/2.0)); segs_[*count_].y2 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + dist_) * sin(pos_n_.phi - M_PI/2.0)); *count_ += 1; segs_[*count_].x1 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + dist_) * cos(pos_n_.phi - M_PI/2.0)); segs_[*count_].y1 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + dist_) * sin(pos_n_.phi - M_PI/2.0)); } } } orient_ = pos_n_.phi - M_PI / 5.0; /* Rotation until robot is parallel to new side of obstacle */ while((dist_ = MAP_Dist(vw_, psd_[2], psd_[0], &map_[0])) <= prev_){ prev_ = dist_; if((dist_ <= 120) && (turn_ == 0) && (*count_ < GRID_DIMENSIONS*10)){/*120- magic number*/ MAP_Position(vw_, &pos_n_, &map_[0]); /* Condition to store configuration space map */ if(MAP_Angle(orient_, pos_n_.phi) >= (M_PI / 12.0)){ orient_ = pos_n_.phi; segs_[*count_].x2 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + dist_) * cos(pos_n_.phi - M_PI/2.0)); segs_[*count_].y2 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + dist_) * sin(pos_n_.phi - M_PI/2.0)); *count_ += 1; segs_[*count_].x1 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + dist_) * cos(pos_n_.phi - M_PI/2.0)); segs_[*count_].y1 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + dist_) * sin(pos_n_.phi - M_PI/2.0)); } } } VEHStop(vw_); turn_ = 0; } else{ MAP_Pos(pos_n_, ROBOT_RADIUS, -M_PI/2.0, &x1, &y1); MAP_Pos(pos_n_, GRID_WIDTH + ROBOT_RADIUS, -M_PI/2.0, &x2, &y2); /* Boundary condition reached - robot at end of grid map * Robot must maintain trajectory to avoid crossing the boundary */ if((map_[y1 * GRID_DIMENSIONS + x1] == MAP_BORDER/*5*/) || (map_[y2 * GRID_DIMENSIONS + x2] == MAP_BORDER/*5*/)) VWSetSpeed(vw_, 0.15, 0); /* 0.15- magic number */ /* Right PSD to detect collision with the obstacle */ else if((PSDGet(psd_[2]) - OFFSET_RIGHT) < FOLLOW_GAP/*80*/)/* 80 chose arbitarily */ VWSetSpeed(vw_, 0, 0.2); /* 0.2- magic number */ /* Obstacle not detected beside robot (outward corner) - * rotate accordingly to locate obstacle */ else if((PSDGet(psd_[2]) - OFFSET_RIGHT) > ADJUST_LIMIT/*95*/){/* 95- magic number */ /* Store the configuration space map */ if((prev_ <= ADJUST_LIMIT/*95*/) && (turn_ == 0) && (*count_ < GRID_DIMENSIONS*10)){/* 95- magic number */ MAP_Position(vw_, &pos_n_, &map_[0]); segs_[*count_].x2 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + prev_) * cos(pos_n_.phi - M_PI/2.0)); segs_[*count_].y2 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + prev_) * sin(pos_n_.phi - M_PI/2.0)); *count_ += 1; segs_[*count_].x1 = (int) (MAP_Segment(pos_n_.x) + (ROBOT_RADIUS + prev_) * cos(pos_n_.phi - M_PI/2.0)); segs_[*count_].y1 = (int) (MAP_Segment(pos_n_.y) + (ROBOT_RADIUS + prev_) * sin(pos_n_.phi - M_PI/2.0)); } VWSetSpeed(vw_, 0.05, -0.55); } /* Veering too far away from obstacle, adjust trajectory */ else if((prev_ != -1) && (dist_ < prev_)) VWSetSpeed(vw_, 0.15, 0.2); /* Veering too close to obstacle, adjust trajectory */ else if((prev_ != -1) && (dist_ > prev_)) VWSetSpeed(vw_, 0.15, -0.2); /* Robot is moving parallel to obstacle - maintain trajectory */ else VWSetSpeed(vw_, 0.15, 0); } prev_ = dist_; MAP_Position(vw_, &pos_n_, &map_[0]); /* Set condition to determine the end of the wall following routine */ if((fabs(start_.x - pos_n_.x)>0.12)||(fabs(start_.y - pos_n_.y)>0.12))/*0.12- magic number*/ looped_ = 1; } VEHStop(vw_); /* Store final point in the configuration space for the obstacle */ if(*count_ < 10 * GRID_DIMENSIONS){ segs_[*count_].x2 = (int) (MAP_Segment(start_.x) + (ROBOT_RADIUS + val_) * cos(start_.phi-M_PI/2.0)); segs_[*count_].y2 = (int) (MAP_Segment(start_.y) + (ROBOT_RADIUS + val_) * sin(start_.phi-M_PI/2.0)); *count_ += 1; } } /* 13-----------------------= LCD_MAP =----------------------------- */ /** Draws the occupational grid onto the LCD display. The map is centred on the robot. @param vw_ The VW Handle @param map_ The address of the grid @see Display_MAP UpLoad_Grid */ void LCD_MAP(VWHandle vw_, char *map_) { int i = 0, j = 0, x, y; PositionType pos_n_; /* Centres the map on the robot position */ VWGetPosition(vw_, &pos_n_); MAP_Pos(pos_n_, 0, 0, &x, &y); /* Adjusts map if it encounters the end of the grid boundaries */ if(x < 64) x = 64; else if(x > (GRID_DIMENSIONS - 64)) x = GRID_DIMENSIONS - 64; if(y < 32) y = 32; else if(y > (GRID_DIMENSIONS - 32)) y = GRID_DIMENSIONS - 32; LCDClear(); /* Draws the map on the LCD Display */ while((j < 64) && ((y + j - 32) < GRID_DIMENSIONS)){ i = 0; while((i < 128) && ((x + i - 64) < GRID_DIMENSIONS)){ if((x + i - 64) >= 0) if((y + j - 32) >= 0) if(map_[(y + j - 32)*GRID_DIMENSIONS+(x + i - 64)] == BLOCKED /*1*/) LCDSetPixel(j, i, 1); i++; } j++; } } /* 14-----------------------= Display_MAP =------------------------- */ /** Displays the map in ascii format (Used for simulator only). @param map_ The address of the grids @see LCD_MAP UpLoad_Grid */ void Display_MAP(char *map_) { int i, j; for(i = 0; i < GRID_DIMENSIONS; i++){ for(j = 0; j < GRID_DIMENSIONS; j++) switch(map_[i * GRID_DIMENSIONS + j]){ case 0: fprintf(stderr," "); break; case 1: fprintf(stderr,"@"); break; case 3: fprintf(stderr,":"); break; case 4: fprintf(stderr,"X"); break; case 5: fprintf(stderr,"*"); break; case 6: fprintf(stderr,"."); break; default: fprintf(stderr,"-"); break; } fprintf(stderr,"\n"); } } /* 15-----------------------= MAP_Target =------------------------- */ /** Locates an unexplored cell and returns the index as the target. @param map_ The address of the occupational grids */ int MAP_Target(char *map_) { int i = 0; while (i < (GRID_DIMENSIONS*GRID_DIMENSIONS)){ if((map_[i] == CLEAR_UNEXP /*6*/) || (map_[i] == BLOCKED_UNEXP /*4*/)) return i; i++; } return IS_EXPLORED; /*-1;*/ } /* 16------------------------= UpLoad_VG =-------------------------- */ /** Loads the map through the SERIAL1 link Loads the configuration space system. @param values The configuration space address @param v_count The counter for the configuration space @see UpLoad_Grid */ void UpLoad_VG(Segment *values, int v_count) { char string[50], term = 4; int i, j, len; string[0] = '\0'; len = sprintf(string, "width %d\n", GRID_DIMENSIONS * GRID_DIMENSIONS + 100); for(j = 0; j < len; j++) OSSendRS232(&string[j], SERIAL1); string[0] = '\0'; len = sprintf(string, "height %d\n", GRID_DIMENSIONS * GRID_DIMENSIONS + 100); for(j = 0; j < len; j++) OSSendRS232(&string[j], SERIAL1); for(i = 0; i < v_count; i++){ len = sprintf(string, "%d %d %d %d\n", values[i].x1, values[i].y1, values[i].x2, values[i].y2); for(j = 0; j < len; j++) OSSendRS232(&string[j], SERIAL1); } OSSendRS232(&term, SERIAL1); LCDPutString("Map UpLoad complete!\n"); } /* 17------------------------= UpLoad_Grid =------------------------ */ /** Loads the occupational grids system through the SERIAL2 link. @param info The address of the grids map representation @see UpLoad_VG Display_MAP LCD_MAP */ void UpLoad_Grid(char *info) { char term = 4, obs = 'X', clr = ' ', nl = '\n'; int i, j; for(i = 0; i < GRID_DIMENSIONS; i++){ for(j = 0; j < GRID_DIMENSIONS; j++) if(info[i*GRID_DIMENSIONS + j] == 1) OSSendRS232(&obs, SERIAL2); else OSSendRS232(&clr, SERIAL2); OSSendRS232(&nl, SERIAL2); } OSSendRS232(&term, SERIAL2); LCDPutString("UpLoad_Grid complete\n"); } /* 18========================= main function ======================= */ int main () { /* -------- Variable declarations -------- */ VWHandle vw; Segment data[GRID_DIMENSIONS*10]; int count = 0, i; char map[GRID_DIMENSIONS*GRID_DIMENSIONS] = {1}; PSDHandle psd[NUM_PSD]; for(i=GRID_DIMENSIONS;i<GRID_DIMENSIONS*GRID_DIMENSIONS;i++) map[i] = NOT_BORDER; /*3;*/ for(i=0;i<GRID_DIMENSIONS;i++){ map[i] = MAP_BORDER; /*5;*/ map[GRID_DIMENSIONS*GRID_DIMENSIONS - 1 - i] = MAP_BORDER; map[GRID_DIMENSIONS*i] = MAP_BORDER; map[GRID_DIMENSIONS*i + GRID_DIMENSIONS-1] = MAP_BORDER; } LCDMode(SCROLLING|NOCURSOR); /* - - - - - - - PSD Handler - - - - - - - */ psd[0] = PSDInit(PSD_LEFT); if(psd[0] == 0){ LCDPutString("PSDInit Error!\n"); OSWait(20); exit(1); } psd[1] = PSDInit(PSD_FRONT); if(psd[1] == 0){ LCDPutString("PSDInit Error!\n"); OSWait(20); exit(1); } psd[2] = PSDInit(PSD_RIGHT); if(psd[2] == 0){ LCDPutString("PSDInit Error!\n"); OSWait(20); exit(1); } PSDStart(psd[0] + psd[1] + psd[2], TRUE); /* - - - - init v-omega interface - - - - */ vw = VWInit(VW_DRIVE,1); if(vw == 0){ LCDPutString("VWInit Error!\n"); OSWait(200); exit(1); } VWSetPosition(vw, 0.0, 0.0, 0.0); VWStartControl(vw,V_LIN,T_LIN,V_ROT,T_ROT); /* - - Initialize rs232 with given setting - - */ OSInitRS232(SER115200, RTSCTS, SERIAL1); /************ main action loop ************/ while(TRUE){ LCDPutString("Scanning...\n"); if(!MAP_Locate(vw, psd[1], &map[0])){ i = MAP_Target(&map[0]); if(i != IS_EXPLORED /*-1*/){ MAP_Navigation(vw, &psd[0], i, &map[0]); } else{ LCDPrintf("\nMap Generation Finished\n"); LCDMenu("MAP","GRID","LINE","STOP"); do{ i = KEYRead(); switch (i){ case KEY1: break; case KEY2: UpLoad_Grid(&map[0]); break; case KEY3: UpLoad_VG(&data[0], count); break; case KEY4: PSDRelease(); VWRelease(vw); exit(0); default: break; } }while (i != KEY1); LCDMenu("","","",""); count = 0; for(i=GRID_DIMENSIONS;i<GRID_DIMENSIONS*GRID_DIMENSIONS;i++) map[i] = NOT_BORDER; /*3;*/ for(i=0;i<GRID_DIMENSIONS;i++){ map[i] = MAP_BORDER; /*5;*/ map[GRID_DIMENSIONS*GRID_DIMENSIONS - 1 - i] = MAP_BORDER; map[GRID_DIMENSIONS*i] = MAP_BORDER; map[GRID_DIMENSIONS*i + GRID_DIMENSIONS-1] = MAP_BORDER; } } } else{ LCDPutString("Wall-following\n"); Wall_Follow_Right(vw, &psd[0], &map[0], &data[0], &count); LCD_MAP(vw, &map[0]); KEYWait(ANYKEY); /* LCDMenu("Cont","","","Load"); i = KEYRead(); if(i == KEY4){ LCDMenu("Map","Grid","Ln",""); do{ i = KEYRead(); switch (i){ case KEY1: break; case KEY2: UpLoad_Grid(&map[0]); break; case KEY3: UpLoad_VG(&data[0], count); break; default: break; } }while (i != KEY1); } LCDMenu("Map","","","Stop"); i = KEYRead(); if(i == KEY1){ LCDPutString("Hit a key to go\n"); KEYWait(ANYKEY); } else if(i == KEY4){ PSDRelease(); VWRelease(vw); exit(0); }*/ } } } /* end of program */