Homero Silva / Mbed 2 deprecated PRGP_Pi_Swarm_ground_search_algorithm

Dependencies:   mbed

Fork of Pi_Swarm_Blank by James Hilder

Committer:
homero
Date:
Tue Aug 25 17:49:16 2015 +0000
Revision:
17:4fa7c9e1b512
Parent:
16:a32ee9ed15c4
revision tested

Who changed what in which revision?

UserRevisionLine numberNew contents of line
re633 11:c5094a68283f 1 /*
re633 11:c5094a68283f 2 * Software License Agreement (BSD License)
re633 11:c5094a68283f 3 *
re633 11:c5094a68283f 4 * Copyright (c) 2015, University of York Robotics Laboratory (YRL).
re633 11:c5094a68283f 5 * All rights reserved.
re633 11:c5094a68283f 6 *
re633 11:c5094a68283f 7 * Redistribution and use in source and binary forms, with or without
re633 11:c5094a68283f 8 * modification, are permitted provided that the following conditions
re633 11:c5094a68283f 9 * are met:
re633 11:c5094a68283f 10 *
re633 11:c5094a68283f 11 * * Redistributions of source code must retain the above copyright
re633 11:c5094a68283f 12 * notice, this list of conditions and the following disclaimer.
re633 11:c5094a68283f 13 * * Redistributions in binary form must reproduce the above
re633 11:c5094a68283f 14 * copyright notice, this list of conditions and the following
re633 11:c5094a68283f 15 * disclaimer in the documentation and/or other materials provided
re633 11:c5094a68283f 16 * with the distribution.
re633 11:c5094a68283f 17 *
re633 11:c5094a68283f 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
re633 11:c5094a68283f 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
re633 11:c5094a68283f 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
re633 11:c5094a68283f 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
re633 11:c5094a68283f 22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
re633 11:c5094a68283f 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
re633 11:c5094a68283f 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
re633 11:c5094a68283f 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
re633 11:c5094a68283f 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
re633 11:c5094a68283f 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
re633 11:c5094a68283f 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
re633 11:c5094a68283f 29 * POSSIBILITY OF SUCH DAMAGE.
re633 11:c5094a68283f 30 */
re633 11:c5094a68283f 31 /**
re633 11:c5094a68283f 32 * @file main.cpp
re633 11:c5094a68283f 33 * @brief The Ticker fucntion for gaining sensor data and the main function for the PRGP Pi-Swarm Controllers.
re633 11:c5094a68283f 34 * @details In this file the main function for the Pi-Swarm Controller is defined.
re633 11:c5094a68283f 35 * @version 1.0
homero 13:c18d82f62d38 36 * @author Robert Evans
re633 11:c5094a68283f 37 * @date 24/07/15
homero 13:c18d82f62d38 38 * @version 2.0
homero 13:c18d82f62d38 39 * @author Homero Silva
homero 13:c18d82f62d38 40 * @date 16/08/15
homero 13:c18d82f62d38 41 * @ultrasonic sensor added
homero 15:f7a8989a3cd3 42 * @version 3.0
homero 13:c18d82f62d38 43 * @author Robert Evans
homero 13:c18d82f62d38 44 * @date 17/08/15
homero 13:c18d82f62d38 45 * @communication added
re633 11:c5094a68283f 46 */
jah128 3:1aa1de26966a 47 #include "main.h" // Certain parameters can be set by changing the defines in piswarm.h
homero 14:fc406dfff94f 48 #include "pi_swarm_functions.h"
homero 13:c18d82f62d38 49 #include "hcsr04.h"
jah128 0:46cd1498a39a 50
jah128 1:37502eb3b70f 51 PiSwarm piswarm;
jah128 1:37502eb3b70f 52 Serial pc (USBTX,USBRX);
homero 13:c18d82f62d38 53 HCSR04 usensor(p30,p14);
jah128 0:46cd1498a39a 54
re633 9:ef0907fda2f1 55 //Tickers
homero 14:fc406dfff94f 56 Ticker ticker_25ms; //Ticker used to periodically obtain new IR readings.
homero 14:fc406dfff94f 57 Ticker ticker_ultrasonic50ms; //Ticker used to periodically obtain a new ultrasonic reading.
homero 13:c18d82f62d38 58
homero 13:c18d82f62d38 59 //Timeouts
homero 14:fc406dfff94f 60 Timeout tickChangeTimeout; //Timeout used to adjust IR read ticker phase to enable to beacon syncronisation.
homero 14:fc406dfff94f 61 Timeout broadcastTimeout; //Timeout used for broadcasting messages multiple times with a set interval.
homero 17:4fa7c9e1b512 62 Timeout stopSearchTimeout;
homero 13:c18d82f62d38 63
homero 13:c18d82f62d38 64 //Timers
homero 14:fc406dfff94f 65 Timer turn_timer; //Timer used to turn a user specified number of degrees.
homero 14:fc406dfff94f 66 Timer levy_timer; //Timer used to control time between levy walk steps.
homero 17:4fa7c9e1b512 67 Timer back_move_timer; //Timer used to make the piswarm move back and turn periodically in case it is stuck moving to the beacon.
re633 9:ef0907fda2f1 68
re633 9:ef0907fda2f1 69 //Global Variables
homero 14:fc406dfff94f 70
homero 14:fc406dfff94f 71 //Individucal Pi-Swarm variables: speed and motor trim etc
homero 14:fc406dfff94f 72 float BASE_SPEED = 0.6; //The input to the motor functions when the robot is moving forward and does not detect obstacles.
homero 14:fc406dfff94f 73 float r_mot_scaler = 1; //This variable is allows particular pi swarms to be adjusted to travel in a straight line.
homero 14:fc406dfff94f 74 float l_mot_scaler = 1; //This variable is allows particular pi swarms to be adjusted to travel in a straight line.
homero 14:fc406dfff94f 75 uint16_t at_beacon_threshold = 3800; //A raw IR reading greater than this value indicates the robot is at a beacon.
homero 14:fc406dfff94f 76 int16_t g_currentHeading = 0; //The current heading of the Pi-swarm relative to the IR beacon.
homero 14:fc406dfff94f 77 uint8_t robot_id; //The id unique to each Pi-Swarm robot
homero 14:fc406dfff94f 78
homero 14:fc406dfff94f 79 //Finite state machine information
homero 14:fc406dfff94f 80 uint8_t volatile gv_state = States::READY_TO_START; //This is the current state of the finite state machine
homero 14:fc406dfff94f 81 int8_t g_obstacle_type = 0; //The Pi-Swarm will perform different obstacle avoidance behaviours depending on which sensors detect obstacles. This variable is used to note which sensor detected the obstacle.
homero 17:4fa7c9e1b512 82 uint8_t consecutive_turn_count = 0;
homero 17:4fa7c9e1b512 83 uint8_t volatile stop_search_flag = 0; //Set to one ten seconds after command five received. Means stop searching for target beacon.
homero 17:4fa7c9e1b512 84 uint8_t volatile sync_attempt_count = 0;
homero 14:fc406dfff94f 85
homero 14:fc406dfff94f 86 //IR Readings + beacon syncronisation variables
re633 9:ef0907fda2f1 87 uint8_t const IR_READ_PER_BEAC = 20; //The number of IR readings between beacon flashes
re633 9:ef0907fda2f1 88 uint16_t volatile gv_IRVals[IR_READ_PER_BEAC][8] = {0}; //The passive IR values each are stored in this array every 25ms for the last 0.5 seconds
homero 14:fc406dfff94f 89 int16_t volatile gv_IRValDiffs[IR_READ_PER_BEAC][8] = {0};//The difference between consective IR readings.
homero 14:fc406dfff94f 90 int16_t volatile gv_IRValDiffsTwo[IR_READ_PER_BEAC][8] = {0};//The difference between IR readings seperated by two ticks
homero 14:fc406dfff94f 91 uint8_t volatile beacon_detected[8] = {0}; //An IR sensor is judged to have a detected the beacon in a valid way the corresponding array variable will be set to 1, else 0.
re633 9:ef0907fda2f1 92 int8_t volatile gv_counter25ms = 0; //This counter is increased every 25ms and resets to zero after one second. (It is signed because 1 is subtracted from it in ReadIRs)
homero 14:fc406dfff94f 93 int8_t g_beaconOn = 100; //The first tick at which the beacon is illuminated
homero 13:c18d82f62d38 94 uint8_t const BEACON_SUSPECTED = 20; //Value by which consecutive IR sensor readings need to jump by for in order to cause beacon to be suspected.
homero 14:fc406dfff94f 95 uint8_t volatile gv_IRDistances[8]; //Using the custom distance function the active IR readings are converted to distances and stored here every 25ms.
re633 11:c5094a68283f 96 int8_t volatile tick_beacon_suspected = 100; //Is set to the tick value within the period between beacon flashes that the beacon flash is suspected to begin at
re633 11:c5094a68283f 97 int8_t tick_beacon_period_check = 100; //Is used to temporarily store the value of tick_beacon_suspected
homero 14:fc406dfff94f 98 uint8_t beacon_syncronised_flag = 0; //Set to one when the robot is synchronised with the beacon
homero 14:fc406dfff94f 99 uint8_t volatile beacon_illuminated_flag = 0; //Should be 1 when beacon is illuminated otherwise 0
homero 14:fc406dfff94f 100
homero 14:fc406dfff94f 101 //Ultrasonic Readings
homero 14:fc406dfff94f 102 float volatile distance_ultrasonic_sensor = 1000; //Here is stored the latest reading from the ultrasonic sensor in mm from 1 -800. 1000 is an error value.
homero 14:fc406dfff94f 103
homero 14:fc406dfff94f 104 //Levy walk variables
homero 14:fc406dfff94f 105 uint32_t levy_target_time_us = 0; //The amount of time in micro seconds by which the robot needs to move in order to reach the distance required in next section of the levy walk.
homero 14:fc406dfff94f 106 uint8_t g_back_count = 0; //After a set number of Levy walk turns the robot will move backward. This variable monitors how many Levy turns since the last backward move.
homero 14:fc406dfff94f 107 uint8_t set_new_levy_time_flag = 1; //Must start as 1. If fwd move state is entered following a levy turn the flag will be 1 indicating a new time should be set.
homero 14:fc406dfff94f 108
homero 14:fc406dfff94f 109
homero 15:f7a8989a3cd3 110 //Communication
homero 14:fc406dfff94f 111 uint8_t broadcasted_flag = 1; //Set to one when a message has been broadcast. 0 when about to broadcast a new message
homero 14:fc406dfff94f 112 uint8_t broadcasted_count = 0; //The number of messages that have been broadcasted in one batch
homero 17:4fa7c9e1b512 113 int8_t volatile start_flag = 0; //Set to 1 on receiving a command by RF. Indicates robot can start searching for target beacon.
homero 14:fc406dfff94f 114 int8_t volatile back_flag = 0; //Set to 1 on receiving a command by RF. Indicates robot can start searching for home beacon, unless it is at the target beacon.
homero 14:fc406dfff94f 115 int8_t volatile return_flag = 0; //Set to 1 on receiving a command by RF. Indicates all robots now start or continue searching for home beacon.
homero 13:c18d82f62d38 116
re633 9:ef0907fda2f1 117 //Ticker Function*************************************************************************************
re633 9:ef0907fda2f1 118 //This function is called by a ticker every 25ms
re633 9:ef0907fda2f1 119 //The function firstly stores the background IRS values.
re633 9:ef0907fda2f1 120 //Secondly if beacon is off it uses illuminated IR sensors to estimate distances
re633 9:ef0907fda2f1 121 //Each second it will update when it believes beacon illumination time to be
re633 9:ef0907fda2f1 122 //It will work out which sensors spotted then beacon and will illuminate the Leds accordingly
homero 15:f7a8989a3cd3 123 void readIRs()
homero 15:f7a8989a3cd3 124 {
homero 15:f7a8989a3cd3 125
re633 9:ef0907fda2f1 126 //Fistly update the beaconVisable flag if possible
homero 15:f7a8989a3cd3 127 if(gv_counter25ms == mod8((g_beaconOn - 1), IR_READ_PER_BEAC)) {
homero 14:fc406dfff94f 128 beacon_illuminated_flag = 1;
re633 9:ef0907fda2f1 129 }
homero 15:f7a8989a3cd3 130
homero 15:f7a8989a3cd3 131 if(gv_counter25ms == mod8((g_beaconOn + 2), IR_READ_PER_BEAC)) {
homero 14:fc406dfff94f 132 beacon_illuminated_flag = 0;
re633 9:ef0907fda2f1 133 }
re633 9:ef0907fda2f1 134 //Firstly store background values
re633 9:ef0907fda2f1 135 //Also make a note of which point in the second did the values change most.
re633 9:ef0907fda2f1 136 //For which sensor specifically did the values change the most
re633 9:ef0907fda2f1 137 //That sensor will be used to estimate the beacon start time if a threshold value is met
re633 9:ef0907fda2f1 138 piswarm.store_background_raw_ir_values();
re633 9:ef0907fda2f1 139 int16_t IRchange = 0;
homero 13:c18d82f62d38 140 int16_t IRchange2 = 0;
re633 9:ef0907fda2f1 141 uint8_t loopCounter = 0;
re633 9:ef0907fda2f1 142 //In this loop the raw IR values are read.
re633 9:ef0907fda2f1 143 //If the points where the IR values have increased by the greatest amount are noted as this indicates a beacon illumination
re633 9:ef0907fda2f1 144 for(loopCounter = 0; loopCounter < 8; loopCounter++) {
re633 9:ef0907fda2f1 145 gv_IRVals[gv_counter25ms][loopCounter] = piswarm.get_background_raw_ir_value(loopCounter);
homero 15:f7a8989a3cd3 146
homero 13:c18d82f62d38 147 IRchange = gv_IRVals[gv_counter25ms][loopCounter]-gv_IRVals[mod8((gv_counter25ms-1),IR_READ_PER_BEAC)][loopCounter];
homero 13:c18d82f62d38 148 IRchange2 = gv_IRVals[gv_counter25ms][loopCounter]-gv_IRVals[mod8((gv_counter25ms-2),IR_READ_PER_BEAC)][loopCounter];
re633 9:ef0907fda2f1 149 gv_IRValDiffs[gv_counter25ms][loopCounter] = IRchange;
homero 13:c18d82f62d38 150 gv_IRValDiffsTwo[gv_counter25ms][loopCounter] = IRchange2;
homero 15:f7a8989a3cd3 151
re633 9:ef0907fda2f1 152 //printf("change %d count %d\n",IRchange);
re633 9:ef0907fda2f1 153 //If difference is greater than a threshold value then the beacon is suspected. This will be confirmed depending on the robots state of movement.
homero 15:f7a8989a3cd3 154 if (IRchange > BEACON_SUSPECTED) {
re633 11:c5094a68283f 155 tick_beacon_suspected = gv_counter25ms;
re633 9:ef0907fda2f1 156 piswarm.cls();
re633 11:c5094a68283f 157 piswarm.printf("%d",tick_beacon_suspected);
homero 15:f7a8989a3cd3 158 }
re633 9:ef0907fda2f1 159 }
homero 15:f7a8989a3cd3 160
re633 9:ef0907fda2f1 161 //Now store the illuminated values if the beacon is not illuminated-
re633 9:ef0907fda2f1 162 piswarm.store_illuminated_raw_ir_values();
homero 15:f7a8989a3cd3 163
homero 15:f7a8989a3cd3 164 //In this loop convert each raw active IR reading into a distance estimate
re633 9:ef0907fda2f1 165 for(loopCounter = 0; loopCounter < 8; loopCounter++) {
homero 15:f7a8989a3cd3 166
re633 9:ef0907fda2f1 167 //Specific sensor readings converted to distances
re633 9:ef0907fda2f1 168 float temp = piswarm.get_illuminated_raw_ir_value(loopCounter);
homero 13:c18d82f62d38 169 //if(gv_counter25ms == 1) pc.printf("sen %d :%f\n", loopCounter,temp);
homero 15:f7a8989a3cd3 170 if(gv_counter25ms == 0) {
homero 13:c18d82f62d38 171 pc.printf("sen %d raw: %f",loopCounter,temp);
homero 13:c18d82f62d38 172 }
homero 15:f7a8989a3cd3 173 if(temp>3500) {
homero 15:f7a8989a3cd3 174 temp = 3500;
homero 15:f7a8989a3cd3 175 } else if (temp < 97) {
homero 15:f7a8989a3cd3 176 temp = 97;
re633 9:ef0907fda2f1 177 }
homero 15:f7a8989a3cd3 178 //#put this into a function
re633 9:ef0907fda2f1 179 //Switch case for robot 5
homero 15:f7a8989a3cd3 180 switch(robot_id) {
homero 13:c18d82f62d38 181 case 9:
homero 15:f7a8989a3cd3 182 switch(loopCounter) {
homero 13:c18d82f62d38 183 case 0:
homero 13:c18d82f62d38 184 temp = 1643 * sqrt(1/(temp-190))-35;
homero 15:f7a8989a3cd3 185 break;
homero 13:c18d82f62d38 186 case 1:
homero 13:c18d82f62d38 187 temp = 1097 * sqrt(1/(temp-190))-24;
homero 15:f7a8989a3cd3 188 break;
homero 13:c18d82f62d38 189 case 2:
homero 13:c18d82f62d38 190 temp = 838 * sqrt(1/(temp-120))-17;
homero 13:c18d82f62d38 191 break;
homero 13:c18d82f62d38 192 case 3:
homero 13:c18d82f62d38 193 temp = 1017 * sqrt(1/(temp-175))-22;
homero 13:c18d82f62d38 194 break;
homero 13:c18d82f62d38 195 case 4:
homero 13:c18d82f62d38 196 temp = 777 * sqrt(1/(temp-130))-16;
homero 13:c18d82f62d38 197 break;
homero 13:c18d82f62d38 198 case 5:
homero 13:c18d82f62d38 199 temp = 765 * sqrt(1/(temp-115))-11;
homero 13:c18d82f62d38 200 break;
homero 13:c18d82f62d38 201 case 6:
homero 13:c18d82f62d38 202 temp = 1086 * sqrt(1/(temp-150))-17;
homero 13:c18d82f62d38 203 break;
homero 13:c18d82f62d38 204 case 7:
homero 13:c18d82f62d38 205 temp = 1578 * sqrt(1/(temp-220))-24;
homero 13:c18d82f62d38 206 break;
homero 13:c18d82f62d38 207 }
re633 9:ef0907fda2f1 208 break;
homero 13:c18d82f62d38 209 case 12:
homero 15:f7a8989a3cd3 210 switch(loopCounter) {
homero 13:c18d82f62d38 211 case 0:
homero 13:c18d82f62d38 212 temp = 877 * sqrt(1/(temp-80))-13;
homero 15:f7a8989a3cd3 213 break;
homero 13:c18d82f62d38 214 case 1:
homero 13:c18d82f62d38 215 temp = 887 * sqrt(1/(temp-110))-13;
homero 15:f7a8989a3cd3 216 break;
homero 13:c18d82f62d38 217 case 2:
homero 13:c18d82f62d38 218 temp = 744 * sqrt(1/(temp-90))-8;
homero 13:c18d82f62d38 219 break;
homero 13:c18d82f62d38 220 case 3:
homero 13:c18d82f62d38 221 temp = 816 * sqrt(1/(temp-105))-17;
homero 13:c18d82f62d38 222 break;
homero 13:c18d82f62d38 223 case 4:
homero 13:c18d82f62d38 224 temp = 821 * sqrt(1/(temp-125))-7;
homero 13:c18d82f62d38 225 break;
homero 13:c18d82f62d38 226 case 5:
homero 13:c18d82f62d38 227 temp = 741 * sqrt(1/(temp-110))-7;
homero 13:c18d82f62d38 228 break;
homero 13:c18d82f62d38 229 case 6:
homero 13:c18d82f62d38 230 temp = 1000 * sqrt(1/(temp-95))-18;
homero 13:c18d82f62d38 231 break;
homero 13:c18d82f62d38 232 case 7:
homero 13:c18d82f62d38 233 temp = 924 * sqrt(1/(temp-115))-12;
homero 13:c18d82f62d38 234 break;
homero 13:c18d82f62d38 235 }
re633 9:ef0907fda2f1 236 break;
homero 13:c18d82f62d38 237 default:
homero 15:f7a8989a3cd3 238 temp = 662 * sqrt(1/(temp-152));
homero 13:c18d82f62d38 239
re633 9:ef0907fda2f1 240 }
homero 15:f7a8989a3cd3 241
homero 15:f7a8989a3cd3 242 if(gv_counter25ms == 0) {
homero 15:f7a8989a3cd3 243 pc.printf("sen %d dist:%f\n",loopCounter,temp);
homero 13:c18d82f62d38 244 }
homero 15:f7a8989a3cd3 245 if (temp > 130) {
re633 9:ef0907fda2f1 246 temp = 130;
re633 9:ef0907fda2f1 247 }
homero 15:f7a8989a3cd3 248 gv_IRDistances[loopCounter] = temp;
re633 9:ef0907fda2f1 249
homero 13:c18d82f62d38 250 }
homero 15:f7a8989a3cd3 251
re633 9:ef0907fda2f1 252 //reset counter after 1 second (beacon period)
re633 9:ef0907fda2f1 253 gv_counter25ms = mod8(gv_counter25ms + 1,IR_READ_PER_BEAC);
re633 9:ef0907fda2f1 254 }
re633 9:ef0907fda2f1 255
homero 15:f7a8989a3cd3 256 //Get the distance of the ultrsonic sensor in cm
homero 15:f7a8989a3cd3 257 void get_ultrasonic_readings()
homero 15:f7a8989a3cd3 258 {
homero 13:c18d82f62d38 259 float old_dist = distance_ultrasonic_sensor;
homero 15:f7a8989a3cd3 260 int static count = 0;
homero 13:c18d82f62d38 261 distance_ultrasonic_sensor = usensor.get_dist_mm();
homero 15:f7a8989a3cd3 262 if(count <100) {
homero 17:4fa7c9e1b512 263 //pc.printf("US: %.1f, %d\n",distance_ultrasonic_sensor, count);
homero 13:c18d82f62d38 264 count ++;
homero 15:f7a8989a3cd3 265 } else {
homero 13:c18d82f62d38 266 count =0;
homero 13:c18d82f62d38 267 }
homero 15:f7a8989a3cd3 268
homero 15:f7a8989a3cd3 269 if(distance_ultrasonic_sensor <= 0 || distance_ultrasonic_sensor == 1000) {
homero 13:c18d82f62d38 270 distance_ultrasonic_sensor = old_dist;
homero 13:c18d82f62d38 271 }
homero 13:c18d82f62d38 272 usensor.start();
homero 13:c18d82f62d38 273 }
homero 13:c18d82f62d38 274
homero 13:c18d82f62d38 275 //When called the readIRs ticker will be reattached after the specified time.
homero 15:f7a8989a3cd3 276 void atTimeout()
homero 15:f7a8989a3cd3 277 {
homero 13:c18d82f62d38 278 ticker_25ms.attach_us(&readIRs,25000);
homero 13:c18d82f62d38 279 }
homero 13:c18d82f62d38 280
homero 15:f7a8989a3cd3 281 void atBroadcastTimeout()
homero 15:f7a8989a3cd3 282 {
homero 13:c18d82f62d38 283 char function;
homero 17:4fa7c9e1b512 284 if(robot_id == 1|| robot_id == 9) {
homero 13:c18d82f62d38 285 function = 2;
homero 17:4fa7c9e1b512 286 } else if(robot_id == 12) {
homero 13:c18d82f62d38 287 function = 3;
homero 13:c18d82f62d38 288 }
homero 15:f7a8989a3cd3 289
homero 13:c18d82f62d38 290 char message[2];
homero 13:c18d82f62d38 291 message[0] = piswarm.get_id()+48;
homero 13:c18d82f62d38 292 broadcast_user_rf_command(function,message,1);
homero 13:c18d82f62d38 293 broadcasted_count++;
homero 13:c18d82f62d38 294 broadcasted_flag = 1;
homero 13:c18d82f62d38 295 }
homero 17:4fa7c9e1b512 296
homero 17:4fa7c9e1b512 297 void atStopSearchTimeout(){
homero 17:4fa7c9e1b512 298 stop_search_flag = 1;
homero 17:4fa7c9e1b512 299 }
homero 13:c18d82f62d38 300 //This is a wait function for one
homero 13:c18d82f62d38 301
re633 9:ef0907fda2f1 302 //*******************************************************************************************************
homero 15:f7a8989a3cd3 303 //This is where the program code goes.
homero 15:f7a8989a3cd3 304 int main()
homero 15:f7a8989a3cd3 305 {
homero 15:f7a8989a3cd3 306 init();
homero 13:c18d82f62d38 307 robot_id = piswarm.get_id();
re633 9:ef0907fda2f1 308 //starting point in state 11
homero 15:f7a8989a3cd3 309 //usensor.start(); // get first reading of the ultrasonic sensor required before ticker
homero 13:c18d82f62d38 310 //wait_ms(50);
homero 15:f7a8989a3cd3 311
homero 15:f7a8989a3cd3 312
homero 13:c18d82f62d38 313 //wait(1); //Wait a second to allow IR array to be filled
homero 15:f7a8989a3cd3 314
re633 9:ef0907fda2f1 315 //Controller is a finite state machine
homero 15:f7a8989a3cd3 316 while(1) {
homero 15:f7a8989a3cd3 317
re633 9:ef0907fda2f1 318 //Waiting for signal to begin searching
homero 15:f7a8989a3cd3 319 if(gv_state == States::READY_TO_START) {
homero 13:c18d82f62d38 320 //pc.printf("%d\n",start_flag);
homero 15:f7a8989a3cd3 321 if(start_flag == 1) {
re633 12:118f2b0ed8eb 322 //Change state here after recieving a radio command
homero 13:c18d82f62d38 323 ticker_25ms.attach_us(&readIRs,25000);
homero 15:f7a8989a3cd3 324
homero 15:f7a8989a3cd3 325 if(robot_id == 1) {
homero 14:fc406dfff94f 326 at_beacon_threshold = 3850;
homero 13:c18d82f62d38 327 }
homero 15:f7a8989a3cd3 328
homero 15:f7a8989a3cd3 329 else if (robot_id == 9) {
homero 17:4fa7c9e1b512 330 at_beacon_threshold = 3925;
homero 13:c18d82f62d38 331 }
homero 15:f7a8989a3cd3 332
homero 15:f7a8989a3cd3 333 else if (robot_id == 12) {
homero 17:4fa7c9e1b512 334 at_beacon_threshold = 3825;
homero 17:4fa7c9e1b512 335 r_mot_scaler = 1.03;
homero 17:4fa7c9e1b512 336 l_mot_scaler = 0.97;
homero 13:c18d82f62d38 337 }
homero 15:f7a8989a3cd3 338
homero 15:f7a8989a3cd3 339 else {
homero 14:fc406dfff94f 340 at_beacon_threshold = 3900;
homero 13:c18d82f62d38 341 }
homero 15:f7a8989a3cd3 342
homero 15:f7a8989a3cd3 343 usensor.start(); // get first reading of the ultrasonic sensor required before ticker
homero 13:c18d82f62d38 344 wait_ms(50);
homero 13:c18d82f62d38 345 ticker_ultrasonic50ms.attach_us(&get_ultrasonic_readings,50000);
homero 15:f7a8989a3cd3 346
homero 14:fc406dfff94f 347 turn_timer.start();
homero 14:fc406dfff94f 348 levy_timer.start();
homero 13:c18d82f62d38 349 //pc.printf("why\n");
homero 13:c18d82f62d38 350 changeState(States::SEARCHING_FWD);
re633 10:da62735d6df9 351 }
homero 15:f7a8989a3cd3 352
homero 15:f7a8989a3cd3 353 //Searching state
homero 15:f7a8989a3cd3 354 } else if (gv_state == States::SEARCHING_FWD || gv_state == States::SEARCHING_TURNING) {
homero 15:f7a8989a3cd3 355
re633 12:118f2b0ed8eb 356 //Do something here on receipt of 'function 5' if necessary.
re633 12:118f2b0ed8eb 357 //As currently the home beacon will immediately switch on that is not necessary.
homero 15:f7a8989a3cd3 358
re633 12:118f2b0ed8eb 359 //Determine if suspected beacon is actually the beacon.
re633 9:ef0907fda2f1 360 //This is done by checking the period between flashes matches the beacon period
homero 15:f7a8989a3cd3 361 if(tick_beacon_suspected != 100) {
re633 9:ef0907fda2f1 362 //When the beacon flag is first raised store its value and reset it
homero 15:f7a8989a3cd3 363 if(tick_beacon_period_check == 100) {
re633 11:c5094a68283f 364 tick_beacon_period_check = tick_beacon_suspected;
re633 11:c5094a68283f 365 tick_beacon_suspected = 100;
homero 15:f7a8989a3cd3 366 //Check the timing of the latest jump with the last one to see if period matches the Beacon.
re633 9:ef0907fda2f1 367 } else {
re633 9:ef0907fda2f1 368 piswarm.locate(0,1);
re633 11:c5094a68283f 369 piswarm.printf("%d %d",tick_beacon_period_check,tick_beacon_suspected);
re633 11:c5094a68283f 370 //printf("%d %d *********************************",tick_beacon_period_check,tick_beacon_suspected);
re633 9:ef0907fda2f1 371 //If the two numbers are similar then test will be low. For this to work the period of the ticker and beacon should be the same.
re633 11:c5094a68283f 372 int8_t test = (tick_beacon_period_check - tick_beacon_suspected);
homero 15:f7a8989a3cd3 373
re633 9:ef0907fda2f1 374 test = test * test;
homero 15:f7a8989a3cd3 375
re633 9:ef0907fda2f1 376 //if test is low then identify the beacon as the cause of the flags
homero 15:f7a8989a3cd3 377 if(test < 2) {
re633 9:ef0907fda2f1 378 //Beacon found change to state 2
re633 11:c5094a68283f 379 g_beaconOn = tick_beacon_period_check; //update the global variable that stores when beacon flashes occur
homero 15:f7a8989a3cd3 380
homero 13:c18d82f62d38 381 //wait(2);
homero 13:c18d82f62d38 382 changeState(States::MOVING_TO_BEACON);
re633 9:ef0907fda2f1 383 } else {
re633 9:ef0907fda2f1 384 //Reset the flag to try again
re633 11:c5094a68283f 385 tick_beacon_period_check = 100;
re633 9:ef0907fda2f1 386 }
re633 9:ef0907fda2f1 387 }
re633 9:ef0907fda2f1 388 }
homero 15:f7a8989a3cd3 389
homero 15:f7a8989a3cd3 390 if(gv_state == States::SEARCHING_FWD) {
homero 15:f7a8989a3cd3 391
homero 17:4fa7c9e1b512 392 if(stop_search_flag == 1 && back_flag == 0){
homero 17:4fa7c9e1b512 393 piswarm.stop();
homero 17:4fa7c9e1b512 394 piswarm.set_oled_colour(0,255,255);
homero 17:4fa7c9e1b512 395 ticker_25ms.detach();
homero 17:4fa7c9e1b512 396 ticker_ultrasonic50ms.detach();
homero 17:4fa7c9e1b512 397 while(back_flag == 0){
homero 17:4fa7c9e1b512 398
homero 17:4fa7c9e1b512 399 }
homero 17:4fa7c9e1b512 400
homero 17:4fa7c9e1b512 401 ticker_25ms.attach_us(&readIRs,25000);
homero 17:4fa7c9e1b512 402 ticker_ultrasonic50ms.attach_us(&get_ultrasonic_readings,50000);
homero 17:4fa7c9e1b512 403
homero 17:4fa7c9e1b512 404
homero 17:4fa7c9e1b512 405 } else if(gv_IRDistances[0] < 100 || gv_IRDistances[1] < 100) {
re633 9:ef0907fda2f1 406 piswarm.stop();
homero 15:f7a8989a3cd3 407 piswarm.cls();
re633 10:da62735d6df9 408 piswarm.printf("ob R");
re633 10:da62735d6df9 409 piswarm.play_tune("CC",1);
homero 14:fc406dfff94f 410 g_obstacle_type = 1;
homero 13:c18d82f62d38 411 changeState(States::SEARCHING_TURNING);
homero 15:f7a8989a3cd3 412
homero 15:f7a8989a3cd3 413 //Avoid obstacle to the left
homero 15:f7a8989a3cd3 414 } else if(gv_IRDistances[6] < 100 || gv_IRDistances[7] < 100) {
re633 9:ef0907fda2f1 415 piswarm.stop();
homero 15:f7a8989a3cd3 416 piswarm.cls();
re633 10:da62735d6df9 417 piswarm.printf("ob L");
re633 10:da62735d6df9 418 piswarm.play_tune("CC",1);
homero 14:fc406dfff94f 419 g_obstacle_type = 2;
homero 15:f7a8989a3cd3 420 changeState(States::SEARCHING_TURNING);
homero 15:f7a8989a3cd3 421
homero 15:f7a8989a3cd3 422 } else if(distance_ultrasonic_sensor < 70) {
homero 13:c18d82f62d38 423 piswarm.stop();
homero 15:f7a8989a3cd3 424 piswarm.cls();
homero 13:c18d82f62d38 425 piswarm.printf("ob F");
homero 13:c18d82f62d38 426 piswarm.play_tune("DD",1);
homero 13:c18d82f62d38 427 //wait(0.1);
homero 14:fc406dfff94f 428 g_obstacle_type = 3;
homero 13:c18d82f62d38 429 changeState(States::SEARCHING_TURNING);
homero 15:f7a8989a3cd3 430
homero 15:f7a8989a3cd3 431
homero 15:f7a8989a3cd3 432 } else if(distance_ultrasonic_sensor <= 80) {
homero 15:f7a8989a3cd3 433 g_obstacle_type = 3;
homero 15:f7a8989a3cd3 434 changeState(States::SEARCHING_TURNING);
homero 15:f7a8989a3cd3 435
homero 15:f7a8989a3cd3 436 } else if(levy_timer.read_us() > levy_target_time_us) {
homero 14:fc406dfff94f 437 g_back_count++;
homero 14:fc406dfff94f 438 set_new_levy_time_flag = 1;
re633 10:da62735d6df9 439 piswarm.play_tune("G",1);
homero 13:c18d82f62d38 440 piswarm.set_oled_colour(255,0,0);
homero 13:c18d82f62d38 441 changeState(States::SEARCHING_TURNING);
homero 15:f7a8989a3cd3 442 } else if(g_back_count >=8) {
homero 14:fc406dfff94f 443 g_back_count = 0;
homero 13:c18d82f62d38 444 piswarm.stop();
homero 13:c18d82f62d38 445 wait_ms(200);
homero 13:c18d82f62d38 446 piswarm.left_motor(-0.4*l_mot_scaler);
homero 15:f7a8989a3cd3 447 piswarm.right_motor(-0.4*r_mot_scaler);
homero 13:c18d82f62d38 448 wait(0.5);
homero 13:c18d82f62d38 449 changeState(States::SEARCHING_TURNING);
homero 15:f7a8989a3cd3 450
homero 15:f7a8989a3cd3 451 } else if (distance_ultrasonic_sensor <= 800) {
homero 17:4fa7c9e1b512 452 consecutive_turn_count = 0;
homero 15:f7a8989a3cd3 453 //decrease speed when PiSwarm is getting close to an obstacle
homero 15:f7a8989a3cd3 454 float velocity = 0.2;
homero 15:f7a8989a3cd3 455 if(distance_ultrasonic_sensor > 100) {
homero 15:f7a8989a3cd3 456 velocity = (distance_ultrasonic_sensor*0.00057) + 0.142;
homero 15:f7a8989a3cd3 457 }
homero 15:f7a8989a3cd3 458 piswarm.left_motor(velocity*l_mot_scaler);
homero 15:f7a8989a3cd3 459 piswarm.right_motor(velocity*r_mot_scaler);
homero 17:4fa7c9e1b512 460 wait_ms(100);
homero 15:f7a8989a3cd3 461
homero 15:f7a8989a3cd3 462
homero 15:f7a8989a3cd3 463 //Otherwise continue moving forward until distance determined by levy algorithm is calculated.
homero 15:f7a8989a3cd3 464
homero 15:f7a8989a3cd3 465
homero 13:c18d82f62d38 466 } else {
homero 17:4fa7c9e1b512 467 consecutive_turn_count = 0;
homero 13:c18d82f62d38 468 piswarm.right_motor(BASE_SPEED*r_mot_scaler);
homero 15:f7a8989a3cd3 469 piswarm.left_motor(BASE_SPEED*l_mot_scaler);
homero 13:c18d82f62d38 470 }
homero 13:c18d82f62d38 471 //wait to get new ultrasound reading
homero 15:f7a8989a3cd3 472 //wait_ms(50);
homero 15:f7a8989a3cd3 473
homero 15:f7a8989a3cd3 474
homero 15:f7a8989a3cd3 475 } else if(gv_state == States::SEARCHING_TURNING) {
re633 9:ef0907fda2f1 476 piswarm.stop();//Stop the robot.
re633 9:ef0907fda2f1 477 int16_t randomAngle;
re633 9:ef0907fda2f1 478 //If sent here beacuse of obstacle find angle between -180 to -90 and 90 to 180
homero 15:f7a8989a3cd3 479 if(g_obstacle_type == 1) {
re633 10:da62735d6df9 480 randomAngle = rand()%90 - 135;
homero 15:f7a8989a3cd3 481
homero 15:f7a8989a3cd3 482 } else if(g_obstacle_type == 2) {
re633 10:da62735d6df9 483 randomAngle = rand()%90 + 45;
homero 15:f7a8989a3cd3 484
homero 15:f7a8989a3cd3 485 } else if(g_obstacle_type == 3) {
homero 14:fc406dfff94f 486 randomAngle = rand()%90 + 45;
homero 15:f7a8989a3cd3 487
homero 15:f7a8989a3cd3 488 //Otherwise if here due to levy walk: turn to any random angle
re633 9:ef0907fda2f1 489 } else {
homero 15:f7a8989a3cd3 490 randomAngle = rand()%360 - 180;
re633 9:ef0907fda2f1 491 }
re633 9:ef0907fda2f1 492 turnDegrees(randomAngle); //Make the turn
homero 14:fc406dfff94f 493 g_obstacle_type = 0;
homero 13:c18d82f62d38 494 changeState(States::SEARCHING_FWD);//Move back into state 11
homero 15:f7a8989a3cd3 495
homero 16:a32ee9ed15c4 496 }
homero 16:a32ee9ed15c4 497 //Beacon found state
homero 16:a32ee9ed15c4 498 } else if (gv_state == States::MOVING_TO_BEACON) {
homero 16:a32ee9ed15c4 499
homero 16:a32ee9ed15c4 500 //Do something here on receipt of 'function 5' if necessary.
homero 16:a32ee9ed15c4 501 //As currently the home beacon will immediately switch on that is not necessary.
homero 16:a32ee9ed15c4 502
homero 16:a32ee9ed15c4 503 static int16_t valid_distances[8] = {0};
homero 15:f7a8989a3cd3 504
homero 16:a32ee9ed15c4 505 int16_t maxValue[2] = {0,100}; //Value and sensor position
homero 16:a32ee9ed15c4 506 int8_t loopCounter = 0;
homero 16:a32ee9ed15c4 507
homero 16:a32ee9ed15c4 508 if(beacon_illuminated_flag == 0) {
homero 16:a32ee9ed15c4 509 for(loopCounter = 0; loopCounter < 8; loopCounter++) {
homero 16:a32ee9ed15c4 510 valid_distances[loopCounter] = gv_IRDistances[loopCounter];
homero 16:a32ee9ed15c4 511 }
homero 16:a32ee9ed15c4 512 }
re633 9:ef0907fda2f1 513
homero 16:a32ee9ed15c4 514 //If beacon visible
homero 16:a32ee9ed15c4 515 if(beacon_syncronised_flag == 1) {
homero 16:a32ee9ed15c4 516
homero 16:a32ee9ed15c4 517 //Firstly check beacon is still visible
homero 16:a32ee9ed15c4 518 beacon_syncronised_flag = 0;
homero 16:a32ee9ed15c4 519 //Update array concerning which IRs can see the beacon
homero 16:a32ee9ed15c4 520 for(loopCounter = 0; loopCounter<8; loopCounter++) {
homero 15:f7a8989a3cd3 521
homero 16:a32ee9ed15c4 522 //Find which sensor has the highest reading
homero 16:a32ee9ed15c4 523 if( gv_IRValDiffs[g_beaconOn][loopCounter] > BEACON_SUSPECTED) {
homero 16:a32ee9ed15c4 524 if( valid_distances[loopCounter] > 100 && valid_distances[mod8((loopCounter + 1),8)]>100 && valid_distances[mod8((loopCounter - 1),8)]>100) {
homero 16:a32ee9ed15c4 525 if(gv_IRVals[g_beaconOn][loopCounter] > maxValue[0]) {
homero 16:a32ee9ed15c4 526 maxValue[0] = gv_IRVals[g_beaconOn][loopCounter];
homero 16:a32ee9ed15c4 527 maxValue[1] = loopCounter;
homero 16:a32ee9ed15c4 528 beacon_syncronised_flag = 1; //This will remain as one so long as at least on sensor can see beacon
homero 16:a32ee9ed15c4 529 }
homero 16:a32ee9ed15c4 530 }
re633 9:ef0907fda2f1 531 }
re633 9:ef0907fda2f1 532 }
homero 15:f7a8989a3cd3 533
homero 16:a32ee9ed15c4 534 //Only do this if beacon still visible
homero 15:f7a8989a3cd3 535 if(beacon_syncronised_flag == 1) {
homero 15:f7a8989a3cd3 536
homero 16:a32ee9ed15c4 537 //If the adjacent two sensors are above the threshold too then they can also be marked as illuminated
homero 15:f7a8989a3cd3 538 for(loopCounter = 0; loopCounter<8; loopCounter++) {
re633 9:ef0907fda2f1 539
homero 16:a32ee9ed15c4 540 //reset all beacon detected values
homero 16:a32ee9ed15c4 541 beacon_detected[loopCounter] = 0;
homero 16:a32ee9ed15c4 542
homero 16:a32ee9ed15c4 543 if(abs(maxValue[1] - loopCounter)< 3 || abs(maxValue[1] + 8 - loopCounter)< 3 || abs(maxValue[1] - 8 - loopCounter)< 3) {
homero 16:a32ee9ed15c4 544 if(gv_IRValDiffs[g_beaconOn][loopCounter] > BEACON_SUSPECTED) {
homero 16:a32ee9ed15c4 545 beacon_detected[loopCounter] = 1;
re633 9:ef0907fda2f1 546 }
re633 9:ef0907fda2f1 547 }
re633 9:ef0907fda2f1 548 }
homero 15:f7a8989a3cd3 549
homero 14:fc406dfff94f 550
homero 16:a32ee9ed15c4 551 //Update the piswarm LEDS so the ones that can see the beacon are on.
homero 16:a32ee9ed15c4 552 piswarm.set_oleds(beacon_detected[0]||beacon_detected[1],
homero 16:a32ee9ed15c4 553 beacon_detected[1]||beacon_detected[2],
homero 16:a32ee9ed15c4 554 beacon_detected[2],
homero 16:a32ee9ed15c4 555 beacon_detected[3],
homero 16:a32ee9ed15c4 556 0,
homero 16:a32ee9ed15c4 557 beacon_detected[4],
homero 16:a32ee9ed15c4 558 beacon_detected[5],
homero 16:a32ee9ed15c4 559 beacon_detected[5]||beacon_detected[6],
homero 16:a32ee9ed15c4 560 beacon_detected[6]||beacon_detected[7],
homero 16:a32ee9ed15c4 561 beacon_detected[7]||beacon_detected[0]);
homero 15:f7a8989a3cd3 562
homero 16:a32ee9ed15c4 563 //If the max IR value is below a threshold then move toward beacon. Else change state
homero 16:a32ee9ed15c4 564 if(maxValue[0] < at_beacon_threshold) {
homero 16:a32ee9ed15c4 565
homero 16:a32ee9ed15c4 566 //Calculate the heading of Pi-Swarm Relative to beacon
homero 16:a32ee9ed15c4 567 calculateNewHeading();
homero 16:a32ee9ed15c4 568
homero 16:a32ee9ed15c4 569 if(g_currentHeading > 5 || g_currentHeading < -5) {
homero 16:a32ee9ed15c4 570 turnDegrees(-g_currentHeading);
re633 9:ef0907fda2f1 571 }
homero 15:f7a8989a3cd3 572
homero 16:a32ee9ed15c4 573 //If the beacon is not currently on but obstacle detected then do obstacle avoidance
homero 16:a32ee9ed15c4 574 int16_t randomAngle;
homero 16:a32ee9ed15c4 575 if(beacon_illuminated_flag == 0) {
homero 16:a32ee9ed15c4 576 if(gv_IRDistances[0] < 100 || gv_IRDistances[1] < 100) {
homero 17:4fa7c9e1b512 577 back_move_timer.reset();
homero 16:a32ee9ed15c4 578 randomAngle = rand()%90 - 135;
homero 16:a32ee9ed15c4 579 piswarm.stop();
homero 16:a32ee9ed15c4 580 wait_ms(100);
homero 16:a32ee9ed15c4 581 piswarm.backward(0.3);
homero 16:a32ee9ed15c4 582 wait_ms(200);
homero 16:a32ee9ed15c4 583 turnDegrees(randomAngle);
homero 16:a32ee9ed15c4 584 } else if (gv_IRDistances[6] < 100 || gv_IRDistances[7] < 100) {
homero 17:4fa7c9e1b512 585 back_move_timer.reset();
homero 16:a32ee9ed15c4 586 randomAngle = rand()%90 + 45;
homero 16:a32ee9ed15c4 587 piswarm.stop();
homero 16:a32ee9ed15c4 588 wait_ms(100);
homero 16:a32ee9ed15c4 589 piswarm.backward(0.3);
homero 16:a32ee9ed15c4 590 wait_ms(200);
homero 16:a32ee9ed15c4 591 turnDegrees(randomAngle);
homero 16:a32ee9ed15c4 592 } else if ( distance_ultrasonic_sensor < 100) {
homero 17:4fa7c9e1b512 593 back_move_timer.reset();
homero 16:a32ee9ed15c4 594 randomAngle = rand()%60 - 30;
homero 16:a32ee9ed15c4 595 piswarm.stop();
homero 16:a32ee9ed15c4 596 wait_ms(100);
homero 16:a32ee9ed15c4 597 piswarm.backward(0.3);
homero 16:a32ee9ed15c4 598 wait_ms(200);
homero 16:a32ee9ed15c4 599 turnDegrees(randomAngle);
homero 17:4fa7c9e1b512 600 } else if (back_move_timer.read() > 10){
homero 17:4fa7c9e1b512 601 back_move_timer.reset();
homero 17:4fa7c9e1b512 602 randomAngle = rand()%90 + 45;
homero 17:4fa7c9e1b512 603 piswarm.stop();
homero 17:4fa7c9e1b512 604 wait_ms(100);
homero 17:4fa7c9e1b512 605 piswarm.backward(0.5);
homero 17:4fa7c9e1b512 606 wait_ms(200);
homero 17:4fa7c9e1b512 607 turnDegrees(randomAngle);
homero 15:f7a8989a3cd3 608 }
homero 13:c18d82f62d38 609 }
homero 16:a32ee9ed15c4 610 piswarm.right_motor(0.3*r_mot_scaler*r_mot_scaler);
homero 16:a32ee9ed15c4 611 piswarm.left_motor(0.3*l_mot_scaler*l_mot_scaler);
homero 16:a32ee9ed15c4 612 wait_ms(500);
homero 16:a32ee9ed15c4 613 //Should be at beacon
homero 16:a32ee9ed15c4 614 } else {
homero 16:a32ee9ed15c4 615 piswarm.stop();
homero 17:4fa7c9e1b512 616 //homero comment this
homero 17:4fa7c9e1b512 617 /* calculateNewHeading();
homero 16:a32ee9ed15c4 618 if(g_currentHeading > 5 || g_currentHeading < -5) {
homero 17:4fa7c9e1b512 619 turnDegrees(-g_currentHeading);*/
homero 15:f7a8989a3cd3 620
homero 16:a32ee9ed15c4 621 //If either of these flags is one then the beacon should be the home beacon so change to state 4.
homero 16:a32ee9ed15c4 622 if(return_flag == 1 || back_flag == 1) {
homero 16:a32ee9ed15c4 623 changeState(States::AT_HOME_BEACON);
re633 12:118f2b0ed8eb 624 } else {
homero 16:a32ee9ed15c4 625 changeState(States::AT_TARGET_BEACON);
re633 12:118f2b0ed8eb 626 }
re633 9:ef0907fda2f1 627 }
re633 9:ef0907fda2f1 628 }
homero 16:a32ee9ed15c4 629 //Else need to syncronise with beacon
homero 16:a32ee9ed15c4 630 } else {
homero 15:f7a8989a3cd3 631
homero 16:a32ee9ed15c4 632 while(beacon_syncronised_flag == 0) {
homero 15:f7a8989a3cd3 633
homero 16:a32ee9ed15c4 634 //Sychronise the ticker with the beacon
homero 16:a32ee9ed15c4 635 uint8_t testBefore = 0;
homero 16:a32ee9ed15c4 636 uint8_t testDuring = 0;
homero 16:a32ee9ed15c4 637 uint8_t testAfter = 0;
homero 16:a32ee9ed15c4 638 for(loopCounter = 0; loopCounter < 8; loopCounter++) {
homero 16:a32ee9ed15c4 639 if (gv_IRValDiffs[mod8((g_beaconOn - 1),IR_READ_PER_BEAC)][loopCounter] > BEACON_SUSPECTED) {
homero 16:a32ee9ed15c4 640 testBefore = 1;
homero 16:a32ee9ed15c4 641 }
homero 16:a32ee9ed15c4 642 if (gv_IRValDiffs[g_beaconOn][loopCounter] > BEACON_SUSPECTED) {
homero 16:a32ee9ed15c4 643 testDuring = 1;
homero 16:a32ee9ed15c4 644 }
homero 16:a32ee9ed15c4 645 if (gv_IRValDiffsTwo[mod8((g_beaconOn + 2),IR_READ_PER_BEAC)][loopCounter] > BEACON_SUSPECTED) {
homero 16:a32ee9ed15c4 646 testAfter = 1;
homero 16:a32ee9ed15c4 647 }
homero 16:a32ee9ed15c4 648 if (gv_IRValDiffsTwo[mod8((g_beaconOn + 2),IR_READ_PER_BEAC)][loopCounter] < -BEACON_SUSPECTED) {
homero 16:a32ee9ed15c4 649 testAfter = 2;
homero 16:a32ee9ed15c4 650 }
homero 16:a32ee9ed15c4 651 }
homero 15:f7a8989a3cd3 652
homero 16:a32ee9ed15c4 653 //Firstly if the beacon is not detected by any of the sensors then change state back to search
homero 16:a32ee9ed15c4 654 if(testBefore == 0 && testDuring == 0 && testAfter == 0) {
homero 16:a32ee9ed15c4 655 changeState(States::SEARCHING_FWD);
homero 16:a32ee9ed15c4 656 beacon_syncronised_flag = 1;//to exit while loop
homero 16:a32ee9ed15c4 657
homero 16:a32ee9ed15c4 658 //If the tick before g_beaconOn is detecting the change caused by the flash change the value of g_beaconOn
homero 16:a32ee9ed15c4 659 } else if(testBefore == 1) {
homero 16:a32ee9ed15c4 660 g_beaconOn = g_beaconOn - 1;
homero 16:a32ee9ed15c4 661
homero 16:a32ee9ed15c4 662 //If the After Tick does not show a drop in value then it is also occuring within the beacon flash so delay the ticker by 10ms
homero 16:a32ee9ed15c4 663 } else if(testBefore == 0 && testDuring == 1 && testAfter == 1) {
homero 17:4fa7c9e1b512 664 if(sync_attempt_count > 5){
homero 17:4fa7c9e1b512 665 changeState(States::SEARCHING_FWD);
homero 17:4fa7c9e1b512 666 beacon_syncronised_flag = 1;//to exit while loop
homero 17:4fa7c9e1b512 667 }
homero 17:4fa7c9e1b512 668 else
homero 17:4fa7c9e1b512 669 {
homero 17:4fa7c9e1b512 670 ticker_25ms.detach();
homero 17:4fa7c9e1b512 671 tickChangeTimeout.attach_us(&atTimeout,7000);
homero 17:4fa7c9e1b512 672 wait(1);//Do not delete this wait
homero 17:4fa7c9e1b512 673 sync_attempt_count++;
homero 17:4fa7c9e1b512 674 }
homero 15:f7a8989a3cd3 675
homero 16:a32ee9ed15c4 676 //If successful the set flag
homero 16:a32ee9ed15c4 677 } else if (testBefore == 0 && testDuring == 1 && testAfter == 2) {
homero 16:a32ee9ed15c4 678 beacon_syncronised_flag = 1;
homero 15:f7a8989a3cd3 679
homero 16:a32ee9ed15c4 680 //Error handle. If this happens stop the piswarm
homero 16:a32ee9ed15c4 681 } else {
homero 16:a32ee9ed15c4 682 piswarm.set_oled_colour(255,255,255);
homero 16:a32ee9ed15c4 683 piswarm.set_oleds(1,1,1,1,1,1,1,1,1,1);
homero 16:a32ee9ed15c4 684 piswarm.cls();
homero 16:a32ee9ed15c4 685 piswarm.printf("%d %d %d",testBefore, testDuring,testAfter);
homero 16:a32ee9ed15c4 686 piswarm.stop();
homero 16:a32ee9ed15c4 687 ticker_25ms.detach();
homero 16:a32ee9ed15c4 688 tickChangeTimeout.attach_us(&atTimeout,10000);
homero 16:a32ee9ed15c4 689 wait_ms(500);
homero 16:a32ee9ed15c4 690 beacon_syncronised_flag = 1;
homero 16:a32ee9ed15c4 691 changeState(States::SEARCHING_FWD);
re633 9:ef0907fda2f1 692 }
re633 9:ef0907fda2f1 693 }
homero 16:a32ee9ed15c4 694 }
homero 15:f7a8989a3cd3 695
homero 16:a32ee9ed15c4 696 //At target Beacon.
homero 16:a32ee9ed15c4 697 //Broadcast target beacon found and wait.
homero 16:a32ee9ed15c4 698 } else if (gv_state == States::AT_TARGET_BEACON) {
homero 17:4fa7c9e1b512 699
homero 17:4fa7c9e1b512 700 int8_t aligned_to_beacon = 0;
homero 16:a32ee9ed15c4 701 piswarm.stop();
homero 16:a32ee9ed15c4 702 piswarm.set_oled_colour(150,255,0);
homero 16:a32ee9ed15c4 703 piswarm.set_oleds(1,1,1,1,1,1,1,1,1,1);
homero 17:4fa7c9e1b512 704
homero 17:4fa7c9e1b512 705 //to fully aligned when its near to the target beacon
homero 17:4fa7c9e1b512 706 calculateNewHeading();
homero 17:4fa7c9e1b512 707 while(aligned_to_beacon == 0){
homero 17:4fa7c9e1b512 708 if(g_currentHeading > 5 || g_currentHeading < -5) {
homero 17:4fa7c9e1b512 709 wait(1);
homero 17:4fa7c9e1b512 710 turnDegrees(-g_currentHeading);
homero 17:4fa7c9e1b512 711 }else{
homero 17:4fa7c9e1b512 712 aligned_to_beacon = 1;
homero 17:4fa7c9e1b512 713 }
homero 17:4fa7c9e1b512 714 }
homero 17:4fa7c9e1b512 715
homero 16:a32ee9ed15c4 716 //Detach tickers before broadcasting and waiting for reply
homero 16:a32ee9ed15c4 717 ticker_25ms.detach();
homero 16:a32ee9ed15c4 718 ticker_ultrasonic50ms.detach();
homero 16:a32ee9ed15c4 719
homero 16:a32ee9ed15c4 720 uint8_t const num_to_broadcast = 10;
homero 15:f7a8989a3cd3 721
homero 16:a32ee9ed15c4 722 while(back_flag == 0) {
homero 16:a32ee9ed15c4 723 if(broadcasted_flag == 1 && broadcasted_count < num_to_broadcast) {
homero 16:a32ee9ed15c4 724 broadcastTimeout.attach_us(&atBroadcastTimeout,100000);
homero 16:a32ee9ed15c4 725 broadcasted_flag = 0;
homero 13:c18d82f62d38 726 }
re633 12:118f2b0ed8eb 727 }
homero 16:a32ee9ed15c4 728
homero 16:a32ee9ed15c4 729 ticker_25ms.attach_us(&readIRs,25000);
homero 16:a32ee9ed15c4 730 ticker_ultrasonic50ms.attach_us(&get_ultrasonic_readings,50000);
homero 16:a32ee9ed15c4 731
homero 16:a32ee9ed15c4 732 //Return to beacon search state but now robot is lookling for the home beacon.
homero 16:a32ee9ed15c4 733 changeState(States::SEARCHING_FWD);
homero 16:a32ee9ed15c4 734
homero 16:a32ee9ed15c4 735 //Back at home area. Stop and wait.
homero 16:a32ee9ed15c4 736 } else if (gv_state == States::AT_HOME_BEACON) {
homero 16:a32ee9ed15c4 737 piswarm.stop();
homero 16:a32ee9ed15c4 738 piswarm.set_oleds(1,1,1,1,1,1,1,1,1,1);
homero 16:a32ee9ed15c4 739 piswarm.play_tune( "T180L8O5EERERCL4EGR<GR",22 );
homero 16:a32ee9ed15c4 740 while(1) {
homero 16:a32ee9ed15c4 741 piswarm.set_oled_colour(0,150,0);
homero 16:a32ee9ed15c4 742 wait_ms(200);
homero 16:a32ee9ed15c4 743 piswarm.set_oled_colour(150,0,0);
homero 16:a32ee9ed15c4 744 wait_ms(200);
homero 16:a32ee9ed15c4 745 piswarm.set_oled_colour(0,0,150);
homero 16:a32ee9ed15c4 746 wait_ms(200);
homero 16:a32ee9ed15c4 747 }
re633 9:ef0907fda2f1 748 }
homero 15:f7a8989a3cd3 749 }
jah128 7:d03e54d9eb1c 750 }
homero 16:a32ee9ed15c4 751
jah128 2:e806b595f9ce 752 /***************************************************************************************************************************************
jah128 2:e806b595f9ce 753 *
jah128 4:823174be9a6b 754 * Beyond this point, empty code blocks for optional functions is given
jah128 2:e806b595f9ce 755 *
homero 15:f7a8989a3cd3 756 * These may be left blank if not used, but should not be deleted
jah128 2:e806b595f9ce 757 *
jah128 2:e806b595f9ce 758 **************************************************************************************************************************************/
homero 15:f7a8989a3cd3 759
jah128 1:37502eb3b70f 760 // Communications
jah128 1:37502eb3b70f 761
jah128 1:37502eb3b70f 762 // If using the communication stack (USE_COMMUNICATION_STACK = 1), functionality for handling user RF responses should be added to the following functions
jah128 1:37502eb3b70f 763 // If the communication stack is not being used, all radio data is sent to processRawRFData() instead
jah128 1:37502eb3b70f 764
homero 15:f7a8989a3cd3 765 void handleUserRFCommand(char sender, char broadcast_message, char request_response, char id, char is_command, char function, char * data, char length)
homero 15:f7a8989a3cd3 766 {
jah128 1:37502eb3b70f 767 // A 'user' RF Command has been received: write the code here to process it
jah128 1:37502eb3b70f 768 // sender = ID of the sender, range 0 to 31
jah128 1:37502eb3b70f 769 // broadcast_message = 1 is message sent to all robots, 0 otherwise
jah128 1:37502eb3b70f 770 // request_response = 1 if a response is expected, 0 otherwise
jah128 1:37502eb3b70f 771 // id = Message ID, range 0 to 255
jah128 1:37502eb3b70f 772 // is_command = 1 is message is a command, 0 if it is a request. If RF_ALLOW_COMMANDS is not selected, only requests will be sent to this block
jah128 1:37502eb3b70f 773 // function = The function identifier. Range 0 to 15
jah128 1:37502eb3b70f 774 // * data = Array containing extra data bytes
jah128 1:37502eb3b70f 775 // length = Length of extra data bytes held (range 0 to 57)
homero 15:f7a8989a3cd3 776
homero 15:f7a8989a3cd3 777
jah128 4:823174be9a6b 778 //Do something...
re633 12:118f2b0ed8eb 779 piswarm.cls();
re633 12:118f2b0ed8eb 780 piswarm.locate(0,0);
re633 12:118f2b0ed8eb 781 piswarm.printf("URF:%d",function);
re633 12:118f2b0ed8eb 782 if(length > 0) {
re633 12:118f2b0ed8eb 783 piswarm.locate(0,1);
homero 15:f7a8989a3cd3 784 piswarm.printf("%s",data);
re633 12:118f2b0ed8eb 785 }
re633 12:118f2b0ed8eb 786
homero 15:f7a8989a3cd3 787 if(function == 1) {
re633 12:118f2b0ed8eb 788 start_flag = 1;
re633 12:118f2b0ed8eb 789 }
re633 12:118f2b0ed8eb 790
homero 15:f7a8989a3cd3 791 if(function == 5) {
homero 17:4fa7c9e1b512 792 stopSearchTimeout.attach(&atStopSearchTimeout,6);
re633 12:118f2b0ed8eb 793 return_flag = 1;
re633 12:118f2b0ed8eb 794 }
homero 15:f7a8989a3cd3 795 if(function == 6) {
re633 12:118f2b0ed8eb 796 back_flag = 1;
re633 10:da62735d6df9 797 }
homero 15:f7a8989a3cd3 798 }
jah128 1:37502eb3b70f 799
re633 12:118f2b0ed8eb 800 // This function is used to send the RF message:
re633 12:118f2b0ed8eb 801 void broadcast_user_rf_command(int function, char * message, int length)
re633 12:118f2b0ed8eb 802 {
re633 12:118f2b0ed8eb 803 //This function augments the communications stack
re633 12:118f2b0ed8eb 804 //It sends a 'user' RF command to all members (ie target_id = 0)
re633 12:118f2b0ed8eb 805 //It sends a 'request', not a 'command', meaning it will still be handled if commands are disabled (RF_ALLOW_COMMANDS set to 0, recommended)
re633 12:118f2b0ed8eb 806 //It takes three inputs:
re633 12:118f2b0ed8eb 807 // * function (an integer from 0 to 15)
re633 12:118f2b0ed8eb 808 // * message (a char array)
re633 12:118f2b0ed8eb 809 // * length (length of message in bytes)
re633 12:118f2b0ed8eb 810 send_rf_message(0,48+(function % 16),message,length);
re633 12:118f2b0ed8eb 811 }
re633 12:118f2b0ed8eb 812
homero 15:f7a8989a3cd3 813 void handleUserRFResponse(char sender, char broadcast_message, char success, char id, char is_command, char function, char * data, char length)
homero 15:f7a8989a3cd3 814 {
jah128 1:37502eb3b70f 815 // A 'user' RF Response has been received: write the code here to process it
jah128 1:37502eb3b70f 816 // sender = ID of the sender, range 0 to 31
jah128 1:37502eb3b70f 817 // broadcast_message = 1 is message sent to all robots, 0 otherwise
jah128 1:37502eb3b70f 818 // success = 1 if operation successful, 0 otherwise
jah128 1:37502eb3b70f 819 // id = Message ID, range 0 to 255
jah128 1:37502eb3b70f 820 // is_command = 1 is message is a command, 0 if it is a request. If RF_ALLOW_COMMANDS is not selected, only requests will be sent to this block
jah128 1:37502eb3b70f 821 // function = The function identifier. Range 0 to 15
jah128 1:37502eb3b70f 822 // * data = Array containing extra data bytes
jah128 1:37502eb3b70f 823 // length = Length of extra data bytes held (range 0 to 57)
jah128 4:823174be9a6b 824
homero 15:f7a8989a3cd3 825 //Do something...
homero 15:f7a8989a3cd3 826 }
jah128 1:37502eb3b70f 827
homero 15:f7a8989a3cd3 828 void processRawRFData(char * rstring, char cCount)
homero 15:f7a8989a3cd3 829 {
jah128 1:37502eb3b70f 830 // A raw RF packet has been received: write the code here to process it
jah128 1:37502eb3b70f 831 // rstring = The received packet
jah128 1:37502eb3b70f 832 // cCount = Packet length
homero 15:f7a8989a3cd3 833
jah128 4:823174be9a6b 834 //Do something...
jah128 0:46cd1498a39a 835 }
jah128 0:46cd1498a39a 836
homero 15:f7a8989a3cd3 837 void switch_pressed()
homero 15:f7a8989a3cd3 838 {
jah128 1:37502eb3b70f 839 //Switch(es) pressed {1 = Center 2 = Right 4 = Left 8 = Down 16 = Up}
jah128 1:37502eb3b70f 840 char switches = piswarm.get_switches();
homero 15:f7a8989a3cd3 841
jah128 1:37502eb3b70f 842 //Do something...
homero 13:c18d82f62d38 843 }