diff --git a/frontend/src/data/examples-100-days.ts b/frontend/src/data/examples-100-days.ts index ff0c2249..dec2ac69 100644 --- a/frontend/src/data/examples-100-days.ts +++ b/frontend/src/data/examples-100-days.ts @@ -1969,11 +1969,11 @@ CITY = "city" i2c = I2C(0, scl=Pin(22), sda=Pin(21)) oled = ssd1306.SSD1306_I2C(128, 64, i2c) -# PULL_DOWN, no Pin.IN a secas: los botones van entre 3V3 y el pin, asi que sin -# pull-down el pin queda FLOTANDO cuando el boton esta abierto y pin.value() no -# vale nada. En una placa de verdad se lee ruido; aqui el nodo resuelve a 3,3 V y -# los dos botones parecen pulsados para siempre, con wait_for_release() girando -# en vacio. Es el mismo fallo que en hardware, no un artefacto del emulador. +# PULL_DOWN, not plain Pin.IN: the buttons sit between 3V3 and the pin, so +# without a pull-down the pin FLOATS while the button is open and pin.value() +# is meaningless. On a real board you read noise; here the node resolves to +# 3.3 V and both buttons look pressed forever, with wait_for_release() +# spinning on nothing. Same failure as on real hardware, not an emulator artifact. touch_next = Pin(14, Pin.IN, Pin.PULL_DOWN) touch_sel = Pin(27, Pin.IN, Pin.PULL_DOWN) diff --git a/frontend/src/data/examples-robot-desktop.ts b/frontend/src/data/examples-robot-desktop.ts index 6af5e03d..7b57eaf3 100644 --- a/frontend/src/data/examples-robot-desktop.ts +++ b/frontend/src/data/examples-robot-desktop.ts @@ -82,11 +82,11 @@ export const robotDesktopExamples: ExampleProject[] = [ // the file that matches the directory name), then headers // alphabetical, then .hpp, then .cpp. Tabs left untouched so // the editor matches the upstream source byte-for-byte. - { name: "esp32-eyes.ino", content: "#include \n#include \n#include \n#include \n\n#include \"Face.h\"\n#include \"Weather.h\"\n#include \"Common.h\"\n#include \"SensorDriver.h\"\n#include \"ServoMotorDriver.h\"\n// GLOBALS\nFace *face;\n\nunsigned long lastMovementTime = 0; // Time of the last detected movement\nconst unsigned long WEATHER_TIMEOUT = 600000; // 10 minutos en milisegundos\nconst unsigned long SLEEP_TIMEOUT = 3600000; // 1 hora en milisegundos\n\nint progress = 0;\n\n// Flags that drive the state machine\nbool weatherTimeoutReached = false;\nbool sleepTimeoutReached = false;\n\nunsigned long lastTriggerTime = 0;\nbool lastStateMovement = false;\nbool movementDetected = false;\n\nRobotState lastInsertedState = SLEEP;\n// Estado actual\nRobotState currentState = SLEEP;\n\nTaskHandle_t faceHandle;\nServo ServoDerecha;\nServo ServoIzquierda;\n\nTaskHandle_t servoHandle;\n// GLOBALS\n\neEmotions previousEmotion;\n\nTaskHandle_t soundHandle;\n\nTaskHandle_t sensorHandle;\n\nvoid vUpdateFaceTask(void *pvParameters)\n{\n while (1)\n {\n\n face->RandomBehavior = false;\n face->RandomBlink = true;\n face->RandomLook = true;\n\n if (currentState == NORMAL)\n {\n Serial.println(\"STATE Normal 224****************************************\");\n face->RandomBehavior = true;\n }\n else if (currentState == SOUND)\n {\n // Actions for the NERVOUS state\n eEmotions cEmotion = face->Behavior.CurrentEmotion;\n if (cEmotion != eEmotions::Surprised)\n {\n face->Expression.GoTo_Surprised();\n }\n Serial.println(\"STATE = SONIDO ..... *************************************************\");\n }\n else if (currentState == MOVE)\n {\n // Actions for the MOVE state\n Serial.println(\"STATE = MOVE ...... *************************************************\");\n eEmotions cEmotion = face->Behavior.CurrentEmotion;\n if (cEmotion != eEmotions::Focused)\n {\n face->Expression.GoTo_Focused();\n }\n }\n else if (currentState == SLEEP)\n {\n Serial.println(\"STATE = SLEEP ..... **************************************************\");\n face->RandomBehavior = false;\n face->RandomBlink = false;\n face->RandomLook = false;\n Serial.println(face->Behavior.CurrentEmotion);\n Serial.println(eEmotions::Sleepy);\n if (face->Behavior.CurrentEmotion != eEmotions::Sleepy)\n {\n face->Behavior.CurrentEmotion = eEmotions::Sleepy;\n face->Expression.GoTo_Sleepy();\n Serial.println(\"GoTo_Sleepy\");\n }\n else\n {\n Serial.println(\"Distinto ******------------------------------------------------------------------------------************\");\n face->Update();\n }\n }\n else if (currentState == WEATHER)\n {\n\n Serial.println(\"STATE = Weather ..... ************************************************\");\n Serial.println(analogRead(LDR_PIN));\n face->Expression.GoTo_Normal();\n updateWEATHER();\n vTaskDelay(pdMS_TO_TICKS(100));\n continue;\n }\n else if (currentState == INICIO)\n {\n currentState = SLEEP;\n }\n\n face->Update();\n vTaskDelay(pdMS_TO_TICKS(100));\n }\n}\n\nvoid setup(void)\n{\n // Create a serial connection\n Serial.begin(115200);\n Serial.println(\"Starting.................\");\n ServoDerecha.write(0);\n ServoDerecha.write(90);\n\n pinMode(PIR_PIN, INPUT);\n // pinMode(SOUND_PIN, INPUT);\n pinMode(LDR_PIN, INPUT);\n // insertState(INICIO);\n currentState = SLEEP;\n lastStateMovement = digitalRead(PIR_PIN);\n // Configure input pins\n pinMode(SOUND_PIN, OUTPUT);\n randomSeed(analogRead(0));\n\n // StarWarsPlay();\n // Create a new face\n\n face = new Face(/* screenWidth = */ 128, /* screenHeight = */ 64, /* eyeSize = */ 40);\n\n initDht();\n\n delay(3000);\n // Assign the current expression\n face->Expression.GoTo_Sleepy();\n Serial.println(\"GoTo_Sleepy\");\n\n // Assign a weight to each emotion\n face->Behavior.SetEmotion(eEmotions::Normal, 1.0);\n face->Behavior.SetEmotion(eEmotions::Angry, 1.0);\n face->Behavior.SetEmotion(eEmotions::Glee, 1.0);\n face->Behavior.SetEmotion(eEmotions::Happy, 1.0);\n face->Behavior.SetEmotion(eEmotions::Sad, 1.0);\n face->Behavior.SetEmotion(eEmotions::Worried, 1.0);\n face->Behavior.SetEmotion(eEmotions::Focused, 1.0);\n face->Behavior.SetEmotion(eEmotions::Annoyed, 1.0);\n face->Behavior.SetEmotion(eEmotions::Surprised, 1.0);\n face->Behavior.SetEmotion(eEmotions::Skeptic, 1.0);\n face->Behavior.SetEmotion(eEmotions::Frustrated, 1.0);\n face->Behavior.SetEmotion(eEmotions::Unimpressed, 1.0);\n face->Behavior.SetEmotion(eEmotions::Sleepy, 1.0);\n face->Behavior.SetEmotion(eEmotions::Suspicious, 1.0);\n face->Behavior.SetEmotion(eEmotions::Squint, 1.0);\n face->Behavior.SetEmotion(eEmotions::Furious, 1.0);\n face->Behavior.SetEmotion(eEmotions::Scared, 1.0);\n face->Behavior.SetEmotion(eEmotions::Awe, 1.0);\n\n face->RandomBehavior = false;\n\n // Automatically blink\n face->RandomBlink = true;\n // Set blink rate\n face->Blink.Timer.SetIntervalMillis(8000);\n face->Behavior.Timer.SetIntervalMillis(15000);\n\n // Automatically choose a new random direction to look\n face->RandomLook = true;\n ServoDerecha.attach(SERVO1_Derecha);\n ServoIzquierda.attach(SERVO2_Izquierda);\n ServoIzquierda.write(0);\n ServoDerecha.write(170);\n\n delay(3000);\n\n xTaskCreatePinnedToCore(\n vUpdateFaceTask, /* Task function. */\n \"Update face\", /* name of task. */\n 10000, /* Stack size of task */\n NULL, /* parameter of the task */\n 1, /* priority of the task */\n &faceHandle, /* Task handle to keep track of created task */\n 0); /* pin task to core 0 */\n\n xTaskCreatePinnedToCore(\n vMoveServoTask, /* Task function. */\n \"Update Servo\", /* name of task. */\n 10000, /* Stack size of task */\n face, /* parameter of the task */\n 5, /* priority of the task */\n &servoHandle, /* Task handle to keep track of created task */\n 1); /* pin task to core 0 */\n\n xTaskCreatePinnedToCore(\n vReadSensorTask, /* Task function. */\n \"Read Sensor\", /* name of task. */\n 10000, /* Stack size of task */\n NULL, /* parameter of the task */\n 10, /* priority of the task */\n &sensorHandle, /* Task handle to keep track of created task */\n 1); /* pin task to core 0 */\n\n // Sound task is currently disabled. Kept here for reference\n // (use #if 0 / #endif instead of /* */ so the inner block\n // comments don't terminate the outer one).\n #if 0\n xTaskCreatePinnedToCore(\n vSoundTask, // Task function.\n \"Sound\", // name of task.\n 10000, // Stack size of task\n NULL, // parameter of the task\n 10, // priority of the task\n &sensorHandle, // Task handle to keep track of created task\n 1); // pin task to core 0\n #endif\n\n Serial.println(\"Finalizando MAIN\");\n}\n\nvoid loop()\n{\n // vUpdateFaceTask();\n}\n" }, + { name: "esp32-eyes.ino", content: "#include \n#include \n#include \n#include \n\n#include \"Face.h\"\n#include \"Weather.h\"\n#include \"Common.h\"\n#include \"SensorDriver.h\"\n#include \"ServoMotorDriver.h\"\n// GLOBALS\nFace *face;\n\nunsigned long lastMovementTime = 0; // Time of the last detected movement\nconst unsigned long WEATHER_TIMEOUT = 600000; // 10 minutes in milliseconds\nconst unsigned long SLEEP_TIMEOUT = 3600000; // 1 hour in milliseconds\n\nint progress = 0;\n\n// Flags that drive the state machine\nbool weatherTimeoutReached = false;\nbool sleepTimeoutReached = false;\n\nunsigned long lastTriggerTime = 0;\nbool lastStateMovement = false;\nbool movementDetected = false;\n\nRobotState lastInsertedState = SLEEP;\n// Current state\nRobotState currentState = SLEEP;\n\nTaskHandle_t faceHandle;\nServo ServoRight;\nServo ServoLeft;\n\nTaskHandle_t servoHandle;\n// GLOBALS\n\neEmotions previousEmotion;\n\nTaskHandle_t soundHandle;\n\nTaskHandle_t sensorHandle;\n\nvoid vUpdateFaceTask(void *pvParameters)\n{\n while (1)\n {\n\n face->RandomBehavior = false;\n face->RandomBlink = true;\n face->RandomLook = true;\n\n if (currentState == NORMAL)\n {\n Serial.println(\"STATE Normal 224****************************************\");\n face->RandomBehavior = true;\n }\n else if (currentState == SOUND)\n {\n // Actions for the NERVOUS state\n eEmotions cEmotion = face->Behavior.CurrentEmotion;\n if (cEmotion != eEmotions::Surprised)\n {\n face->Expression.GoTo_Surprised();\n }\n Serial.println(\"STATE = SOUND ..... *************************************************\");\n }\n else if (currentState == MOVE)\n {\n // Actions for the MOVE state\n Serial.println(\"STATE = MOVE ...... *************************************************\");\n eEmotions cEmotion = face->Behavior.CurrentEmotion;\n if (cEmotion != eEmotions::Focused)\n {\n face->Expression.GoTo_Focused();\n }\n }\n else if (currentState == SLEEP)\n {\n Serial.println(\"STATE = SLEEP ..... **************************************************\");\n face->RandomBehavior = false;\n face->RandomBlink = false;\n face->RandomLook = false;\n Serial.println(face->Behavior.CurrentEmotion);\n Serial.println(eEmotions::Sleepy);\n if (face->Behavior.CurrentEmotion != eEmotions::Sleepy)\n {\n face->Behavior.CurrentEmotion = eEmotions::Sleepy;\n face->Expression.GoTo_Sleepy();\n Serial.println(\"GoTo_Sleepy\");\n }\n else\n {\n Serial.println(\"Different ******------------------------------------------------------------------------------************\");\n face->Update();\n }\n }\n else if (currentState == WEATHER)\n {\n\n Serial.println(\"STATE = Weather ..... ************************************************\");\n Serial.println(analogRead(LDR_PIN));\n face->Expression.GoTo_Normal();\n updateWEATHER();\n vTaskDelay(pdMS_TO_TICKS(100));\n continue;\n }\n else if (currentState == START)\n {\n currentState = SLEEP;\n }\n\n face->Update();\n vTaskDelay(pdMS_TO_TICKS(100));\n }\n}\n\nvoid setup(void)\n{\n // Create a serial connection\n Serial.begin(115200);\n Serial.println(\"Starting.................\");\n ServoRight.write(0);\n ServoRight.write(90);\n\n pinMode(PIR_PIN, INPUT);\n // pinMode(SOUND_PIN, INPUT);\n pinMode(LDR_PIN, INPUT);\n // insertState(START);\n currentState = SLEEP;\n lastStateMovement = digitalRead(PIR_PIN);\n // Configure input pins\n pinMode(SOUND_PIN, OUTPUT);\n randomSeed(analogRead(0));\n\n // StarWarsPlay();\n // Create a new face\n\n face = new Face(/* screenWidth = */ 128, /* screenHeight = */ 64, /* eyeSize = */ 40);\n\n initDht();\n\n delay(3000);\n // Assign the current expression\n face->Expression.GoTo_Sleepy();\n Serial.println(\"GoTo_Sleepy\");\n\n // Assign a weight to each emotion\n face->Behavior.SetEmotion(eEmotions::Normal, 1.0);\n face->Behavior.SetEmotion(eEmotions::Angry, 1.0);\n face->Behavior.SetEmotion(eEmotions::Glee, 1.0);\n face->Behavior.SetEmotion(eEmotions::Happy, 1.0);\n face->Behavior.SetEmotion(eEmotions::Sad, 1.0);\n face->Behavior.SetEmotion(eEmotions::Worried, 1.0);\n face->Behavior.SetEmotion(eEmotions::Focused, 1.0);\n face->Behavior.SetEmotion(eEmotions::Annoyed, 1.0);\n face->Behavior.SetEmotion(eEmotions::Surprised, 1.0);\n face->Behavior.SetEmotion(eEmotions::Skeptic, 1.0);\n face->Behavior.SetEmotion(eEmotions::Frustrated, 1.0);\n face->Behavior.SetEmotion(eEmotions::Unimpressed, 1.0);\n face->Behavior.SetEmotion(eEmotions::Sleepy, 1.0);\n face->Behavior.SetEmotion(eEmotions::Suspicious, 1.0);\n face->Behavior.SetEmotion(eEmotions::Squint, 1.0);\n face->Behavior.SetEmotion(eEmotions::Furious, 1.0);\n face->Behavior.SetEmotion(eEmotions::Scared, 1.0);\n face->Behavior.SetEmotion(eEmotions::Awe, 1.0);\n\n face->RandomBehavior = false;\n\n // Automatically blink\n face->RandomBlink = true;\n // Set blink rate\n face->Blink.Timer.SetIntervalMillis(8000);\n face->Behavior.Timer.SetIntervalMillis(15000);\n\n // Automatically choose a new random direction to look\n face->RandomLook = true;\n ServoRight.attach(SERVO1_Right);\n ServoLeft.attach(SERVO2_Left);\n ServoLeft.write(0);\n ServoRight.write(170);\n\n delay(3000);\n\n xTaskCreatePinnedToCore(\n vUpdateFaceTask, /* Task function. */\n \"Update face\", /* name of task. */\n 10000, /* Stack size of task */\n NULL, /* parameter of the task */\n 1, /* priority of the task */\n &faceHandle, /* Task handle to keep track of created task */\n 0); /* pin task to core 0 */\n\n xTaskCreatePinnedToCore(\n vMoveServoTask, /* Task function. */\n \"Update Servo\", /* name of task. */\n 10000, /* Stack size of task */\n face, /* parameter of the task */\n 5, /* priority of the task */\n &servoHandle, /* Task handle to keep track of created task */\n 1); /* pin task to core 0 */\n\n xTaskCreatePinnedToCore(\n vReadSensorTask, /* Task function. */\n \"Read Sensor\", /* name of task. */\n 10000, /* Stack size of task */\n NULL, /* parameter of the task */\n 10, /* priority of the task */\n &sensorHandle, /* Task handle to keep track of created task */\n 1); /* pin task to core 0 */\n\n // Sound task is currently disabled. Kept here for reference\n // (use #if 0 / #endif instead of /* */ so the inner block\n // comments don't terminate the outer one).\n #if 0\n xTaskCreatePinnedToCore(\n vSoundTask, // Task function.\n \"Sound\", // name of task.\n 10000, // Stack size of task\n NULL, // parameter of the task\n 10, // priority of the task\n &sensorHandle, // Task handle to keep track of created task\n 1); // pin task to core 0\n #endif\n\n Serial.println(\"Finishing MAIN\");\n}\n\nvoid loop()\n{\n // vUpdateFaceTask();\n}\n" }, { name: "Animations.h", content: "/***************************************************\nCopyright (c) 2023 Alastair Aitchison, Playful Technology, (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n\nclass IAnimation {\npublic:\n\tvirtual float GetValue() = 0;\n\tvirtual float GetValue(unsigned long overWriteMillis) = 0;\n\tvirtual unsigned long GetElapsed() = 0;\n\nprivate:\n\tvirtual float Calculate(unsigned long elapsedMillis) = 0;\n};\n\nclass AnimationBase : IAnimation {\n public:\n\t AnimationBase(unsigned long interval) : Interval(interval), StarTime(millis()) {}\n\n\t unsigned long Interval;\n\t unsigned long StarTime;\n\n\t virtual void Restart() {\n\t\t StarTime = millis();\n\t }\n\t float GetValue() override final {\n\t\t return GetValue(GetElapsed());\n\t }\n\t float GetValue(unsigned long elapsedMillis) override final {\n\t\t return Calculate(elapsedMillis);\n\t }\n\t unsigned long GetElapsed() override {\n\t\t return static_cast (millis() - StarTime);\n\t }\n\n protected:\n\t float Calculate(unsigned long elapsedMillis) override { return 0.0; }\n};\n\nclass DeltaAnimation : public AnimationBase {\n public:\n\t unsigned long StarTime;\n\t DeltaAnimation(unsigned long interval) : AnimationBase(interval) {};\n\t float Calculate(unsigned long elapsedMillis) {\n\t\t if (elapsedMillis < Interval)\t{\n\t\t\t return 0.0f;\n\t\t }\n\t\t else {\n\t\t\t return 1.0f;\n\t\t }\n\t };\n};\n\n\nclass StepAnimation : public AnimationBase {\n public:\n\t unsigned long Interval;\n\t unsigned long StarTime;\n\t bool IsActive = true;\n \tStepAnimation(unsigned long interval) : AnimationBase(interval) {};\n\n\t float Calculate(unsigned long elapsedMillis) {\n\t\t if (elapsedMillis < Interval)\t{\n\t\t\t return 0.0f;\n\t\t }\n\t\t return 1.0f;\n\t };\n};\n\n\nclass RampAnimation : public AnimationBase {\npublic:\n\n\tunsigned long StarTime;\n\tbool IsActive = true;\n\n\tRampAnimation(unsigned long interval) : AnimationBase(interval) {};\n\n\tfloat Calculate(unsigned long elapsedMillis) {\n\t\tif (elapsedMillis < Interval)\t{\n\t\t\treturn static_cast(elapsedMillis) / Interval;\n\t\t}\n\t\treturn 1.0f;\n\t};\n};\n\nclass TriangleAnimation : public AnimationBase {\npublic:\n\n\tTriangleAnimation(unsigned long interval) : AnimationBase(interval) {\n\t\t_t0 = interval / 2;\n\t\t_t1 = interval - _t0;\n\t}\n\tTriangleAnimation(unsigned long t0, unsigned long t1) : AnimationBase(t0 + t1) {\n\t\t_t0 = t0;\n\t\t_t1 = t1;\n\t};\n\tfloat Calculate(unsigned long elapsedMillis) {\n\t\tif (elapsedMillis % Interval < _t0) {\n\t\t\treturn static_cast(elapsedMillis % Interval) / _t0;\n\t\t}\n\t\treturn 1.0f - (static_cast(elapsedMillis % Interval) - _t0) / _t1;\n\t};\n\tunsigned long _t0;\n\tunsigned long _t1;\n};\n\n\nclass TrapeziumAnimation : public AnimationBase {\npublic:\n\tTrapeziumAnimation(unsigned long t) : AnimationBase(t) {\n\t\t_t0 = t / 3;\n\t\t_t1 = _t0;\n\t\t_t2 = t - _t0 - _t1;\n\t};\n\tTrapeziumAnimation(unsigned long t0, unsigned long t1, unsigned long t2) : AnimationBase(t0 + t1 + t2) {\n\t\t_t0 = t0;\n\t\t_t1 = t1;\n\t\t_t2 = t2;\n\t}; \n\tfloat Calculate(unsigned long elapsedMillis) override {\n\t\tif (elapsedMillis > Interval) return 0.0;\n\t\tif (elapsedMillis < _t0) {\n\t\t\treturn static_cast(elapsedMillis) / _t0;\n\t\t}\n\t\telse if (elapsedMillis < _t0 + _t1) {\n\t\t\treturn 1.0f;\n\t\t}\n\t\telse {\n\t\t\treturn 1.0f - (static_cast(elapsedMillis) - _t1 - _t0) / _t2;\n\t\t}\n\t};\n\n\tunsigned long _t0;\n\tunsigned long _t1;\n\tunsigned long _t2;\n};\n\n\nclass TrapeziumPulseAnimation : public AnimationBase {\npublic:\n\tTrapeziumPulseAnimation(unsigned long t) : AnimationBase(t) {\n\t\t_t0 = 0;\n\t\t_t1 = t / 3;\n\t\t_t2 = t - _t0 - _t0;\n\t\t_t3 = _t1;\n\t\t_t4 = 0;\n\t};\n\n\tTrapeziumPulseAnimation(unsigned long t0, unsigned long t1, unsigned long t2) : AnimationBase(t0 + t1 + t2) {\n\t\t_t0 = 0;\n\t\t_t1 = t0;\n\t\t_t2 = t1;\n\t\t_t3 = t2;\n\t\t_t4 = 0;\n\t};\n\n\tTrapeziumPulseAnimation(unsigned long t0, unsigned long t1, unsigned long t2, unsigned long t3, unsigned long t4) : AnimationBase(t0 + t1 + t2 + t3 + t4) {\n\t\t_t0 = t0;\n\t\t_t1 = t1;\n\t\t_t2 = t2;\n\t\t_t3 = t3;\n\t\t_t4 = t4;\n\t};\n\n\tfloat Calculate(unsigned long elapsedMillis) override {\n\t\tunsigned long elapsed = elapsedMillis % Interval;\n\n\t\tif (elapsed < _t0) {\n\t\t\treturn 0.0;\n\t\t}\n\t\tif (elapsed < _t0 + _t1) {\n\t\t\treturn static_cast(elapsed - _t0) / _t1;\n\t\t}\n\t\telse if (elapsed < _t0 + _t1 + _t2)\t{\n\t\t\treturn 1.0f;\n\t\t}\n\t\telse if (elapsed < _t0 + _t1 + _t2 + _t3)\t{\n\t\t\treturn 1.0f - (static_cast(elapsed) - _t2 - _t1 - _t0) / _t3;\n\t\t}\n\t\treturn 0.0;\n\t};\n\n\tvoid SetInterval(uint16_t t) {\n\t\t_t0 = 0;\n\t\t_t1 = t / 3;\n\t\t_t2 = t - _t0 - _t0;\n\t\t_t3 = _t1;\n\t\t_t4 = 0;\n\t\tInterval = _t0 + _t1 + _t2 + _t3 + _t4;\n\t}\n\n\tvoid SetTriangle(uint16_t t, uint16_t delay) {\n\t\t_t0 = 0;\n\t\t_t1 = t / 2;\n\t\t_t2 = 0;\n\t\t_t3 = _t1;\n\t\t_t4 = delay;\n\t\tInterval = _t0 + _t1 + _t2 + _t3 + _t4;\n\t}\n\n\tvoid SetTriangleCuadrature(uint16_t t, uint16_t delay) {\n\t\t_t0 = delay;\n\t\t_t1 = t / 2;\n\t\t_t2 = 0;\n\t\t_t3 = _t1;\n\t\t_t4 = 0;\n\t\tInterval = _t0 + _t1 + _t2 + _t3 + _t4;\n\t}\n\t\n\tvoid SetPulse(uint16_t t, uint16_t delay) {\n\t\t_t0 = 0;\n\t\t_t1 = t / 3;\n\t\t_t2 = t - _t0 - _t0;\n\t\t_t3 = _t1;\n\t\t_t4 = delay;\n\t\tInterval = _t0 + _t1 + _t2 + _t3 + _t4;\n\t}\n\n\tvoid SetPulseCuadrature(uint16_t t, uint16_t delay) {\n\t\t_t0 = delay;\n\t\t_t1 = t / 3;\n\t\t_t2 = t - _t0 - _t0;\n\t\t_t3 = _t1;\n\t\t_t4 = 0;\n\t\tInterval = _t0 + _t1 + _t2 + _t3 + _t4;\n\t}\n\n\tvoid SetInterval(uint16_t t0, uint16_t t1, uint16_t t2, uint16_t t3, uint16_t t4) {\n\t\t_t0 = t0;\n\t\t_t1 = t1;\n\t\t_t2 = t2;\n\t\t_t3 = t3;\n\t\t_t4 = t4;\n\t\tInterval = _t0 + _t1 + _t2 + _t3 + _t4;\n\t}\n\n\tunsigned long _t0;\n\tunsigned long _t1;\n\tunsigned long _t2;\n\tunsigned long _t3;\n\tunsigned long _t4;\n};\n\n#endif" }, { name: "AsyncTimer.h", content: "/***************************************************\nCopyright (c) 2023 Alastair Aitchison, Playful Technology, (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n\ntypedef void(*AsyncTimerCallback)();\n\nclass AsyncTimer {\n public:\n\tAsyncTimer(unsigned long millisInterval);\n\tAsyncTimer(unsigned long millisInterval, AsyncTimerCallback OnFinish);\n\n\tvoid Start();\n\tvoid Reset();\n\tvoid Stop();\n\tbool Update();\n\n\tvoid SetIntervalMillis(unsigned long interval);\n\t\n\tunsigned long GetStartTime();\n\tunsigned long GetElapsedTime();\n\tunsigned long GetRemainingTime();\n\n\tbool IsActive() const;\n\tbool IsExpired() const;\n\t\n\tunsigned long Interval;\n\t\n\tAsyncTimerCallback OnFinish;\n\nprivate:\n\tbool _isActive;\n\tbool _isExpired;\n\tunsigned long _startTime;\n};\n#endif" }, { name: "BlinkAssistant.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n#include \"Animations.h\"\n#include \"AsyncTimer.h\"\n\nclass Face;\n\nclass BlinkAssistant {\n protected:\n\tFace& _face;\n\n public:\n\tBlinkAssistant(Face& face);\n\n\tAsyncTimer Timer;\n\n\tvoid Update();\n\tvoid Blink();\n};\n\n#endif" }, - { name: "Common.h", content: "#ifndef COMMON_h\n#define COMMON_h\n#include \n#include \nextern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2;\n\n#define DHTPIN 15 // DHT11 data pin\n#define DHTTYPE DHT11 // DHT sensor type (switch to DHT22 if you need to)\n\n#define SERVO1_Derecha 12\n#define SERVO2_Izquierda 13\n#define PIR_PIN 4\n#define SOUND_PIN 2\n#define LDR_PIN 34\n\n\n enum RobotState\n{\n INICIO,\n NORMAL,\n SOUND,\n MOVE,\n SLEEP,\n WEATHER\n};\n\nextern TaskHandle_t faceHandle;\nextern Servo ServoDerecha;\nextern Servo ServoIzquierda;\n\nextern TaskHandle_t servoHandle;\n\n\n\nextern TaskHandle_t soundHandle;\n\nextern TaskHandle_t sensorHandle;\n\n#define speakerPin 2\n\n#define MAX_STATES 100 // Maximum number of states in the queue\n\n\nextern RobotState stateQueue[MAX_STATES]; // Cola de estados\n//extern int queueFront = 0; // Queue front\n//extern int queueRear = -1; // Queue rear\n//extern int queueItemCount = 0; // Number of items in the queue\n\nextern unsigned long lastMovementTime; // Time of the last detected movement\nextern const unsigned long WEATHER_TIMEOUT; // 10 minutos en milisegundos\nextern const unsigned long SLEEP_TIMEOUT ; // 1 hora en milisegundos\n\nextern unsigned long lastTriggerTime;\nextern bool lastStateMovement;\nextern bool movementDetected;\n\n// Flags that drive the state machine\nextern bool weatherTimeoutReached;\nextern bool sleepTimeoutReached ;\n\n// Push a state onto the queue\nextern RobotState lastInsertedState; // Last state pushed\n// Estado actual\nextern RobotState currentState; // Last state pushed\n\nextern bool isLightOn();\nextern bool isMovementDetected();\n\n\n#endif" }, + { name: "Common.h", content: "#ifndef COMMON_h\n#define COMMON_h\n#include \n#include \nextern U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2;\n\n#define DHTPIN 15 // DHT11 data pin\n#define DHTTYPE DHT11 // DHT sensor type (switch to DHT22 if you need to)\n\n#define SERVO1_Right 12\n#define SERVO2_Left 13\n#define PIR_PIN 4\n#define SOUND_PIN 2\n#define LDR_PIN 34\n\n\n enum RobotState\n{\n START,\n NORMAL,\n SOUND,\n MOVE,\n SLEEP,\n WEATHER\n};\n\nextern TaskHandle_t faceHandle;\nextern Servo ServoRight;\nextern Servo ServoLeft;\n\nextern TaskHandle_t servoHandle;\n\n\n\nextern TaskHandle_t soundHandle;\n\nextern TaskHandle_t sensorHandle;\n\n#define speakerPin 2\n\n#define MAX_STATES 100 // Maximum number of states in the queue\n\n\nextern RobotState stateQueue[MAX_STATES]; // State queue\n//extern int queueFront = 0; // Queue front\n//extern int queueRear = -1; // Queue rear\n//extern int queueItemCount = 0; // Number of items in the queue\n\nextern unsigned long lastMovementTime; // Time of the last detected movement\nextern const unsigned long WEATHER_TIMEOUT; // 10 minutes in milliseconds\nextern const unsigned long SLEEP_TIMEOUT ; // 1 hour in milliseconds\n\nextern unsigned long lastTriggerTime;\nextern bool lastStateMovement;\nextern bool movementDetected;\n\n// Flags that drive the state machine\nextern bool weatherTimeoutReached;\nextern bool sleepTimeoutReached ;\n\n// Push a state onto the queue\nextern RobotState lastInsertedState; // Last state pushed\n// Current state\nextern RobotState currentState; // Last state pushed\n\nextern bool isLightOn();\nextern bool isMovementDetected();\n\n\n#endif" }, { name: "Eye.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n#include \"Common.h\"\n#include \"Animations.h\"\n#include \"EyeConfig.h\"\n#include \"EyeDrawer.h\"\n#include \"EyeTransition.h\"\n#include \"EyeTransformation.h\"\n#include \"EyeVariation.h\"\n#include \"EyeBlink.h\"\n#include \"EyeVariation.h\"\n\nclass Face;\n\nclass Eye {\n protected:\n Face& _face;\n\n void Update();\n void ChainOperators();\n\n public:\n Eye(Face& face);\n\n uint16_t CenterX;\n uint16_t CenterY;\n bool IsMirrored = false;\n\n EyeConfig Config;\n EyeConfig* FinalConfig;\n\n EyeTransition Transition;\n EyeTransformation Transformation;\n EyeVariation Variation1;\n EyeVariation Variation2;\n EyeBlink BlinkTransformation;\n\n void ApplyPreset(const EyeConfig preset);\n void TransitionTo(const EyeConfig preset);\n void Draw();\n};\n\n#endif" }, { name: "EyeBlink.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n#include \"Animations.h\"\n#include \"EyeConfig.h\"\n\nclass EyeBlink {\n protected:\n\npublic:\n\tEyeBlink();\n\n\tEyeConfig* Input;\n\tEyeConfig Output;\n\n\tTrapeziumAnimation Animation;\n\n\tint32_t BlinkWidth = 60;\n\tint32_t BlinkHeight = 2;\n\n\tvoid Update();\n\tvoid Apply(float t);\n};\n\n#endif" }, { name: "EyeConfig.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \nstruct EyeConfig\n{\n\tint16_t OffsetX;\n\tint16_t OffsetY;\n\n \tint16_t Height;\n\tint16_t Width;\n\n\tfloat Slope_Top;\n\tfloat Slope_Bottom;\n\n\tint16_t Radius_Top;\n\tint16_t Radius_Bottom;\n\n\tint16_t Inverse_Radius_Top;\n\tint16_t Inverse_Radius_Bottom;\n\n\tint16_t Inverse_Offset_Top;\n\tint16_t Inverse_Offset_Bottom;\n};\n\n#endif" }, @@ -99,8 +99,8 @@ export const robotDesktopExamples: ExampleProject[] = [ { name: "FaceBehavior.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n#include \"FaceEmotions.hpp\"\n#include \"AsyncTimer.h\"\n\nclass Face;\n\nclass FaceBehavior\n{\n protected:\n\tFace& _face;\n\n public:\n\tFaceBehavior(Face& face);\n\n\teEmotions CurrentEmotion;\n\n\tfloat Emotions[eEmotions::EMOTIONS_COUNT];\n\n\tAsyncTimer Timer;\n\n\tvoid SetEmotion(eEmotions emotion, float value);\n\tfloat GetEmotion(eEmotions emotion);\n\n\tvoid Clear();\n\tvoid Update();\n\teEmotions GetRandomEmotion();\n\n\tvoid GoToEmotion(eEmotions emotion);\n};\n\n#endif\n\n" }, { name: "FaceExpression.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n\nclass Face;\n\nclass FaceExpression {\n protected:\n Face& _face;\n\n public:\n FaceExpression(Face& face);\n\n void ClearVariations();\n\n void GoTo_Normal();\n void GoTo_Angry();\n void GoTo_Glee();\n void GoTo_Happy();\n void GoTo_Sad();\n void GoTo_Worried();\n void GoTo_Focused();\n void GoTo_Annoyed();\n void GoTo_Surprised();\n void GoTo_Skeptic();\n void GoTo_Frustrated();\n void GoTo_Unimpressed();\n void GoTo_Sleepy();\n void GoTo_Suspicious();\n void GoTo_Squint();\n void GoTo_Furious();\n void GoTo_Scared();\n void GoTo_Awe();\n};\n\n#endif" }, { name: "LookAssistant.h", content: "/***************************************************\nCopyright (c) 2020 Luis Llamas\n(www.luisllamas.es)\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or (at your option) any later version. \n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see \n#include \"EyeTransformation.h\"\n#include \"AsyncTimer.h\"\n\nclass Face;\n\nclass LookAssistant\n{\n protected:\n\tFace& _face;\n\n public:\n\tLookAssistant(Face& face);\n\n\tTransformation transformation;\n\n\tAsyncTimer Timer;\n\n\tvoid LookAt(float x, float y);\n\tvoid Update();\n};\n\n#endif\n\n" }, - { name: "SensorDriver.h", content: "#ifndef _SENSORDRIVER_h\n#define _SENSORDRIVER_h\n#include \"Common.h\"\n\nint minLuz = 10; // Negative start value means nothing has been read yet\nint maxLuz = 10;\nint umbralLuz = 0;\nunsigned long tiempoUltimaLectura = 0;\nconst unsigned long intervaloAjuste = 10000; // recompute the threshold every 20 seconds\n\nvoid ajustarUmbral() {\n umbralLuz = (minLuz + maxLuz) / 2;\n Serial.print(\"Nuevo umbral de luz calculado: \");\n Serial.println(umbralLuz);\n}\n\nbool isLightOn() {\n int luz = analogRead(LDR_PIN);\n if (luz < minLuz) minLuz = luz;\n if (luz > maxLuz) maxLuz = luz;\n ajustarUmbral(); \n bool hayLuz = (luz < umbralLuz); \n if (!hayLuz) {\n Serial.print(\"No hay Luz: \" );\n Serial.println(luz);\n } else {\n Serial.print(\"Hay Luz: \");\n Serial.println(luz);\n }\n return hayLuz;\n}\n\nbool isMovementDetected()\n{\n int currentStateMovement = digitalRead(PIR_PIN);\n\n if (currentStateMovement != lastStateMovement)\n {\n lastTriggerTime = millis(); // Update the time of the last state change\n lastStateMovement = currentStateMovement; // Update the last recorded state\n movementDetected = true; // A state change was detected\n }\n\n // Check whether less than 5 seconds have passed since the last state change\n if (movementDetected && millis() - lastTriggerTime < 3000)\n {\n Serial.println(\"Movement DETECTED........ 130\");\n return true; // Returns true if a state change happened within 5 seconds\n }\n\n // Check whether more than 5 seconds have passed since the last state change\n if (millis() - lastTriggerTime >= 3000)\n {\n movementDetected = false; // Clear the state-change flag\n }\n\n return false; // If no condition matches, return false\n}\n\nbool isSoundDetected()\n{\n int sonido = digitalRead(SOUND_PIN);\n if (sonido == HIGH)\n {\n Serial.println(\"Sound detected\");\n return true;\n }\n else\n {\n return false;\n }\n}\n\nvoid vReadSensorTask(void *pvParameters)\n{\n Serial.println(\"STARTING SENSOR READS\");\n int lightSignalCount = 0;\n unsigned long lastLightSignalTime = 0;\n bool isLightOnPreviously = false;\n\n while (1)\n {\n int STATE = currentState;\n\n if (isMovementDetected() && STATE == SLEEP)\n {\n // insertState(NORMAL);\n currentState = NORMAL;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>MOVEMENT DETECTED AND STATE=SLEEP 171\");\n lastMovementTime = millis(); // Update the time of the last detected movement\n sleepTimeoutReached = false; // Clear the sleep-timeout flag\n weatherTimeoutReached = false;\n }\n else if (isMovementDetected() && STATE == NORMAL)\n {\n // insertState(MOVE);\n currentState = MOVE;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>>MOVEMENT DETECTED AND STATE == NORMAL 179\");\n lastMovementTime = millis(); // Update the time of the last detected movement\n sleepTimeoutReached = false; // Clear the sleep-timeout flag\n weatherTimeoutReached = false;\n }\n else if (isMovementDetected() && STATE == WEATHER)\n {\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>>>> MOVEMENT DETECTED AND STATE == WEATHER 93\");\n lastMovementTime = millis(); // Update the time of the last detected movement\n sleepTimeoutReached = false; // Clear the sleep-timeout flag\n weatherTimeoutReached = false;\n currentState = NORMAL;\n }\n // Switch to the WEATHER state after 10 minutes with no movement\n if (millis() - lastMovementTime >= WEATHER_TIMEOUT && !weatherTimeoutReached)\n {\n // insertState(WEATHER);\n currentState = WEATHER;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>WEATHER despu\u00e9s 10 minutos sin movimiento\");\n weatherTimeoutReached = true; // Mark the WEATHER timeout as reached\n }\n\n // Switch to the SLEEP state after an hour with no movement\n if (millis() - lastMovementTime >= SLEEP_TIMEOUT && !sleepTimeoutReached)\n {\n // insertState(SLEEP);\n currentState = SLEEP;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>SLEEP despu\u00e9s de una hora sin movimiento\");\n sleepTimeoutReached = true; // Mark the SLEEP timeout as reached\n }\n\n if (STATE == MOVE && millis() - lastMovementTime >= 30000)\n {\n currentState = NORMAL;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>VOLVIENDO A NORMAL despu\u00e9s de 30 segundos en MOVE\");\n }\n\n // Switch to WEATHER if the light signal comes and goes 3 times\n if (!isLightOn())\n {\n // insertState(SLEEP);\n currentState = SLEEP;\n Serial.println(\"NO HAY LUZ --> SLEEP 160\");\n }\n\n if (isLightOn())\n {\n if (!isLightOnPreviously)\n {\n lightSignalCount++;\n isLightOnPreviously = true;\n Serial.println(\"Se\u00f1al de luz recibida\");\n }\n }\n else\n {\n isLightOnPreviously = false;\n }\n\n if (lightSignalCount >= 3)\n {\n currentState = WEATHER;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>> Cambiando a WEATHER despu\u00e9s de recibir y dejar de recibir se\u00f1al de luz 3 veces\");\n lightSignalCount = 0; // Reset the counter\n }\n\n vTaskDelay(pdMS_TO_TICKS(500)); // Wait before polling the sensors again\n }\n}\n\n#endif" }, - { name: "ServoMotorDriver.h", content: "\n#ifndef _SERVOMOTORDRIVER_h\n#define _SERVOMOTORDRIVER_h\n#include \"Common.h\"\n\n#include \"Face.h\"\n\nvoid moveServoWithPID(Servo servo, int fromAngle, int toAngle)\n{\n servo.write(fromAngle);\n vTaskDelay(pdMS_TO_TICKS(105));\n servo.write(toAngle);\n}\n\nvoid vMoveServoTask(void *pvParameters)\n{\n Face *face = (Face *)pvParameters; // Cast the generic pointer back to Face\n while (1)\n {\n Serial.println(\"DRIVER Motor\");\n Serial.println(face->Behavior.CurrentEmotion);\n if (currentState == MOVE || currentState == NORMAL)\n {\n switch (face->Behavior.CurrentEmotion)\n {\n\n case eEmotions::Angry:\n Serial.println(\"Angry Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(90);\n ServoIzquierda.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(90);\n ServoIzquierda.write(0);\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(90);\n ServoIzquierda.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(90);\n ServoIzquierda.write(0);\n break;\n\n case eEmotions::Happy:\n Serial.println(\"Happy Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(45);\n ServoIzquierda.write(170);\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(45);\n ServoIzquierda.write(170);\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(45);\n ServoIzquierda.write(170);\n break;\n\n case eEmotions::Surprised:\n Serial.println(\"Surprised Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(60);\n ServoIzquierda.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(60);\n ServoIzquierda.write(0);\n break;\n\n case eEmotions::Sad:\n Serial.println(\"Sad Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(90);\n ServoIzquierda.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(90);\n ServoIzquierda.write(0);\n break;\n\n case eEmotions::Worried:\n Serial.println(\"Worried Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(90);\n ServoIzquierda.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(90);\n ServoIzquierda.write(0);\n break;\n\n case eEmotions::Suspicious:\n Serial.println(\"Suspicious Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(60);\n ServoIzquierda.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(60);\n ServoIzquierda.write(0);\n break;\n\n case eEmotions::Furious:\n Serial.println(\"Furious Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(45);\n ServoIzquierda.write(170);\n break;\n\n case eEmotions::Scared:\n Serial.println(\"Scared Motor\");\n ServoDerecha.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoDerecha.write(60);\n ServoIzquierda.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoDerecha.write(60);\n ServoIzquierda.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoDerecha.write(60);\n ServoIzquierda.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoDerecha.write(60);\n ServoIzquierda.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoDerecha.write(45);\n ServoIzquierda.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoDerecha.write(60);\n ServoIzquierda.write(60);\n break;\n\n default:\n break;\n }\n }\n\n vTaskDelay(pdMS_TO_TICKS(13000));\n }\n}\n\n#endif" }, + { name: "SensorDriver.h", content: "#ifndef _SENSORDRIVER_h\n#define _SENSORDRIVER_h\n#include \"Common.h\"\n\nint minLight = 10; // Negative start value means nothing has been read yet\nint maxLight = 10;\nint lightThreshold = 0;\nunsigned long lastReadTime = 0;\nconst unsigned long adjustInterval = 10000; // recompute the threshold every 20 seconds\n\nvoid adjustThreshold() {\n lightThreshold = (minLight + maxLight) / 2;\n Serial.print(\"New light threshold computed: \");\n Serial.println(lightThreshold);\n}\n\nbool isLightOn() {\n int light = analogRead(LDR_PIN);\n if (light < minLight) minLight = light;\n if (light > maxLight) maxLight = light;\n adjustThreshold(); \n bool lightPresent = (light < lightThreshold); \n if (!lightPresent) {\n Serial.print(\"No light: \" );\n Serial.println(light);\n } else {\n Serial.print(\"Light present: \");\n Serial.println(light);\n }\n return lightPresent;\n}\n\nbool isMovementDetected()\n{\n int currentStateMovement = digitalRead(PIR_PIN);\n\n if (currentStateMovement != lastStateMovement)\n {\n lastTriggerTime = millis(); // Update the time of the last state change\n lastStateMovement = currentStateMovement; // Update the last recorded state\n movementDetected = true; // A state change was detected\n }\n\n // Check whether less than 5 seconds have passed since the last state change\n if (movementDetected && millis() - lastTriggerTime < 3000)\n {\n Serial.println(\"Movement DETECTED........ 130\");\n return true; // Returns true if a state change happened within 5 seconds\n }\n\n // Check whether more than 5 seconds have passed since the last state change\n if (millis() - lastTriggerTime >= 3000)\n {\n movementDetected = false; // Clear the state-change flag\n }\n\n return false; // If no condition matches, return false\n}\n\nbool isSoundDetected()\n{\n int sound = digitalRead(SOUND_PIN);\n if (sound == HIGH)\n {\n Serial.println(\"Sound detected\");\n return true;\n }\n else\n {\n return false;\n }\n}\n\nvoid vReadSensorTask(void *pvParameters)\n{\n Serial.println(\"STARTING SENSOR READS\");\n int lightSignalCount = 0;\n unsigned long lastLightSignalTime = 0;\n bool isLightOnPreviously = false;\n\n while (1)\n {\n int STATE = currentState;\n\n if (isMovementDetected() && STATE == SLEEP)\n {\n // insertState(NORMAL);\n currentState = NORMAL;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>MOVEMENT DETECTED AND STATE=SLEEP 171\");\n lastMovementTime = millis(); // Update the time of the last detected movement\n sleepTimeoutReached = false; // Clear the sleep-timeout flag\n weatherTimeoutReached = false;\n }\n else if (isMovementDetected() && STATE == NORMAL)\n {\n // insertState(MOVE);\n currentState = MOVE;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>>MOVEMENT DETECTED AND STATE == NORMAL 179\");\n lastMovementTime = millis(); // Update the time of the last detected movement\n sleepTimeoutReached = false; // Clear the sleep-timeout flag\n weatherTimeoutReached = false;\n }\n else if (isMovementDetected() && STATE == WEATHER)\n {\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>>>> MOVEMENT DETECTED AND STATE == WEATHER 93\");\n lastMovementTime = millis(); // Update the time of the last detected movement\n sleepTimeoutReached = false; // Clear the sleep-timeout flag\n weatherTimeoutReached = false;\n currentState = NORMAL;\n }\n // Switch to the WEATHER state after 10 minutes with no movement\n if (millis() - lastMovementTime >= WEATHER_TIMEOUT && !weatherTimeoutReached)\n {\n // insertState(WEATHER);\n currentState = WEATHER;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>WEATHER after 10 minutes without movement\");\n weatherTimeoutReached = true; // Mark the WEATHER timeout as reached\n }\n\n // Switch to the SLEEP state after an hour with no movement\n if (millis() - lastMovementTime >= SLEEP_TIMEOUT && !sleepTimeoutReached)\n {\n // insertState(SLEEP);\n currentState = SLEEP;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>SLEEP after an hour without movement\");\n sleepTimeoutReached = true; // Mark the SLEEP timeout as reached\n }\n\n if (STATE == MOVE && millis() - lastMovementTime >= 30000)\n {\n currentState = NORMAL;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>BACK TO NORMAL after 30 seconds in MOVE\");\n }\n\n // Switch to WEATHER if the light signal comes and goes 3 times\n if (!isLightOn())\n {\n // insertState(SLEEP);\n currentState = SLEEP;\n Serial.println(\"NO LIGHT --> SLEEP 160\");\n }\n\n if (isLightOn())\n {\n if (!isLightOnPreviously)\n {\n lightSignalCount++;\n isLightOnPreviously = true;\n Serial.println(\"Light signal received\");\n }\n }\n else\n {\n isLightOnPreviously = false;\n }\n\n if (lightSignalCount >= 3)\n {\n currentState = WEATHER;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>> Switching to WEATHER after the light signal came and went 3 times\");\n lightSignalCount = 0; // Reset the counter\n }\n\n vTaskDelay(pdMS_TO_TICKS(500)); // Wait before polling the sensors again\n }\n}\n\n#endif" }, + { name: "ServoMotorDriver.h", content: "\n#ifndef _SERVOMOTORDRIVER_h\n#define _SERVOMOTORDRIVER_h\n#include \"Common.h\"\n\n#include \"Face.h\"\n\nvoid moveServoWithPID(Servo servo, int fromAngle, int toAngle)\n{\n servo.write(fromAngle);\n vTaskDelay(pdMS_TO_TICKS(105));\n servo.write(toAngle);\n}\n\nvoid vMoveServoTask(void *pvParameters)\n{\n Face *face = (Face *)pvParameters; // Cast the generic pointer back to Face\n while (1)\n {\n Serial.println(\"DRIVER Motor\");\n Serial.println(face->Behavior.CurrentEmotion);\n if (currentState == MOVE || currentState == NORMAL)\n {\n switch (face->Behavior.CurrentEmotion)\n {\n\n case eEmotions::Angry:\n Serial.println(\"Angry Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(90);\n ServoLeft.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(90);\n ServoLeft.write(0);\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(90);\n ServoLeft.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(90);\n ServoLeft.write(0);\n break;\n\n case eEmotions::Happy:\n Serial.println(\"Happy Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(45);\n ServoLeft.write(170);\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(45);\n ServoLeft.write(170);\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(45);\n ServoLeft.write(170);\n break;\n\n case eEmotions::Surprised:\n Serial.println(\"Surprised Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(60);\n ServoLeft.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(60);\n ServoLeft.write(0);\n break;\n\n case eEmotions::Sad:\n Serial.println(\"Sad Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(90);\n ServoLeft.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(90);\n ServoLeft.write(0);\n break;\n\n case eEmotions::Worried:\n Serial.println(\"Worried Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(90);\n ServoLeft.write(90);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(90);\n ServoLeft.write(0);\n break;\n\n case eEmotions::Suspicious:\n Serial.println(\"Suspicious Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(60);\n ServoLeft.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(60);\n ServoLeft.write(0);\n break;\n\n case eEmotions::Furious:\n Serial.println(\"Furious Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(45);\n ServoLeft.write(170);\n break;\n\n case eEmotions::Scared:\n Serial.println(\"Scared Motor\");\n ServoRight.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoRight.write(60);\n ServoLeft.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(1000));\n ServoRight.write(60);\n ServoLeft.write(0);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoRight.write(60);\n ServoLeft.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoRight.write(60);\n ServoLeft.write(60);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoRight.write(45);\n ServoLeft.write(45);\n vTaskDelay(pdMS_TO_TICKS(505));\n\n ServoRight.write(60);\n ServoLeft.write(60);\n break;\n\n default:\n break;\n }\n }\n\n vTaskDelay(pdMS_TO_TICKS(13000));\n }\n}\n\n#endif" }, { name: "Watchdog.h", content: "#ifndef WATCHDOG_H\n#define WATCHDOG_H\n\n\n#include // Pull in the watchdog library\n\nvoid feedWatchdog() {\n esp_task_wdt_reset();\n}\n\n#endif" }, { name: "Weather.h", content: "#ifndef _WEATHER_h\n#define _WEATHER_h\n\n#include \n\n#define DHTPIN 15 // DHT11 data pin\n#define DHTTYPE DHT11 // DHT sensor type (switch to DHT22 if you need to)\n#define SUN 0\n#define SUN_CLOUD 1\n#define CLOUD 2\n#define RAIN 3\n#define THUNDER 4\nDHT dht(DHTPIN, DHTTYPE);\n\nvoid initDht()\n{\n dht.begin();\n}\n\n\n\nvoid drawWeatherSymbol(u8g2_uint_t x, u8g2_uint_t y, uint8_t symbol)\n{\n // fonts used:\n // u8g2_font_open_iconic_embedded_6x_t\n // u8g2_font_open_iconic_weather_6x_t\n // encoding values, see: https://github.com/olikraus/u8g2/wiki/fntgrpiconic\n\n switch (symbol)\n {\n case SUN:\n u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);\n u8g2.drawGlyph(x, y, 69);\n break;\n case SUN_CLOUD:\n u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);\n u8g2.drawGlyph(x, y, 65);\n break;\n case CLOUD:\n u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);\n u8g2.drawGlyph(x, y, 64);\n break;\n case RAIN:\n u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);\n u8g2.drawGlyph(x, y, 67);\n break;\n case THUNDER:\n u8g2.setFont(u8g2_font_open_iconic_embedded_6x_t);\n u8g2.drawGlyph(x, y, 67);\n break;\n }\n}\nvoid drawWeather(uint8_t symbol, int degree)\n{\n drawWeatherSymbol(0, 48, symbol);\n u8g2.setFont(u8g2_font_logisoso32_tf);\n u8g2.setCursor(48 + 3, 42);\n u8g2.print(degree);\n u8g2.print(\" C\"); // requires enableUTF8Print()\n \n}\n/*\n Draw a string with specified pixel offset.\n The offset can be negative.\n Limitation: The monochrome font with 8 pixel per glyph\n*/\nvoid drawScrollString(int16_t offset, const char *s)\n{\n static char buf[36]; // should for screen with up to 256 pixel width\n size_t len;\n size_t char_offset = 0;\n u8g2_uint_t dx = 0;\n size_t visible = 0;\n len = strlen(s);\n if (offset < 0)\n {\n char_offset = (-offset) / 8;\n dx = offset + char_offset * 8;\n if (char_offset >= u8g2.getDisplayWidth() / 8)\n return;\n visible = u8g2.getDisplayWidth() / 8 - char_offset + 1;\n strncpy(buf, s, visible);\n buf[visible] = '\\0';\n u8g2.setFont(u8g2_font_8x13_mf);\n u8g2.drawStr(char_offset * 8 - dx, 62, buf);\n }\n else\n {\n char_offset = offset / 8;\n if (char_offset >= len)\n return; // nothing visible\n dx = offset - char_offset * 8;\n visible = len - char_offset;\n if (visible > u8g2.getDisplayWidth() / 8 + 1)\n visible = u8g2.getDisplayWidth() / 8 + 1;\n strncpy(buf, s + char_offset, visible);\n buf[visible] = '\\0';\n u8g2.setFont(u8g2_font_8x13_mf);\n u8g2.drawStr(-dx, 62, buf);\n }\n}\nvoid draw(const char *s, uint8_t symbol, int degree)\n{\n int16_t offset = -(int16_t)u8g2.getDisplayWidth();\n int16_t len = strlen(s);\n for (;;)\n {\n u8g2.firstPage();\n do\n {\n drawWeather(symbol, degree);\n drawScrollString(offset, s);\n } while (u8g2.nextPage());\n delay(20);\n offset += 2;\n if (offset > len * 8 + 1)\n break;\n }\n}\n\n\nvoid updateWEATHER() {\n float humidity = dht.readHumidity();\n float temperature = dht.readTemperature();\n\n char scrollText[15];\n sprintf(scrollText, \"Humidity:%3d%%\",(int)humidity);\n\n if (temperature >= 25 && humidity >= 70) {\n draw(scrollText, THUNDER,temperature);\n } else if (temperature >= 20 && humidity >= 60) {\n draw(scrollText, RAIN,temperature);\n } else if (temperature >= 15 && humidity >= 50) {\n draw(scrollText, RAIN, temperature);\n } else if (temperature >= 10 && humidity >= 40) {\n draw(scrollText, SUN_CLOUD,temperature);\n } else if (temperature < 10 && humidity < 40) {\n draw(scrollText, CLOUD, temperature);\n } else {\n draw(scrollText, SUN, temperature);\n }\n}\n\n#endif\n" }, { name: "sound.h", content: "#ifndef _SOUND_h\n#define _SOUND_h\n\n/***************************************************\n Project R2D2 Sound Generator\n\n To all fans of StarWars and Arduino!\n\n Written by Marcelo Larios\n\n BSD license, all text above must be included in any redistribution\n\n Participated in the Instructable Arduino Contest 2019\n https://www.instructables.com/R2D2-Sound-Generator/\n****************************************************/\n\n\n#define speakerPin 2\nint freq = 2000;\nint channel = 0;\nint resolution = 8;\n\n\n#define C0 16.35\n#define Db0 17.32\n#define D0 18.35\n#define Eb0 19.45\n#define E0 20.60\n#define F0 21.83\n#define Gb0 23.12\n#define G0 24.50\n#define Ab0 25.96\n#define LA0 27.50\n#define Bb0 29.14\n#define B0 30.87\n#define C1 32.70\n#define Db1 34.65\n#define D1 36.71\n#define Eb1 38.89\n#define E1 41.20\n#define F1 43.65\n#define Gb1 46.25\n#define G1 49.00\n#define Ab1 51.91\n#define LA1 55.00\n#define Bb1 58.27\n#define B1 61.74\n#define C2 65.41\n#define Db2 69.30\n#define D2 73.42\n#define Eb2 77.78\n#define E2 82.41\n#define F2 87.31\n#define Gb2 92.50\n#define G2 98.00\n#define Ab2 103.83\n#define LA2 110.00\n#define Bb2 116.54\n#define B2 123.47\n#define C3 130.81\n#define Db3 138.59\n#define D3 146.83\n#define Eb3 155.56\n#define E3 164.81\n#define F3 174.61\n#define Gb3 185.00\n#define G3 196.00\n#define Ab3 207.65\n#define LA3 220.00\n#define Bb3 233.08\n#define B3 246.94\n#define C4 261.63\n#define Db4 277.18\n#define D4 293.66\n#define Eb4 311.13\n#define E4 329.63\n#define F4 349.23\n#define Gb4 369.99\n#define G4 392.00\n#define Ab4 415.30\n#define LA4 440.00\n#define Bb4 466.16\n#define B4 493.88\n#define C5 523.25\n#define Db5 554.37\n#define D5 587.33\n#define Eb5 622.25\n#define E5 659.26\n#define F5 698.46\n#define Gb5 739.99\n#define G5 783.99\n#define Ab5 830.61\n#define LA5 880.00\n#define Bb5 932.33\n#define B5 987.77\n#define C6 1046.50\n#define Db6 1108.73\n#define D6 1174.66\n#define Eb6 1244.51\n#define E6 1318.51\n#define F6 1396.91\n#define Gb6 1479.98\n#define G6 1567.98\n#define Ab6 1661.22\n#define LA6 1760.00\n#define Bb6 1864.66\n#define B6 1975.53\n#define C7 2093.00\n#define Db7 2217.46\n#define D7 2349.32\n#define Eb7 2489.02\n#define E7 2637.02\n#define F7 2793.83\n#define Gb7 2959.96\n#define G7 3135.96\n#define Ab7 3322.44\n#define LA7 3520.01\n#define Bb7 3729.31\n#define B7 3951.07\n#define C8 4186.01\n#define Db8 4434.92\n#define D8 4698.64\n#define Eb8 4978.03\n// DURATION OF THE NOTES \n#define BPM 120 // you can change this value changing all the others\n// I think tecnically BPM supposed to be 104, but original 120\n// from instructable sounds good. 180 sounds speedy, 240 sounds mario, 300 sounds\n// middle eastern, 400 middle eastern techno pop?\n#define H 2*Q //half 2/4\n#define Q 60000/BPM //quarter 1/4 \n#define E Q/2 //eighth 1/8\n#define S Q/4 // sixteenth 1/16\n#define W 4*Q // whole 4/4\n\n\n\nvoid phrase1()\n{\n int k = random(1000, 2000);\n for (int i = 0; i <= random(100, 2000); i++)\n {\n tone(speakerPin, k + (-i * 2));\n vTaskDelay(pdMS_TO_TICKS((random(.9, 2))));\n }\n for (int i = 0; i <= random(100, 1000); i++)\n {\n tone(speakerPin, k + (i * 10));\n vTaskDelay(pdMS_TO_TICKS((random(.9, 2))));\n }\n}\n\nvoid phrase2()\n{\n\n int k = random(1000, 2000);\n for (int i = 0; i <= random(100, 2000); i++)\n {\n tone(speakerPin, k + (i * 2));\n vTaskDelay(pdMS_TO_TICKS((random(.9, 2))));\n }\n for (int i = 0; i <= random(100, 1000); i++)\n {\n tone(speakerPin, k + (-i * 10));\n vTaskDelay(pdMS_TO_TICKS((random(.9, 2))));\n }\n}\n\nvoid playerTone()\n{\n int K = 2000;\n switch (random(1, 7))\n {\n case 1:\n phrase1();\n break;\n case 2:\n phrase2();\n break;\n case 3:\n phrase1();\n phrase2();\n break;\n case 4:\n phrase1();\n phrase2();\n phrase1();\n break;\n case 5:\n phrase1();\n phrase2();\n phrase1();\n phrase2();\n phrase1();\n break;\n case 6:\n phrase2();\n phrase1();\n phrase2();\n break;\n }\n for (int i = 0; i <= random(3, 9); i++)\n {\n tone(speakerPin, K + random(-1700, 2000));\n vTaskDelay(pdMS_TO_TICKS((random(70, 170))));\n noTone(speakerPin);\n vTaskDelay(pdMS_TO_TICKS((random(0, 30))));\n }\n noTone(speakerPin);\n vTaskDelay(pdMS_TO_TICKS((random(2000, 4000))));\n}\n\n\n\nvoid mytone(int freq, int duration) {\n ledcWriteTone(channel, freq);\n vTaskDelay(pdMS_TO_TICKS((duration)));\n ledcWriteTone(channel, 0);\n}\n \nvoid StarWars() { \n ledcSetup(channel, freq, resolution);\n ledcAttachPin(speakerPin, channel);\n }\n \nvoid StarWarsPlay() {\n //mytone(note, duration)\n mytone(LA3,Q); \n mytone(LA3,Q);\n mytone(LA3,Q);\n mytone(F3,E+S);\n mytone(C4,S);\n \n mytone(LA3,Q);\n mytone(F3,E+S);\n mytone(C4,S);\n mytone(LA3,H);\n \n mytone(E4,Q); \n mytone(E4,Q);\n mytone(E4,Q);\n mytone(F4,E+S);\n mytone(C4,S);\n \n mytone(Ab3,Q);\n mytone(F3,E+S);\n mytone(C4,S);\n mytone(LA3,H);\n \n mytone(LA4,Q);\n mytone(LA3,E+S);\n mytone(LA3,S);\n mytone(LA4,Q);\n mytone(Ab4,E+S);\n mytone(G4,S);\n \n mytone(Gb4,S);\n mytone(E4,S);\n mytone(F4,E);\n vTaskDelay(pdMS_TO_TICKS((E)));//PAUSE\n mytone(Bb3,E);\n mytone(Eb4,Q);\n mytone(D4,E+S);\n mytone(Db4,S);\n \n mytone(C4,S);\n mytone(B3,S);\n mytone(C4,E);\n vTaskDelay(pdMS_TO_TICKS((E)));//PAUSE QUASI FINE RIGA\n mytone(F3,E);\n mytone(Ab3,Q);\n mytone(F3,E+S);\n mytone(LA3,S);\n \n mytone(C4,Q);\n mytone(LA3,E+S);\n mytone(C4,S);\n mytone(E4,H);\n \n mytone(LA4,Q);\n mytone(LA3,E+S);\n mytone(LA3,S);\n mytone(LA4,Q);\n mytone(Ab4,E+S);\n mytone(G4,S);\n \n mytone(Gb4,S);\n mytone(E4,S);\n mytone(F4,E);\n vTaskDelay(pdMS_TO_TICKS((E)));//PAUSE\n mytone(Bb3,E);\n mytone(Eb4,Q);\n mytone(D4,E+S);\n mytone(Db4,S);\n \n mytone(C4,S);\n mytone(B3,S);\n mytone(C4,E);\n vTaskDelay(pdMS_TO_TICKS((E)));//PAUSE QUASI FINE RIGA\n mytone(F3,E);\n mytone(Ab3,Q);\n mytone(F3,E+S);\n mytone(C4,S);\n \n mytone(LA3,Q);\n mytone(F3,E+S);\n mytone(C4,S);\n mytone(LA3,H);\n \n vTaskDelay(pdMS_TO_TICKS((2*H)));\n}\n\nvoid vSoundTask(void *pvParameters)\n{\n while (1)\n {\n playerTone();\n vTaskDelay(pdMS_TO_TICKS(random(60000, 600000)));\n }\n}\n\n\n#endif" },