/* Thomas Braunl/Birgit Graf, UWA, 1998 */ /* Thomas Braunl, UWA, 2000 */ #include "eyebot.h" #include #include #include #ifndef RIGHT #define RIGHT 1 #endif #ifndef LEFT #define LEFT -1 #endif #define MIDDLE 0 #define THRES 240 /* open way to next field? */ /* #define THRES_WALL 95 */ #define THRES_WALL 120 /* stop in front of wall */ #define PSDSIDE 100 /* PSD-value on side if robot in middle of corridor [mm] */ #define MAZESIZE 8 /* Define the places output can go */ #define LCD 0 #define CONSOLE 1 /* 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 */ /** handles for PSD sensors */ PSDHandle psd_front,psd_left,psd_right; /** handle for motors */ VWHandle vw; int GRAPH,DEBUG,DEBUG2; /** robo position and orientation. dir = 0, 1, 2, 3 equals: north, west, south, east. */ int rob_x, rob_y, rob_dir; /** flag, set to end driving */ int end_drive=FALSE; meterPerSec lin_speed=0.2; /* linear speed [m/s] */ radPerSec rot_speed=1.0; /* rotational speed [rad/s] */ float dist; /* length of one field (depends on lin. speed) */ /** where output should go */ int output; /** play tune. Play tune when reached target */ void tune() { AUTone(1046.5, 200); while(!AUCheckTone()){} AUTone(1396.9, 200); while(!AUCheckTone()){} AUTone(1046.5, 200); while(!AUCheckTone()){} AUTone(698.5, 200); while(!AUCheckTone()){} } void set_speed() { float boc[2]; int ind = 0; int end_proc=FALSE; LCDClear(); LCDMenu(" + "," - ","Nxt","OK"); LCDPrintf("Set speed:\n"); boc[0]=lin_speed; boc[1]=rot_speed; while (!end_proc) { LCDSetPos(2,0); LCDPrintf("lin. spd.: %1.2f\n",lin_speed); LCDPrintf("rot. spd.: %1.2f\n",rot_speed); LCDSetChar(2+ind,15,'*'); switch (KEYGet()) { case KEY1: boc[ind]+=0.02; break; case KEY2: boc[ind]-=0.02; break; case KEY3: LCDSetChar(2+ind,15,' '); ind++; if (ind>1) ind=0; break; case KEY4: LCDClear(); end_proc=TRUE; break; default: break; } lin_speed=boc[0]; rot_speed=boc[1]; } } /** print mark on LCD (6 lines). print positions that robot has already visited. */ void print_mark() { int i,j; if( output == LCD ) { LCDSetPos(1,0); for (i=5; i>=0; i--) { for (j=0; j<14; j++) if (mark[i][j]) LCDPutChar('x'); else LCDPutChar('.'); if (i>0) LCDPutChar('\n'); } } else { fprintf(stderr,"MARK\n"); for (i=MAZESIZE-1; i>=0; i--) { for (j=0; j=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'); } } else { 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,"_"); /* top */ else if (wall[i][j][0]==0) fprintf(stderr," "); else fprintf(stderr,"."); } fprintf(stderr,"\n"); } fprintf(stderr,"\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\a"); } } /** 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 */ } } /** 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; i0 and 0 for input=0. */ int sign(float number) { if (number!=0.0) return (int) number/fabs(number); else return 0; } /** Read PSD. Read PSD value for specified sensor 3 times and return median */ int ReadPSD(int side) { int i,val[3]; switch (side) { case RIGHT: for (i=0;i<3;i++) val[i]=PSDGet(psd_right); break; case LEFT: for (i=0;i<3;i++) val[i]=PSDGet(psd_left); break; case MIDDLE: for (i=0;i<3;i++) val[i]=PSDGet(psd_front); break; } if (val[0]2*PSDSIDE) /* wall on left side */ VWSetSpeed(vw,lin_speed,2*c*(act_l-PSDSIDE)); else if (act_l>2*PSDSIDE&&act_r<2*PSDSIDE) /* wall on right side */ VWSetSpeed(vw,lin_speed,2*c*(PSDSIDE-act_r)); else /* no walls */ VWSetSpeed (vw,lin_speed,0); } end_drive=(KEYRead()==KEY3); VWGetPosition(vw,&pos); if (dir%2) /* heading west or east */ pos_diff=fabs(old_pos-pos.y); else /* heading north or south */ pos_diff=fabs(old_pos-pos.x); } while ((pos_diff THRES; left_open = ReadPSD(LEFT) > THRES; right_open = ReadPSD(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) { LCDMenu("Next"," ","STOP"," "); key=KEYGet(); end_drive=(key==KEY3); } if (!end_drive) { LCDMenu(" "," ","STOP"," "); 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 */ } } } else VWSetSpeed(vw,0,0); } /** print shortest distances from start on LCD (6 lines). */ void print_map() { int i,j; if( output == LCD ) { LCDClear(); LCDPutString("Map distances\n"); for (i=5; i>=0; i--) { for (j=0; j<4; j++) LCDPrintf("%3d",map[i][j]); if (i>0) LCDPutChar('\n'); } } else { fprintf(stderr,"MAP\n"); for (i=MAZESIZE-1; i>=0; i--) { for (j=0; j0) 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*M_PI/2.0, rot_speed); /* turn */ VWDriveWait(vw); rob_dir = 0; } } else for (i=0; i