/* Recursive Maze exploration program */ /* in "MicroMouse" style */ /* */ /* Thomas Braunl, UWA, 1998, 2000, 2004 */ #include "eyebot.h" #include #include #include #include #define DIST 0.36 #define SPEEDFAC 100 #define SPEED (SPEEDFAC*DIST) #define ASPEED (SPEEDFAC*PI/2.0) #define THRES 175 #define MAZESIZE 16 #define PI 3.1415926535 /* pos.0,0 is bottom left, dir. 0 is facing up (north) */ int mark[MAZESIZE][MAZESIZE]; /* 1 if visited */ int wall[MAZESIZE+1][MAZESIZE+1][2]; /* 1 if wall, 0 if free, -1 if unknown */ /* BOTTOM: wall[x][y][0] LEFT: wall[x][y][1] */ int map [MAZESIZE][MAZESIZE]; /* distance to goal */ int nmap[MAZESIZE][MAZESIZE]; /* copy */ int path[MAZESIZE*MAZESIZE]; /* shortest path */ PSDHandle psd_front,psd_left,psd_right; VWHandle vw; int GRAPH,DEBUG,DEBUG2; /** print mark full to X window (sim only). print positions that robot has already visited. */ void print_mark_W() { int i,j; /* print to window (sim. only) */ fprintf(stderr,"MARK\n"); for (i=MAZESIZE-1; i>=0; i--) { for (j=0; j=0; i--) { for (j=0; j<14; j++) if (mark[i][j]) LCDPutChar('x'); else LCDPutChar('.'); if (i>0) LCDPutChar('\n'); } } /** print ful maze in X window (sim only). print maze as explored by robot. */ void print_maze_W() { int i,j; fprintf(stderr,"MAZE\n"); for (i=MAZESIZE; i>=0; i--) { for (j=0; j<=MAZESIZE; j++) { if (wall[i][j][1]==1) fprintf(stderr,"|"); /* left */ else if (wall[i][j][1]==0) fprintf(stderr," "); else fprintf(stderr,"."); if (wall[i][j][0]==1) fprintf(stderr,"_"); /* bottom */ else if (wall[i][j][0]==0) fprintf(stderr," "); else fprintf(stderr,"."); } fprintf(stderr,"\n"); } fprintf(stderr,"\n"); } /** print ful maze on LCD (6 lines). print maze as explored by robot. */ void print_maze() { int i,j; LCDSetPos(1,0); for (i=5; i>=0; i--) { for (j=0; j<=6; j++) { if (wall[i][j][1]==1) LCDPutChar('|'); /* left */ else if (wall[i][j][1]==0) LCDPutChar(' '); else LCDPutChar('.'); if (wall[i][j][0]==1) LCDPutChar('_'); /* bottom */ else if (wall[i][j][0]==0) LCDPutChar(' '); else LCDPutChar('.'); } if (i>0) LCDPutChar('\n'); } } void wall_set(int *w, int v) { if (*w == -1) *w = v; /* not seen before, set value */ else if (*w != v) /* seen before and CONTRADITION */ { *w = 1; /* assume wall to be safe */ LCDSetString(0,0,"CONTRADICTION\n"); AUBeep(); } } /** maze_entry. enter recognized walls or doors. */ void maze_entry(int x, int y, int dir, int open) { switch(dir) /* record bottom or left wall per square */ { case 0: wall_set(&wall[y+1][x ][0], !open); break; /* top = bottom of next */ case 2: wall_set(&wall[y ][x ][0], !open); break; case 1: wall_set(&wall[y ][x ][1], !open); break; case 3: wall_set(&wall[y ][x+1][1], !open); break; /* right = left of next */ } } /** robo position and orientation. dir = 0, 1, 2, 3 equals: north, west, south, east. */ int rob_x, rob_y, rob_dir; /** init_maze. inits internal map of maze. set marks to 0 and walls to -1 (unknown). */ void init_maze() { int i,j; for (i=0; i THRES; left_open = PSDGet(psd_left) > THRES; right_open = PSDGet(psd_right) > THRES; maze_entry(rob_x,rob_y,rob_dir, front_open); maze_entry(rob_x,rob_y,(rob_dir+1)%4, left_open); maze_entry(rob_x,rob_y,(rob_dir+3)%4, right_open); check_mark(); old_dir = rob_dir; if (GRAPH) { LCDSetPos(0,0); LCDPrintf("Pos[%2d,%2d,%1d]", rob_x,rob_y,rob_dir); if (left_open) LCDSetChar(0,13,'<'); else LCDSetChar(0,13,'|'); if (front_open) LCDSetChar(0,14,'^'); else LCDSetChar(0,14,'-'); if (right_open) LCDSetChar(0,15,'>'); else LCDSetChar(0,15,'|'); print_maze(); } if (DEBUG) { print_mark_W(); print_maze_W(); LCDMenu("Next"," "," "," "); KEYWait(KEY1); LCDMenu(" "," "," "," "); } if (front_open && unmarked(rob_y,rob_x,old_dir)) /* then go straight */ { go_to(old_dir); /* go 1 forward, 0 if first choice */ explore(); /* recursive call */ go_to(old_dir+2); /* go 1 back */ } if (left_open && unmarked(rob_y,rob_x,old_dir+1)) /* then turn left */ { go_to(old_dir+1); /* go 1 left */ explore(); /* recursive call */ go_to(old_dir-1); /* go 1 right, -1 = +3 */ } if (right_open && unmarked(rob_y,rob_x,old_dir-1)) /* then turn right */ { go_to(old_dir-1); /* go 1 right, -1 = +3 */ explore(); /* recursive call */ go_to(old_dir+1); /* go 1 left */ } } /** print shortest distances from start in X window (sim only). */ void print_map_W() { int i,j; fprintf(stderr,"MAP\n"); for (i=MAZESIZE-1; i>=0; i--) { for (j=0; j=0; i--) { for (j=0; j<4; j++) LCDPrintf("%3d",map[i][j]); if (i>0) LCDPutChar('\n'); } } /** shortest_path. analyze shortest path after maze has been searched. returns path length to goal. or -1 if no path could be found. */ int shortest_path(int goal_y, int goal_x) { int i,j,iter; LCDSetString(0,0," "); /* clear top line */ LCDSetPos(0,0); LCDPutString("Map.."); for (i=0; i0) if (!wall[i][j][0] && map[i-1][j] != -1) nmap[i][j] = map[i-1][j] + 1; if (i0) if (!wall[i][j][1] && map[i][j-1] != -1) nmap[i][j] = map[i][j-1] + 1; if (j=0; k--) { if (i>0 && !wall[i][j][0] && map[i-1][j] == k) { i--; path[k] = 0; /* north */ } else if (i0 && !wall[i][j][1] && map[i][j-1] == k) { j--; path[k] = 3; /* east */ } else if (j0) LCDSetChar(6-i,2*j+1,'*'); /* path */ else LCDSetChar(6-i,2*j+1,'S'); /* start */ } if (DEBUG2) fprintf(stderr,"path %3d:%1d\n", k, path[k]); } LCDSetString(0,6,"done"); } /** drive path. drive path after building it. parametere specifies start to finish (0). or finish to start (1). */ void drive_path(int len, int reverse) { int i; if (reverse) { for (i=len-1; i>=0; i--) go_to(path[i]+2); if (rob_dir != 0) /* back in start field */ { VWDriveTurn(vw, -rob_dir*PI/2.0, ASPEED); /* turn */ VWDriveWait(vw); rob_dir = 0; } } else for (i=0; i