// Code generated with the help of AI from the prompt described in the documentation; manually reviewed and adapted. #include #include #include // -------------------- BOARD CONFIG -------------------- // This PCB is installed in the VISITOR goal. // If the ball enters here, LOCAL scores. #define BOARD_ID_VISITOR_GOAL 2 #define EVENT_GOAL_LOCAL 1 // MAIN MAC Address uint8_t mainMAC[] = {0x58, 0xE6, 0xC5, 0x02, 0xF7, 0xC4}; // -------------------- PINS -------------------- #define IR_SENSOR_PIN D1 #define BUTTON_RIGHT D8 #define BUTTON_LEFT D10 #define SERVO_RIGHT_PIN 17 // D7 = GPIO17 #define SERVO_LEFT_PIN D2 // -------------------- SERVOS -------------------- Servo servoRight; Servo servoLeft; // Right servo: clockwise movement const int RIGHT_REST_POS = 130; const int RIGHT_HIT_POS = 70; // Left servo: inverse movement / anticlockwise const int LEFT_REST_POS = 70; const int LEFT_HIT_POS = 130; const unsigned long HIT_HOLD_TIME = 180; // -------------------- IR SENSOR -------------------- const int GOAL_DETECTED_STATE = LOW; bool lastIrState = HIGH; unsigned long lastGoalTime = 0; const unsigned long GOAL_DEBOUNCE_TIME = 300; // -------------------- BUTTON STATES -------------------- bool lastRightButtonState = HIGH; bool lastLeftButtonState = HIGH; bool rightFlipperActive = false; bool leftFlipperActive = false; unsigned long rightHitStartTime = 0; unsigned long leftHitStartTime = 0; // -------------------- ESP-NOW MESSAGE -------------------- typedef struct { uint8_t boardID; uint8_t eventType; } EspNowMessage; EspNowMessage messageToSend; // -------------------- ESP-NOW CALLBACK -------------------- void onDataSent(const wifi_tx_info_t *info, esp_now_send_status_t status) { Serial.print("ESP-NOW send status: "); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "SUCCESS" : "FAIL"); } // -------------------- ESP-NOW FUNCTIONS -------------------- void sendGoalLocal() { messageToSend.boardID = BOARD_ID_VISITOR_GOAL; messageToSend.eventType = EVENT_GOAL_LOCAL; esp_err_t result = esp_now_send(mainMAC, (uint8_t *)&messageToSend, sizeof(messageToSend)); if (result == ESP_OK) { Serial.println("ESP-NOW message sent: GOAL LOCAL"); } else { Serial.println("ESP-NOW send error"); } } void setupEspNow() { WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("ESP-NOW init failed"); return; } esp_now_register_send_cb(onDataSent); esp_now_peer_info_t peerInfo = {}; memcpy(peerInfo.peer_addr, mainMAC, 6); peerInfo.channel = 0; peerInfo.encrypt = false; if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("Failed to add MAIN peer"); return; } Serial.println("ESP-NOW ready"); } // -------------------- SETUP -------------------- void setup() { Serial.begin(115200); delay(1000); pinMode(IR_SENSOR_PIN, INPUT_PULLUP); pinMode(BUTTON_RIGHT, INPUT_PULLUP); pinMode(BUTTON_LEFT, INPUT_PULLUP); servoRight.attach(SERVO_RIGHT_PIN, 500, 2500); servoLeft.attach(SERVO_LEFT_PIN, 500, 2500); servoRight.write(RIGHT_REST_POS); servoLeft.write(LEFT_REST_POS); lastIrState = digitalRead(IR_SENSOR_PIN); setupEspNow(); Serial.println("VISITOR GOAL PCB READY"); Serial.println("IR goal here = LOCAL scores"); } // -------------------- LOOP -------------------- void loop() { unsigned long now = millis(); bool rightButtonState = digitalRead(BUTTON_RIGHT); bool leftButtonState = digitalRead(BUTTON_LEFT); bool irState = digitalRead(IR_SENSOR_PIN); // -------------------- IR GOAL DETECTION -------------------- if (lastIrState != GOAL_DETECTED_STATE && irState == GOAL_DETECTED_STATE) { if (now - lastGoalTime >= GOAL_DEBOUNCE_TIME) { lastGoalTime = now; Serial.println("GOAL DETECTED IN VISITOR GOAL"); Serial.println("LOCAL SCORES"); sendGoalLocal(); } } lastIrState = irState; // -------------------- RIGHT BUTTON -> RIGHT SERVO -------------------- if (lastRightButtonState == HIGH && rightButtonState == LOW && !rightFlipperActive) { Serial.println("RIGHT HIT"); servoRight.write(RIGHT_HIT_POS); rightFlipperActive = true; rightHitStartTime = now; } // -------------------- LEFT BUTTON -> LEFT SERVO -------------------- if (lastLeftButtonState == HIGH && leftButtonState == LOW && !leftFlipperActive) { Serial.println("LEFT HIT"); servoLeft.write(LEFT_HIT_POS); leftFlipperActive = true; leftHitStartTime = now; } // -------------------- RIGHT RETURN -------------------- if (rightFlipperActive && now - rightHitStartTime >= HIT_HOLD_TIME) { servoRight.write(RIGHT_REST_POS); rightFlipperActive = false; Serial.println("RIGHT RETURN"); } // -------------------- LEFT RETURN -------------------- if (leftFlipperActive && now - leftHitStartTime >= HIT_HOLD_TIME) { servoLeft.write(LEFT_REST_POS); leftFlipperActive = false; Serial.println("LEFT RETURN"); } lastRightButtonState = rightButtonState; lastLeftButtonState = leftButtonState; }