// Alisdair Gurney, January 2020 // // This version is for five targets, with sword to ground for Sabre. // // The centre target is made from a beer can base, padded with neoprene and covered with lame material. // Similarly, the edges neoprene wrapped aaround chipboard and covered with lame material // Each target is connected to an input pin in PULLUP mode, and has an associated indicator light on an output pin. // A hit is registered by pulling the pin to ground (via the sword blade - not tip as in the epee targets ). // // hit on target = light flashes // wrong target or miss - nothing happens // // Components: 6 x LEDs, 6 x resistors (to suit LEDs) // // modus operandi: // // When first powered-on all the LEDs flash three times to confirm they work OK. // Target's eyes blink to indicate the start of the countdown. // An LED beside a random target is illuminated, the aim is to hit this target // Initially the period between each target is three seconds. // If you hit a target the next one is indicated immediately, you don't have to wait (there's also a short flash on the box LED). // When you hit a target the cycling delay is reduced (by 50 millisecondss), so the cycling gradually speeds up // Information about period, response time, HIT/MISS and accuracy are written to the serial console (you can connect a phone or laptop using USB) // The push switch on the box performs a reset, no need to cycle the power if you want to restart. // Detailed information about how it works is included in comments below. // You only need one additional library: #include // ####################################################### // this is the initial target light delay in milliseconds, adjust accordingly const long INITIAL_DELAY_TIME = 3000; //###################################################### // setup target pins: L - LED indicator, T - target const int L1 = 2; const int L2 = 3; const int L3 = 4; const int L4 = 5; const int L5 = 6; const int T1 = 7; const int T2 = 8; const int T3 = 9; const int T4 = 10; const int T5 = 11; // setup pins for box const int redLED = 12; // Score [shows on box ] // amount to speed up after a hit const int increment = 50; int target; // which target to be lit/scored ... Add 6 for associated pin if using my Fritz sketch int tipval; // Tip hit state : 0 is a hit int targval; // Target hit state int responseTime; // response time, milliseconds int prevTarget; // try to avoid repeating the same target int totalhits = 0; // fencer's hits on target int posshits = 0; // number of targets that were lit // initialize target countdown timer unsigned long DELAY_TIME = INITIAL_DELAY_TIME; millisDelay ledDelay; // initialise session countdown timer unsigned long SESSION_TIME = 30000; // length of session millisDelay Session; // ################### SETUP void setup() { Serial.begin(9600); // use serial port to monitor status randomSeed(analogRead(0)); // initialize the LED pins as output: // pinMode(whiteLED, OUTPUT); ... on control box and maybe also on target - not needde for Sabre pinMode(redLED, OUTPUT); // on control box and maybe also on target pinMode(L1, OUTPUT); // light on target 1 pinMode(L2, OUTPUT); // on target 2 pinMode(L3, OUTPUT); // on target 3 pinMode(L4, OUTPUT); // on target 4 pinMode(L5, OUTPUT); // on target 5 // and input. INPUT_PULLUP is used to avoid spurious results from external factors pinMode(T1, INPUT_PULLUP); // target 1 pinMode(T2, INPUT_PULLUP); pinMode(T3, INPUT_PULLUP); pinMode(T4, INPUT_PULLUP); pinMode(T5, INPUT_PULLUP); // loop three times to flash lights to confirm all are OK for (int i = 1 ; i <= 3; i++) { // turn the box LEDs ON to check they are working: digitalWrite(redLED, HIGH); delay(400); digitalWrite(redLED, LOW); flash(800); // box LED is lit separately, simply because there wasn't enough power available to drive six LEDs simultaneously // due to resistor settings in my prototype } // write to serial console Serial.println("------------------------"); Serial.println("---- Sabre target ----"); Serial.println("------------------------"); Serial.print("Initial period: "); Serial.print(DELAY_TIME); Serial.println("ms"); Serial.print("Increases "); Serial.print(increment); Serial.println("ms each miss,"); Serial.print("decreases "); Serial.print(increment); Serial.println("ms each hit."); // pret delay(2000); // flash the eyses .. allez blink(); // start the countdown timer Session.start(SESSION_TIME); } // end of setup void loop() { // loop until target has been hit // cycle random targets depending on the period // if there's a hit on the correct target, reduce the timeout and return do { if ( Session.remaining() == 0 ) {timeout(); } if ( ledDelay.remaining() == 0 ) {nextTarget(); } tipval=digitalRead(target + 6); } while ( tipval > 0 ) ; // we're out of the loop because a hit has been made or we've timed out responseTime = DELAY_TIME - ledDelay.remaining(); // in millisecs //write result to console Serial.println("------------------------"); Serial.print("period: "); Serial.print(DELAY_TIME); Serial.println("ms"); Serial.print("response: "); Serial.print(responseTime); Serial.println("ms"); Serial.print("Remaining : "); Serial.print(Session.remaining() / 1000); Serial.println(" seconds"); // read the status of the target target switch (target) { case 1: targval = digitalRead(T1); break; case 2: targval = digitalRead(T2); break; case 3: targval = digitalRead(T3); break; case 4: targval= digitalRead(T4); break; case 5: targval= digitalRead(T5); break; } if (targval > 0) // hit wrong target ... { // shouldn't be here with sabre target unless very short contact Serial.print("target: "); Serial.print(target); Serial.println(" MISS"); // pause delay(1500); DELAY_TIME = DELAY_TIME + increment; nextTarget(); } else // hit was on target, quick flash, reduce interval, continue { totalhits = totalhits + 1; digitalWrite(redLED, HIGH); Serial.print("target: "); Serial.print(target); Serial.print(" HIT. Total hits : "); Serial.println(totalhits); Serial.print("Accuracy: "); Serial.print( (100 / posshits) * totalhits); Serial.println("%"); DELAY_TIME = DELAY_TIME - increment; delay(200); digitalWrite(redLED, LOW); nextTarget(); } // go around again } void nextTarget() { // lights off digitalWrite(L1, LOW); digitalWrite(L2, LOW); digitalWrite(L3, LOW); digitalWrite(L4, LOW); digitalWrite(L5, LOW); //short pause before next light delay(300); // reset the countdown timer ledDelay.start(DELAY_TIME); prevTarget = target; // pick a random target, but not the current one do { target = random(5) + 1; } while (target == prevTarget); posshits = posshits + 1; //turn selected target on switch (target) { case 1: digitalWrite(L1, HIGH); break; case 2: digitalWrite(L2, HIGH); break; case 3: digitalWrite(L3, HIGH); break; case 4: digitalWrite(L4, HIGH); break; case 5: digitalWrite(L5, HIGH); break; } } void timeout() { //write result to console Serial.println("##########################"); Serial.println("Time up .. "); Serial.print("Number of hits in "); Serial.print(SESSION_TIME / 1000); Serial.print(" seconds: "); Serial.println(totalhits); Serial.print("Targets lit : "); Serial.println(posshits); Serial.print("Accuracy: "); Serial.print( (100 / posshits) * totalhits); Serial.println("%"); Serial.println("##########################"); Serial.println(); // all target lights ON to indicate timeout flash(3000); //reset score totalhits=0; posshits=0; DELAY_TIME = INITIAL_DELAY_TIME; delay (3000); blink(); // reset the countdown timer Session.start(SESSION_TIME); } void flash(int pause) { // flash all target LEDs // digitalWrite(whiteLED, HIGH); // turn all the target LEDs ON digitalWrite(L1, HIGH); digitalWrite(L2, HIGH); digitalWrite(L3, HIGH); digitalWrite(L4, HIGH); digitalWrite(L5, HIGH); // Pause before clearing the lights delay(pause); digitalWrite(L1, LOW); digitalWrite(L2, LOW); digitalWrite(L3, LOW); digitalWrite(L4, LOW); digitalWrite(L5, LOW); delay (500); } void blink() { // Blink the eyes digitalWrite(L1, LOW); digitalWrite(L2, LOW); delay(100); digitalWrite(L1, HIGH); digitalWrite(L2, HIGH); delay(100); digitalWrite(L1, LOW); digitalWrite(L2, LOW); delay(200); digitalWrite(L1, HIGH); digitalWrite(L2, HIGH); delay(100); digitalWrite(L1, LOW); digitalWrite(L2, LOW); delay (2000); }