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
beacon.cpp
00001 /// PsiSwarm Beautiful Meme Project Source Code 00002 /// Version 0.1 00003 /// James Hilder, Alan Millard, Homero Elizondo, Jon Timmis 00004 /// University of York 00005 00006 // beacon.cpp - Functions for detecting the beacon and taking IR readings of the robots 00007 00008 #include "main.h" 00009 00010 int pulse_step = 1; //Pulse-step corresponds to which timeslot (0-9) is currently active, where beacon=0 and robots=2-8 00011 int low_threshold; //Set to be 2x mean background IR 00012 int beacon_threshold; //Set to be 4x mean background IR 00013 unsigned short ir_sensor_data[9][8]; // The raw sensor data from all 9x 50ms sample windows 00014 Ticker ir_sample_ticker; // Ticker for the IR data sampling and processing; runs every 50ms in middle of timeslot 00015 Ticker ir_emitter_ticker; // Ticker for turning on the IR emitters; runs every 50ms near start of timeslot 00016 Timeout ir_emitter_timeout; // Timeout for turning off the IR emitters after 40ms 00017 Timer beacon_debug_timer; // Timer for debug information only [remove later?] 00018 00019 char show_ir_debug_info = 0; // Set to 1 to display (via PC) the list of IR readings & visible robots every timestep 00020 00021 /// The locate beacon function samples the IR radiation from all 8 side sensors over a period of 1 second in [BEACON_PERIOD / 2.5] (20ms) blocks. 00022 /// The infrared beacon is set to give a 50ms burst of IR every 500ms. We should thus see in the sampled radiation 2 blocks 00023 /// of samples, 2 or 3 samples in duration, when a significant peak occurs; the blocks should be 25 samples apart. 00024 void locate_beacon() 00025 { 00026 int sample_period = (BEACON_PERIOD * 2) / 5; 00027 out("1) Searching for IR beacon..."); 00028 unsigned short samples[50][9]; 00029 Timer beacon_timer; 00030 beacon_timer.start(); 00031 int offset = 0; 00032 //This loop samples the background IR values at 50Hz for 1 second and stores in an array 00033 for(int i=0; i<50; i++) { 00034 store_background_raw_ir_values (); 00035 if(i%2 == 0){ 00036 set_center_led(1, 0.5); 00037 set_leds(0xAA,0x55); 00038 }else{ 00039 set_center_led(2, 0.5); 00040 set_leds(0x55,0xAA); 00041 } 00042 samples[i][8]=0; 00043 for(int j=0; j<8; j++) { 00044 samples[i][j] = get_background_raw_ir_value(j); 00045 samples[i][8] += get_background_raw_ir_value(j); 00046 } 00047 offset+=sample_period; 00048 while(beacon_timer.read_us() < offset) {} 00049 } 00050 00051 //Print values: for testing [comment out] 00052 /* 00053 for(int i=0; i<50; i++) { 00054 out("IR %d:",i); 00055 for(int j=0; j<8; j++) { 00056 out("[%d:%d]",j,samples[i][j]); 00057 } 00058 out(" [SUM:%d]\n",samples[i][8]); 00059 } 00060 */ 00061 00062 //Bubble sort sums to find (6) highest values 00063 unsigned short sorted_array[50]; 00064 for(int i=0; i<50; i++) { 00065 sorted_array[i]=samples[i][8]; 00066 } 00067 for (int c = 0 ; c < 49; c++) { 00068 for (int d = 0 ; d < (50-c-1); d++) { 00069 if (sorted_array[d] > sorted_array[d+1]) { 00070 unsigned short swap = sorted_array[d]; 00071 sorted_array[d] = sorted_array[d+1]; 00072 sorted_array[d+1] = swap; 00073 } 00074 } 00075 } 00076 00077 //Print sorted values: for testing [comment out] 00078 /* 00079 out("Sorted values:"); 00080 for (int c = 0 ; c < 50 ; c++ ) { 00081 out("%d", sorted_array[c]); 00082 if(c<49)out(","); 00083 } 00084 out("\n"); 00085 */ 00086 00087 // Calculate mean background sum value by looking at 44 lowest sum values 00088 int background_mean = 0; 00089 for(int i=0;i<44;i++)background_mean += sorted_array[i]; 00090 background_mean /= 44; 00091 00092 //out("Background mean value: %d\n",background_mean); 00093 00094 //Our beacon threshold will be 4x the background mean value; find all instances where this occurs 00095 low_threshold = background_mean * 2; 00096 beacon_threshold = background_mean * 4; 00097 char beacon_detected_indices[50]; 00098 for(int i=0;i<50;i++){ 00099 if(samples[i][8] > beacon_threshold) beacon_detected_indices[i]=1; 00100 else beacon_detected_indices[i]=0; 00101 } 00102 //Count and display matches 00103 int beacon_detected_count = 0; 00104 //char output_string[251] = ""; 00105 for(int i=0;i<50;i++){ 00106 if(beacon_detected_indices[i] == 1){ 00107 beacon_detected_count++; 00108 // char index_string[6]; 00109 // sprintf(index_string,"[%d],",i); 00110 // strcat(output_string,index_string); 00111 } 00112 } 00113 //out("%d samples are above threshold:%s\n",beacon_detected_count,output_string); 00114 00115 //We will use this array to store average values for each sensor when the beacon is detected 00116 unsigned short beacon_averages[8]; 00117 char beacon_averages_count = 0; 00118 for(int i=0;i<8;i++)beacon_averages[i]=0; 00119 00120 //Now determine if the beacon is correctly found: must adhere to a set of rules 00121 //Firstly, we should have not less than 4 and not more than 6 positive matches 00122 if(beacon_detected_count>3 && beacon_detected_count<7){ 00123 // Now verify that the positive samples are in valid places... 00124 // Find first positive sample 00125 int first_index = 0; 00126 //out("Here\n",first_index); 00127 00128 while(beacon_detected_indices[first_index]==0)first_index ++; 00129 00130 //out("First index:%d\n",first_index); 00131 00132 00133 // Check if first index is zero: if so, we need to check index 49 (and 48) to see if they are also high 00134 if(first_index == 0){ 00135 if(beacon_detected_indices[49]>0)first_index = 49; 00136 if(beacon_detected_indices[48]>0)first_index = 48; 00137 } 00138 00139 beacon_averages_count++; 00140 for(int i=0;i<8;i++){beacon_averages[i]+=samples[first_index][i];} 00141 00142 // Now count the length of the 'block' of positive hits: must be equal to 2 or 3 00143 char block_length = 1; 00144 int end_index = first_index + 1; 00145 if(end_index == 50) end_index = 0; 00146 while(beacon_detected_indices[end_index]>0){ 00147 beacon_averages_count++; 00148 for(int i=0;i<8;i++){beacon_averages[i]+=samples[end_index][i];} 00149 block_length ++; 00150 end_index ++; 00151 if(end_index == 50) end_index = 0; 00152 } 00153 if(block_length==2 || block_length == 3){ 00154 //We have found the first correct block and it is valid; now calculate its mid-point and check that the second block is also present 500ms later 00155 float mid_point; 00156 char second_block_okay = 0; 00157 if(block_length == 2){ 00158 mid_point = first_index + 0.5; 00159 char second_block_low = first_index + 25; 00160 char second_block_high = first_index + 26; 00161 if(second_block_low > 49) second_block_low -= 50; 00162 if(second_block_high > 49) second_block_high -= 50; 00163 beacon_averages_count+=2; 00164 for(int i=0;i<8;i++){beacon_averages[i]+=samples[second_block_low][i]+samples[second_block_high][i];} 00165 if(beacon_detected_indices[second_block_low]>0 && beacon_detected_indices[second_block_high]>0) second_block_okay = 1; 00166 } 00167 if(block_length == 3){ 00168 mid_point = first_index + 1; 00169 if(mid_point == 50) mid_point = 0; 00170 char second_block_single = first_index + 26; 00171 if(second_block_single > 49) second_block_single -= 50; 00172 beacon_averages_count++; 00173 for(int i=0;i<8;i++){beacon_averages[i]+=samples[second_block_single][i];} 00174 if(beacon_detected_indices[second_block_single]>0) second_block_okay = 1; 00175 } 00176 if(second_block_okay >0){ 00177 beacon_found = 1; 00178 beacon_heading = get_bearing_from_ir_array(beacon_averages); 00179 out("Found at %d degrees\n",beacon_heading); 00180 //for(int i=0;i<8;i++){ 00181 // beacon_averages[i] /= beacon_averages_count; 00182 // out("[%d]",beacon_averages[i]); 00183 //} 00184 out("2) Synchronising...\n"); 00185 // Calculate the offset to the expected start of the next beacon pulse 00186 int microseconds_offset = (sample_period * mid_point) - sample_period - (sample_period / 4); 00187 //out("MS Offset:%d Midpoint:%f\n Current Time:%d\n",microseconds_offset,mid_point,beacon_timer.read_us()); 00188 int cycle_period = (BEACON_PERIOD * 10); 00189 if(microseconds_offset < 0) microseconds_offset += cycle_period; 00190 //If we have missed the start of the beacon this cycle, wait until the next cycle 00191 while(beacon_timer.read_us()% (cycle_period) > microseconds_offset){}; 00192 //Now wait until the start of the beacon pulse 00193 while(beacon_timer.read_us()% (cycle_period) < microseconds_offset){}; 00194 /* 00195 out("Now:%d",beacon_timer.read_us()); 00196 Timer test_timer; 00197 test_timer.start(); 00198 for(int i=0;i<50;i++){ 00199 store_background_raw_ir_values (); 00200 out("Time %d: %d\n",test_timer.read_ms(),get_background_raw_ir_value(2)); 00201 while(test_timer.read_ms() % 10 < 9){}; 00202 } 00203 */ 00204 }else{ 00205 beacon_found = 0; 00206 out("Beacon not found: a matching second block %dms after first block not detected\n",(BEACON_PERIOD / 100)); 00207 } 00208 }else{ 00209 beacon_found = 0; 00210 if(block_length == 1) out("Beacon not found: a single sample [%d] was high but not its neighbours\n",first_index); 00211 if(block_length > 3) out("Beacon not found: a block of %d high samples was detected\n",block_length); 00212 } 00213 } else { 00214 beacon_found = 0; 00215 if(beacon_detected_count > 6) out("Beacon not found: too many high samples [%d]\n",beacon_detected_count); 00216 else out("Beacon not found: too few high samples [%d]\n",beacon_detected_count); 00217 } 00218 if(beacon_found == 0){ 00219 set_leds(0x00,0x00); 00220 set_center_led(1, 1); 00221 display.clear_display(); 00222 display.set_position(0,0); 00223 display.write_string("BEACON NOT FOUND"); 00224 } 00225 } 00226 00227 // The start_infrared_timers() function is called as soon as the beacon has been detected and synchronised to 00228 // It launches 2 tickers at offset times; the first is responsible for turning the robots IR emitters on in its proper timeslot 00229 // The other reads the values given from the IR sensor in the middle of each timeslot and processes that information in the final timeslot 00230 void start_infrared_timers() 00231 { 00232 // At this point we should be exactly at the start of a beacon cycle. 00233 // We want the emitter ticker to start in approx 5ms (this will let us set a 40ms pulse) 00234 // We want the sample ticker to start in approx 25ms (this will let us sample in the middle each step 00235 out("3) Starting TDMA infrared timers\n"); 00236 beacon_debug_timer.start(); 00237 wait_us(BEACON_PERIOD / 10); 00238 ir_emitter_ticker.attach_us(emitter_ticker_block,BEACON_PERIOD); 00239 wait_us(((BEACON_PERIOD * 4) / 10)); //Wait for middle of pulse 00240 ir_sample_ticker.attach_us(sample_ticker_block,BEACON_PERIOD); 00241 } 00242 00243 00244 //Return the max value in IR array 00245 unsigned short get_highest_sample(unsigned short * ir_array){ 00246 unsigned short highest = 0; 00247 for(int i=0;i<8;i++){ 00248 if(ir_array[i]>highest) highest=ir_array[i]; 00249 } 00250 return highest; 00251 } 00252 00253 //Return the sum total of IR array 00254 unsigned short get_sum_sample(unsigned short * ir_array){ 00255 unsigned short sum = 0; 00256 for(int i=0;i<8;i++){ 00257 sum+=ir_array[i]; 00258 } 00259 return sum; 00260 } 00261 00262 //The emitter_ticker_block function runs every 50ms and turns the IR emitters on when pulse_step-1 matches the robot ID 00263 //It then starts a timeout to run emitter_timeout_block after 40ms, which turns off the emitters 00264 void emitter_ticker_block(){ 00265 //If the time-step (-1) equals my ID, turn on my emitters for 40ms 00266 if(pulse_step-1 == robot_id && disable_ir_emitters == 0){ 00267 IF_set_IR_emitter_output(0, 1); 00268 IF_set_IR_emitter_output(1, 1); 00269 ir_emitter_timeout.attach_us(emitter_timeout_block,(BEACON_PERIOD * 8)/10); 00270 } 00271 } 00272 00273 //Turn off the emitters 00274 void emitter_timeout_block(){ 00275 //Turn off IR emitters 00276 IF_set_IR_emitter_output(0, 0); 00277 IF_set_IR_emitter_output(1, 0); 00278 } 00279 00280 //The function sample_ticker_block() is called every 50ms, and should run close to the middle of every timeslot 00281 //There are 10 time slots in each 500ms period 00282 //Slot 0 is when the beacon is flashing 00283 //Slot 1 should be IR-free and is used to measure background IR data, stored in background_sensor_data[] 00284 //Slot 2-8 are for the 7 robots; slot-1 = robot_id 00285 //In slot 9, the robot processes the data [and doesn't store and new readings] 00286 //It checks if the beacon is visible, if any robots are, calculates their bearings if they are, and transfers the background and active IR data for the robot 00287 void sample_ticker_block(){ 00288 //If we are in time-step 0 to 8, store the background data in an array 00289 if(pulse_step < 9){ 00290 store_background_raw_ir_values (); 00291 for(int i=0;i<8;i++)ir_sensor_data[pulse_step][i]=get_background_raw_ir_value(i); 00292 }else{ 00293 //If not, process the data 00294 for(int i=0;i<9;i++){ 00295 unsigned short sum = get_sum_sample(ir_sensor_data[i]); 00296 unsigned short highest = get_highest_sample(ir_sensor_data[i]); 00297 //Check if beacon is visible 00298 if(i==0){ 00299 if(sum > beacon_threshold){ 00300 beacon_found = 1; 00301 beacon_heading = get_bearing_from_ir_array (ir_sensor_data[0]); 00302 }else beacon_found = 0; 00303 //out("Beacon sum:%d 0:%d 4:%d\n",sum,ir_sensor_data[0][0],ir_sensor_data[0][4]); 00304 } 00305 if(i==1){ 00306 for(int j=0;j<8;j++)background_sensor_data[j]=ir_sensor_data[1][j]; 00307 } 00308 if(i>1){ 00309 char test_robot = i-1; 00310 if(test_robot == robot_id){ 00311 for(int j=0;j<8;j++)reflected_sensor_data[j]=ir_sensor_data[i][j]; 00312 }else{ 00313 if(sum > low_threshold){ 00314 robots_found[test_robot] = 1; 00315 //Debug-- 00316 //out("Robot %d: [%d][%d][%d][%d][%d][%d][%d][%d]\n",test_robot,ir_sensor_data[i][0],ir_sensor_data[i][1],ir_sensor_data[i][2],ir_sensor_data[i][3],ir_sensor_data[i][4],ir_sensor_data[i][5],ir_sensor_data[i][6],ir_sensor_data[i][7]); 00317 robots_heading[test_robot] = get_bearing_from_ir_array (ir_sensor_data[i]); 00318 robots_distance[test_robot] = highest; 00319 }else robots_found[test_robot] = 0; 00320 } 00321 } 00322 } 00323 if(show_ir_debug_info == 1)display_ir_readings(); 00324 } 00325 //Increment pulse step 00326 pulse_step++; 00327 if(pulse_step == 10) pulse_step = 0; 00328 } 00329 00330 00331 //Testing function to print out lines showing what robot can currently see in terms of beacon, other robots and obstacles 00332 void display_ir_readings() 00333 { 00334 out("____________________________________\nInfrared Detection at %d ms\n",beacon_debug_timer.read_ms()); 00335 if(beacon_found==1){ 00336 out("Beacon detected at %d degrees\n",beacon_heading); 00337 } 00338 for(int j=1;j<8;j++){ 00339 if(robots_found[j])out("Robot %d detected at %d degrees, %d distance\n",j,robots_heading[j],robots_distance[j]); 00340 } 00341 out("Reflected values:"); 00342 for(int i=0;i<8;i++){ 00343 out("[%d,%d]",i,reflected_sensor_data[i]); 00344 } 00345 out("\nBackground values:"); 00346 for(int i=0;i<8;i++){ 00347 out("[%d,%d]",i,background_sensor_data[i]); 00348 } 00349 out("\n\n"); 00350 } 00351 00352 //Returns a 0 if turn is likely to complete in a single timestep, 1 if it is beyond range for single timestep and 2 if the beacon is not found so bearing unknown 00353 char turn_to_bearing(int bearing) 00354 { 00355 if(beacon_found == 0){ 00356 out("Beacon not found: cannot turn to specific bearing\n"); 00357 return 2; 00358 }else{ 00359 //First calculate the bearing using the angle of beacon relative to robot 00360 int current_bearing = 360 - beacon_heading; 00361 //Now work out turn needed to face intended heading 00362 int target_turn = (bearing - current_bearing) % 360; 00363 //Adjust to take 10% off turn, stops overshoot 00364 target_turn = (target_turn * 9) / 10; 00365 if(target_turn > 180) target_turn -= 360; 00366 if(target_turn < -180) target_turn += 360; 00367 //We can't reliably turn more than 280 degrees per second, so set a limit for the turn to that 00368 char beyond_limit = 0; 00369 int turn_limit = BEACON_PERIOD / 358; 00370 if(target_turn > turn_limit) {target_turn = turn_limit; beyond_limit = 1;}; 00371 if(target_turn < -turn_limit) {target_turn = -turn_limit; beyond_limit = 1;}; 00372 out("Turning %d degrees\n",target_turn); 00373 time_based_turn_degrees(1, target_turn,1); 00374 return beyond_limit; 00375 } 00376 }
Generated on Fri Jul 15 2022 08:26:10 by
1.7.2
