Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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