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.
Fork of BeautifulMemeProject by
programs.cpp
00001 /// PsiSwarm Beautiful Meme Project Source Code 00002 /// Version 0.2 00003 /// James Hilder, Alan Millard, Homero Elizondo, Jon Timmis 00004 /// University of York 00005 00006 // programs.cpp - Various PsiSwarm Programs for Beautiful Meme Project 00007 00008 #include "main.h" 00009 00010 int obstacle_avoidance_threshold = 300; 00011 int robot_avoidance_threshold = 2000; 00012 00013 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00014 /// head_to_bearing_program 00015 char was_turning = 0; 00016 00017 ///The head to bearing program moves towards a given bearing (eg 0 for the beacon or 180 for the opposite wall) and keeps going until an obstacle is detected in front of it 00018 void head_to_bearing_program(int target_bearing) 00019 { 00020 if(step_cycle == 0 || was_turning == 0) { 00021 // Check if we are heading in the right bearing (+- 25 degrees) 00022 int current_bearing = (360 - beacon_heading) % 360; 00023 // Current bearing should range from 0 to 359; target_bearing likewise; check the are within 25 degrees of each other 00024 char bearing_ok = 0; 00025 int lower_bound = target_bearing - 25; 00026 int upper_bound = target_bearing + 25; 00027 if(lower_bound < 0) { 00028 if(current_bearing > (lower_bound + 360) || current_bearing < upper_bound) bearing_ok = 1; 00029 } else if(upper_bound > 359) { 00030 if(current_bearing > lower_bound || current_bearing < (upper_bound - 360)) bearing_ok = 1; 00031 } else if(current_bearing > lower_bound && current_bearing < upper_bound) bearing_ok = 1; 00032 // Check if there is an obstacle in front of us 00033 if((reflected_sensor_data[7] > 1000 || reflected_sensor_data[0] > 1000) && bearing_ok == 1) target_reached = 1; 00034 else { 00035 // Now move forward if we are facing correct bearing, otherwise turn 00036 if(bearing_ok == 1) { 00037 //Check if anything is in front of us to determine speed - if it is, move slowly 00038 int t_time = 6 * BEACON_PERIOD; 00039 float t_speed = 1.0; 00040 if(reflected_sensor_data[7] > 150 || reflected_sensor_data[0] > 150) { 00041 t_time = 4 * BEACON_PERIOD; 00042 t_speed = 0.6; 00043 } 00044 if(reflected_sensor_data[7] > 300 || reflected_sensor_data[0] > 300) { 00045 t_time = 3 * BEACON_PERIOD; 00046 t_speed = 0.4; 00047 } 00048 if(reflected_sensor_data[7] > 500 || reflected_sensor_data[0] > 500) { 00049 t_time = 2 * BEACON_PERIOD; 00050 t_speed = 0.2; 00051 } 00052 time_based_forward(t_speed,t_time,0); 00053 was_turning = 0; 00054 } else { 00055 turn_to_bearing(target_bearing); 00056 was_turning = 1; 00057 } 00058 } 00059 } 00060 } 00061 00062 00063 00064 00065 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00066 /// recharging_program 00067 00068 char recharge_power_check_count = 0; 00069 char battery_low_count = 0; 00070 00071 void recharging_program() 00072 { 00073 switch(recharging_state) { 00074 case 0: 00075 // We are not currently recharging, check the battery state 00076 if(get_battery_voltage() < battery_low_threshold) { 00077 // Battery is below low threshold 00078 battery_low_count ++; 00079 // We don't immediately start recharging routine in case as battery level can fluctuate a little due to load; if we get a low value for 4 continuous timesteps we start recharging routine 00080 if(battery_low_count > 3) { 00081 // Set recharging state to 'looking for charger' 00082 recharging_state = 1; 00083 strcpy(prog_name,"CHARGING PROGRAM"); 00084 set_program_info("HEAD TO BEACON"); 00085 } 00086 } else battery_low_count = 0; 00087 break; 00088 // State 1: Head to beacon [as this is where battery charger is] 00089 case 1: 00090 target_reached = 0; 00091 head_to_bearing_program(0); 00092 if(target_reached == 1) { 00093 recharging_state = 2; 00094 set_program_info("TURN 90 DEGREES"); 00095 } 00096 break; 00097 // Stage 2: Turn 90 degrees to align with charging pads 00098 case 2: 00099 disable_ir_emitters = 1; 00100 time_based_turn_degrees(0.8, 70.0, 1); 00101 recharge_power_check_count = 0; 00102 recharging_state = 3; 00103 break; 00104 // Stage 3: Wait for turn to complete 00105 case 3: 00106 if (time_based_motor_action != 1) { 00107 recharging_state = 4; 00108 set_program_info("CHECK FOR POWER"); 00109 } 00110 break; 00111 // Stage 4: Check if charging 00112 case 4: 00113 recharge_power_check_count++; 00114 if(get_dc_status() == 1) { 00115 recharging_state = 5; 00116 } else { 00117 if(recharge_power_check_count < 10)recharging_state = 6; 00118 else { 00119 recharging_state = 7; 00120 set_program_info("NO POWER - RETRY"); 00121 } 00122 } 00123 break; 00124 // Stage 5: Charging. Wait until threshold voltage exceeded 00125 case 5: 00126 if(get_battery_voltage() > battery_high_threshold) { 00127 set_program_info("LEAVE CHARGER"); 00128 recharging_state = 7; 00129 } else { 00130 char b_voltage[16]; 00131 sprintf(b_voltage,"CHARGE: %1.3fV",get_battery_voltage()); 00132 set_program_info(b_voltage); 00133 } 00134 break; 00135 // Stage 6: We didn't find power, keep turning a couple of degrees at a time a recheck 00136 case 6: 00137 time_based_turn_degrees(0.5,4,1); 00138 recharging_state = 4; 00139 break; 00140 // Stage 7: Charge may be finished. Turn 90 degrees then move away and resume previous program 00141 case 7: 00142 time_based_turn_degrees(0.8, 90.0, 1); 00143 recharging_state = 8; 00144 break; 00145 00146 // Stage 8: Wait for turn to complete 00147 case 8: 00148 if (time_based_motor_action != 1) recharging_state = 9; 00149 break; 00150 // Stage 9: Move away 00151 case 9: 00152 time_based_forward(0.5, 1000000, 1); 00153 recharging_state = 10; 00154 break; 00155 // Stage 10: Wait for move to complete 00156 case 10: 00157 if (time_based_motor_action != 1) recharging_state = 11; 00158 break; 00159 // Stage 11: Check if battery is below low threshold; if it is, start over, else end charge cycle 00160 case 11: 00161 disable_ir_emitters = 0; 00162 if (get_battery_voltage() < battery_low_threshold) { 00163 recharging_state = 1; 00164 } else { 00165 recharging_state = 0; 00166 //Restore name of old program on display 00167 set_program(main_program_state); 00168 } 00169 break; 00170 } 00171 } 00172 00173 00174 00175 00176 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00177 /// curved_walk_with_interaction_program (Alan's Random Walk\Obstacle Avoid and Robot Interaction Program) 00178 00179 enum random_walk_state {random_walk, turn_towards, interact, turn_away, avoid_obstacle}; 00180 enum random_walk_state internal_state = random_walk; 00181 char action_timeout = 0; 00182 char interaction_timeout = 0; 00183 char random_walk_timeout = 0; 00184 float previous_left_motor_speed = 0.5; 00185 float previous_right_motor_speed = 0.5; 00186 00187 void curved_random_walk_with_interaction_program() 00188 { 00189 if(internal_state == random_walk) { 00190 if(interaction_timeout < 4) 00191 interaction_timeout++; 00192 00193 int closest_robot = -1; 00194 unsigned short shortest_distance = 0; 00195 00196 // Check whether there are any other robots within range 00197 for(int i = 0; i < 8; i++) { 00198 if(robots_found[i]) { 00199 if(robots_distance[i] > shortest_distance) { 00200 shortest_distance = robots_distance[i]; 00201 closest_robot = i; 00202 } 00203 } 00204 } 00205 00206 // Turn towards the closest robot 00207 if(closest_robot >= 0 && shortest_distance > 300 && interaction_timeout >= 4) { 00208 time_based_turn_degrees(1, robots_heading[closest_robot], 1); 00209 00210 action_timeout = 0; 00211 internal_state = turn_towards; 00212 char temp_message[17]; 00213 sprintf(temp_message,"FACE ROBOT %d",closest_robot); 00214 set_program_info(temp_message); 00215 } else { // Otherwise, do a random walk 00216 // Check the front sensors for obstacles 00217 if(reflected_sensor_data[0] > obstacle_avoidance_threshold || 00218 reflected_sensor_data[1] > obstacle_avoidance_threshold || 00219 reflected_sensor_data[6] > obstacle_avoidance_threshold || 00220 reflected_sensor_data[7] > obstacle_avoidance_threshold) { 00221 // Ignore the rear sensors when calculating the heading 00222 reflected_sensor_data[2] = 0; 00223 reflected_sensor_data[3] = 0; 00224 reflected_sensor_data[4] = 0; 00225 reflected_sensor_data[5] = 0; 00226 00227 // Turn 180 degrees away from the sensed obstacle 00228 int heading = get_bearing_from_ir_array (reflected_sensor_data) + 180; 00229 00230 // Normalise 00231 heading %= 360; 00232 00233 if(heading < -180) 00234 heading += 360; 00235 00236 if(heading > 180) 00237 heading -= 360; 00238 set_program_info("AVOID OBSTACLE"); 00239 time_based_turn_degrees(1, heading, 1); 00240 00241 action_timeout = 0; 00242 internal_state = turn_away; 00243 } else { 00244 // Change motor speeds every 1s 00245 if(random_walk_timeout >= 2) { 00246 float random_offset = (((float) rand() / (float) RAND_MAX) - 0.5) * 0.5; 00247 00248 float left_motor_speed = previous_left_motor_speed - random_offset; 00249 float right_motor_speed = previous_right_motor_speed + random_offset; 00250 00251 float threshold = 0.25; 00252 00253 if(left_motor_speed < threshold) 00254 left_motor_speed = threshold; 00255 00256 if(right_motor_speed < threshold) 00257 right_motor_speed = threshold; 00258 00259 set_left_motor_speed(left_motor_speed); 00260 set_right_motor_speed(right_motor_speed); 00261 00262 random_walk_timeout = 0; 00263 } 00264 00265 random_walk_timeout++; 00266 } 00267 } 00268 } else if(internal_state == turn_towards) { 00269 if(action_timeout < 4) 00270 action_timeout++; 00271 else { 00272 set_program_info("SAY HELLO"); 00273 vibrate(); 00274 00275 action_timeout = 0; 00276 internal_state = interact; 00277 } 00278 } else if(internal_state == interact) { 00279 if(action_timeout < 4) 00280 action_timeout++; 00281 else { 00282 set_program_info("TURN AROUND"); 00283 time_based_turn_degrees(1, 180, 1); 00284 00285 action_timeout = 0; 00286 internal_state = turn_away; 00287 } 00288 00289 } else if(internal_state == turn_away) { 00290 if(action_timeout < 4) 00291 action_timeout++; 00292 else { 00293 set_program_info("RANDOM WALK"); 00294 interaction_timeout = 0; 00295 internal_state = random_walk; 00296 } 00297 } else if(internal_state == avoid_obstacle) { 00298 if(action_timeout < 4) 00299 action_timeout++; 00300 else 00301 set_program_info("RANDOM WALK"); 00302 internal_state = random_walk; 00303 } 00304 } 00305 00306 00307 00308 00309 00310 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00311 /// straight_random_walk_with_interaction_program 00312 00313 void straight_random_walk_with_interaction_program() 00314 { 00315 00316 } 00317 00318 00319 00320 00321 00322 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00323 /// find_space_program 00324 00325 char prog_debug = 1 ; 00326 float target_wheel_speed; 00327 int random_walk_bearing; 00328 00329 void find_space_program(char bidirectional) 00330 { 00331 // The find_space_program is a continuous turn-move vector program 00332 00333 if(program_run_init == 1) { 00334 // Setup the LEDs to red 00335 set_leds(0x00,0xFF); 00336 set_center_led(1,1); 00337 program_run_init = 0; 00338 random_walk_bearing = rand() % 360; 00339 } 00340 00341 // When step_cycle = 0 we calculate a vector to move to and a target distance 00342 if(step_cycle == 0) { 00343 struct FloatVector target_vector; 00344 target_vector.angle = 0; 00345 target_vector.distance = 0; 00346 // Check for near robots within range 00347 for(int i = 1; i < 8; i++) { 00348 if(robots_found[i]) { 00349 int res_bearing = robots_heading[i]; 00350 res_bearing += 180; 00351 if(res_bearing > 180) res_bearing -= 360; 00352 target_vector = addVector(target_vector,res_bearing,robots_distance[i]); 00353 if(prog_debug) out("Repelled from robot %d at bearing %d, strength %d, resultant b:%f, d:%f\n",i,robots_heading[i],robots_distance[i],target_vector.angle,target_vector.distance); 00354 } 00355 } 00356 if(target_vector.angle!=0){ 00357 set_leds(0xFF,0xFF); 00358 set_center_led(3,1); 00359 } 00360 // Check for obstacles 00361 char obstacle = 0; 00362 int peak_strength = 0; 00363 for(int i=0; i<8; i++){ 00364 if(reflected_sensor_data[i] > peak_strength) peak_strength = reflected_sensor_data[i]; 00365 if(peak_strength > obstacle_avoidance_threshold) obstacle = 1; 00366 } 00367 if(obstacle){ 00368 //Choose new random walk bearing 00369 set_leds(0x00,0xFF); 00370 set_center_led(1,1); 00371 random_walk_bearing = rand() % 360; 00372 int obstacle_bearing = get_bearing_from_ir_array (reflected_sensor_data); 00373 int obs_bearing = obstacle_bearing + 180; 00374 if(obs_bearing > 180) obs_bearing -= 360; 00375 target_vector = addVector(target_vector,obs_bearing,peak_strength); 00376 if(prog_debug) out("Repelled from obstacle at bearing %d, strength %d, resultant b:%f, d:%f\n",obstacle_bearing,peak_strength,target_vector.angle,target_vector.distance); 00377 } 00378 00379 if(target_vector.angle == 0 && target_vector.distance == 0){ 00380 set_leds(0xFF,0x00); 00381 set_center_led(2,1); 00382 random_walk_bearing += 180; 00383 if(random_walk_bearing > 360) random_walk_bearing -= 360; 00384 target_vector.distance = 100; 00385 int current_bearing = 360 - beacon_heading; 00386 //Now work out turn needed to face intended heading 00387 int target_turn = (random_walk_bearing - current_bearing) % 360; 00388 if(target_turn > 180) target_turn -= 360; 00389 if(target_turn < -180) target_turn += 360; 00390 target_vector.angle = target_turn; 00391 if(prog_debug) out("Random walk bearing:%d Current:%d Target:%f\n",random_walk_bearing,current_bearing,target_vector.angle); 00392 } 00393 char wheel_direction = 1; 00394 if(bidirectional){ 00395 // Allow reverse wheel direction 00396 if(target_vector.angle < -90) {target_vector.angle += 180; wheel_direction = 0;} 00397 else if(target_vector.angle > 90) {target_vector.angle -= 180; wheel_direction = 0;} 00398 } 00399 //Now turn to angle 00400 float maximum_turn_angle = get_maximum_turn_angle(BEACON_PERIOD*10); 00401 if(target_vector.angle < 0){ 00402 if(target_vector.angle < -maximum_turn_angle){ 00403 target_vector.angle = -maximum_turn_angle; 00404 target_vector.distance = 100; 00405 } 00406 }else{ 00407 if(target_vector.angle > maximum_turn_angle){ 00408 target_vector.angle = maximum_turn_angle; 00409 target_vector.distance = 100; 00410 } 00411 } 00412 //Set the wheel speed for next action 00413 if(target_vector.distance < 120) target_wheel_speed = 0.25; 00414 else if(target_vector.distance < 240) target_wheel_speed = 0.35; 00415 else if(target_vector.distance < 480) target_wheel_speed = 0.45; 00416 else if(target_vector.distance < 960) target_wheel_speed = 0.55; 00417 else target_wheel_speed = 0.65; 00418 if(wheel_direction == 0) target_wheel_speed = 0-target_wheel_speed; 00419 00420 //Now turn... 00421 time_based_turn_degrees(1, (int) target_vector.angle, 1); 00422 } else time_based_forward(target_wheel_speed,BEACON_PERIOD*6,0); 00423 } 00424 00425 00426 00427 00428 00429 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00430 /// clustering_program 00431 00432 00433 void clustering_program(char invert, char bidirectional) 00434 { 00435 // The clustering program is a continuous turn-move vector program 00436 // In normal mode (invert = 0) it is attracted to same-group robots and repels opposite-group, walls and very close same-group robots 00437 // In invert mode (invert = 1) it avoids same-group and is attracted to opposite group 00438 00439 // Store the robot group: even robots (0) are green, odd robots (1) are red 00440 char group = robot_id % 2; 00441 00442 if(program_run_init == 1) { 00443 // Setup the LEDs based on robot_id 00444 if(group == 0) { 00445 set_leds(0xFF,0x00); 00446 set_center_led(2,1); 00447 } else { 00448 set_leds(0x00,0xFF); 00449 set_center_led(1,1); 00450 } 00451 program_run_init = 0; 00452 random_walk_bearing = rand() % 360; 00453 } 00454 00455 // When step_cycle = 0 we calculate a vector to move to and a target distance 00456 if(step_cycle == 0) { 00457 char avoiding_friend = 0; 00458 struct FloatVector target_vector; 00459 target_vector.angle = 0; 00460 target_vector.distance = 0; 00461 // Check for near robots within range 00462 for(int i = 1; i < 8; i++) { 00463 if(robots_found[i]) { 00464 // Determine if the robot is an attractor or a repellor 00465 char attract = 0; 00466 if((invert==0 && ((i%2) == group)) || (invert==1 && ((i%2) != group))) attract = 1; 00467 // Avoid very close attractors to stop collisions 00468 if(attract==1 && robots_distance[i] > robot_avoidance_threshold) {attract = 0; avoiding_friend = 1;} 00469 int res_bearing = robots_heading[i]; 00470 if(attract==0){ 00471 res_bearing += 180; 00472 if(res_bearing > 180) res_bearing -= 360; 00473 } 00474 target_vector = addVector(target_vector,res_bearing,robots_distance[i]); 00475 if(prog_debug) { 00476 if(attract) { 00477 out("Attracted to robot %d at bearing %d, strength %d, resultant b:%f, d:%f\n",i,robots_heading[i],robots_distance[i],target_vector.angle,target_vector.distance); 00478 } else { 00479 out("Repelled from robot %d at bearing %d, strength %d, resultant b:%f, d:%f\n",i,robots_heading[i],robots_distance[i],target_vector.angle,target_vector.distance); 00480 } 00481 } 00482 } 00483 } 00484 00485 // Check for obstacles 00486 char obstacle = 0; 00487 int peak_strength = 0; 00488 for(int i=0; i<8; i++){ 00489 if(reflected_sensor_data[i] > peak_strength) peak_strength = reflected_sensor_data[i]; 00490 if(peak_strength > obstacle_avoidance_threshold) obstacle = 1; 00491 } 00492 if(obstacle){ 00493 //Choose new random walk bearing 00494 random_walk_bearing = rand() % 360; 00495 int obstacle_bearing = get_bearing_from_ir_array (reflected_sensor_data); 00496 int obs_bearing = obstacle_bearing + 180; 00497 if(obs_bearing > 180) obs_bearing -= 360; 00498 target_vector = addVector(target_vector,obs_bearing,peak_strength); 00499 if(prog_debug) out("Repelled from obstacle at bearing %d, strength %d, resultant b:%f, d:%f\n",obstacle_bearing,peak_strength,target_vector.angle,target_vector.distance); 00500 } 00501 if(target_vector.angle == 0 && target_vector.distance == 0){ 00502 //I have nothing attracting me so persist with random walk: with a 2% chance pick new bearing 00503 if(rand() % 100 > 97) random_walk_bearing = rand() % 360; 00504 target_vector.distance = 100; 00505 int current_bearing = 360 - beacon_heading; 00506 //Now work out turn needed to face intended heading 00507 int target_turn = (random_walk_bearing - current_bearing) % 360; 00508 if(target_turn > 180) target_turn -= 360; 00509 if(target_turn < -180) target_turn += 360; 00510 target_vector.angle = target_turn; 00511 if(prog_debug) out("Random walk bearing:%d Current:%d Target:%f\n",random_walk_bearing,current_bearing,target_vector.angle); 00512 } 00513 char wheel_direction = 1; 00514 if(bidirectional){ 00515 // Allow reverse wheel direction 00516 if(target_vector.angle < -90) {target_vector.angle += 180; wheel_direction = 0;} 00517 else if(target_vector.angle > 90) {target_vector.angle -= 180; wheel_direction = 0;} 00518 } 00519 //Now turn to angle 00520 float maximum_turn_angle = get_maximum_turn_angle(BEACON_PERIOD*10); 00521 if(target_vector.angle < 0){ 00522 if(target_vector.angle < -maximum_turn_angle){ 00523 target_vector.angle = -maximum_turn_angle; 00524 target_vector.distance = 100; 00525 } 00526 }else{ 00527 if(target_vector.angle > maximum_turn_angle){ 00528 target_vector.angle = maximum_turn_angle; 00529 target_vector.distance = 100; 00530 } 00531 } 00532 if(avoiding_friend) target_vector.distance = 100; 00533 //Set the wheel speed for next action 00534 if(target_vector.distance < 120) target_wheel_speed = 0.25; 00535 else if(target_vector.distance < 240) target_wheel_speed = 0.35; 00536 else if(target_vector.distance < 480) target_wheel_speed = 0.5; 00537 else if(target_vector.distance < 960) target_wheel_speed = 0.65; 00538 else target_wheel_speed = 0.85; 00539 if(wheel_direction == 0) target_wheel_speed = 0-target_wheel_speed; 00540 00541 //Now turn... 00542 time_based_turn_degrees(1, (int) target_vector.angle, 1); 00543 } else time_based_forward(target_wheel_speed,BEACON_PERIOD*7,0); 00544 } 00545 00546 00547 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00548 /// stop_program - Pauses robot 00549 00550 void stop_program() 00551 { 00552 if(program_run_init == 1) { 00553 save_led_states(); 00554 set_leds(0,0); 00555 set_center_led(0,0); 00556 stop(); 00557 program_run_init = 0; 00558 } 00559 } 00560 00561 00562 00563 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00564 /// tag_game_program 00565 00566 enum tag_game_role {hunter, hunted}; 00567 enum tag_game_role role; 00568 int tag_distance = 500; 00569 char hunters[8]; // Memory of which robots have come within tag distance - assumed to be hunters 00570 Timeout hunter_timeout; // Timeout before robots switch back to being hunted 00571 char initial_hunter = 2; // Robot with this ID is permanently a hunter 00572 00573 // Resets hunter robots to hunted after timeout 00574 void role_reset() 00575 { 00576 role = hunted; 00577 set_program_info("HUNTED"); 00578 // Clear memory of hunters 00579 for(int i = 0; i < 8; i++) 00580 hunters[i] = 0; 00581 } 00582 00583 void tag_game_program() 00584 { 00585 // Initialisation 00586 if(program_run_init == 1) { 00587 00588 // Set robot roles 00589 if(robot_id == initial_hunter){ 00590 role = hunter; 00591 set_program_info("FIRST HUNTER"); 00592 } 00593 else { 00594 role = hunted; 00595 set_program_info("HUNTED"); 00596 } 00597 // Clear memory of hunters 00598 for(int i = 0; i < 8; i++) 00599 hunters[i] = 0; 00600 00601 program_run_init = 0; 00602 } 00603 00604 // Bias forward movement 00605 float left_motor_speed = 0.5; 00606 float right_motor_speed = 0.5; 00607 00608 // Check the front sensors for obstacles 00609 if(reflected_sensor_data[0] > obstacle_avoidance_threshold || 00610 reflected_sensor_data[1] > obstacle_avoidance_threshold || 00611 reflected_sensor_data[6] > obstacle_avoidance_threshold || 00612 reflected_sensor_data[7] > obstacle_avoidance_threshold) 00613 { 00614 // Ignore the rear sensors when calculating the heading 00615 reflected_sensor_data[2] = 0; 00616 reflected_sensor_data[3] = 0; 00617 reflected_sensor_data[4] = 0; 00618 reflected_sensor_data[5] = 0; 00619 00620 // Get heading of sensed obstacle 00621 int heading = get_bearing_from_ir_array(reflected_sensor_data); 00622 00623 // Turn in opposite direction 00624 if(heading > 0 && heading < 90) 00625 { 00626 left_motor_speed -= 0.75; 00627 right_motor_speed += 0.5; 00628 } 00629 else if(heading < 0 && heading > -90) 00630 { 00631 left_motor_speed += 0.5; 00632 right_motor_speed -= 0.75; 00633 } 00634 00635 set_left_motor_speed(left_motor_speed); 00636 set_right_motor_speed(right_motor_speed); 00637 00638 // Return early - obstacle avoidance is the top priority 00639 return; 00640 } 00641 00642 int closest_robot = -1; 00643 unsigned short shortest_distance = 0; 00644 00645 // Check whether there are any other robots within range 00646 for(int i = 0; i < 8; i++) 00647 { 00648 if(robots_found[i]) 00649 { 00650 if(robots_distance[i] > shortest_distance) 00651 { 00652 shortest_distance = robots_distance[i]; 00653 closest_robot = i; 00654 } 00655 } 00656 } 00657 00658 // If the closest robot is within tag distance, this robot has been tagged 00659 if(shortest_distance > tag_distance) 00660 { 00661 // Switch role to hunter 00662 if(role == hunted) 00663 { 00664 role = hunter; 00665 set_program_info("NEW HUNTER"); 00666 // Reset to hunted after 10 seconds 00667 hunter_timeout.attach(&role_reset, 10); 00668 } 00669 00670 // Keep a record of which robot tagged them, so hunters do not chase hunters 00671 // Unless they are the initial hunter, who is aggresive towards everyone 00672 if(robot_id != initial_hunter) 00673 hunters[closest_robot] = 1; 00674 } 00675 00676 if(role == hunter) 00677 { 00678 // Set LEDS to red 00679 set_leds(0x00, 0xFF); 00680 set_center_led(1, 1); 00681 00682 if(closest_robot >= 0 && !hunters[closest_robot]) // Ignore other hunters 00683 { 00684 // Turn towards closest hunted robot (unless it is straight ahead, or behind) 00685 if(robots_heading[closest_robot] > 22.5 && robots_heading[closest_robot] < 90) 00686 { 00687 left_motor_speed += 0.5; 00688 right_motor_speed -= 0.5; 00689 } 00690 else if(robots_heading[closest_robot] < -22.5 && robots_heading[closest_robot] > -90) 00691 { 00692 left_motor_speed -= 0.5; 00693 right_motor_speed += 0.5; 00694 } 00695 } 00696 00697 set_left_motor_speed(left_motor_speed); 00698 set_right_motor_speed(right_motor_speed); 00699 } 00700 else // role == hunted 00701 { 00702 // Set LEDs to green 00703 set_leds(0xFF, 0x00); 00704 set_center_led(2, 1); 00705 00706 // Avoid everyone 00707 if(closest_robot >= 0) 00708 { 00709 // Turn away from closest robot 00710 if(robots_heading[closest_robot] >= 0 && robots_heading[closest_robot] < 90) 00711 { 00712 left_motor_speed -= 0.5; 00713 right_motor_speed += 0.5; 00714 } 00715 else if(robots_heading[closest_robot] < 0 && robots_heading[closest_robot] > -90) 00716 { 00717 left_motor_speed += 0.5; 00718 right_motor_speed -= 0.5; 00719 } 00720 } 00721 00722 set_left_motor_speed(left_motor_speed); 00723 set_right_motor_speed(right_motor_speed); 00724 } 00725 } 00726 00727 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00728 /// flocking_program 00729 00730 void flocking_program() 00731 { 00732 char display_line[16] = " "; 00733 int average_heading = 0; 00734 int number_of_neighbours = 0; 00735 int number_of_flocking_headings = 0; 00736 int target_heading = 0; 00737 int angles = 0; 00738 int ir_sensor_threshold = 600; 00739 int sensors_activated = 0; 00740 00741 struct FloatVector obstacle_vector; 00742 obstacle_vector.angle = 0; 00743 obstacle_vector.distance = 0; 00744 00745 struct FloatVector cohesion_vector; 00746 cohesion_vector.angle = 0; 00747 cohesion_vector.distance = 0; 00748 00749 for(int i = 0; i < 8; i++) 00750 { 00751 if(reflected_sensor_data[i] > ir_sensor_threshold) 00752 { 00753 obstacle_vector = addVector(obstacle_vector, get_bearing_from_ir_array(reflected_sensor_data), reflected_sensor_data[i]); 00754 sensors_activated++; 00755 } 00756 00757 if(robots_found[i]) 00758 { 00759 // -180 degrees is reserved for "no byte received" 00760 if(flocking_headings[i] != -180) 00761 { 00762 average_heading += flocking_headings[i]; 00763 number_of_flocking_headings++; 00764 } 00765 00766 cohesion_vector = addVector(cohesion_vector, robots_heading[i], robots_distance[i]); 00767 number_of_neighbours++; 00768 } 00769 } 00770 00771 cohesion_vector.distance /= number_of_neighbours; // Normalise 00772 obstacle_vector.distance /= sensors_activated; // Normalise 00773 00774 int obstacle_avoidance_angle; 00775 00776 if(sensors_activated > 0) 00777 { 00778 obstacle_avoidance_angle = obstacle_vector.angle + 180; 00779 00780 if(obstacle_avoidance_angle > 180) 00781 obstacle_avoidance_angle -= 360; 00782 if(obstacle_avoidance_angle < -180) 00783 obstacle_avoidance_angle += 360; 00784 00785 target_heading += obstacle_avoidance_angle; 00786 angles++; 00787 } 00788 00789 int cohesion_angle; 00790 00791 // Don't bother performing cohesion if robots are already close enough 00792 if(number_of_neighbours > 0 && cohesion_vector.distance < 200) 00793 { 00794 cohesion_angle = cohesion_vector.angle; 00795 00796 if(cohesion_angle > 180) 00797 cohesion_angle -= 360; 00798 if(cohesion_angle < -180) 00799 cohesion_angle += 360; 00800 00801 target_heading += cohesion_angle; 00802 angles++; 00803 } 00804 00805 int relative_flocking_heading; 00806 00807 if(number_of_flocking_headings > 0) 00808 { 00809 average_heading /= number_of_flocking_headings; 00810 00811 relative_flocking_heading = beacon_heading - average_heading; 00812 00813 if(relative_flocking_heading > 180) 00814 relative_flocking_heading -= 360; 00815 if(relative_flocking_heading < -180) 00816 relative_flocking_heading += 360; 00817 00818 target_heading += relative_flocking_heading; 00819 angles++; 00820 } 00821 00822 if(angles > 0) 00823 target_heading /= angles; // Calculate average 00824 00825 float left_motor_speed = 0.25; 00826 float right_motor_speed = 0.25; 00827 00828 if(target_heading > 22.5) 00829 right_motor_speed *= -1; 00830 else if(target_heading < -22.5) 00831 left_motor_speed *= -1; 00832 00833 set_left_motor_speed(left_motor_speed); 00834 set_right_motor_speed(right_motor_speed); 00835 00836 // Only transmit beacon heading if the beacon is visible 00837 if(beacon_found) 00838 { 00839 float degrees_per_value = 256.0f / 360.0f; 00840 char beacon_heading_byte = (beacon_heading + 180) * degrees_per_value; // Convert beacon heading from +/-180 degrees into a single byte value 00841 00842 bt.putc(beacon_heading_byte); 00843 } 00844 00845 sprintf(display_line, "%d %d %d %d", target_heading, obstacle_avoidance_angle, cohesion_angle, relative_flocking_heading); 00846 00847 set_program_info(display_line); 00848 } 00849 00850 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00851 /// generic_program - Framework for building typical programs 00852 00853 void generic_program() 00854 { 00855 // Do something on the first run of a program 00856 if(program_run_init == 1) { 00857 // Initialisation code goes here... 00858 00859 program_run_init = 0; 00860 } 00861 00862 // step_cycle is either zero or one; use this avoid estimating bearings on the cycle after a turn (as the results will be skewed by the turn) 00863 if(step_cycle == 0) { 00864 // Do something based on sensor data (eg turn) 00865 } else { 00866 // Do something ignoring sensor data (eg move, or nothing!) 00867 } 00868 00869 }
Generated on Fri Jul 15 2022 08:26:10 by
1.7.2
