From b567ba2faf69c413df4c10f7553e4de7062df03a Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Thu, 30 Jul 2026 15:22:05 +0200 Subject: [PATCH] i18n(examples): la galeria, toda en ingles Velxio es internacional y su galeria estaba mezclada. Tres focos: - examples-robot-desktop: el codigo que el ejemplo ENTREGA al usuario llevaba 33 comentarios en castellano ("Tiempo del ultimo movimiento detectado", "Cola de estados") y 7 cadenas que el sketch imprime por serie ("INICIO DE LA LECTURA DE SENSORES", "Movimiento DETECTADO"). Traducido todo y reescrito en ASCII, como el resto de la galeria. - examples.ts: siete comentarios mios en castellano, de cuando anadi las resistencias en serie a los LEDs. El resto del fichero estaba en ingles; los deje incoherentes. Sin cambios de comportamiento: solo texto. Los tests de galeria siguen en verde (167). --- frontend/src/data/examples-robot-desktop.ts | 12 ++++---- frontend/src/data/examples.ts | 31 +++++++++++---------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/frontend/src/data/examples-robot-desktop.ts b/frontend/src/data/examples-robot-desktop.ts index 6a18e469..6af5e03d 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; // Tiempo del \u00faltimo movimiento detectado\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 para controlar el estado\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 // Acciones para el estado NERVIOSO\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 // Acciones para el estado MOVE\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(\"Iniciando................\");\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 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: "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 // Pin de datos del sensor DHT11\n#define DHTTYPE DHT11 // Tipo de sensor DHT (puedes cambiar a DHT22 si es necesario)\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 // N\u00famero m\u00e1ximo de estados en la cola\n\n\nextern RobotState stateQueue[MAX_STATES]; // Cola de estados\n//extern int queueFront = 0; // Frente de la cola\n//extern int queueRear = -1; // Final de la cola\n//extern int queueItemCount = 0; // N\u00famero de elementos en la cola\n\nextern unsigned long lastMovementTime; // Tiempo del \u00faltimo movimiento detectado\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 para controlar el estado\nextern bool weatherTimeoutReached;\nextern bool sleepTimeoutReached ;\n\n// Funci\u00f3n para insertar un estado en la cola\nextern RobotState lastInsertedState; // Variable para almacenar el \u00faltimo estado insertado\n// Estado actual\nextern RobotState currentState; // Variable para almacenar el \u00faltimo estado insertado\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_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: "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,10 +99,10 @@ 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; // Valor inicial negativo para indicar que no se ha le\u00eddo a\u00fan\nint maxLuz = 10;\nint umbralLuz = 0;\nunsigned long tiempoUltimaLectura = 0;\nconst unsigned long intervaloAjuste = 10000; // 20 segundos recalcula el umbral\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(); // Actualiza el tiempo del \u00faltimo cambio de estado\n lastStateMovement = currentStateMovement; // Actualiza el \u00faltimo estado registrado\n movementDetected = true; // Indica que se ha detectado un cambio de estado\n }\n\n // Verifica si ha pasado menos de 5 segundos desde el \u00faltimo cambio de estado\n if (movementDetected && millis() - lastTriggerTime < 3000)\n {\n Serial.println(\"Movimiento DETECTADO..... 130\");\n return true; // Retorna true si se detect\u00f3 un cambio de estado en menos de 5 segundos\n }\n\n // Verifica si han pasado m\u00e1s de 5 segundos desde el \u00faltimo cambio de estado\n if (millis() - lastTriggerTime >= 3000)\n {\n movementDetected = false; // Reinicia la bandera de detecci\u00f3n de cambio de estado\n }\n\n return false; // Si no se cumple ninguna condici\u00f3n, retorna false\n}\n\nbool isSoundDetected()\n{\n int sonido = digitalRead(SOUND_PIN);\n if (sonido == HIGH)\n {\n Serial.println(\"Sonido Detectado\");\n return true;\n }\n else\n {\n return false;\n }\n}\n\nvoid vReadSensorTask(void *pvParameters)\n{\n Serial.println(\"INICIO DE LA LECTURA DE SENSORES\");\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(\">>>>>>>>>>>>>>>>>>>>>>MOVIMIENTO DETECTADO AND STATE=SLEEP 171\");\n lastMovementTime = millis(); // Actualizar el tiempo del \u00faltimo movimiento detectado\n sleepTimeoutReached = false; // Reiniciar la bandera del timeout de sue\u00f1o\n weatherTimeoutReached = false;\n }\n else if (isMovementDetected() && STATE == NORMAL)\n {\n // insertState(MOVE);\n currentState = MOVE;\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>>MOVIMIENTO DETECTADO AND STATE == NORMAL 179\");\n lastMovementTime = millis(); // Actualizar el tiempo del \u00faltimo movimiento detectado\n sleepTimeoutReached = false; // Reiniciar la bandera del timeout de sue\u00f1o\n weatherTimeoutReached = false;\n }\n else if (isMovementDetected() && STATE == WEATHER)\n {\n Serial.println(\">>>>>>>>>>>>>>>>>>>>>>>>> MOVIMIENTO DETECTADO AND STATE == WEATHER 93\");\n lastMovementTime = millis(); // Actualizar el tiempo del \u00faltimo movimiento detectado\n sleepTimeoutReached = false; // Reiniciar la bandera del timeout de sue\u00f1o\n weatherTimeoutReached = false;\n currentState = NORMAL;\n }\n // L\u00f3gica adicional para cambiar al estado WEATHER despu\u00e9s de 10 minutos sin movimiento\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; // Marcar que se alcanz\u00f3 el tiempo l\u00edmite para el estado WEATHER\n }\n\n // L\u00f3gica adicional para cambiar al estado SLEEP despu\u00e9s de una hora sin movimiento\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; // Marcar que se alcanz\u00f3 el tiempo l\u00edmite para el estado SLEEP\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 // L\u00f3gica adicional para cambiar al estado WEATHER si se recibe y deja de recibir se\u00f1al de luz 3 veces\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; // Reiniciar el contador\n }\n\n vTaskDelay(pdMS_TO_TICKS(500)); // Espera antes de volver a verificar los sensores\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; // Convertir el puntero gen\u00e9rico a 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: "Watchdog.h", content: "#ifndef WATCHDOG_H\n#define WATCHDOG_H\n\n\n#include // Agregar la biblioteca para el watchdog\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 // Pin de datos del sensor DHT11\n#define DHTTYPE DHT11 // Tipo de sensor DHT (puedes cambiar a DHT22 si es necesario)\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: "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: "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" }, { name: "FaceEmotions.hpp", 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\nenum eEmotions {\n\tNormal=0,\n\tAngry,\n\tGlee,\n\tHappy,\n\tSad,\n\tWorried,\n\tFocused,\n\tAnnoyed,\n\tSurprised,\n\tSkeptic,\n\tFrustrated,\n\tUnimpressed,\n\tSleepy,\n\tSuspicious,\n\tSquint,\n\tFurious,\n\tScared,\n\tAwe,\n\tEMOTIONS_COUNT\n};\n\n#endif\n" }, { name: "AsyncTimer.cpp", 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 (millis() - _startTime) >= Interval) {\n\t\t_isExpired = true;\n\t\tif (OnFinish != nullptr) OnFinish();\n\t\tReset();\n\t}\n\treturn _isExpired;\n}\n\nvoid AsyncTimer::SetIntervalMillis(unsigned long interval) {\n\tInterval = interval;\n}\n\nunsigned long AsyncTimer::GetStartTime() {\n\treturn _startTime;\n}\n\nunsigned long AsyncTimer::GetElapsedTime() {\n\treturn millis() - _startTime;\n}\n\nunsigned long AsyncTimer::GetRemainingTime() {\n\treturn Interval - millis() + _startTime;\n}\n\nbool AsyncTimer::IsActive() const {\n\treturn _isActive;\n}\n\nbool AsyncTimer::IsExpired() const{\n\treturn _isExpired;\n}" }, diff --git a/frontend/src/data/examples.ts b/frontend/src/data/examples.ts index 405a3a32..b3b827c4 100644 --- a/frontend/src/data/examples.ts +++ b/frontend/src/data/examples.ts @@ -6074,9 +6074,9 @@ void loop() { components: [ { type: 'wokwi-pushbutton', id: 'btn1', x: 420, y: 120, properties: {} }, { type: 'wokwi-led', id: 'led1', x: 420, y: 260, properties: { color: 'red' } }, - // 220 ohm entre cada GPIO y su LED — (5V - ~2V) / 220R ~= 14 mA, por debajo - // de los 20 mA del LED. La resistencia en serie que le faltaba: sin ella el verificador de - // circuito calcula un cortocircuito y se niega a ejecutar el ejemplo. + // 220 ohm between each GPIO and its LED — (5V - ~2V) / 220R ~= 14 mA, + // under the LED's 20 mA. This is the series resistor it was missing: + // without it the circuit checker computes a short and refuses to run. { type: 'wokwi-resistor', id: 'r-led1', x: 420, y: 200, properties: { value: '220' } }, ], wires: [ @@ -6275,9 +6275,9 @@ void loop() { { type: 'wokwi-led', id: 'led7', x: 620, y: 80, properties: { color: 'purple' } }, { type: 'wokwi-led', id: 'led8', x: 660, y: 80, properties: { color: 'white' } }, { type: 'wokwi-led', id: 'led9', x: 700, y: 80, properties: { color: 'red' } }, - // 220 ohm entre cada GPIO y su LED — (5V - ~2V) / 220R ~= 14 mA, por debajo - // de los 20 mA del LED. Una resistencia en serie por LED. Sin ellas el verificador de circuito - // ve un cortocircuito y bloquea el Run del ejemplo entero. + // 220 ohm between each GPIO and its LED — (5V - ~2V) / 220R ~= 14 mA, + // under the LED's 20 mA. One series resistor per LED: without them the + // circuit checker sees a short and blocks Run for the whole example. { type: 'wokwi-resistor', id: 'mr-led2', x: 420, y: 20, properties: { value: '220' } }, { type: 'wokwi-resistor', id: 'mr-led3', x: 460, y: 20, properties: { value: '220' } }, { type: 'wokwi-resistor', id: 'mr-led4', x: 500, y: 20, properties: { value: '220' } }, @@ -6487,8 +6487,8 @@ void loop() { { type: 'wokwi-led', id: 'mled7', x: 620, y: 80, properties: { color: 'purple' } }, { type: 'wokwi-led', id: 'mled8', x: 660, y: 80, properties: { color: 'white' } }, { type: 'wokwi-led', id: 'mled9', x: 700, y: 80, properties: { color: 'red' } }, - // 220 ohm entre cada GPIO y su LED — (5V - ~2V) / 220R ~= 14 mA, por debajo - // de los 20 mA del LED. Una resistencia en serie por LED, como en el resto de la galeria. + // 220 ohm between each GPIO and its LED — (5V - ~2V) / 220R ~= 14 mA, + // under the LED's 20 mA. One series resistor per LED, as everywhere else. { type: 'wokwi-resistor', id: 'msr-mled2', x: 420, y: 20, properties: { value: '220' } }, { type: 'wokwi-resistor', id: 'msr-mled3', x: 460, y: 20, properties: { value: '220' } }, { type: 'wokwi-resistor', id: 'msr-mled4', x: 500, y: 20, properties: { value: '220' } }, @@ -6855,10 +6855,11 @@ void loop() { }`, components: [ { type: 'wokwi-pushbutton', id: 'c3-btn1', x: 440, y: 120, properties: {} }, - // 220 ohm en serie con el LED — nunca cuelgues un LED directo de un GPIO. - // (3.3V - ~2.8V del azul) / 220R ~= 2 mA, holgadamente por debajo de los 20 mA - // que aguanta. Sin ella el verificador de circuito calcula 506 mA y, con razon, - // se niega a ejecutar: en una placa de verdad ese LED dura un suspiro. + // 220 ohm in series with the LED — never hang an LED straight off a + // GPIO. (3.3V - ~2.8V for the blue one) / 220R ~= 2 mA, comfortably + // under the 20 mA it takes. Without it the circuit checker computes + // 506 mA and rightly refuses to run: on real hardware that LED would + // not last long. { type: 'wokwi-resistor', id: 'c3-r-led', x: 440, y: 200, properties: { value: '220' } }, { type: 'wokwi-led', id: 'c3-led-btn', x: 440, y: 260, properties: { color: 'blue' } }, ], @@ -7416,9 +7417,9 @@ void loop() { }`, components: [ { type: 'wokwi-pushbutton', id: 'pico-btn1', x: 440, y: 120, properties: {} }, - // 220 ohm en serie con el LED — igual que en el resto de ejemplos. Un LED - // colgado directo de un GPIO se pasa del limite de corriente y el verificador - // de circuito lo bloquea, con razon. + // 220 ohm in series with the LED — as in every other example. An LED + // hung straight off a GPIO goes over the current limit and the circuit + // checker blocks it, rightly. { type: 'wokwi-resistor', id: 'pico-r-led', x: 440, y: 200, properties: { value: '220' } }, { type: 'wokwi-led', id: 'pico-led-btn', x: 440, y: 260, properties: { color: 'yellow' } }, ],