/*
###### Airsoft/Paintball Domination Game ######
Description:
No space for the batteries, so that was a bad design. Everything but the 6 LED lamps is powered
by a 5v USB battery bank. The LED lamps are powered by an airsoft 11.1v lipo.
To start a game, just press and release the "admin" button (the yellow/orange middle one that
doesn't illuminate. That immediately begins starts the game timer (which can be changed in the code).
The box blinks orange to indicate no team has held the point yet.
Blue team presses and releases the blue button and their time begins immediately, complete
with the blue flashing light. Green button does the same.
When the game timer runs out, the program looks at the two accrued times, and whichever
team has the most time, the box will rapidly blink that team's color LED lamps.
In the case of a tie, the box will rapidly blink the orange admin lights. And, of course,
The circuit:
Arduino Uno R3.
SunFounder IIC I2C 16x2.
3 momentary push buttons (two illuminate).
Three relays.
Six LED lamps in appropriate colors.
Translucent ammo can.
Created 21 September 2023
Modified 6 October 2023
added "Press Start"
LCD now shows HH:MM:SS
By BearsoftME
for Southern Aroostook Action Sports
SAASMaine.com
Any questions or comments, please email the author: [email protected]
Demo: https://www.youtube.com/watch?v=ft3u3nQDFkM
Partial Parts List:
The board is ELEGOO UNO: https://www.amazon.com/gp/product/B01EWOE0UU/
The display is a standard I2C: https://www.amazon.com/gp/product/B019K5X53O/
The relays: https://www.amazon.com/gp/product/B07BVXT1ZK/
The buttons: https://www.amazon.com/gp/product/B071CNX3CF/
The LEDs... pick your colors: https://www.amazon.com/gp/product/B07FXTGBBB/
The box is a clear ammo can-style box from Walmart.. find it in home improvement.
Instead of powering the LEDs via the relays with the 5v from the board, I used an airsoft 11.1v lipo.
I powered the ELEGOO with a USB power bank.
I used a "breadboard" and jumper wires to build mine, as I was pressed for time, but I would HIGHLY
recommend getting a breakout board. I'll be getting one this winter and rewiring my DOMBOX. It'll
make better and stronger connections: https://www.amazon.com/s?k=uno+breakout+board
***** Code updated on 1/24/2025 by Surfer to include a 3 second button press.
There is no indicator if you pressed the button long enough until you let go and see the led
Also include a way to change the game time before the game starts the default is 15 mminutes.
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Initialize the LCD
const int orangeButtonPin = 2; // Orange button pin
const int blueButtonPin = 3; // Blue team button pin
const int redButtonPin = 4; // Red team button pin
const int orangeRelayPin = 5; // Orange relay pin
const int blueRelayPin = 6; // Blue team relay pin
const int redRelayPin = 7; // Red team relay pin
const unsigned long buttonHoldTime = 3000; // 3 seconds in milliseconds
unsigned long blueButtonPressStartTime = 0; // Start time for blue button press
unsigned long redButtonPressStartTime = 0; // Start time for red button press
bool blueButtonPressedForLong = false; // Flag to check if blue button was pressed long enough
bool redButtonPressedForLong = false; // Flag to check if red button was pressed long enough
unsigned long gameStartTime = 0;
unsigned long blueStartTime = 0;
unsigned long redStartTime = 0;
unsigned long blueElapsedTime = 0;
unsigned long redElapsedTime = 0;
unsigned long blueTime = 0;
unsigned long redTime = 0;
unsigned long bluePausedTime = 0;
unsigned long redPausedTime = 0;
unsigned long gameDuration = 900000; // in milliseconds (15 minutes)
bool gameTimerRunning = false;
bool blueTimerRunning = false;
bool redTimerRunning = false;
bool blueButtonStatePrev = false;
bool redButtonStatePrev = false;
void setup() {
lcd.init();
lcd.backlight();
pinMode(orangeButtonPin, INPUT_PULLUP);
pinMode(blueButtonPin, INPUT_PULLUP);
pinMode(redButtonPin, INPUT_PULLUP);
pinMode(orangeRelayPin, OUTPUT);
pinMode(blueRelayPin, OUTPUT);
pinMode(redRelayPin, OUTPUT);
lcd.setCursor(2, 0);
lcd.print("PRESS START");
lcd.setCursor(0, 1);
lcd.print("B 00:00 R 00:00");
}
void loop() {
bool orangeButtonState = digitalRead(orangeButtonPin) == LOW;
bool blueButtonState = digitalRead(blueButtonPin) == LOW;
bool redButtonState = digitalRead(redButtonPin) == LOW;
unsigned long currentTime = millis();
// Adjust game time using red and blue buttons when the game is not running
if (!gameTimerRunning) {
if (redButtonState && !redButtonStatePrev) {
gameDuration += 60000; // Increase game duration by 1 minute
displayGameDuration();
}
if (blueButtonState && !blueButtonStatePrev) {
if (gameDuration > 60000) { // Ensure game duration does not go below 1 minute
gameDuration -= 60000; // Decrease game duration by 1 minute
displayGameDuration();
}
}
}
// Check if the game timer is running
if (gameTimerRunning) {
unsigned long elapsedTime = currentTime - gameStartTime;
unsigned long remainingTime = (elapsedTime <= gameDuration) ? (gameDuration - elapsedTime) : 0;
// Calculate remaining game time
int gameMinutes = (remainingTime / 60000); // Calculate minutes
int gameSeconds = (remainingTime / 1000) % 60; // Calculate seconds
displayTime(gameMinutes, gameSeconds);
// Check if the game timer has reached its duration
if (remainingTime == 0) {
blueTimerRunning = false; // Stop the blue timer
redTimerRunning = false; // Stop the red timer
gameTimerRunning = false; // Stop the game timer
displayWinner(); // Display the winner based on total time
}
// Blink orange relay if blue or red timers are not running
if (!blueTimerRunning && !redTimerRunning) {
// Blink the orange relay (1 second on, 1 second off)
unsigned long orangeRelayTime = currentTime % 2000;
digitalWrite(orangeRelayPin, (orangeRelayTime < 1000));
} else {
// Turn off the orange relay when blue or red timers are running
digitalWrite(orangeRelayPin, LOW);
}
} else {
// Turn off the orange relay when the game timer is not running
digitalWrite(orangeRelayPin, LOW);
}
// Check for game start (orange button press)
if (orangeButtonState && !gameTimerRunning) {
startGameTimer(currentTime);
}
// Blink blue relay if blue timer is running
if (blueTimerRunning) {
// Blink blue relay (1 second on, 1 second off)
unsigned long blueRelayTime = currentTime % 2000;
digitalWrite(blueRelayPin, (blueRelayTime < 1000));
} else {
// Turn off the blue relay when red timer is running
digitalWrite(blueRelayPin, LOW);
}
// Blink red relay if red timer is running
if (redTimerRunning) {
// Blink red relay (1 second on, 1 second off)
unsigned long redRelayTime = currentTime % 2000;
digitalWrite(redRelayPin, (redRelayTime < 1000));
} else {
// Turn off the red relay when blue timer is running
digitalWrite(redRelayPin, LOW);
}
// Only allow blue and red buttons to work after the game has started
if (gameTimerRunning) {
// Check for blue team button (3-second hold)
if (blueButtonState && !blueButtonStatePrev) {
blueButtonPressStartTime = currentTime; // Start the timer when the button is pressed
}
// Check if the blue button is held for 3 seconds
if (blueButtonState && (currentTime - blueButtonPressStartTime >= buttonHoldTime)) {
blueButtonPressedForLong = true;
}
// If the blue button was pressed long enough and it's a new press
if (blueButtonPressedForLong && !blueButtonStatePrev) {
if (!blueTimerRunning) {
if (blueStartTime == 0) {
blueStartTime = currentTime;
} else {
blueStartTime = currentTime - blueTime;
}
blueTimerRunning = true;
}
if (redTimerRunning) {
redPausedTime += currentTime - redStartTime;
redTimerRunning = false;
}
blueButtonPressedForLong = false; // Reset the flag
}
// Check for red team button (3-second hold)
if (redButtonState && !redButtonStatePrev) {
redButtonPressStartTime = currentTime; // Start the timer when the button is pressed
}
// Check if the red button is held for 3 seconds
if (redButtonState && (currentTime - redButtonPressStartTime >= buttonHoldTime)) {
redButtonPressedForLong = true;
}
// If the red button was pressed long enough and it's a new press
if (redButtonPressedForLong && !redButtonStatePrev) {
if (!redTimerRunning) {
if (redStartTime == 0) {
redStartTime = currentTime;
} else {
redStartTime = currentTime - redTime;
}
redTimerRunning = true;
}
if (blueTimerRunning) {
bluePausedTime += currentTime - blueStartTime;
blueTimerRunning = false;
}
redButtonPressedForLong = false; // Reset the flag
}
}
// Store the button states for the next iteration
blueButtonStatePrev = blueButtonState;
redButtonStatePrev = redButtonState;
// Update blue timer if running
if (blueTimerRunning) {
unsigned long blueElapsed = currentTime - blueStartTime;
int blueMinutes = blueElapsed / 60000;
int blueSeconds = (blueElapsed / 1000) % 60;
lcd.setCursor(0, 1);
lcd.print("B ");
if (blueMinutes < 10) {
lcd.print("0");
}
lcd.print(blueMinutes);
lcd.print(":");
if (blueSeconds < 10) {
lcd.print("0");
}
lcd.print(blueSeconds);
blueTime = blueElapsed;
}
// Update red timer if running
if (redTimerRunning) {
unsigned long redElapsed = currentTime - redStartTime;
int redMinutes = redElapsed / 60000;
int redSeconds = (redElapsed / 1000) % 60;
lcd.setCursor(9, 1);
lcd.print("R ");
if (redMinutes < 10) {
lcd.print("0");
}
lcd.print(redMinutes);
lcd.print(":");
if (redSeconds < 10) {
lcd.print("0");
}
lcd.print(redSeconds);
redTime = redElapsed;
}
}
void displayTime(int minutes, int seconds) {
lcd.setCursor(0, 0);
lcd.print(" GAME ");
lcd.setCursor(8, 0);
if (minutes < 10) {
lcd.print("0");
}
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) {
lcd.print("0");
}
lcd.print(seconds);
}
void displayGameDuration() {
int minutes = gameDuration / 60000;
lcd.setCursor(0, 0);
lcd.print("GAME TIME: ");
lcd.setCursor(11, 0);
if (minutes < 10) {
lcd.print("0");
}
lcd.print(minutes);
lcd.print("");
}
void startGameTimer(unsigned long currentTime) {
gameTimerRunning = true;
gameStartTime = currentTime;
}
void displayWinner() {
int relay = 0;
lcd.setCursor(0, 0);
lcd.print(" "); // Clear the first line
if (blueTime > redTime) {
lcd.setCursor(0, 0);
lcd.print("!BLUE TEAM WINS!");
digitalWrite(orangeRelayPin, LOW);
digitalWrite(redRelayPin, LOW);
// Blink blue relay
while (relay < 500) {
digitalWrite(blueRelayPin, LOW);
delay(125);
digitalWrite(blueRelayPin, HIGH);
delay(125);
relay++;
}
} else if (redTime > blueTime) {
lcd.setCursor(0, 0);
lcd.print("!RED TEAM WINS!!");
digitalWrite(blueRelayPin, LOW);
digitalWrite(orangeRelayPin, LOW);
// Blink red relay
while (relay < 500) {
digitalWrite(redRelayPin, LOW);
delay(125);
digitalWrite(redRelayPin, HIGH);
delay(125);
relay++;
}
} else {
lcd.setCursor(2, 0);
lcd.print("IT'S A TIE!");
digitalWrite(blueRelayPin, LOW);
digitalWrite(redRelayPin, LOW);
// Blink orange relay
while (relay < 500) {
digitalWrite(orangeRelayPin, LOW);
delay(125);
digitalWrite(orangeRelayPin, HIGH);
delay(125);
relay++;
}
}
}