// Alisdair Gurney, January 2020 // // When the epee tip is depressed, near and centre body wires complete the circuit and pull 'swordtipIn' to ground. // The sword tip becomes part of the circuit when depressed. // Body wire pin 3 (far) is not used. // Fencing target made from beer can bases. // 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 closed sword tip). // // this sketch uses an epee but scores like a foil, so: // hit not on target = white light // hit on target = red light // light touch on target = no light (tip not depressed so no circuit) // // Components: 6 (or 8) x LEDs, 6 (or 8) x resistors (to suit LEDs) // // modus operandi: // // When first powered-on all the LEDs flash a couple of times to confirm they work OK. // 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, you don't have to wait (there's also a brief flash on the box coloured LED). // If you hit the target the cycling delay is reduced (by 50 millisecondss), so the cycling gradually speeds up // If the target is missed the white LED is illuminated, and there's a short pause before the next one is indicated. // If you miss, the cycling delay is extended by 50 milliseconds, so gradually slowing the cycling. // If there are no strikes the cycling of targets continues with no change. // Information about period, response time and HIT/MISS are written to the serial console (9600 baud) // 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 // 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 T1 = 6; const int T2 = 7; const int T3 = 8; const int T4 = 9; // setup pins for box const int whiteLED = 10; // Miss const int redLED = 11; // Score // and the sword const int swordtipIn = 12; // pin for sword tip // amount to speed up or slow down const int increment = 50; int target; // which target to be lit/scored 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 // initialize countdown timer unsigned long DELAY_TIME = 3000; // 3 seconds initial period .. changes depending on success millisDelay ledDelay; 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 pinMode(redLED, OUTPUT); // on control box and maybe also on target pinMode(L1, OUTPUT); // on target 1 pinMode(L2, OUTPUT); // on target 2 pinMode(L3, OUTPUT); // on target 3 pinMode(L4, OUTPUT); // on target 4 // and input. INPUT_PULLUP is used to avoid spurious results from external factors pinMode(T1, INPUT_PULLUP); pinMode(T2, INPUT_PULLUP); pinMode(T3, INPUT_PULLUP); pinMode(T4, INPUT_PULLUP); // and the sword pinMode(swordtipIn, 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); digitalWrite(whiteLED, HIGH); // turn the target LEDs on to confirm they are working digitalWrite(L1, HIGH); digitalWrite(L2, HIGH); digitalWrite(L3, HIGH); digitalWrite(L4, HIGH); // Pause before clearing the lights delay (800); digitalWrite(redLED, LOW); digitalWrite(whiteLED, LOW); digitalWrite(L1, LOW); digitalWrite(L2, LOW); digitalWrite(L3, LOW); digitalWrite(L4, LOW); delay (500); } // write to serial console Serial.println("------------------------"); Serial.println("---- Fencing 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."); } void loop() { // loop until tip is pressed // cycle random targets depending on the period // if it's a hit on target, reduce the timeout and return // if a miss then light white light, increase period and return do { if ( ledDelay.remaining() == 0 ) {nextTarget(); } tipval=digitalRead(swordtipIn); } while (tipval > 0) ; // we're out of the loop because a hit has been made 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"); // 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; } if (targval > 0) // hit not on target {digitalWrite(whiteLED, HIGH); Serial.print("target: "); Serial.print(target); Serial.println(" MISS"); // pause with MISS light on delay(1500); DELAY_TIME = DELAY_TIME + increment; // loop to ensure tip is removed from target before progressing do { tipval=digitalRead(swordtipIn); } while (tipval == 0) ; digitalWrite(whiteLED, LOW); // tip's disengaged so indicate next target nextTarget(); } else // hit was on target, quick flash, reduce interval, continue {digitalWrite(redLED, HIGH); Serial.print("target: "); Serial.print(target); Serial.println(" HIT"); DELAY_TIME = DELAY_TIME - increment; // loop to ensure tip is removed from before progressing do { tipval=digitalRead(swordtipIn); } while (tipval == 0) ; digitalWrite(redLED, LOW); nextTarget(); } // go around again } void nextTarget() { // lights off digitalWrite(L1, LOW); digitalWrite(L2, LOW); digitalWrite(L3, LOW); digitalWrite(L4, 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(4) + 1; } while (target == prevTarget); //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; } }