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.
Dependencies: mbed
Fork of PsiSwarm-BeaconDemo_Bluetooth 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 25ms burst of IR every 250ms. 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"); 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 Thu Jul 14 2022 08:02:39 by
1.7.2
