EE149
/
FinalProject
Final Project files for mBed development.
Embed:
(wiki syntax)
Show/hide line numbers
main.c
00001 /** 00002 * @file driver.c 00003 * @brief Primary control logic for robot. 00004 * 00005 * @author John Wilkey 00006 * @author Alec Guertin 00007 * @author Chester Chu 00008 */ 00009 #include "main.h" 00010 00011 m3pi pi; /**< m3pi Object for all control operations. */ 00012 Timer timer; /**< Timer used to wait in timerWait. */ 00013 DigitalIn start_button(p21); /**< Pi start button input on mBed pin 32 */ 00014 int draw; /**< Boolean for drawing/moving. */ 00015 00016 /* 4 mBed onboard LEDs */ 00017 DigitalOut oled_1(LED1), oled_2(LED2), oled_3(LED3), oled_4(LED4); 00018 00019 /* 8 LEDs driven from mBed digital outs. */ 00020 DigitalOut pin13(p13), pin14(p14), pin15(p15), pin16(p16), 00021 pin17(p17), pin18(p18), pin19(p19), pin20(p20); 00022 00023 /* Local File System */ 00024 LocalFileSystem local("local"); 00025 00026 /* States specifying the robot's behavior. */ 00027 enum RobotState { 00028 ERROR, 00029 LINE_CAL, 00030 FIND_CORNER, 00031 REV_TURN, 00032 DRAW_INIT, 00033 PARSE, 00034 TURN, 00035 MOVE, 00036 DRAW, 00037 FINISHED, 00038 }; 00039 00040 /** @brief Entry point. Main loop. */ 00041 int main() 00042 { 00043 Timer caltimer; 00044 FILE *ps_file; 00045 RobotState state, last_state; 00046 double dist; 00047 float delta_a, angle, cal_time, pos, last_pos; 00048 size_t bytes_read; 00049 int corner, err, init, x, y, last_x, last_y, dim_x, dim_y, offset, right_found; 00050 char instbuf[INST_BUF_SIZE]; 00051 char *cur, *next; 00052 angle = 0; 00053 x = 0; 00054 y = 0; 00055 last_x = 0; 00056 last_y = 0; 00057 bytes_read = 0; 00058 offset = 0; 00059 init = 0; 00060 right_found = 0; 00061 delta_a = 0; 00062 angle = 0; 00063 cal_time = 0; 00064 pos = 0; 00065 last_pos = 0; 00066 cur = NULL; 00067 next = NULL; 00068 ps_file = NULL; 00069 caltimer = Timer(); 00070 00071 /* 00072 * File open and buffer setup. Begin reading instructions and 00073 * moving robot. Refill buffer after each instruction. 00074 */ 00075 state = LINE_CAL; 00076 last_state = LINE_CAL; 00077 while (1) { 00078 switch (state) { 00079 00080 // Calibrate the m3pi line sensors 00081 case LINE_CAL: 00082 pi.sensor_auto_calibrate(); 00083 timerWait(0.2); 00084 last_state = state; 00085 state = FIND_CORNER; 00086 break; 00087 00088 // Find a corner of the frame 00089 case FIND_CORNER: 00090 last_state = state; 00091 // Corner we are looking for specified by right_found 00092 // If we already found the right corner, measure frame 00093 if (right_found) { 00094 caltimer.start(); 00095 } 00096 corner = find_corner(1-right_found); 00097 if (!corner) { 00098 state = ERROR; 00099 break; 00100 } 00101 if (right_found) { 00102 caltimer.stop(); 00103 cal_time = caltimer.read_ms(); 00104 } 00105 state = REV_TURN; 00106 break; 00107 00108 // Reverse robot to face other corner of frame 00109 case REV_TURN: 00110 last_state = state; 00111 if (right_found) { 00112 right(HALF_TURN); 00113 state = DRAW_INIT; 00114 } else { 00115 left(HALF_TURN); 00116 state = FIND_CORNER; 00117 right_found = 1; 00118 } 00119 break; 00120 00121 // Setup for drawing stage 00122 case DRAW_INIT: 00123 // Backup to start at (0,0) 00124 timerWait(0.2); 00125 backward(400); 00126 last_state = state; 00127 00128 // Open the instructions file 00129 ps_file = fopen("/local/control.ps", "r"); 00130 if (ps_file == NULL) { 00131 state = ERROR; 00132 break; 00133 } 00134 00135 // Read start of file into buffer 00136 memset(instbuf, 0, INST_BUF_SIZE); 00137 bytes_read = fread(instbuf, sizeof(char), INST_BUF_SIZE-1, ps_file); 00138 if (bytes_read == 0) { 00139 state = ERROR; 00140 break; 00141 } 00142 00143 // Find dimensions of PS instructions 00144 err = sscanf(instbuf, "%d/%d", &dim_x, &dim_y); 00145 if (err != 2) { 00146 state = ERROR; 00147 break; 00148 } 00149 cur = strchr(instbuf, '\n'); 00150 cur++; 00151 offset = instbuf+INST_BUF_SIZE-cur-1; 00152 memcpy(instbuf, cur, offset); 00153 state = PARSE; 00154 break; 00155 00156 // Retrieve the next instruction 00157 // Update robot vars to give desired position 00158 case PARSE: 00159 // Parsing uses in place buffer 00160 // next instruction is at start of buffer 00161 last_state = state; 00162 if (init) { 00163 // Advance to next instruction 00164 next = strchr(cur, '\n'); 00165 if (next == NULL) { 00166 state = ERROR; 00167 break; 00168 } 00169 cur = next+1; 00170 offset = instbuf+INST_BUF_SIZE-cur-1; 00171 memcpy(instbuf, cur, offset); 00172 } 00173 init = 1; 00174 00175 memset(instbuf+offset, 0, INST_BUF_SIZE-offset); 00176 bytes_read = fread(instbuf+offset, sizeof(char), INST_BUF_SIZE-1-offset, ps_file); 00177 if (instbuf[0] == '\0') { 00178 pen_up(); 00179 state = FINISHED; 00180 break; 00181 } 00182 00183 // Update robot position 00184 last_x = x; 00185 last_y = y; 00186 00187 // Get next instruction 00188 cur = instbuf; 00189 err = retrieve_inst(instbuf, &x, &y, &draw); 00190 if (err == 0) { 00191 state = ERROR; 00192 break; 00193 } else { 00194 state = TURN; 00195 break; 00196 } 00197 00198 // Move angle needed to reach desired position 00199 case TURN: 00200 last_state = state; 00201 00202 // Computed necessary angle 00203 delta_a = compute_turn_angle(last_x, last_y, x, y, angle); 00204 00205 // Update robot angle 00206 angle += delta_a; 00207 if (angle >= FULL_TURN) { 00208 angle -= FULL_TURN; 00209 } 00210 if (angle <= -FULL_TURN) { 00211 angle += FULL_TURN; 00212 } 00213 00214 // Move desired angle 00215 left(delta_a); 00216 if (draw) { 00217 state = DRAW; 00218 break; 00219 } else { 00220 state = MOVE; 00221 break; 00222 } 00223 00224 // Move to desired position while drawing 00225 case DRAW: 00226 // Compute Euclidean distance between points 00227 dist = fabs(distance(last_x, last_y, x, y)); 00228 pen_down(); 00229 // Move desired distance 00230 forward(CAL_FACTOR*cal_time*(dist/(double)dim_x)); 00231 pen_up(); 00232 last_state = state; 00233 state = PARSE; 00234 break; 00235 00236 // Move to desired position w/o drawing 00237 // (lifting pen and starting somewhere else) 00238 case MOVE: 00239 // Compute Euclidean distance 00240 dist = fabs(distance(last_x, last_y, x, y)); 00241 // Move desired distance 00242 forward(CAL_FACTOR*cal_time*(dist/(double)dim_x)); 00243 last_state = state; 00244 state = PARSE; 00245 break; 00246 00247 // Done drawing - alert user 00248 case FINISHED: 00249 pi.stop(); 00250 pen_up(); 00251 robot_printf(0, "done"); 00252 while(1); 00253 00254 // Error - alert user 00255 case ERROR: 00256 pi.stop(); 00257 pen_up(); 00258 robot_printf(0, "E:%d", last_state); 00259 while(1); 00260 00261 // Unrecognized state - go to ERROR 00262 default: 00263 last_state = state; 00264 state = ERROR; 00265 break; 00266 } 00267 } 00268 } 00269 00270 float compute_turn_angle(int last_x, int last_y, int x, int y, float angle) 00271 { 00272 int delta_x, delta_y; 00273 float theta, delta_a; 00274 delta_x = x-last_x; 00275 delta_y = y-last_y; 00276 if (delta_y == 0) { 00277 if (delta_x < 0) { 00278 theta = HALF_TURN; 00279 } else { 00280 theta = 0; 00281 } 00282 } else if (delta_x == 0) { 00283 if (delta_y < 0) { 00284 theta = -QUARTER_TURN; 00285 } else { 00286 theta = QUARTER_TURN; 00287 } 00288 } else { 00289 theta = atan(((double) delta_y)/((double) delta_x)); 00290 theta *= RAD_TO_DEG; 00291 } 00292 if (delta_x < 0 && delta_y > 0) { 00293 theta += HALF_TURN; 00294 } 00295 delta_a = theta-angle; 00296 00297 if (delta_x < 0 && delta_y < 0) { 00298 delta_a += HALF_TURN; 00299 } 00300 00301 if (delta_a > HALF_TURN) { 00302 delta_a -= FULL_TURN; 00303 } else if (delta_a < -HALF_TURN) { 00304 delta_a = FULL_TURN + delta_a; 00305 } 00306 return delta_a; 00307 } 00308 00309 void robot_printf(int line, const char *format, ...) 00310 { 00311 char buf[18]; 00312 va_list args; 00313 pi.cls(); 00314 pi.locate(0,line); 00315 va_start(args, format); 00316 vsprintf(buf, format, args); 00317 pi.printf("%s", buf); 00318 va_end(args); 00319 } 00320 00321 float distance(int x1, int y1, int x2, int y2) 00322 { 00323 return sqrt(pow((double) (x2-x1),2) + pow((double) (y2-y1), 2)); 00324 } 00325 00326 void find_line() 00327 { 00328 float pos, pos1; 00329 pi.forward(DRIVE_SPEED); 00330 pos1 = pi.line_position(); 00331 pos = pos1; 00332 while (fabs(pos1-pos) < 0.1 || pos == -1) { 00333 pos = pi.line_position(); 00334 robot_printf(0, "%f", pos); 00335 } 00336 robot_printf(0, "f:%f", pos); 00337 pi.stop(); 00338 } 00339 00340 int find_corner(int left) 00341 { 00342 float pos; 00343 float threshold = CORNER_THRESHOLD; 00344 if (left) { 00345 threshold *= -1; 00346 } 00347 do { 00348 pos = pi.line_position(); 00349 if(pos > CORRECTION_THRESHOLD) { 00350 pi.right_motor(CAL_SPEED); 00351 pi.left_motor(CAL_SPEED-CORRECTION_SPEED); 00352 } else if(pos < -CORRECTION_THRESHOLD) { 00353 pi.left_motor(CAL_SPEED); 00354 pi.right_motor(CAL_SPEED-CORRECTION_SPEED); 00355 } else { 00356 pi.right_motor(CAL_SPEED); 00357 pi.left_motor(CAL_SPEED); 00358 } 00359 robot_printf(0, "Pos: %f", pos); 00360 } while(pos != -1 && ((left && pos > threshold) || (!left && pos < threshold))); 00361 pi.stop(); 00362 if(pos == -1) { 00363 oled_1 = 1; 00364 return 0; 00365 } 00366 return 1; 00367 } 00368 00369 int retrieve_inst(char *buf, int *x, int *y, int *draw) 00370 { 00371 int matches; 00372 char *srch; 00373 matches = sscanf(buf, "%d %d", x, y); 00374 if (matches != 2) { 00375 robot_printf(0, "nomatch"); 00376 return 0; 00377 } 00378 srch = strchr(buf, ' '); 00379 srch++; 00380 srch = strchr(srch, ' '); 00381 srch++; 00382 if (srch[0] == 'm') { 00383 *draw = 0; 00384 } else if (srch[0] == 'l') { 00385 *draw = 1; 00386 } else { 00387 robot_printf(0, "%.8s", srch); 00388 return 0; 00389 } 00390 return 1; 00391 } 00392 00393 void forward(int amt) 00394 { 00395 Timer t; 00396 float ms = 0; 00397 float last_ms = 0; 00398 robot_printf(0, "Fwd %d", amt); 00399 t.start(); 00400 pi.left_motor(DRIVE_SPEED+.002); 00401 pi.right_motor(DRIVE_SPEED); 00402 ms = t.read_ms(); 00403 while(ms < amt) { 00404 if (ms-last_ms > 500) { 00405 t.stop(); 00406 right(1.5); 00407 last_ms = ms; 00408 t.start(); 00409 pi.left_motor(DRIVE_SPEED+.002); 00410 pi.right_motor(DRIVE_SPEED); 00411 } 00412 ms = t.read_ms(); 00413 } 00414 pi.stop(); 00415 } 00416 00417 void backward(int amt) 00418 { 00419 Timer t; 00420 t.start(); 00421 pi.backward(.5*DRIVE_SPEED); 00422 while(t.read_ms() < amt); 00423 pi.stop(); 00424 } 00425 00426 void left(float deg) 00427 { 00428 Timer t; 00429 deg += DEGREE_CORRECTION; 00430 if(deg < 0) { 00431 return right(-1*deg); 00432 } 00433 float amt = (((float)deg)/FULL_TURN)*TIME_FACT*1000; 00434 pi.left(TURN_SPEED); 00435 t.start(); 00436 while(t.read_us() < amt); 00437 pi.stop(); 00438 } 00439 00440 void right(float deg) 00441 { 00442 Timer t; 00443 deg += DEGREE_CORRECTION; 00444 if(deg < 0) { 00445 return left(-1*deg); 00446 } 00447 float amt = ((((float)deg)/FULL_TURN)*TIME_FACT*1000); 00448 t.start(); 00449 pi.right(TURN_SPEED); 00450 while(t.read_us() < amt); 00451 pi.stop(); 00452 } 00453 00454 void timerWait(float seconds) 00455 { 00456 Timer t; 00457 t.start(); 00458 while(t.read_us() < 1000000*seconds); 00459 } 00460 00461 void pen_down() 00462 { 00463 oled_3 = 1; 00464 } 00465 00466 void pen_up() 00467 { 00468 oled_3 = 0; 00469 }
Generated on Mon Jul 18 2022 15:37:44 by 1.7.2