This shows you the differences between two versions of the page.
|
pm:prj2023:adarmaz:kings-cup [2023/05/30 03:48] mihnea.branzeu [Cod Master] |
pm:prj2023:adarmaz:kings-cup [2023/05/30 09:24] (current) mihnea.branzeu [Rezultate Obţinute] |
||
|---|---|---|---|
| Line 747: | Line 747: | ||
| ==== Cod Player ==== | ==== Cod Player ==== | ||
| + | Asemanator cu Masterul, Playerul este construi tot sub forma unui state-machine: | ||
| + | <code cpp> | ||
| + | #include <esp_now.h> | ||
| + | #include <WiFi.h> | ||
| + | #define THUMB_MASTER_BUTTON_PIN 18 | ||
| + | #define GENERAL_PURPOSE_BUTTON_PIN 19 | ||
| + | #define FORCE_SENSOR_PIN 36 | ||
| + | #define LED_PIN 22 | ||
| + | #define LED2_PIN 17 | ||
| + | #define BUZZER_PIN 23 | ||
| + | |||
| + | #define IDLE_STATE 0 | ||
| + | #define SHOULD_DRINK_STATE 1 | ||
| + | #define SHOULD_SAY_STATE 2 | ||
| + | #define THUMB_MASTER_STATE 3 | ||
| + | #define WATERFALL_STATE 4 | ||
| + | |||
| + | #define MESSAGE_DRINK 0 | ||
| + | #define MESSAGE_CONFIRM 1 | ||
| + | #define MESSAGE_SCREAM 2 | ||
| + | #define MESSAGE_SAY 3 | ||
| + | #define MESSAGE_GO_NEXT 4 | ||
| + | #define MESSAGE_THUMB_MASTER 5 | ||
| + | #define MESSAGE_WATERFALL_GO 6 | ||
| + | #define MESSAGE_WATERFALL_STOP 7 | ||
| + | #define MESSAGE_WATERFALL_GO_INITIATOR 8 | ||
| + | |||
| + | |||
| + | #define GLASS_NOT_LIFTED 0 | ||
| + | #define GLASS_LIFTED 1 | ||
| + | #define GLASS_BACK 2 | ||
| + | |||
| + | typedef struct message_t { | ||
| + | int sender; | ||
| + | int receiver; | ||
| + | int messageType; | ||
| + | } message_t; | ||
| + | |||
| + | // MAC Address of the master ESP | ||
| + | uint8_t broadcastAddress[] = {0xE8, 0x31, 0xCD, 0x14, 0x21, 0x1C}; | ||
| + | |||
| + | // The player ID | ||
| + | int myId = -1; | ||
| + | |||
| + | // Peer info structure | ||
| + | esp_now_peer_info_t peerInfo; | ||
| + | |||
| + | // The drinking flag | ||
| + | int currentState; | ||
| + | |||
| + | // The state of the buzzer | ||
| + | bool buzzerOn = false; | ||
| + | |||
| + | // The state of the glass | ||
| + | int glassState; | ||
| + | |||
| + | // Flag for the waterfall challenge | ||
| + | bool canPutBack; | ||
| + | bool isInitiator; | ||
| + | |||
| + | const int movingAvgLength = 10; | ||
| + | int movingAvgBuffer[movingAvgLength]; | ||
| + | int movingAvgIndex = 0; | ||
| + | |||
| + | // Callback function executed when data is received | ||
| + | void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) { | ||
| + | message_t message; | ||
| + | |||
| + | memcpy(&message, incomingData, sizeof(message_t)); | ||
| + | Serial.print("Data received: "); | ||
| + | Serial.println(len); | ||
| + | Serial.print("Sender: "); | ||
| + | Serial.println(message.sender); | ||
| + | Serial.print("Message type: "); | ||
| + | Serial.println(message.messageType == 0 ? "DRINK" : "CONFIRM"); | ||
| + | |||
| + | if (message.messageType == MESSAGE_DRINK) { | ||
| + | currentState = SHOULD_DRINK_STATE; | ||
| + | glassState = GLASS_NOT_LIFTED; | ||
| + | } | ||
| + | |||
| + | if (message.messageType == MESSAGE_SCREAM) { | ||
| + | buzzerOn = true; | ||
| + | } | ||
| + | |||
| + | if (message.messageType == MESSAGE_SAY) { | ||
| + | currentState = SHOULD_SAY_STATE; | ||
| + | } | ||
| + | |||
| + | if (message.messageType == MESSAGE_THUMB_MASTER) { | ||
| + | currentState = THUMB_MASTER_STATE; | ||
| + | } | ||
| + | |||
| + | if (message.messageType == MESSAGE_WATERFALL_GO) { | ||
| + | currentState = WATERFALL_STATE; | ||
| + | glassState = GLASS_NOT_LIFTED; | ||
| + | canPutBack = false; | ||
| + | isInitiator = false; | ||
| + | } | ||
| + | |||
| + | if (message.messageType == MESSAGE_WATERFALL_GO_INITIATOR) { | ||
| + | currentState = WATERFALL_STATE; | ||
| + | glassState = GLASS_NOT_LIFTED; | ||
| + | canPutBack = false; | ||
| + | isInitiator = true; | ||
| + | } | ||
| + | |||
| + | if (message.messageType == MESSAGE_WATERFALL_STOP) { | ||
| + | canPutBack = true; | ||
| + | } | ||
| + | |||
| + | // Check if it's the first message and update ID | ||
| + | if (myId == -1) { | ||
| + | myId = message.receiver; | ||
| + | } | ||
| + | |||
| + | | ||
| + | } | ||
| + | |||
| + | // Callback when data is sent | ||
| + | void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { | ||
| + | char macStr[18]; | ||
| + | Serial.print("Packet to: "); | ||
| + | // Copies the sender mac address to a string | ||
| + | snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", | ||
| + | mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); | ||
| + | Serial.print(macStr); | ||
| + | Serial.print(" send status:\t"); | ||
| + | Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); | ||
| + | } | ||
| + | |||
| + | int calculateMovingAverage(int sensorValue) { | ||
| + | movingAvgBuffer[movingAvgIndex] = sensorValue; | ||
| + | movingAvgIndex = (movingAvgIndex + 1) % movingAvgLength; | ||
| + | |||
| + | int sum = 0; | ||
| + | for (int i = 0; i < movingAvgLength; i++) { | ||
| + | sum += movingAvgBuffer[i]; | ||
| + | } | ||
| + | |||
| + | return sum / movingAvgLength; | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | void setup() { | ||
| + | // Initialize serial communication at 9600 bits per second: | ||
| + | Serial.begin(9600); | ||
| + | |||
| + | // Initialize ESP NOW stuff | ||
| + | // Set ESP32 as a Wi-Fi Station | ||
| + | WiFi.mode(WIFI_STA); | ||
| + | |||
| + | // Initilize ESP-NOW stuff | ||
| + | if (esp_now_init() != ESP_OK) { | ||
| + | Serial.println("Error initializing ESP-NOW"); | ||
| + | return; | ||
| + | } | ||
| + | | ||
| + | // Register callback function | ||
| + | esp_now_register_recv_cb(OnDataRecv); | ||
| + | esp_now_register_send_cb(OnDataSent); | ||
| + | |||
| + | memcpy(peerInfo.peer_addr, broadcastAddress, 6); | ||
| + | if (esp_now_add_peer(&peerInfo) != ESP_OK){ | ||
| + | Serial.println("Failed to add peer"); | ||
| + | return; | ||
| + | } | ||
| + | |||
| + | |||
| + | // Initialize the thumb master button | ||
| + | pinMode(THUMB_MASTER_BUTTON_PIN, INPUT_PULLUP); | ||
| + | pinMode(GENERAL_PURPOSE_BUTTON_PIN, INPUT_PULLUP); | ||
| + | // Initialize the led | ||
| + | pinMode(LED_PIN, OUTPUT); | ||
| + | pinMode(LED2_PIN, OUTPUT); | ||
| + | // Initialize the buzzer | ||
| + | pinMode(BUZZER_PIN, OUTPUT); | ||
| + | |||
| + | currentState = IDLE_STATE; | ||
| + | } | ||
| + | |||
| + | void loop() { | ||
| + | if (currentState == SHOULD_DRINK_STATE) { | ||
| + | // Turn on the LED | ||
| + | digitalWrite(LED_PIN, HIGH); | ||
| + | digitalWrite(LED2_PIN, LOW); | ||
| + | |||
| + | if (buzzerOn) { | ||
| + | digitalWrite(BUZZER_PIN, HIGH); | ||
| + | } | ||
| + | |||
| + | // Read the FSR value | ||
| + | int forceSensorValue = calculateMovingAverage(analogRead(FORCE_SENSOR_PIN)); | ||
| + | |||
| + | | ||
| + | if ((forceSensorValue <5) && glassState == GLASS_NOT_LIFTED) { | ||
| + | glassState = GLASS_LIFTED; | ||
| + | } | ||
| + | |||
| + | if ((forceSensorValue > 100) && glassState == GLASS_LIFTED) { | ||
| + | glassState = GLASS_BACK; | ||
| + | } | ||
| + | |||
| + | if (glassState == GLASS_BACK) { | ||
| + | // Send the confirmation message | ||
| + | // Create the message | ||
| + | message_t message = {myId, 3, MESSAGE_CONFIRM}; | ||
| + | | ||
| + | // Send the message | ||
| + | esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message_t)); | ||
| + | |||
| + | // Check the result | ||
| + | if (result == ESP_OK) { | ||
| + | Serial.println("Sent with success"); | ||
| + | currentState = IDLE_STATE; | ||
| + | buzzerOn = false; | ||
| + | } | ||
| + | else { | ||
| + | Serial.println("Error sending the data"); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if (currentState == SHOULD_SAY_STATE) { | ||
| + | // Turn on the LED | ||
| + | digitalWrite(LED2_PIN, HIGH); | ||
| + | | ||
| + | // Wait for the button press | ||
| + | int generalPurposeButtonState = digitalRead(GENERAL_PURPOSE_BUTTON_PIN); | ||
| + | |||
| + | if (!generalPurposeButtonState) { | ||
| + | // Send the message to master to go to the next player | ||
| + | message_t message = {myId, 3, MESSAGE_GO_NEXT}; | ||
| + | esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message_t)); | ||
| + | if (result == ESP_OK) { | ||
| + | Serial.println("Sent with success"); | ||
| + | currentState = IDLE_STATE; | ||
| + | buzzerOn = false; | ||
| + | } | ||
| + | else { | ||
| + | Serial.println("Error sending the data"); | ||
| + | } | ||
| + | digitalWrite(LED2_PIN, LOW); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if (currentState == THUMB_MASTER_STATE) { | ||
| + | int thumbMasterButtonState = digitalRead(THUMB_MASTER_BUTTON_PIN); | ||
| + | if (!thumbMasterButtonState) { | ||
| + | message_t message = {myId, 3, MESSAGE_THUMB_MASTER}; | ||
| + | esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message_t)); | ||
| + | if (result == ESP_OK) { | ||
| + | Serial.println("Sent with success"); | ||
| + | currentState = IDLE_STATE; | ||
| + | buzzerOn = false; | ||
| + | } | ||
| + | else { | ||
| + | Serial.println("Error sending the data"); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if (currentState == WATERFALL_STATE) { | ||
| + | int forceSensorValue = calculateMovingAverage(analogRead(FORCE_SENSOR_PIN)); | ||
| + | if (forceSensorValue <5 && (glassState == GLASS_NOT_LIFTED || glassState == GLASS_BACK)) { | ||
| + | glassState = GLASS_LIFTED; | ||
| + | } | ||
| + | |||
| + | if (forceSensorValue > 5 && glassState == GLASS_LIFTED) { | ||
| + | glassState = GLASS_BACK; | ||
| + | if (isInitiator) { | ||
| + | canPutBack = true; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if ((glassState == GLASS_NOT_LIFTED || glassState == GLASS_BACK) && !canPutBack) { | ||
| + | // Turn on the alert | ||
| + | digitalWrite(LED_PIN, HIGH); | ||
| + | digitalWrite(BUZZER_PIN, HIGH); | ||
| + | } | ||
| + | |||
| + | if (glassState == GLASS_LIFTED && !canPutBack) { | ||
| + | digitalWrite(LED_PIN, LOW); | ||
| + | digitalWrite(BUZZER_PIN, LOW); | ||
| + | } | ||
| + | |||
| + | if (glassState == GLASS_BACK && canPutBack) { | ||
| + | message_t message = {myId, 3, MESSAGE_WATERFALL_STOP}; | ||
| + | esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &message, sizeof(message_t)); | ||
| + | if (result == ESP_OK) { | ||
| + | Serial.println("Sent with success"); | ||
| + | currentState = IDLE_STATE; | ||
| + | buzzerOn = false; | ||
| + | } | ||
| + | else { | ||
| + | Serial.println("Error sending the data"); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if (currentState == IDLE_STATE) { | ||
| + | // Turn off the LED | ||
| + | digitalWrite(LED_PIN, LOW); | ||
| + | digitalWrite(BUZZER_PIN, LOW); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </code> | ||
| ===== Rezultate Obţinute ===== | ===== Rezultate Obţinute ===== | ||
| + | Modulul Master: | ||
| - | <note tip> | + | {{:pm:prj2023:adarmaz:modulmasterkingspoza.jpeg?300|}} |
| - | Care au fost rezultatele obţinute în urma realizării proiectului vostru. | + | |
| - | </note> | + | |
| - | ===== Concluzii ===== | + | Modul Player: |
| - | ===== Download ===== | + | {{:pm:prj2023:adarmaz:modulplayerkingspoza.jpeg?300|}} |
| - | <note warning> | + | Video cu flow-ul jocului: |
| - | O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-). | + | |
| - | Fişierele se încarcă pe wiki folosind facilitatea **Add Images or other files**. Namespace-ul în care se încarcă fişierele este de tipul **:pm:prj20??:c?** sau **:pm:prj20??:c?:nume_student** (dacă este cazul). **Exemplu:** Dumitru Alin, 331CC -> **:pm:prj2009:cc:dumitru_alin**. | + | <html> |
| - | </note> | + | <iframe width="560" height="315" src="https://www.youtube.com/embed/KnaIk49ovkk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe></html> |
| + | ===== Concluzii ===== | ||
| + | Obiectivul meu in cadrul proiectului a fost sa gasesc o idee noua, si sa o implementez intr-un mod care sa ma invete ceva nou. Consider ca am atins ambele obiective. Nu am putut gasi pe internet ceva asemanator, ceea ce a fost in acelasi timp satisfacator si challenging, pentru ca nu am avut nicio varianta de fallback. Cel mai important lucru pe care l-am invatat este functionalitatea bibliotecii ESP-NOW. | ||
| + | Cel mai mare challenge are legatura cu faptul ca proiectul este alcatuit din multe module, ceea ce a facut testarea destul de dificila. Pe partea de cod, implementarea initiala a comunicarii si a unei provocari de test a fost cea mai interesanta, urmand ca restul de functionalitati sa fie usor de implementat, fiind foarte asemanatoare cu prima. | ||
| + | |||
| + | ===== Download ===== | ||
| + | Link Github: https://github.com/mihneabranzeu/King-s-Cup-Arduino | ||
| ===== Jurnal ===== | ===== Jurnal ===== | ||
| * 5 Mai - Am creat pagina de documentatie | * 5 Mai - Am creat pagina de documentatie | ||
| + | * 6 Mai - Am comandat piesele | ||
| + | * 10 Mai - Au ajuns piesele | ||
| + | * 20 - 23 Mai - Am lucrat la proiect | ||
| + | * 24 Mai - Am prezentat proiectul la laborator | ||
| + | * 30 Mai - PM Fair | ||
| ===== Bibliografie/Resurse ===== | ===== Bibliografie/Resurse ===== | ||
| - | + | * https://www.youtube.com/watch?v=bEKjCDDUPaU | |
| - | <note> | + | * https://dronebotworkshop.com/esp-now/ |
| - | Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe **Resurse Software** şi **Resurse Hardware**. | + | |
| - | </note> | + | |
| - | + | ||
| - | <html><a class="media mediafile mf_pdf" href="?do=export_pdf">Export to PDF</a></html> | + | |