Compare commits
25 Commits
fe9173ca88
...
v1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d9a1a778c | |||
| 4d7a43c9d1 | |||
| c450cfb7c9 | |||
| 7c3dbfab63 | |||
| fc472600c4 | |||
| 649cbe63b1 | |||
| 79c734bd34 | |||
| 3e29ab76e2 | |||
| d81ab7da89 | |||
| 5e5ff83506 | |||
| 606219b8bd | |||
| d93b283d2c | |||
| c9c4b1c1c5 | |||
| 4698dd7d42 | |||
| ee6b87399e | |||
| f53744c23c | |||
| 6c5586e71b | |||
| 70d4b3886d | |||
| b82e4eb58b | |||
| 06a286eadd | |||
| 508f5f32e4 | |||
| 4dc9ef1db7 | |||
| 20fe660838 | |||
| c2bffd7a26 | |||
| 9e708d461a |
@@ -8,31 +8,16 @@ void pollInput (){
|
|||||||
buttonRESET.poll();
|
buttonRESET.poll();
|
||||||
switchRUMBLE.poll();
|
switchRUMBLE.poll();
|
||||||
switchPIT.poll();
|
switchPIT.poll();
|
||||||
buttonREDTEAM.poll();
|
switchLIGHT.poll();
|
||||||
buttonBLUETEAM.poll();
|
switchTESTmode.poll();
|
||||||
|
|
||||||
if (buttonSTART.pushed()) {
|
// only set the var if the button was actually pushed or released, to prevent overriding data from the remote
|
||||||
buttonSTARTvar = true;
|
if (buttonSTART.singleClick() || buttonSTART.longPress() || buttonPAUSE.singleClick() || buttonPIT.singleClick() || buttonPIT.switched() || buttonRESET.longPress()) {
|
||||||
}
|
buttonSTARTvar = buttonSTART.singleClick();
|
||||||
if (buttonPAUSE.pushed()) {
|
buttonSTARTforced = buttonSTART.longPress();
|
||||||
buttonPAUSEvar = true;
|
buttonPAUSEvar = buttonPAUSE.singleClick();
|
||||||
}
|
buttonPITvar = buttonPIT.singleClick();
|
||||||
if (buttonPIT.pushed()) {
|
buttonPIThold = buttonPIT.on();
|
||||||
buttonPITvar = true;
|
buttonRESETvar = buttonRESET.longPress();
|
||||||
}
|
|
||||||
if (buttonRESET.pushed()) {
|
|
||||||
buttonRESETvar = true;
|
|
||||||
}
|
|
||||||
if (buttonREDTEAM.pushed()) {
|
|
||||||
buttonREDTEAMvar = true;
|
|
||||||
if (ARENA_READY && !REDTEAM_READY) {
|
|
||||||
BLINK_COUNTER_REDTEAM = 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (buttonBLUETEAM.pushed()) {
|
|
||||||
buttonBLUETEAMvar = true;
|
|
||||||
if (ARENA_READY && !BLUETEAM_READY) {
|
|
||||||
BLINK_COUNTER_BLUETEAM = 5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// contains all the functions to drive the LEDs
|
|
||||||
|
|
||||||
// 0
|
|
||||||
const int LitArray0 [] = {8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55};
|
|
||||||
// 1
|
|
||||||
const int LitArray1 [] = {8,9,10,11,12,13,14,15,48,49,50,51,52,53,54,55};
|
|
||||||
// 2
|
|
||||||
const int LitArray2 [] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47};
|
|
||||||
// 3
|
|
||||||
const int LitArray3 [] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55};
|
|
||||||
// 4
|
|
||||||
const int LitArray4 [] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31,48,49,50,51,52,53,54,55};
|
|
||||||
// 5
|
|
||||||
const int LitArray5 [] = {0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55};
|
|
||||||
// 6
|
|
||||||
const int LitArray6 [] = {0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55};
|
|
||||||
// 7
|
|
||||||
const int LitArray7 [] = {8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,48,49,50,51,52,53,54,55};
|
|
||||||
// 8
|
|
||||||
const int LitArray8 [] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55};
|
|
||||||
// 9
|
|
||||||
const int LitArray9 [] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55};
|
|
||||||
// colon
|
|
||||||
const int COLONArray [] = {224,225,226,227,228,229,230,231};
|
|
||||||
|
|
||||||
// set digits of the timer/clock, use: setDIGIT(<digit ID>, <Number>, <red channel intensity 0-255>, <green channel intensity 0-255>, <blue channel intensity 0-255>)
|
|
||||||
|
|
||||||
void setDIGIT(int DIGIT_ID, int DIGIT, int RED, int GREEN, int BLUE) {
|
|
||||||
DIGIT_ID = map(DIGIT_ID, 1, 4, 0, 3); // swap index/ID number from 1-4 to 0-3
|
|
||||||
switch (DIGIT) {
|
|
||||||
case 0:
|
|
||||||
// set 0
|
|
||||||
for (int i : LitArray0) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// set 1
|
|
||||||
for (int i : LitArray1) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
// set 2
|
|
||||||
for (int i : LitArray2) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// set 3
|
|
||||||
for (int i : LitArray3) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
// set 4
|
|
||||||
for (int i : LitArray4) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
// set 5
|
|
||||||
for (int i : LitArray5) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
// set 6
|
|
||||||
for (int i : LitArray6) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
// set 7
|
|
||||||
for (int i : LitArray7) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
// set 8
|
|
||||||
for (int i : LitArray8) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
// set 9
|
|
||||||
for (int i : LitArray9) {
|
|
||||||
leds_TIMER[i + (NUM_LEDS_PER_DIGIT * DIGIT_ID )].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set colon
|
|
||||||
void setCOLON(int RED, int GREEN, int BLUE) {
|
|
||||||
for (int i : COLONArray) {
|
|
||||||
leds_TIMER[(i)].setRGB(RED,GREEN,BLUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set all digits
|
|
||||||
void setTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE) {
|
|
||||||
setDIGIT(1, ((MINUTES/10)%10), RED, GREEN, BLUE);
|
|
||||||
setDIGIT(2, (MINUTES%10), RED, GREEN, BLUE);
|
|
||||||
setDIGIT(3, ((SECONDS/10)%10), RED, GREEN, BLUE);
|
|
||||||
setDIGIT(4, (SECONDS%10), RED, GREEN, BLUE);
|
|
||||||
setCOLON(RED, GREEN, BLUE);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void showTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE) {
|
|
||||||
EVERY_N_MILLISECONDS(5) {
|
|
||||||
// toggle between reading ADC data and refreshing LED strings (dunno, some artefacts appear if you do both really quickly after each other).
|
|
||||||
// leave this in here, if needed, expand the delay between executions
|
|
||||||
if (toggle) {
|
|
||||||
toggle = false;
|
|
||||||
if (prevMINUTES != MINUTES || prevSECONDS != SECONDS || prevCLOCKRED != RED || prevCLOCKGREEN != GREEN || prevCLOCKBLUE != BLUE) {
|
|
||||||
setTimeDisplay(MINUTES, SECONDS, RED, GREEN, BLUE);
|
|
||||||
FastLED.show(CLOCK_LED_BRIGHTNESS);
|
|
||||||
FastLED.clearData();
|
|
||||||
prevMINUTES = MINUTES;
|
|
||||||
prevSECONDS = SECONDS;
|
|
||||||
prevCLOCKRED = RED;
|
|
||||||
prevCLOCKGREEN = GREEN;
|
|
||||||
prevCLOCKBLUE = BLUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
toggle = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
void checkPIT() {
|
void checkPIT() {
|
||||||
if ((digitalRead(PIT_RELEASE_PIN)) && (millis() - PITopenTimestamp >= PITopenTime)) {
|
if ((digitalRead(!PIT_RELEASE_PIN)) && (millis() - PITopenTimestamp >= PITopenTime)) {
|
||||||
digitalWrite(PIT_RELEASE_PIN, LOW);
|
//digitalWrite(PIT_RELEASE_PIN, relayOffState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,24 +8,115 @@ void openPIT() {
|
|||||||
if (!PITreleased) {
|
if (!PITreleased) {
|
||||||
PITreleased = true;
|
PITreleased = true;
|
||||||
PITopenTimestamp = millis();
|
PITopenTimestamp = millis();
|
||||||
digitalWrite(PIT_RELEASE_PIN, HIGH);
|
//digitalWrite(PIT_RELEASE_PIN, relayOnState);
|
||||||
|
sendToPitController.PIT = true;
|
||||||
|
esp_now_send(broadcastAddressPitController, (uint8_t *) &sendToPitController, sizeof(sendToPitController));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// usage: blink_LED_BlueTeam(<interval in milliseconds>);
|
void openPITmanually() {
|
||||||
void blink_LED_BlueTeam(int BLINK_INTERVAL) {
|
PITreleased = true;
|
||||||
EVERY_N_MILLISECONDS(BLINK_INTERVAL) {
|
PITopenTimestamp = millis();
|
||||||
if (BLINK_COUNTER_BLUETEAM-- > 0) {
|
//digitalWrite(PIT_RELEASE_PIN, relayOnState);
|
||||||
digitalWrite(BLUE_TEAM_LED_PIN, !digitalRead(BLUE_TEAM_LED_PIN));
|
sendToPitController.PIT = true;
|
||||||
}
|
esp_now_send(broadcastAddressPitController, (uint8_t *) &sendToPitController, sizeof(sendToPitController));
|
||||||
|
}
|
||||||
|
|
||||||
|
void arenaLIGHT() {
|
||||||
|
if (switchLIGHT.on()) {
|
||||||
|
digitalWrite(LIGHT_PIN, LOW);
|
||||||
|
digitalWrite(LIGHT_PIN2, LOW);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digitalWrite(LIGHT_PIN, HIGH);
|
||||||
|
digitalWrite(LIGHT_PIN2, HIGH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// usage: blink_LED_RedTeam(<interval in milliseconds times two>);
|
void statusLEDs() {
|
||||||
void blink_LED_RedTeam(int BLINK_INTERVAL) {
|
if (!switchLIGHT.on()) {
|
||||||
EVERY_N_MILLISECONDS(BLINK_INTERVAL) {
|
digitalWrite(LIGHT_STATUS_LED, HIGH);
|
||||||
if (BLINK_COUNTER_REDTEAM-- > 0) {
|
|
||||||
digitalWrite(RED_TEAM_LED_PIN, !digitalRead(RED_TEAM_LED_PIN));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
digitalWrite(LIGHT_STATUS_LED, LOW);
|
||||||
|
}
|
||||||
|
if (switchPIT.on()) {
|
||||||
|
digitalWrite(AUTOPIT_STATUS_LED, HIGH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digitalWrite(AUTOPIT_STATUS_LED, LOW);
|
||||||
|
}
|
||||||
|
if (switchRUMBLE.on()) {
|
||||||
|
digitalWrite(MODE_STATUS_LED, HIGH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digitalWrite(MODE_STATUS_LED, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateTEAMLEDs() {
|
||||||
|
if ((buttonREDTEAMvar == true) && (sendToREDTEAMbutton.TEAMLED == false)) {
|
||||||
|
sendToREDTEAMbutton.TEAMLED = true;
|
||||||
|
esp_now_send(broadcastAddressREDTEAMbutton, (uint8_t *)&sendToREDTEAMbutton, sizeof(sendToREDTEAMbutton));
|
||||||
|
}
|
||||||
|
// else if ((buttonREDTEAMvar == false) && (sendToREDTEAMbutton.TEAMLED == true)) {
|
||||||
|
// sendToREDTEAMbutton.TEAMLED = false;
|
||||||
|
// esp_now_send(broadcastAddressREDTEAMbutton, (uint8_t *)&sendToREDTEAMbutton, sizeof(sendToREDTEAMbutton));
|
||||||
|
// }
|
||||||
|
|
||||||
|
if ((buttonBLUETEAMvar == true) && (sendToBLUETEAMbutton.TEAMLED == false)) {
|
||||||
|
sendToBLUETEAMbutton.TEAMLED = true;
|
||||||
|
esp_now_send(broadcastAddressBLUETEAMbutton, (uint8_t *)&sendToBLUETEAMbutton, sizeof(sendToBLUETEAMbutton));
|
||||||
|
}
|
||||||
|
// else if ((buttonBLUETEAMvar == false) && (sendToBLUETEAMbutton.TEAMLED == true)) {
|
||||||
|
// sendToBLUETEAMbutton.TEAMLED = false;
|
||||||
|
// esp_now_send(broadcastAddressBLUETEAMbutton, (uint8_t *)&sendToBLUETEAMbutton, sizeof(sendToBLUETEAMbutton));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void REDTEAM_LED(bool STATE) {
|
||||||
|
if (STATE) {
|
||||||
|
sendToREDTEAMbutton.TEAMLED = true;
|
||||||
|
esp_now_send(broadcastAddressREDTEAMbutton, (uint8_t *)&sendToREDTEAMbutton, sizeof(sendToREDTEAMbutton));
|
||||||
|
} else {
|
||||||
|
sendToREDTEAMbutton.TEAMLED = false;
|
||||||
|
esp_now_send(broadcastAddressREDTEAMbutton, (uint8_t *)&sendToREDTEAMbutton, sizeof(sendToREDTEAMbutton));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLUETEAM_LED(bool STATE) {
|
||||||
|
if (STATE) {
|
||||||
|
sendToBLUETEAMbutton.TEAMLED = true;
|
||||||
|
esp_now_send(broadcastAddressBLUETEAMbutton, (uint8_t *)&sendToBLUETEAMbutton, sizeof(sendToBLUETEAMbutton));
|
||||||
|
} else {
|
||||||
|
sendToBLUETEAMbutton.TEAMLED = false;
|
||||||
|
esp_now_send(broadcastAddressBLUETEAMbutton, (uint8_t *)&sendToBLUETEAMbutton, sizeof(sendToBLUETEAMbutton));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// void blink_LED_BlueTeam() {
|
||||||
|
// EVERY_N_MILLISECONDS(BLINK_INTERVAL) {
|
||||||
|
// if (BLINK_COUNTER_BLUETEAM-- > 0) {
|
||||||
|
// if (sendToBLUETEAMbutton.TEAMLED == false) {
|
||||||
|
// sendToBLUETEAMbutton.TEAMLED = true;
|
||||||
|
// } else {
|
||||||
|
// sendToBLUETEAMbutton.TEAMLED = false;
|
||||||
|
// }
|
||||||
|
// esp_now_send(broadcastAddressBLUETEAMbutton, (uint8_t *)&sendToBLUETEAMbutton, sizeof(sendToBLUETEAMbutton));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// void blink_LED_RedTeam() {
|
||||||
|
// EVERY_N_MILLISECONDS(BLINK_INTERVAL) {
|
||||||
|
// if (BLINK_COUNTER_REDTEAM-- > 0) {
|
||||||
|
// if (sendToREDTEAMbutton.TEAMLED == false) {
|
||||||
|
// sendToREDTEAMbutton.TEAMLED = true;
|
||||||
|
// } else {
|
||||||
|
// sendToREDTEAMbutton.TEAMLED = false;
|
||||||
|
// }
|
||||||
|
// esp_now_send(broadcastAddressREDTEAMbutton, (uint8_t *)&sendToREDTEAMbutton, sizeof(sendToREDTEAMbutton));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,123 +1,283 @@
|
|||||||
// ROFLS+ Arena Controller
|
// ROFLS+ Arena Controller
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include <esp_wifi.h> // Required for wifi_tx_info_t
|
||||||
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
||||||
#include <Preferences.h> // automatically installed for ESP32 boards
|
#include <Preferences.h> // automatically installed for ESP32 boards
|
||||||
#include <FastLED.h> // https://fastled.io/
|
|
||||||
#include <avdweb_Switch.h> // https://github.com/avdwebLibraries/avdweb_Switch
|
#include <avdweb_Switch.h> // https://github.com/avdwebLibraries/avdweb_Switch
|
||||||
#include <CountDown.h> // https://github.com/RobTillaart/CountDown
|
#include <CountDown.h> // https://github.com/RobTillaart/CountDown
|
||||||
#include <StopWatch.h> // https://github.com/RobTillaart/StopWatch_RT
|
#include <StopWatch.h> // https://github.com/RobTillaart/StopWatch_RT
|
||||||
|
|
||||||
// Hardware connections
|
// set Arena, switches the MAC addresses out
|
||||||
#define START_BTN_PIN 1
|
// 1 = Arena A (Ant)
|
||||||
#define PAUSE_BTN_PIN 2
|
// 2 = Arena B (Beetle)
|
||||||
#define PIT_BTN_PIN 3
|
#define ARENA 1
|
||||||
#define RESET_BTN_PIN 4
|
|
||||||
#define RUMBLE_SWITCH_PIN 5
|
|
||||||
#define PIT_ENABLE_SWITCH_PIN 6
|
|
||||||
#define RED_TEAM_BTN_PIN 7
|
|
||||||
#define RED_TEAM_LED_PIN 39
|
|
||||||
#define BLUE_TEAM_BTN_PIN 6
|
|
||||||
#define BLUE_TEAM_LED_PIN 40
|
|
||||||
#define PIT_RELEASE_PIN 35
|
|
||||||
|
|
||||||
// LED Strip setup
|
// Hardware connections
|
||||||
#define NUM_LEDS_PER_DIGIT 56
|
// Buttons:
|
||||||
#define NUM_OF_DIGITS 4
|
#define START_BTN_PIN 1
|
||||||
#define NUM_LEDS_COLON 8
|
#define PAUSE_BTN_PIN 3
|
||||||
#define NUM_LEDS_TIMER (NUM_LEDS_PER_DIGIT * NUM_OF_DIGITS + NUM_LEDS_COLON) // + 1 because of the makeshift Levelshifter
|
#define PIT_BTN_PIN 5
|
||||||
#define LED_DATA_PIN_TIMER 16
|
#define RESET_BTN_PIN 7
|
||||||
// This is an array of leds. One item for each led in your strip.
|
// Switches:
|
||||||
CRGB leds_TIMER[NUM_LEDS_TIMER];
|
#define RUMBLE_SWITCH_PIN 9
|
||||||
|
#define PIT_ENABLE_SWITCH_PIN 11
|
||||||
|
#define LIGHT_SWITCH_PIN 12
|
||||||
|
#define TESTmode_SWITCH_PIN 4
|
||||||
|
// LEDs:
|
||||||
|
#define LIGHT_STATUS_LED 10
|
||||||
|
#define AUTOPIT_STATUS_LED 13
|
||||||
|
#define MODE_STATUS_LED 14
|
||||||
|
// Relays:
|
||||||
|
#define PIT_RELEASE_PIN 37
|
||||||
|
#define LIGHT_PIN 39
|
||||||
|
#define LIGHT_PIN2 35
|
||||||
|
#define UNUSED_RELAY4_PIN 33
|
||||||
|
|
||||||
|
const byte relayOnState = LOW;
|
||||||
|
const byte relayOffState = HIGH;
|
||||||
|
|
||||||
// define buttons and switches
|
// define buttons and switches
|
||||||
Switch buttonSTART = Switch(START_BTN_PIN);
|
//
|
||||||
|
// constructor Switch
|
||||||
|
// Parameters: byte _pin, byte PinMode = 5, bool polarity = 0, unsigned long debouncePeriod = 50, unsigned long longPressPeriod = 300, unsigned long doubleClickPeriod = 250, unsigned long deglitchPeriod = 10
|
||||||
|
Switch buttonSTART = Switch(START_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
Switch buttonPAUSE = Switch(PAUSE_BTN_PIN);
|
Switch buttonPAUSE = Switch(PAUSE_BTN_PIN);
|
||||||
Switch buttonPIT = Switch(PIT_BTN_PIN);
|
Switch buttonPIT = Switch(PIT_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
Switch buttonRESET = Switch(RESET_BTN_PIN);
|
Switch buttonRESET = Switch(RESET_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
Switch switchRUMBLE = Switch(RUMBLE_SWITCH_PIN);
|
Switch switchRUMBLE = Switch(RUMBLE_SWITCH_PIN);
|
||||||
Switch switchPIT = Switch(PIT_ENABLE_SWITCH_PIN);
|
Switch switchPIT = Switch(PIT_ENABLE_SWITCH_PIN);
|
||||||
Switch buttonREDTEAM = Switch(RED_TEAM_BTN_PIN);
|
Switch switchLIGHT = Switch(LIGHT_SWITCH_PIN);
|
||||||
Switch buttonBLUETEAM = Switch(BLUE_TEAM_BTN_PIN);
|
Switch switchTESTmode = Switch(TESTmode_SWITCH_PIN);
|
||||||
|
|
||||||
bool buttonSTARTvar = false;
|
bool buttonSTARTvar = false;
|
||||||
|
bool buttonSTARTforced = false;
|
||||||
bool buttonPAUSEvar = false;
|
bool buttonPAUSEvar = false;
|
||||||
bool buttonPITvar = false;
|
bool buttonPITvar = false;
|
||||||
|
bool buttonPIThold = false;
|
||||||
bool buttonRESETvar = false;
|
bool buttonRESETvar = false;
|
||||||
bool buttonREDTEAMvar = false;
|
bool buttonREDTEAMvar = false;
|
||||||
|
bool buttonREDTEAMtapout = false;
|
||||||
bool buttonBLUETEAMvar = false;
|
bool buttonBLUETEAMvar = false;
|
||||||
|
bool buttonBLUETEAMtapout = false;
|
||||||
unsigned long PITopenTimestamp = 0;
|
unsigned long PITopenTimestamp = 0;
|
||||||
const long PITopenTime = 1000; // activate solenoid for 1000ms
|
|
||||||
bool PITreleased = false;
|
bool PITreleased = false;
|
||||||
|
|
||||||
const int countdownTIME = 3; // countdown timer length in minutes
|
const long PITopenTime = 500; // default: 500 activate solenoid for 500ms
|
||||||
const int countdownToFight = 3; // countdown timer length in seconds
|
const int countdownTIME = 180; // default: 180 countdown timer length in seconds, actual countdown for the fight
|
||||||
const int PITreleaseTime = 90; // automatic pit release time in seconds until end of countdown
|
const int countdownToFightTIME = 3; // default: 3 countdown timer length in seconds, "ready" countdown
|
||||||
|
const int PITreleaseTime = 90; // default: 90 automatic pit release time in seconds until end of countdown
|
||||||
bool countdownPAUSED = false;
|
bool countdownPAUSED = false;
|
||||||
CountDown FightCountDown[1];
|
CountDown FightCountDown(CountDown::SECONDS);
|
||||||
|
CountDown ReadyCountDown(CountDown::SECONDS);
|
||||||
|
|
||||||
// Rumble stopwatch
|
// Rumble stopwatch
|
||||||
StopWatch rumbleTIME;
|
StopWatch rumbleTIME(StopWatch::SECONDS);
|
||||||
|
|
||||||
int prevMINUTES = 0;
|
int CLOCK_LED_BRIGHTNESS = 128; // 64 is okay
|
||||||
int prevSECONDS = 0;
|
|
||||||
int prevCLOCKRED = 0;
|
|
||||||
int prevCLOCKGREEN = 0;
|
|
||||||
int prevCLOCKBLUE = 0;
|
|
||||||
|
|
||||||
int CLOCK_LED_BRIGHTNESS = 16; // 64 is okay
|
|
||||||
|
|
||||||
int BLINK_COUNTER_REDTEAM = 0;
|
int BLINK_COUNTER_REDTEAM = 0;
|
||||||
int BLINK_COUNTER_BLUETEAM = 0;
|
int BLINK_COUNTER_BLUETEAM = 0;
|
||||||
|
int BLINK_INTERVAL = 200;
|
||||||
|
|
||||||
bool ARENA_READY = true;
|
|
||||||
|
bool ARENA_READY = false;
|
||||||
bool REDTEAM_READY = false;
|
bool REDTEAM_READY = false;
|
||||||
bool BLUETEAM_READY = false;
|
bool BLUETEAM_READY = false;
|
||||||
|
bool resumeFight = false;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
// ESP-NOW config
|
// ESP-NOW config
|
||||||
|
// send config, Clock:
|
||||||
|
#if ARENA == 1
|
||||||
|
// A Arena
|
||||||
|
uint8_t broadcastAddressClock1[] = {0x48, 0x27, 0xE2, 0x5D, 0xB6, 0x84};
|
||||||
|
uint8_t broadcastAddressClock2[] = {0xD8, 0x3B, 0xDA, 0xC9, 0x49, 0xC6};
|
||||||
|
#elif ARENA == 2
|
||||||
|
// B Arena
|
||||||
|
uint8_t broadcastAddressClock1[] = {0xD8, 0x3B, 0xDA, 0xC8, 0xFF, 0xFA};
|
||||||
|
uint8_t broadcastAddressClock2[] = {0xD8, 0x3B, 0xDA, 0xC8, 0x95, 0x42};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// struct for clock data
|
||||||
|
typedef struct struct_message_Clock {
|
||||||
|
int sendMinutes;
|
||||||
|
int sendSeconds;
|
||||||
|
int sendREDchannel;
|
||||||
|
int sendGREENchannel;
|
||||||
|
int sendBLUEchannel;
|
||||||
|
int sendBrightness;
|
||||||
|
} struct_message_Clock;
|
||||||
|
|
||||||
|
|
||||||
|
struct_message_Clock sendClockDATA;
|
||||||
|
|
||||||
|
// send config, pilot buttons:
|
||||||
|
#if ARENA == 1
|
||||||
|
// A Arena
|
||||||
|
uint8_t broadcastAddressREDTEAMbutton[] = {0x84, 0xFC, 0xE6, 0xC7, 0x23, 0x14};
|
||||||
|
uint8_t broadcastAddressBLUETEAMbutton[] = {0x84, 0xFC, 0xE6, 0xC7, 0x1A, 0x02};
|
||||||
|
#elif ARENA == 2
|
||||||
|
// B Arena
|
||||||
|
uint8_t broadcastAddressREDTEAMbutton[] = {0xD8, 0x3B, 0xDA, 0xC8, 0x95, 0x58};
|
||||||
|
uint8_t broadcastAddressBLUETEAMbutton[] = {0xD8, 0x3B, 0xDA, 0xC8, 0x95, 0x1C};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Structure for sending data
|
||||||
|
typedef struct struct_message_send {
|
||||||
|
bool TEAMLED; // LED state
|
||||||
|
} struct_message_send;
|
||||||
|
|
||||||
|
// Create struct_message instances for sending to both receivers
|
||||||
|
struct_message_send sendToREDTEAMbutton;
|
||||||
|
struct_message_send sendToBLUETEAMbutton;
|
||||||
|
|
||||||
|
// ESP-Now stuff for the Pit controller
|
||||||
|
#if ARENA == 1
|
||||||
|
// A Arena
|
||||||
|
uint8_t broadcastAddressPitController[] = {0x84, 0xFC, 0xE6, 0xC7, 0x19, 0xDE};
|
||||||
|
#elif ARENA == 2
|
||||||
|
// B Arena
|
||||||
|
uint8_t broadcastAddressPitController[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xB0, 0x0B};
|
||||||
|
#endif
|
||||||
|
// Test Pit controller
|
||||||
|
//uint8_t broadcastAddressPitController[] = {0x94, 0xA9, 0x90, 0x0B, 0x21, 0x64};
|
||||||
|
|
||||||
|
// Structure for sending data
|
||||||
|
typedef struct struct_message_pit {
|
||||||
|
bool PIT; // LED state
|
||||||
|
} struct_message_pit;
|
||||||
|
struct_message_pit sendToPitController;
|
||||||
|
|
||||||
|
esp_now_peer_info_t peerInfo;
|
||||||
|
|
||||||
|
// callback when data is sent
|
||||||
|
|
||||||
|
void OnDataSent(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
|
||||||
|
Serial.print("\r\nLast Packet Send Status:\t");
|
||||||
|
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// receive config
|
||||||
// Structure example to send data
|
// Structure example to send data
|
||||||
// Must match the receiver structure
|
// Must match the receiver structure
|
||||||
typedef struct struct_message {
|
typedef struct struct_message_receive {
|
||||||
bool buttonSTARTremote;
|
int boardID;
|
||||||
bool buttonPAUSEremote;
|
bool buttonSTART;
|
||||||
bool buttonPITremote;
|
bool buttonSTARTforced;
|
||||||
bool buttonRESETremote;
|
bool buttonPAUSE;
|
||||||
bool buttonREDTEAMremote;
|
bool buttonPIT;
|
||||||
bool buttonBLUETEAMremote;
|
bool buttonPIThold;
|
||||||
} struct_message;
|
bool buttonRESET;
|
||||||
|
bool buttonREDTEAM;
|
||||||
|
bool buttonREDTEAMtapout;
|
||||||
|
bool buttonBLUETEAM;
|
||||||
|
bool buttonBLUETEAMtapout;
|
||||||
|
} struct_message_receive;
|
||||||
|
|
||||||
// Create a struct_message called remoteDATA
|
// Create a struct_message called receiveDATA
|
||||||
struct_message remoteDATA;
|
struct_message_receive receiveDATA;
|
||||||
|
|
||||||
// callback function that will be executed when data is received
|
// callback function that will be executed when data is received
|
||||||
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
||||||
memcpy(&remoteDATA, incomingData, sizeof(remoteDATA));
|
memcpy(&receiveDATA, incomingData, sizeof(receiveDATA));
|
||||||
if (remoteDATA.buttonSTARTremote) {
|
// only fill the data to the right vars
|
||||||
buttonSTARTvar = true;
|
switch (receiveDATA.boardID) {
|
||||||
}
|
case 0:
|
||||||
if (remoteDATA.buttonPAUSEremote) {
|
// referee remote
|
||||||
buttonPAUSEvar = true;
|
buttonSTARTvar = receiveDATA.buttonSTART;
|
||||||
}
|
buttonSTARTforced = receiveDATA.buttonSTARTforced;
|
||||||
if (remoteDATA.buttonPITremote) {
|
buttonPAUSEvar = receiveDATA.buttonPAUSE;
|
||||||
buttonPITvar = true;
|
buttonPITvar = receiveDATA.buttonPIT;
|
||||||
}
|
buttonPIThold = receiveDATA.buttonPIThold;
|
||||||
if (remoteDATA.buttonRESETremote) {
|
buttonRESETvar = receiveDATA.buttonRESET;
|
||||||
buttonRESETvar = true;
|
break;
|
||||||
|
case 1:
|
||||||
|
// RED team button
|
||||||
|
// ignore button input if in rumble mode
|
||||||
|
if (!switchRUMBLE.on()) {
|
||||||
|
// ignore button press while in fight
|
||||||
|
if (!FightCountDown.isRunning()) {
|
||||||
|
buttonREDTEAMvar = receiveDATA.buttonREDTEAM;
|
||||||
|
}
|
||||||
|
// ignore tapout while not in fight
|
||||||
|
if (FightCountDown.isRunning()) {
|
||||||
|
buttonREDTEAMtapout = receiveDATA.buttonREDTEAMtapout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// BLUE team button
|
||||||
|
// ignore button input if in rumble mode
|
||||||
|
if (!switchRUMBLE.on()) {
|
||||||
|
// ignore button press while in fight
|
||||||
|
if (!FightCountDown.isRunning()) {
|
||||||
|
buttonBLUETEAMvar = receiveDATA.buttonBLUETEAM;
|
||||||
|
}
|
||||||
|
// ignore tapout while not in fight
|
||||||
|
if (FightCountDown.isRunning()) {
|
||||||
|
buttonBLUETEAMtapout = receiveDATA.buttonBLUETEAMtapout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send data to clock:
|
||||||
|
void sendTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE, int BRIGHTNESS) {
|
||||||
|
// only send data if there was a change
|
||||||
|
if ((sendClockDATA.sendMinutes != MINUTES) || (sendClockDATA.sendSeconds != SECONDS) || (sendClockDATA.sendREDchannel != RED) || (sendClockDATA.sendGREENchannel != GREEN) || (sendClockDATA.sendBLUEchannel != BLUE) || (sendClockDATA.sendBrightness != BRIGHTNESS)) {
|
||||||
|
sendClockDATA.sendMinutes = MINUTES;
|
||||||
|
sendClockDATA.sendSeconds = SECONDS;
|
||||||
|
sendClockDATA.sendREDchannel = RED;
|
||||||
|
sendClockDATA.sendGREENchannel = GREEN;
|
||||||
|
sendClockDATA.sendBLUEchannel = BLUE;
|
||||||
|
sendClockDATA.sendBrightness = BRIGHTNESS;
|
||||||
|
// actually send it to first clock
|
||||||
|
esp_err_t result1 = esp_now_send(broadcastAddressClock1, (uint8_t *) &sendClockDATA, sizeof(sendClockDATA));
|
||||||
|
// actually send it to second clock
|
||||||
|
esp_err_t result2 = esp_now_send(broadcastAddressClock2, (uint8_t *) &sendClockDATA, sizeof(sendClockDATA));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global Vars for tap out states
|
||||||
|
bool redTapOutActive = false;
|
||||||
|
unsigned long redTapOutStartTime = 0;
|
||||||
|
int redTapOutStage = 0;
|
||||||
|
|
||||||
|
bool blueTapOutActive = false;
|
||||||
|
unsigned long blueTapOutStartTime = 0;
|
||||||
|
int blueTapOutStage = 0;
|
||||||
|
|
||||||
|
// Global Vars for Fight end
|
||||||
|
bool fightStarted = false;
|
||||||
|
bool fightEnded = false;
|
||||||
|
const int END_BLINK_COUNT = 3;
|
||||||
|
const unsigned long END_BLINK_INTERVAL = 500; // in milliseconds
|
||||||
|
int endBlinkTransitions = 0;
|
||||||
|
bool endBlinkState = false;
|
||||||
|
unsigned long lastEndBlinkTime = 0;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// set outputs
|
|
||||||
pinMode(RED_TEAM_LED_PIN, OUTPUT);
|
|
||||||
pinMode(BLUE_TEAM_LED_PIN, OUTPUT);
|
|
||||||
pinMode(PIT_RELEASE_PIN, OUTPUT);
|
|
||||||
|
|
||||||
digitalWrite(BLUE_TEAM_LED_PIN, LOW);
|
|
||||||
digitalWrite(RED_TEAM_LED_PIN, LOW);
|
|
||||||
digitalWrite(PIT_RELEASE_PIN, LOW);
|
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
// set relay outputs:
|
||||||
|
pinMode(PIT_RELEASE_PIN, OUTPUT);
|
||||||
|
digitalWrite(PIT_RELEASE_PIN, relayOffState);
|
||||||
|
pinMode(LIGHT_PIN, OUTPUT);
|
||||||
|
digitalWrite(LIGHT_PIN, LOW); // have it by default on, to prevent flickering, needs a better fix tho
|
||||||
|
pinMode(LIGHT_PIN2, OUTPUT);
|
||||||
|
digitalWrite(LIGHT_PIN2, LOW); // have it by default on, to prevent flickering, needs a better fix tho
|
||||||
|
pinMode(UNUSED_RELAY4_PIN, OUTPUT);
|
||||||
|
digitalWrite(UNUSED_RELAY4_PIN, relayOffState);
|
||||||
|
// set status LED outputs:
|
||||||
|
pinMode(LIGHT_STATUS_LED, OUTPUT);
|
||||||
|
digitalWrite(LIGHT_STATUS_LED, HIGH);
|
||||||
|
pinMode(AUTOPIT_STATUS_LED, OUTPUT);
|
||||||
|
digitalWrite(AUTOPIT_STATUS_LED, LOW);
|
||||||
|
pinMode(MODE_STATUS_LED, OUTPUT);
|
||||||
|
digitalWrite(MODE_STATUS_LED, LOW);
|
||||||
|
|
||||||
// Set device as a Wi-Fi Station
|
// Set device as a Wi-Fi Station
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
@@ -127,91 +287,391 @@ void setup() {
|
|||||||
Serial.println("Error initializing ESP-NOW");
|
Serial.println("Error initializing ESP-NOW");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// ESP Now send part:
|
||||||
|
// Once ESPNow is successfully Init, we will register for Send CB to
|
||||||
|
// get the status of Transmitted packet
|
||||||
|
esp_now_register_send_cb(OnDataSent);
|
||||||
|
|
||||||
|
// Register first clock peer
|
||||||
|
memcpy(peerInfo.peer_addr, broadcastAddressClock1, 6);
|
||||||
|
peerInfo.channel = 0;
|
||||||
|
peerInfo.encrypt = false;
|
||||||
|
// Add peer
|
||||||
|
if (esp_now_add_peer(&peerInfo) != ESP_OK){
|
||||||
|
Serial.println("Failed to add Clock1 peer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Register second clock peer
|
||||||
|
memcpy(peerInfo.peer_addr, broadcastAddressClock2, 6);
|
||||||
|
// peerInfo.channel & peerInfo.encrypt already set above
|
||||||
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
||||||
|
Serial.println("Failed to add Clock2 peer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send initial data (I think that doesn't work but meh...)
|
||||||
|
esp_err_t result1 = esp_now_send(broadcastAddressClock1, (uint8_t *) &sendClockDATA, sizeof(sendClockDATA));
|
||||||
|
esp_err_t result2 = esp_now_send(broadcastAddressClock2, (uint8_t *) &sendClockDATA, sizeof(sendClockDATA));
|
||||||
|
|
||||||
|
// Register Red Team Button peer
|
||||||
|
memcpy(peerInfo.peer_addr, broadcastAddressREDTEAMbutton, 6);
|
||||||
|
peerInfo.channel = 0;
|
||||||
|
peerInfo.encrypt = false;
|
||||||
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
||||||
|
Serial.println("Failed to add receiver 1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register Blue Team Button peer
|
||||||
|
memcpy(peerInfo.peer_addr, broadcastAddressBLUETEAMbutton, 6);
|
||||||
|
peerInfo.channel = 0;
|
||||||
|
peerInfo.encrypt = false;
|
||||||
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
||||||
|
Serial.println("Failed to add receiver 2");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register Pit controller peer
|
||||||
|
memcpy(peerInfo.peer_addr, broadcastAddressPitController, 6);
|
||||||
|
peerInfo.channel = 0;
|
||||||
|
peerInfo.encrypt = false;
|
||||||
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
||||||
|
Serial.println("Failed to add receiver 3");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize both Team button LED states and pit controller state
|
||||||
|
sendToREDTEAMbutton.TEAMLED = false;
|
||||||
|
sendToBLUETEAMbutton.TEAMLED = false;
|
||||||
|
sendToPitController.PIT = false;
|
||||||
|
// reset remote button LEDs and pit
|
||||||
|
esp_now_send(broadcastAddressREDTEAMbutton, (uint8_t *)&sendToREDTEAMbutton, sizeof(sendToREDTEAMbutton));
|
||||||
|
esp_now_send(broadcastAddressBLUETEAMbutton, (uint8_t *)&sendToBLUETEAMbutton, sizeof(sendToBLUETEAMbutton));
|
||||||
|
esp_now_send(broadcastAddressPitController, (uint8_t *)&sendToPitController, sizeof(sendToPitController));
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// ESP Now receive part:
|
||||||
// Once ESPNow is successfully Init, we will register for recv CB to
|
// Once ESPNow is successfully Init, we will register for recv CB to
|
||||||
// get recv packer info
|
// get recv packer info
|
||||||
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
|
esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
|
||||||
|
|
||||||
|
|
||||||
// set rumble stopwatch resolution to seconds
|
|
||||||
|
|
||||||
// sanity check delay - allows reprogramming if accidently blowing power w/leds
|
|
||||||
delay(2000);
|
|
||||||
// This function sets up the leds and tells the controller about them
|
|
||||||
FastLED.addLeds<WS2811Controller800Khz, LED_DATA_PIN_TIMER, GRB>(leds_TIMER, NUM_LEDS_TIMER); // GRB ordering is typical
|
|
||||||
//FastLED.setMaxRefreshRate(10, true);
|
|
||||||
FastLED.setMaxPowerInVoltsAndMilliamps(5,2000); // Limit to 10W of output power
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int XDAS = 255;
|
//----------------------------------------------------------------------------------------
|
||||||
bool toggle = false;
|
|
||||||
void loop() {
|
|
||||||
// poll all the switch/button inputs
|
|
||||||
pollInput();
|
|
||||||
// deactivate solenoids if needed
|
|
||||||
checkPIT();
|
|
||||||
|
|
||||||
// Normal fight routine
|
// Handler for the START button logic.
|
||||||
while (!switchRUMBLE.on()) {
|
void handleStartButton() {
|
||||||
// poll all the switch/button inputs
|
if (buttonSTARTvar) {
|
||||||
pollInput();
|
buttonSTARTvar = false;
|
||||||
// deactivate solenoids if needed
|
// Fresh start: no countdown is running, and the fight hasn't been paused.
|
||||||
checkPIT();
|
if (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
||||||
// start button logic
|
if (switchRUMBLE.on()) {
|
||||||
if (buttonSTARTvar) {
|
buttonREDTEAMvar = false;
|
||||||
buttonSTARTvar = false;
|
buttonBLUETEAMvar = false;
|
||||||
if (!FightCountDown[0].isRunning() && countdownPAUSED == false) {
|
ARENA_READY = true;
|
||||||
if (buttonREDTEAMvar && buttonBLUETEAMvar) {
|
REDTEAM_LED(true);
|
||||||
buttonREDTEAMvar = false;
|
BLUETEAM_LED(true);
|
||||||
buttonBLUETEAMvar = false;
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
FightCountDown[0].start(0,0,countdownTIME,0);
|
}
|
||||||
}
|
else if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||||
|
buttonREDTEAMvar = false;
|
||||||
|
buttonBLUETEAMvar = false;
|
||||||
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Resume (unpause) branch: instead of calling FightCountDown.resume() immediately,
|
||||||
|
// we want to display ReadyCountDown first.
|
||||||
|
if (buttonREDTEAMvar && buttonBLUETEAMvar && !switchRUMBLE.on()) {
|
||||||
|
buttonREDTEAMvar = false;
|
||||||
|
buttonBLUETEAMvar = false;
|
||||||
|
resumeFight = true; // Mark that we want to resume later.
|
||||||
|
countdownPAUSED = false;
|
||||||
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
|
}
|
||||||
|
else if (switchRUMBLE.on()) {
|
||||||
|
buttonREDTEAMvar = false;
|
||||||
|
buttonBLUETEAMvar = false;
|
||||||
|
resumeFight = true;
|
||||||
|
countdownPAUSED = false;
|
||||||
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler for the forced start button logic.
|
||||||
|
void handleForcedStartButton() {
|
||||||
|
if (buttonSTARTforced) {
|
||||||
|
buttonSTARTforced = false;
|
||||||
|
if (!FightCountDown.isRunning() && !rumbleTIME.isRunning() && countdownPAUSED == false) {
|
||||||
|
buttonREDTEAMvar = false;
|
||||||
|
buttonBLUETEAMvar = false;
|
||||||
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buttonREDTEAMvar = false;
|
||||||
|
buttonBLUETEAMvar = false;
|
||||||
|
resumeFight = true;
|
||||||
|
countdownPAUSED = false;
|
||||||
|
ARENA_READY = true;
|
||||||
|
REDTEAM_LED(true);
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
ReadyCountDown.start(countdownToFightTIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler for the pause button logic.
|
||||||
|
void handlePauseButton() {
|
||||||
|
if (buttonPAUSEvar) {
|
||||||
|
buttonPAUSEvar = false;
|
||||||
|
if (FightCountDown.isRunning()) {
|
||||||
|
countdownPAUSED = true;
|
||||||
|
FightCountDown.stop();
|
||||||
|
}
|
||||||
|
if (rumbleTIME.isRunning()) {
|
||||||
|
countdownPAUSED = true;
|
||||||
|
rumbleTIME.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler for the pit button logic.
|
||||||
|
void handlePitButton() {
|
||||||
|
if (buttonPITvar) {
|
||||||
|
buttonPITvar = false;
|
||||||
|
buttonPIThold = false;
|
||||||
|
openPITmanually();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for automatic pit release.
|
||||||
|
void handleAutoPitRelease() {
|
||||||
|
// Only release the pit if it hasn't already been released.
|
||||||
|
if (!PITreleased) {
|
||||||
|
if (FightCountDown.remaining() <= PITreleaseTime && FightCountDown.remaining() != 0 &&
|
||||||
|
!switchRUMBLE.on() && switchPIT.on() && buttonPIThold == false) {
|
||||||
|
openPIT();
|
||||||
|
}
|
||||||
|
else if (rumbleTIME.elapsed() >= PITreleaseTime && switchRUMBLE.on() &&
|
||||||
|
switchPIT.on() && buttonPIThold == false) {
|
||||||
|
openPIT();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler for transitioning from ReadyCountDown to the fight (or rumble) countdown.
|
||||||
|
void handleCountdownTransition() {
|
||||||
|
if (ReadyCountDown.remaining() == 0 && ARENA_READY) {
|
||||||
|
ARENA_READY = false;
|
||||||
|
REDTEAM_LED(false);
|
||||||
|
BLUETEAM_LED(false);
|
||||||
|
if (!switchRUMBLE.on()) {
|
||||||
|
if (resumeFight) {
|
||||||
|
FightCountDown.resume(); // Resume the paused fight countdown.
|
||||||
|
resumeFight = false;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (buttonREDTEAMvar && buttonBLUETEAMvar) {
|
FightCountDown.start(countdownTIME); // Fresh start.
|
||||||
buttonREDTEAMvar = false;
|
fightStarted = true;
|
||||||
buttonBLUETEAMvar = false;
|
|
||||||
countdownPAUSED = false;
|
|
||||||
FightCountDown[0].cont();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (switchRUMBLE.on()) {
|
||||||
|
// For the rumble branch, you may decide if a resume is relevant.
|
||||||
|
// Here we simply start the rumble timer as before.
|
||||||
|
rumbleTIME.start();
|
||||||
|
resumeFight = false;
|
||||||
}
|
}
|
||||||
// pause button logic
|
}
|
||||||
if (buttonPAUSEvar) {
|
}
|
||||||
buttonPAUSEvar = false;
|
|
||||||
if (FightCountDown[0].isRunning()) {
|
// The display update logic now considers all conditions in order.
|
||||||
countdownPAUSED = true;
|
void updateDisplay() {
|
||||||
FightCountDown[0].stop();
|
if (ReadyCountDown.isRunning()) {
|
||||||
}
|
// Display Ready Countdown in Yellow
|
||||||
}
|
sendTimeDisplay((ReadyCountDown.remaining()/60 % 60), (ReadyCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
// pit button logic
|
} else if (switchRUMBLE.on()) {
|
||||||
if (buttonPITvar) {
|
// Display the Rumble Timer
|
||||||
buttonPITvar = false;
|
sendTimeDisplay((rumbleTIME.elapsed()/60 % 60), (rumbleTIME.elapsed()%60), 0, 255, 255, CLOCK_LED_BRIGHTNESS);
|
||||||
openPIT();
|
} else if (!FightCountDown.isRunning() && !countdownPAUSED) {
|
||||||
}
|
// Choose green if both team buttons are active; otherwise, choose magenta.
|
||||||
// automatic pit release
|
if (buttonREDTEAMvar && buttonBLUETEAMvar) {
|
||||||
if (FightCountDown[0].remaining() <= PITreleaseTime && FightCountDown[0].remaining() > 0 && switchPIT.on()) {
|
sendTimeDisplay((countdownTIME/60 % 60), (countdownTIME%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
openPIT();
|
} else {
|
||||||
}
|
sendTimeDisplay((countdownTIME/60 % 60), (countdownTIME%60), 255, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||||
// reset button logic
|
}
|
||||||
if (buttonRESETvar) {
|
} else {
|
||||||
buttonRESETvar = false;
|
// choose yellow if countdown is paused and both teams aren't ready
|
||||||
PITreleased = false;
|
if (countdownPAUSED && (!buttonREDTEAMvar || !buttonBLUETEAMvar)) {
|
||||||
ESP.restart();
|
sendTimeDisplay((FightCountDown.remaining()/60 % 60), (FightCountDown.remaining()%60), 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
}
|
} else {
|
||||||
blink_LED_RedTeam(200);
|
// Display the countdown in green
|
||||||
blink_LED_BlueTeam(200);
|
sendTimeDisplay((FightCountDown.remaining()/60 % 60), (FightCountDown.remaining()%60), 0, 255, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
// update the LED Display
|
}
|
||||||
showTimeDisplay((FightCountDown[0].remaining()/60%10), (FightCountDown[0].remaining()%60), 0, XDAS, 0);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// endless cycling for Red Team tap-out.
|
||||||
// Rumble fightroutine
|
void handleRedTapOut() {
|
||||||
while (switchRUMBLE.on()) {
|
// When the red tap-out is first triggered.
|
||||||
// poll all the switch/button inputs
|
if (!redTapOutActive && buttonREDTEAMtapout && !switchRUMBLE.on() && !blueTapOutActive) {
|
||||||
pollInput();
|
buttonREDTEAMtapout = false;
|
||||||
// deactivate solenoids if needed
|
countdownPAUSED = true;
|
||||||
checkPIT();
|
FightCountDown.stop();
|
||||||
// update the LED Display
|
REDTEAM_LED(true);
|
||||||
showTimeDisplay(12, 34, XDAS, 0, XDAS);
|
redTapOutActive = true;
|
||||||
|
redTapOutStartTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If tap-out is active, continuously update the display in a cycle.
|
||||||
|
if (redTapOutActive) {
|
||||||
|
// Define a full cycle period of 8'000 ms.
|
||||||
|
const unsigned long cycleDuration = 8000;
|
||||||
|
// Compute how far into the current cycle we are.
|
||||||
|
unsigned long cycleTime = (millis() - redTapOutStartTime) % cycleDuration;
|
||||||
|
|
||||||
|
if (cycleTime < 1500) {
|
||||||
|
// Stage 1 (0 - 1500ms): Display first tap-out message.
|
||||||
|
sendTimeDisplay(99, 0, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
else if (cycleTime < 3000) {
|
||||||
|
// Stage 2 (1500 - 3000ms): Display second tap-out message.
|
||||||
|
sendTimeDisplay(0, 99, 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Stage 3 (3000 - 10'000ms): Show the remaining fight countdown.
|
||||||
|
sendTimeDisplay((FightCountDown.remaining() / 60 % 60), (FightCountDown.remaining() % 60), 255, 0, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endless cycling for Blue Team tap-out.
|
||||||
|
void handleBlueTapOut() {
|
||||||
|
// When the blue tap-out is first triggered.
|
||||||
|
if (!blueTapOutActive && buttonBLUETEAMtapout && !switchRUMBLE.on() && !redTapOutActive) {
|
||||||
|
buttonBLUETEAMtapout = false;
|
||||||
|
countdownPAUSED = true;
|
||||||
|
FightCountDown.stop();
|
||||||
|
BLUETEAM_LED(true);
|
||||||
|
blueTapOutActive = true;
|
||||||
|
blueTapOutStartTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If tap-out is active, continuously update the display in a cycle.
|
||||||
|
if (blueTapOutActive) {
|
||||||
|
// Define a full cycle period of 8'000 ms.
|
||||||
|
const unsigned long cycleDuration = 8000;
|
||||||
|
// Compute the cycle progress.
|
||||||
|
unsigned long cycleTime = (millis() - blueTapOutStartTime) % cycleDuration;
|
||||||
|
|
||||||
|
if (cycleTime < 1500) {
|
||||||
|
// Stage 1 (0 - 1500ms): Display first tap-out message.
|
||||||
|
sendTimeDisplay(99, 0, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
else if (cycleTime < 3000) {
|
||||||
|
// Stage 2 (1500 - 3000ms): Display second tap-out message.
|
||||||
|
sendTimeDisplay(0, 99, 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Stage 3 (3000 - 10'000ms): Show the remaining fight countdown.
|
||||||
|
sendTimeDisplay((FightCountDown.remaining() / 60 % 60), (FightCountDown.remaining() % 60), 0, 0, 255, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFightEnd() {
|
||||||
|
// When the countdown hits 0 and the fight had started, mark it as ended.
|
||||||
|
if ((FightCountDown.remaining() == 0) && fightStarted) {
|
||||||
|
fightEnded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only do blinking if the fight has ended.
|
||||||
|
if (!fightEnded) {
|
||||||
|
return; // Skip the rest until fightEnded becomes true.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each full blink cycle includes an "on" and "off" state.
|
||||||
|
// Therefore, we count transitions: total transitions = END_BLINK_COUNT * 2.
|
||||||
|
const int totalTransitions = END_BLINK_COUNT * 2 + 1;
|
||||||
|
|
||||||
|
// If we haven't completed our full blink sequence, manage timing:
|
||||||
|
if (endBlinkTransitions < totalTransitions) {
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
if (currentMillis - lastEndBlinkTime >= END_BLINK_INTERVAL) {
|
||||||
|
endBlinkState = !endBlinkState; // Toggle between on and off states.
|
||||||
|
endBlinkTransitions++; // Count this toggle.
|
||||||
|
lastEndBlinkTime = currentMillis; // Reset the timer.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depending on the blink state, update the display.
|
||||||
|
// When endBlinkState is true, use the normal brightness.
|
||||||
|
// When false, replace CLOCK_LED_BRIGHTNESS with 0 to blank the display.
|
||||||
|
if (endBlinkState) {
|
||||||
|
sendTimeDisplay(0, 0, 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
} else {
|
||||||
|
sendTimeDisplay(0, 0, 255, 165, 0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// After completing the blink sequence, ensure that the display remains on.
|
||||||
|
sendTimeDisplay(0, 0, 255, 165, 0, CLOCK_LED_BRIGHTNESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Poll and update low-level I/O and LEDs.
|
||||||
|
pollInput();
|
||||||
|
checkPIT();
|
||||||
|
arenaLIGHT();
|
||||||
|
statusLEDs();
|
||||||
|
updateTEAMLEDs();
|
||||||
|
|
||||||
|
|
||||||
|
// Process button events.
|
||||||
|
handleStartButton();
|
||||||
|
handleForcedStartButton();
|
||||||
|
handlePauseButton();
|
||||||
|
handlePitButton();
|
||||||
|
handleAutoPitRelease();
|
||||||
|
|
||||||
|
|
||||||
|
// Process tap-out sequences.
|
||||||
|
if (!switchRUMBLE.on()) {
|
||||||
|
handleRedTapOut();
|
||||||
|
handleBlueTapOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle reset
|
||||||
|
if (buttonRESETvar) {
|
||||||
|
buttonRESETvar = false;
|
||||||
|
PITreleased = false;
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transition from ReadyCountDown to the appropriate fight countdown.
|
||||||
|
handleCountdownTransition();
|
||||||
|
|
||||||
|
// End display
|
||||||
|
handleFightEnd();
|
||||||
|
|
||||||
|
// When no team is in a tap‐out sequence and fight hasn't ended, update the display.
|
||||||
|
if (!redTapOutActive && !blueTapOutActive && !fightEnded) {
|
||||||
|
updateDisplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ const int LitArray9 [] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,2
|
|||||||
// colon
|
// colon
|
||||||
const int COLONArray [] = {224,225,226,227,228,229,230,231};
|
const int COLONArray [] = {224,225,226,227,228,229,230,231};
|
||||||
|
|
||||||
|
// tap out
|
||||||
|
const int LitArrayTap [] = {0,1,2,3,4,5,6,7,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151};
|
||||||
|
//const int LitArrayOut [] = {0,1,2,3,4,5,6,7,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159};
|
||||||
|
const int LitArrayOut [] = {56,57,58,59,60,61,62,63,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215};
|
||||||
|
|
||||||
|
|
||||||
// set digits of the timer/clock, use: setDIGIT(<digit ID>, <Number>, <red channel intensity 0-255>, <green channel intensity 0-255>, <blue channel intensity 0-255>)
|
// set digits of the timer/clock, use: setDIGIT(<digit ID>, <Number>, <red channel intensity 0-255>, <green channel intensity 0-255>, <blue channel intensity 0-255>)
|
||||||
|
|
||||||
void setDIGIT(int DIGIT_ID, int DIGIT, int RED, int GREEN, int BLUE) {
|
void setDIGIT(int DIGIT_ID, int DIGIT, int RED, int GREEN, int BLUE) {
|
||||||
@@ -98,14 +104,23 @@ void setCOLON(int RED, int GREEN, int BLUE) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void showTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE, int BRIGHTNESS) {
|
void showTimeDisplay(int MINUTES, int SECONDS, int RED, int GREEN, int BLUE, int BRIGHTNESS) {
|
||||||
// set all digits
|
// set all digits
|
||||||
setDIGIT(1, ((MINUTES/10)%10), RED, GREEN, BLUE);
|
if (MINUTES == 99) {
|
||||||
setDIGIT(2, (MINUTES%10), RED, GREEN, BLUE);
|
for (int i : LitArrayTap) {
|
||||||
setDIGIT(3, ((SECONDS/10)%10), RED, GREEN, BLUE);
|
leds_TIMER[i].setRGB(RED,GREEN,BLUE);
|
||||||
setDIGIT(4, (SECONDS%10), RED, GREEN, BLUE);
|
}
|
||||||
setCOLON(RED, GREEN, BLUE);
|
} else if (SECONDS == 99) {
|
||||||
|
for (int i : LitArrayOut) {
|
||||||
|
leds_TIMER[i].setRGB(RED,GREEN,BLUE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setDIGIT(1, ((MINUTES/10)%10), RED, GREEN, BLUE);
|
||||||
|
setDIGIT(2, (MINUTES%10), RED, GREEN, BLUE);
|
||||||
|
setDIGIT(3, ((SECONDS/10)%10), RED, GREEN, BLUE);
|
||||||
|
setDIGIT(4, (SECONDS%10), RED, GREEN, BLUE);
|
||||||
|
setCOLON(RED, GREEN, BLUE);
|
||||||
|
}
|
||||||
// actually display the digits
|
// actually display the digits
|
||||||
FastLED.show(BRIGHTNESS);
|
FastLED.show(BRIGHTNESS);
|
||||||
// clear the arrays
|
// clear the arrays
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
// ROFLS+ Arena Controller
|
// ROFLS+ Arena Controller
|
||||||
|
|
||||||
|
// MAC address of the MCU:
|
||||||
|
// 48:27:E2:50:86:84
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include <esp_wifi.h> // Required for wifi_tx_info_t
|
||||||
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
||||||
#include <Preferences.h> // automatically installed for ESP32 boards
|
#include <Preferences.h> // automatically installed for ESP32 boards
|
||||||
#include <FastLED.h> // https://fastled.io/
|
#include <FastLED.h> // https://fastled.io/
|
||||||
@@ -27,12 +31,13 @@ typedef struct struct_message {
|
|||||||
int receiveBrightness;
|
int receiveBrightness;
|
||||||
} struct_message;
|
} struct_message;
|
||||||
|
|
||||||
// Create a struct_message called remoteDATA
|
// Create a struct_message called receiveDATA
|
||||||
struct_message receiveDATA;
|
struct_message receiveDATA;
|
||||||
|
|
||||||
// callback function that will be executed when data is received
|
// callback function that will be executed when data is received
|
||||||
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
||||||
memcpy(&receiveDATA, incomingData, sizeof(receiveDATA));
|
memcpy(&receiveDATA, incomingData, sizeof(receiveDATA));
|
||||||
|
showTimeDisplay(receiveDATA.receiveMinutes, receiveDATA.receiveSeconds, receiveDATA.receiveREDchannel, receiveDATA.receiveGREENchannel, receiveDATA.receiveBLUEchannel, receiveDATA.receiveBrightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -51,21 +56,16 @@ void setup() {
|
|||||||
// sanity check delay - allows reprogramming if accidently blowing power w/leds
|
// sanity check delay - allows reprogramming if accidently blowing power w/leds
|
||||||
delay(2000);
|
delay(2000);
|
||||||
// This function sets up the leds and tells the controller about them
|
// This function sets up the leds and tells the controller about them
|
||||||
FastLED.addLeds<WS2811Controller800Khz, LED_DATA_PIN_TIMER, GRB>(leds_TIMER, NUM_LEDS_TIMER); // GRB ordering is typical
|
//FastLED.addLeds<WS2811Controller800Khz, LED_DATA_PIN_TIMER, GRB>(leds_TIMER, NUM_LEDS_TIMER); // GRB ordering is typical
|
||||||
|
FastLED.addLeds<WS2812B, LED_DATA_PIN_TIMER, GRB>(leds_TIMER, NUM_LEDS_TIMER); // GRB ordering is typical
|
||||||
//FastLED.setMaxRefreshRate(10, true);
|
//FastLED.setMaxRefreshRate(10, true);
|
||||||
FastLED.setMaxPowerInVoltsAndMilliamps(5,2000); // Limit to 10W of output power
|
FastLED.setMaxPowerInVoltsAndMilliamps(5,4000); // Limit to 20W of output power
|
||||||
|
|
||||||
// set default values
|
// set default values
|
||||||
receiveDATA.receiveMinutes = 12;
|
// default screen, just to show it's up and running but hasn't received any data, should display 00:00 in blue
|
||||||
receiveDATA.receiveSeconds = 34;
|
showTimeDisplay(0, 0, 0, 0, 255, 32);
|
||||||
receiveDATA.receiveREDchannel = 128;
|
|
||||||
receiveDATA.receiveGREENchannel = 128;
|
|
||||||
receiveDATA.receiveBLUEchannel = 128;
|
|
||||||
receiveDATA.receiveBrightness = 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// update the LED Display
|
// nothing to see here, everything get's handled by the callback function
|
||||||
showTimeDisplay(receiveDATA.receiveMinutes, receiveDATA.receiveSeconds, receiveDATA.receiveREDchannel, receiveDATA.receiveGREENchannel, receiveDATA.receiveBLUEchannel, receiveDATA.receiveBrightness);
|
|
||||||
// showTimeDisplay(12, 34, 150, 0, 150, 16);
|
|
||||||
}
|
}
|
||||||
|
|||||||
78
ROFLS_Arena_Pit_Controller/ROFLS_Arena_Pit_Controller.ino
Normal file
78
ROFLS_Arena_Pit_Controller/ROFLS_Arena_Pit_Controller.ino
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Pit controller
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <esp_now.h>
|
||||||
|
#include <ESP32Servo.h>
|
||||||
|
|
||||||
|
// Define the pins for the two servos
|
||||||
|
#define SERVO1_PIN 9
|
||||||
|
#define SERVO2_PIN 7
|
||||||
|
|
||||||
|
// Define pulse widths (in microseconds)
|
||||||
|
#define DEFAULT_PULSE 2000 // Default position
|
||||||
|
#define ACTUATED_PULSE 1000 // Actuated position
|
||||||
|
|
||||||
|
// Define the reset time in milliseconds
|
||||||
|
#define RESET_TIME_MS 1000
|
||||||
|
|
||||||
|
// Create two Servo objects for the two servos
|
||||||
|
Servo servo1;
|
||||||
|
Servo servo2;
|
||||||
|
|
||||||
|
// Global variables to manage servo reset timing
|
||||||
|
volatile bool servoActuated = false; // Tracks if servos are currently actuated
|
||||||
|
unsigned long actuatedTimestamp = 0; // Stores the time when the servos were actuated
|
||||||
|
|
||||||
|
// Updated ESP‑Now receive callback function with the correct signature
|
||||||
|
void OnDataRecv(const esp_now_recv_info_t *recv_info, const uint8_t *incomingData, int len) {
|
||||||
|
// We expect one boolean (1 byte)
|
||||||
|
bool command = false;
|
||||||
|
if (len == sizeof(command)) {
|
||||||
|
memcpy(&command, incomingData, sizeof(command));
|
||||||
|
if (command) {
|
||||||
|
// Actuate both servos to the actuated position
|
||||||
|
servo1.writeMicroseconds(ACTUATED_PULSE);
|
||||||
|
servo2.writeMicroseconds(ACTUATED_PULSE);
|
||||||
|
// Record the time when the servos were actuated
|
||||||
|
actuatedTimestamp = millis();
|
||||||
|
servoActuated = true;
|
||||||
|
} else {
|
||||||
|
// Immediately reset both servos to the default position
|
||||||
|
servo1.writeMicroseconds(DEFAULT_PULSE);
|
||||||
|
servo2.writeMicroseconds(DEFAULT_PULSE);
|
||||||
|
servoActuated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize WiFi in station mode (required for ESP‑Now)
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
|
// Attach the servos to their respective pins and set to default position
|
||||||
|
servo1.attach(SERVO1_PIN);
|
||||||
|
servo2.attach(SERVO2_PIN);
|
||||||
|
servo1.writeMicroseconds(DEFAULT_PULSE);
|
||||||
|
servo2.writeMicroseconds(DEFAULT_PULSE);
|
||||||
|
|
||||||
|
// Initialize ESP‑Now
|
||||||
|
if (esp_now_init() != ESP_OK) {
|
||||||
|
// Optionally handle initialization errors
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Register the ESP‑Now receive callback function
|
||||||
|
esp_now_register_recv_cb(OnDataRecv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Check if the servos are in the actuated state and if RESET_TIME_MS has elapsed
|
||||||
|
if (servoActuated && (millis() - actuatedTimestamp >= RESET_TIME_MS)) {
|
||||||
|
// Reset both servos back to the default position after the delay
|
||||||
|
servo1.writeMicroseconds(DEFAULT_PULSE);
|
||||||
|
servo2.writeMicroseconds(DEFAULT_PULSE);
|
||||||
|
servoActuated = false;
|
||||||
|
}
|
||||||
|
// Yield a little time for other tasks
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -6,17 +6,23 @@ void pollInput (){
|
|||||||
buttonPAUSE.poll();
|
buttonPAUSE.poll();
|
||||||
buttonPIT.poll();
|
buttonPIT.poll();
|
||||||
buttonRESET.poll();
|
buttonRESET.poll();
|
||||||
|
buttonTEAM.poll();
|
||||||
|
|
||||||
if (buttonSTART.pushed()) {
|
// only set the var if the button was actually pushed or released, to prevent overriding data from the controller
|
||||||
buttonSTARTvar = true;
|
if (buttonSTART.singleClick() || buttonSTART.longPress() || buttonPAUSE.singleClick() || buttonPIT.singleClick() || buttonPIT.switched() || buttonRESET.longPress() || buttonTEAM.singleClick() || buttonTEAM.longPress()) {
|
||||||
}
|
sendDATAvar = true;
|
||||||
if (buttonPAUSE.pushed()) {
|
buttonSTARTvar = buttonSTART.singleClick();
|
||||||
buttonPAUSEvar = true;
|
buttonSTARTforced = buttonSTART.longPress();
|
||||||
}
|
buttonPAUSEvar = buttonPAUSE.singleClick();
|
||||||
if (buttonPIT.pushed()) {
|
buttonPITvar = buttonPIT.singleClick();
|
||||||
buttonPITvar = true;
|
buttonPIThold = buttonPIT.on();
|
||||||
}
|
buttonRESETvar = buttonRESET.longPress();
|
||||||
if (buttonRESET.pushed()) {
|
if (boardID == 1) {
|
||||||
buttonRESETvar = true;
|
buttonREDTEAMvar = buttonTEAM.singleClick();
|
||||||
|
buttonREDTEAMtapout = buttonTEAM.longPress();
|
||||||
|
} else if (boardID == 2) {
|
||||||
|
buttonBLUETEAMvar = buttonTEAM.singleClick();
|
||||||
|
buttonBLUETEAMtapout = buttonTEAM.longPress();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,59 +1,131 @@
|
|||||||
// ROFLS+ Referee Remote
|
// ROFLS+ Referee Remote
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
#include <esp_wifi.h> // Required for wifi_tx_info_t
|
||||||
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
||||||
#include <Preferences.h> // automatically installed for ESP32 boards
|
#include <Preferences.h> // automatically installed for ESP32 boards
|
||||||
#include <avdweb_Switch.h> // https://github.com/avdwebLibraries/avdweb_Switch
|
#include <avdweb_Switch.h> // https://github.com/avdwebLibraries/avdweb_Switch
|
||||||
|
|
||||||
|
// set board ID
|
||||||
|
// This is only needed for the initial flashing, as it writes the ID in to the ESPs internal flash
|
||||||
|
//
|
||||||
|
// 0 = referee remote
|
||||||
|
// 1 = Red Team Button
|
||||||
|
// 2 = Blue Team Button
|
||||||
|
const bool writeBoardID = false;
|
||||||
|
int boardID = 1;
|
||||||
|
|
||||||
|
// set Arena, switches the MAC addresses out
|
||||||
|
// 1 = Arena A (Ant)
|
||||||
|
// 2 = Arena B (Beetle)
|
||||||
|
#define ARENA 1
|
||||||
|
|
||||||
// Hardware connections
|
// Hardware connections
|
||||||
#define START_BTN_PIN 4
|
#define START_BTN_PIN 10
|
||||||
#define PAUSE_BTN_PIN 3
|
#define PAUSE_BTN_PIN 8
|
||||||
#define PIT_BTN_PIN 2
|
#define PIT_BTN_PIN 1
|
||||||
#define RESET_BTN_PIN 1
|
#define RESET_BTN_PIN 3
|
||||||
|
#define TEAM_BTN_PIN 16
|
||||||
|
#define TEAM_LED_PIN 17
|
||||||
|
|
||||||
// define buttons and switches
|
// define buttons and switches
|
||||||
Switch buttonSTART = Switch(START_BTN_PIN);
|
Switch buttonSTART = Switch(START_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
Switch buttonPAUSE = Switch(PAUSE_BTN_PIN);
|
Switch buttonPAUSE = Switch(PAUSE_BTN_PIN);
|
||||||
Switch buttonPIT = Switch(PIT_BTN_PIN);
|
Switch buttonPIT = Switch(PIT_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
Switch buttonRESET = Switch(RESET_BTN_PIN);
|
Switch buttonRESET = Switch(RESET_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
|
Switch buttonTEAM = Switch(TEAM_BTN_PIN, INPUT_PULLUP, LOW, 50, 1000);
|
||||||
|
|
||||||
bool buttonSTARTvar = false;
|
bool buttonSTARTvar = false;
|
||||||
|
bool buttonSTARTforced = false;
|
||||||
bool buttonPAUSEvar = false;
|
bool buttonPAUSEvar = false;
|
||||||
bool buttonPITvar = false;
|
bool buttonPITvar = false;
|
||||||
|
bool buttonPIThold = false;
|
||||||
bool buttonRESETvar = false;
|
bool buttonRESETvar = false;
|
||||||
|
bool buttonREDTEAMvar = false;
|
||||||
|
bool buttonREDTEAMtapout = false;
|
||||||
|
bool buttonBLUETEAMvar = false;
|
||||||
|
bool buttonBLUETEAMtapout = false;
|
||||||
|
|
||||||
bool sendDATA = false;
|
bool sendDATAvar = false;
|
||||||
|
|
||||||
// ESP-NOW config
|
// ESP-NOW config
|
||||||
|
|
||||||
// REPLACE WITH YOUR RECEIVER MAC Address
|
// REPLACE WITH YOUR RECEIVER MAC Address
|
||||||
uint8_t broadcastAddress[] = {0x84, 0xFC, 0xE6, 0xC7, 0x1A, 0x8C};
|
#if ARENA == 1
|
||||||
|
// A Arena Controller MAC Address
|
||||||
|
uint8_t broadcastAddress[] = {0x84, 0xFC, 0xE6, 0xC7, 0x1A, 0x8C};
|
||||||
|
#elif ARENA == 2
|
||||||
|
// B Arena Controller MAC Address
|
||||||
|
uint8_t broadcastAddress[] = {0xD8, 0x3B, 0xDA, 0xC9, 0x0C, 0xEE};
|
||||||
|
#endif
|
||||||
|
|
||||||
// Structure example to send data
|
// Structure example to send data
|
||||||
// Must match the receiver structure
|
// Must match the receiver structure
|
||||||
typedef struct struct_message {
|
typedef struct struct_message_send {
|
||||||
bool buttonSTARTremote;
|
int boardID;
|
||||||
bool buttonPAUSEremote;
|
bool buttonSTART;
|
||||||
bool buttonPITremote;
|
bool buttonSTARTforced;
|
||||||
bool buttonRESETremote;
|
bool buttonPAUSE;
|
||||||
} struct_message;
|
bool buttonPIT;
|
||||||
|
bool buttonPIThold;
|
||||||
|
bool buttonRESET;
|
||||||
|
bool buttonREDTEAM;
|
||||||
|
bool buttonREDTEAMtapout;
|
||||||
|
bool buttonBLUETEAM;
|
||||||
|
bool buttonBLUETEAMtapout;
|
||||||
|
} struct_message_send;
|
||||||
|
|
||||||
// Create a struct_message called myData
|
// Create a struct_message called myData
|
||||||
struct_message remoteDATA;
|
struct_message_send sendDATA;
|
||||||
|
|
||||||
|
// Add struct for receiving ESP-NOW data
|
||||||
|
typedef struct struct_message_receive {
|
||||||
|
bool TEAMLED; // Boolean to control the team LED
|
||||||
|
} struct_message_receive;
|
||||||
|
|
||||||
|
// Create instance for receiving ESP-NOW data
|
||||||
|
struct_message_receive receiveDATA;
|
||||||
|
|
||||||
esp_now_peer_info_t peerInfo;
|
esp_now_peer_info_t peerInfo;
|
||||||
|
|
||||||
|
Preferences preferences;
|
||||||
|
|
||||||
// callback when data is sent
|
// callback when data is sent
|
||||||
/*
|
void OnDataSent(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
|
||||||
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
|
|
||||||
Serial.print("\r\nLast Packet Send Status:\t");
|
Serial.print("\r\nLast Packet Send Status:\t");
|
||||||
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
|
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
// Callback function for receiving ESP-NOW data
|
||||||
|
void OnDataReceive(const esp_now_recv_info *recv_info, const uint8_t *incomingData, int len) {
|
||||||
|
// Copy the received data into the struct
|
||||||
|
memcpy(&receiveDATA, incomingData, sizeof(receiveDATA));
|
||||||
|
|
||||||
|
// Update the LED state based on received data
|
||||||
|
digitalWrite(TEAM_LED_PIN, receiveDATA.TEAMLED ? HIGH : LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// write boardID to internal Flash if needed
|
||||||
|
if (writeBoardID) {
|
||||||
|
// open preferences, namespace, RW mode = false
|
||||||
|
preferences.begin("Arena-remote", false);
|
||||||
|
preferences.putUInt("boardID", boardID);
|
||||||
|
} else {
|
||||||
|
// open preferences, namespace, RO mode = true
|
||||||
|
preferences.begin("Arena-remote", true);
|
||||||
|
}
|
||||||
|
// read board ID from internal flash
|
||||||
|
boardID = preferences.getUInt("boardID", 0);
|
||||||
|
preferences.end();
|
||||||
|
|
||||||
|
// configure and set the LED output pin
|
||||||
|
pinMode(TEAM_LED_PIN, OUTPUT);
|
||||||
|
digitalWrite(TEAM_LED_PIN, LOW);
|
||||||
|
|
||||||
// Set device as a Wi-Fi Station
|
// Set device as a Wi-Fi Station
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
@@ -63,8 +135,8 @@ void setup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Once ESPNow is successfully Init, we will register for Send CB to
|
// Once ESPNow is successfully Init, we will register for Send CB to
|
||||||
// get the status of Trasnmitted packet
|
// get the status of Transmitted packet
|
||||||
//esp_now_register_send_cb(OnDataSent);
|
esp_now_register_send_cb(OnDataSent);
|
||||||
|
|
||||||
// Register peer
|
// Register peer
|
||||||
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
|
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
|
||||||
@@ -75,69 +147,54 @@ void setup() {
|
|||||||
Serial.println("Failed to add peer");
|
Serial.println("Failed to add peer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register receive callback
|
||||||
|
esp_now_register_recv_cb(OnDataReceive);
|
||||||
|
|
||||||
|
// populate sendDATA struct with some data:
|
||||||
|
sendDATA.boardID = boardID;
|
||||||
|
sendDATA.buttonSTART = false;
|
||||||
|
sendDATA.buttonSTARTforced = false;
|
||||||
|
sendDATA.buttonPAUSE = false;
|
||||||
|
sendDATA.buttonPIT = false;
|
||||||
|
sendDATA.buttonPIThold = false;
|
||||||
|
sendDATA.buttonRESET = false;
|
||||||
|
sendDATA.buttonREDTEAM = false;
|
||||||
|
sendDATA.buttonREDTEAMtapout = false;
|
||||||
|
sendDATA.buttonBLUETEAM = false;
|
||||||
|
sendDATA.buttonBLUETEAMtapout = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendDATA_to_controller() {
|
||||||
|
// if ((sendDATA.buttonSTART != buttonSTARTvar) || (sendDATA.buttonSTARTforced != buttonSTARTforced) || (sendDATA.buttonPAUSE !=buttonPAUSEvar) || (sendDATA.buttonPIT != buttonPITvar) || (sendDATA.buttonPIThold != buttonPIThold) || (sendDATA.buttonRESET != buttonRESETvar) || (sendDATA.buttonREDTEAM != buttonREDTEAMvar) || (sendDATA.buttonREDTEAMtapout != buttonREDTEAMtapout) || (sendDATA.buttonBLUETEAM != buttonBLUETEAMvar) || (sendDATA.buttonBLUETEAMtapout != buttonBLUETEAMtapout)) {
|
||||||
|
if (sendDATAvar) {
|
||||||
|
sendDATAvar = false;
|
||||||
|
// prepare sendDATA data
|
||||||
|
sendDATA.boardID = boardID;
|
||||||
|
sendDATA.buttonSTART = buttonSTARTvar;
|
||||||
|
sendDATA.buttonSTARTforced = buttonSTARTforced;
|
||||||
|
sendDATA.buttonPAUSE = buttonPAUSEvar;
|
||||||
|
sendDATA.buttonPIT = buttonPITvar;
|
||||||
|
sendDATA.buttonPIThold = buttonPIThold;
|
||||||
|
sendDATA.buttonRESET = buttonRESETvar;
|
||||||
|
sendDATA.buttonREDTEAM = buttonREDTEAMvar;
|
||||||
|
sendDATA.buttonREDTEAMtapout = buttonREDTEAMtapout;
|
||||||
|
sendDATA.buttonBLUETEAM = buttonBLUETEAMvar;
|
||||||
|
sendDATA.buttonBLUETEAMtapout = buttonBLUETEAMtapout;
|
||||||
|
// send data
|
||||||
|
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &sendDATA, sizeof(sendDATA));
|
||||||
|
// check if transmission was successfull
|
||||||
|
// if (result == ESP_OK) {
|
||||||
|
// Serial.println("Sent with success");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// Serial.println("Error sending the data");
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
// poll all the switch/button inputs
|
// poll all the switch/button inputs
|
||||||
pollInput();
|
pollInput();
|
||||||
// start button logic
|
sendDATA_to_controller();
|
||||||
if (buttonSTARTvar) {
|
|
||||||
buttonSTARTvar = false;
|
|
||||||
remoteDATA.buttonSTARTremote = true;
|
|
||||||
sendDATA = true;
|
|
||||||
}
|
|
||||||
// pause button logic
|
|
||||||
if (buttonPAUSEvar) {
|
|
||||||
buttonPAUSEvar = false;
|
|
||||||
remoteDATA.buttonPAUSEremote = true;
|
|
||||||
sendDATA = true;
|
|
||||||
}
|
|
||||||
// pit button logic
|
|
||||||
if (buttonPITvar) {
|
|
||||||
buttonPITvar = false;
|
|
||||||
remoteDATA.buttonPITremote = true;
|
|
||||||
sendDATA = true;
|
|
||||||
}
|
|
||||||
// reset button logic
|
|
||||||
if (buttonRESETvar) {
|
|
||||||
buttonRESETvar = false;
|
|
||||||
remoteDATA.buttonRESETremote = true;
|
|
||||||
sendDATA = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set values to send
|
|
||||||
//remoteDATA.buttonSTARTremote = false;
|
|
||||||
//remoteDATA.buttonPAUSEremote = false;
|
|
||||||
//remoteDATA.buttonPITremote = false;
|
|
||||||
//remoteDATA.buttonRESETremote = false;
|
|
||||||
|
|
||||||
// Send message via ESP-NOW
|
|
||||||
//esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &remoteDATA, sizeof(remoteDATA));
|
|
||||||
if (sendDATA == true) {
|
|
||||||
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &remoteDATA, sizeof(remoteDATA));
|
|
||||||
sendDATA = false;
|
|
||||||
// clear remoteDATA struct
|
|
||||||
remoteDATA.buttonSTARTremote = false;
|
|
||||||
remoteDATA.buttonPAUSEremote = false;
|
|
||||||
remoteDATA.buttonPITremote = false;
|
|
||||||
remoteDATA.buttonRESETremote = false;
|
|
||||||
|
|
||||||
if (result == ESP_OK) {
|
|
||||||
Serial.println("Sent with success");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Serial.println("Error sending the data");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (result == ESP_OK) {
|
|
||||||
Serial.println("Sent with success");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Serial.println("Error sending the data");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
//delay(2000);
|
|
||||||
}
|
}
|
||||||
|
|||||||
80
Reference_Manual.md
Normal file
80
Reference_Manual.md
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# ROFLS Arena Reference Manual
|
||||||
|
|
||||||
|
### Before a fight/tournament (omit step 1-6 after initial setup):
|
||||||
|
1. Check all connections
|
||||||
|
2. Power on the PSU
|
||||||
|
3. Turn on the Teambuttons and the Referee Remote
|
||||||
|
4. Wait for the 7 Segment Clock to turn on (~2s)
|
||||||
|
5. Turn on the lights (if off and needed)
|
||||||
|
6. Open the Controller Box and set the brightness with the potentiometer on the top right
|
||||||
|
7. Select the mode (explanations for the modes, see below):
|
||||||
|
8. Press and Hold Reset for >1s, can be on the Controller itself or the Referee Remote
|
||||||
|
9. Arena is ready
|
||||||
|
|
||||||
|
|
||||||
|
### Start a normal fight:
|
||||||
|
1. for good measure: Press and Hold Reset for >1s, can be on the Controller itself or the Referee Remote.
|
||||||
|
2. Team Red and Team Blue need to (short) press their respective Teambuttons, the Clock turns green to signal that both are ready.
|
||||||
|
3. Press Start, if the Teambuttons are not working, the Start button can be long pressed (>1s), to force a start.
|
||||||
|
4. To prevent the automatic pit opening, press and hold the Pit button, as soon as the pit button gets released, the pit will open.
|
||||||
|
|
||||||
|
### Start a rumble fight:
|
||||||
|
1. for good measure: Press and Hold Reset for >1s, can be on the Controller itself or the Referee Remote.
|
||||||
|
2. Press Start
|
||||||
|
3. To prevent the automatic pit opening, press and hold the Pit button, as soon as the pit button gets released, the pit will open.
|
||||||
|
|
||||||
|
### Pausing a running fight:
|
||||||
|
1. Press the Pause button
|
||||||
|
2. To resume:
|
||||||
|
- normal fight:
|
||||||
|
Both Teams need to press their respective Teambuttons to signal that they are both ready.
|
||||||
|
- Press start, after 3s, the timer resumes.
|
||||||
|
- rumble fight:
|
||||||
|
- Press start, after 3s, the stop watch resumes.
|
||||||
|
|
||||||
|
## Modes
|
||||||
|
* Normal Mode:
|
||||||
|
* Normal fight mode, 3 Minute Timer, Tapout enabled, after 90s (halftime) automatic pit opening (if enabled)
|
||||||
|
* Teambuttons are active and need to be pressed once to sign that they are ready. They light up if ready.
|
||||||
|
* Teambuttons LEDs turn of when the fight starts
|
||||||
|
* During a running fight, if one of the Teambuttons is pressed >1s, it counts as a tapout. The Timer stops and displays "TAPOUT", cycles between "TAPOUT" and the end time.
|
||||||
|
* Can be paused, resuming works the same as starting, Teams must be ready
|
||||||
|
* Rumble Mode:
|
||||||
|
* Rumble mode, stop watch counting up, Tapout disabled, after 90s automatic pit opening (if enabled)
|
||||||
|
* Match starts 3s after pressing start
|
||||||
|
* Teambuttons are inactive
|
||||||
|
* Teambutton LEDs Light up 3s before the match begins, and turn off when it starts.
|
||||||
|
* No Tapout available
|
||||||
|
* Can be paused, resuming works the same as starting, Teams must be ready
|
||||||
|
|
||||||
|
## Buttons explained
|
||||||
|
> The 4 buttons on the referee remote and the controller box have the same function and can both be used.
|
||||||
|
* Start
|
||||||
|
* Starts a fight, can be long pressed (>1s) to force start a fight
|
||||||
|
* Pause
|
||||||
|
* Pauses a fight
|
||||||
|
* Pit
|
||||||
|
* Short press (<1s) immediately opens the pit, Long press (>1s) prevents the pit from automatically open, but opens immediately after released
|
||||||
|
* Reset
|
||||||
|
* Resets the Arena Controller, needs to be long pressed (>1s)
|
||||||
|
* Lights Switch
|
||||||
|
* Turns on/off the Arena Lights, lights up if lights are on.
|
||||||
|
* Auto Pit Switch
|
||||||
|
* Turn on/off the automatic pit opening, lights up if enabled
|
||||||
|
* Mode Switch
|
||||||
|
* R = Rumble mode
|
||||||
|
* N = Normal mode
|
||||||
|
* T = Self Test (not implemented yet)
|
||||||
|
|
||||||
|
## Display Colours & Status explained
|
||||||
|
| Colour | Meaning |
|
||||||
|
|--------|---------|
|
||||||
|
| Blue with one purple segment, displaying 00:00 | not initialized (hit reset to fix) |
|
||||||
|
| Purple, displaying 03:00 | Normal Mode, Idle/Arena Ready |
|
||||||
|
| Green | Normal Mode, Both Teams Ready/Running Fight |
|
||||||
|
| Yellow | 3s Ready Countdown or Paused |
|
||||||
|
| Yellow, initally blinking 3 times | Timer run out / finish |
|
||||||
|
| Red, cycling between tap, out and time | Red Team has tapped out |
|
||||||
|
| Blue, cycling between tap, out and time | Blue Team has tapped out |
|
||||||
|
| Teal, displaying 00:00 | Rumble mode, Idle/Arena Ready |
|
||||||
|
| Teal, displaying timer | Rumble mode, active fight |
|
||||||
1317
Schematics/ESP32-S2_Interface_Board.diy
Normal file
1317
Schematics/ESP32-S2_Interface_Board.diy
Normal file
File diff suppressed because it is too large
Load Diff
1296
Schematics/MOSFET_Switching_Board.diy
Normal file
1296
Schematics/MOSFET_Switching_Board.diy
Normal file
File diff suppressed because it is too large
Load Diff
106
Test/LED_Strip_send_test/LED_Strip_send_test.ino
Normal file
106
Test/LED_Strip_send_test/LED_Strip_send_test.ino
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
// ROFLS+ Arena Controller
|
||||||
|
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <esp_now.h> // automatically installed for ESP32 boards, I think?
|
||||||
|
#include <Preferences.h> // automatically installed for ESP32 boards
|
||||||
|
#include <CountDown.h> // https://github.com/RobTillaart/CountDown
|
||||||
|
#include <StopWatch.h> // https://github.com/RobTillaart/StopWatch_RT
|
||||||
|
|
||||||
|
|
||||||
|
const int countdownTIME = 3; // countdown timer length in minutes
|
||||||
|
const int countdownToFight = 3; // countdown timer length in seconds
|
||||||
|
const int PITreleaseTime = 90; // automatic pit release time in seconds until end of countdown
|
||||||
|
bool countdownPAUSED = false;
|
||||||
|
CountDown FightCountDown[1];
|
||||||
|
|
||||||
|
// Rumble stopwatch
|
||||||
|
StopWatch rumbleTIME;
|
||||||
|
|
||||||
|
int CLOCK_LED_BRIGHTNESS = 16; // 64 is okay
|
||||||
|
|
||||||
|
// REPLACE WITH YOUR RECEIVER MAC Address
|
||||||
|
uint8_t broadcastAddress[] = {0x48, 0x27, 0xE2, 0x5D, 0xB6, 0x84};
|
||||||
|
// ESP-NOW config
|
||||||
|
|
||||||
|
// Structure example to send data
|
||||||
|
// Must match the receiver structure
|
||||||
|
typedef struct struct_message {
|
||||||
|
int sendMinutes;
|
||||||
|
int sendSeconds;
|
||||||
|
int sendREDchannel;
|
||||||
|
int sendGREENchannel;
|
||||||
|
int sendBLUEchannel;
|
||||||
|
int sendBrightness;
|
||||||
|
} struct_message;
|
||||||
|
|
||||||
|
// Create a struct_message called remoteDATA
|
||||||
|
struct_message sendDATA;
|
||||||
|
|
||||||
|
esp_now_peer_info_t peerInfo;
|
||||||
|
|
||||||
|
// callback when data is sent
|
||||||
|
|
||||||
|
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
|
||||||
|
Serial.print("\r\nLast Packet Send Status:\t");
|
||||||
|
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Serial.begin(115200);
|
||||||
|
// Set device as a Wi-Fi Station
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
|
// Init ESP-NOW
|
||||||
|
if (esp_now_init() != ESP_OK) {
|
||||||
|
Serial.println("Error initializing ESP-NOW");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Once ESPNow is successfully Init, we will register for Send CB to
|
||||||
|
// get the status of Trasnmitted packet
|
||||||
|
esp_now_register_send_cb(OnDataSent);
|
||||||
|
|
||||||
|
// Register peer
|
||||||
|
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
|
||||||
|
peerInfo.channel = 0;
|
||||||
|
peerInfo.encrypt = false;
|
||||||
|
// Add peer
|
||||||
|
if (esp_now_add_peer(&peerInfo) != ESP_OK){
|
||||||
|
Serial.println("Failed to add peer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set rumble stopwatch resolution to seconds
|
||||||
|
|
||||||
|
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &sendDATA, sizeof(sendDATA));
|
||||||
|
sendDATA.sendMinutes = 88;
|
||||||
|
sendDATA.sendSeconds = 88;
|
||||||
|
sendDATA.sendREDchannel = 63;
|
||||||
|
sendDATA.sendGREENchannel = 0;
|
||||||
|
sendDATA.sendBLUEchannel = 0;
|
||||||
|
sendDATA.sendBrightness = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &sendDATA, sizeof(sendDATA));
|
||||||
|
sendDATA.sendMinutes = 88;
|
||||||
|
sendDATA.sendSeconds = 88;
|
||||||
|
sendDATA.sendREDchannel = 63;
|
||||||
|
sendDATA.sendGREENchannel = 0;
|
||||||
|
sendDATA.sendBLUEchannel = 0;
|
||||||
|
sendDATA.sendBrightness = 32;
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
// if (result == ESP_OK) {
|
||||||
|
// Serial.println("Sent with success");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// Serial.println("Error sending the data");
|
||||||
|
// }
|
||||||
|
|
||||||
|
//showTimeDisplay((FightCountDown[0].remaining()/60%10), (FightCountDown[0].remaining()%60), 0, XDAS, 0);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/// @file Blink.ino
|
|
||||||
/// @brief Blink the first LED of an LED strip
|
|
||||||
/// @example Blink.ino
|
|
||||||
|
|
||||||
#include <FastLED.h>
|
|
||||||
|
|
||||||
// How many leds in your strip?
|
|
||||||
#define NUM_LEDS 3
|
|
||||||
|
|
||||||
// For led chips like WS2812, which have a data line, ground, and power, you just
|
|
||||||
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
|
|
||||||
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
|
|
||||||
// Clock pin only needed for SPI based chipsets when not using hardware SPI
|
|
||||||
#define DATA_PIN 3
|
|
||||||
//#define CLOCK_PIN 13
|
|
||||||
|
|
||||||
// Define the array of leds
|
|
||||||
CRGB leds[NUM_LEDS];
|
|
||||||
|
|
||||||
#define POTI_PIN 2
|
|
||||||
int POTI_VALUE = 0;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS); // GRB ordering is typical
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
leds[0] = CRGB::Red;
|
|
||||||
leds[1] = CRGB::Blue;
|
|
||||||
leds[2] = CRGB::Green;
|
|
||||||
FastLED.setBrightness(map(analogRead(POTI_PIN), 0, 8191, 8, 255));
|
|
||||||
FastLED.show();
|
|
||||||
delay(1);
|
|
||||||
//POTI_VALUE = map(analogRead(POTI_PIN), 0, 8191, 0, 255);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user