Categoría: STEM

  • Sistema de gestión de batería avanzado Analogico + SBS

    Sistema de gestión de batería avanzado Analogico + SBS

    A veces, en ingeniería, el reto no es solo crear algo nuevo, sino hacer que conviva con lo que ya existe. Hace poco estuve trabajando en un proyecto muy interesante que resume perfectamente esta idea: un sistema de gestión y registro de baterías (Datalogger) capaz de hablar dos “idiomas” distintos.

    El problema: Lo viejo vs. Lo nuevo

    En el mundo de las baterías hay, básicamente, dos grandes grupos conviviendo:

    1. Las baterías “inteligentes” (SBS): Son las modernas. Ellas mismas te dicen “estoy al 80%”, “tengo esta temperatura” o “me quedan tantos ciclos de vida”. Se comunican digitalmente.
    2. Las baterías “tradicionales” (Analógicas): Son las de toda la vida. No “hablan”, así que para saber cómo están tienes que medir físicamente su voltaje, la corriente que entra y sale, y usar sondas externas para vigilar que no se calienten.

    El objetivo era crear un cerebro único que pudiera manejar ambas situaciones sin despeinarse.

    La solución: Un sistema híbrido

    Desarrollé un firmware capaz de trabajar en dos modos. Si el sistema detecta una batería moderna, se comporta como un “host” digital: lee directamente los datos internos (voltaje, amperaje, salud de la batería) a través de protocolos de comunicación estándar. Es limpio y preciso.

    Pero, si conectamos una batería analógica, el sistema cambia el chip. Pasa a usar sensores físicos para leer la corriente y el voltaje, y gestiona sondas de temperatura externas para asegurarse de que todo opera dentro de los márgenes de seguridad.

    ¿Por qué es útil esto?

    Lo bonito de este desarrollo es la versatilidad. El dispositivo no solo gestiona la carga, sino que actúa como una “caja negra”:

    • Registro de datos: Guarda un historial diario en una tarjeta SD con todo lo que pasa (ciclos de carga, temperaturas, potencias…).
    • Seguridad: Tiene alarmas programadas. Si una batería se calienta demasiado o baja de cierto nivel, el sistema avisa y corta para prevenir daños, da igual si la batería es digital o analógica.
    • Visualización: Toda la info se muestra sencilla en una pantalla OLED para que el usuario sepa qué pasa de un vistazo.

    Al final, este proyecto ha sido un buen ejercicio de adaptación. La electrónica sirve para hacer de puente entre tecnologías distintas, alargando la vida útil de los equipos y mejorando la seguridad, sea cual sea la batería que se use.

  • Sensor de humedad de suelo con control de alimentación (moisture-sensor-for-plants)

    Sensor de humedad de suelo con control de alimentación (moisture-sensor-for-plants)

    moisture-sensor-for-plants

    Este proyecto implementa un sistema básico para medir la humedad del suelo mediante un microcontrolador, optimizando el consumo de energía de la sonda gracias a un pin de alimentación controlado por software. Está diseñado para facilitar la integración en entornos de bajo consumo o alimentados por baterías.

    Ver repositorio en Github

    Objetivo

    Obtener lecturas confiables del nivel de humedad del suelo mientras se evita la corrosión y el consumo innecesario de corriente de la sonda, encendiéndola solo durante el tiempo mínimo necesario para la medición.

    Estructura del proyecto

    El código está organizado en tres partes principales:

    1. Encabezado (moisture.h)

    Define la interfaz de uso:

    • moistureInit(): inicializa los pines para alimentar la sonda y leer la señal analógica.
    • moistureSetWarmup(): permite configurar el tiempo de precalentamiento antes de la medición.
    • moistureRead(): realiza la lectura del valor crudo del ADC.

    2. Implementación (moisture.cpp)

    Contiene la lógica de funcionamiento:

    • Al inicializar, configura el pin de alimentación como salida y lo apaga por defecto.
    • Durante la lectura, habilita la alimentación, espera el tiempo de calentamiento configurado (300 ms por defecto) y luego toma la muestra analógica.
    • Apaga la alimentación inmediatamente después de la lectura para reducir la corrosión y el consumo.

    3. Sketch principal (moisture1.ino)

    Ejemplo de uso que inicializa el sensor con pines definidos, configura el precalentamiento si es necesario y lee los valores de humedad periódicamente, mostrando los resultados por el puerto serial.

    Características destacadas

    • Control programático de la alimentación de la sonda.
    • Configuración flexible del tiempo de precalentamiento.
    • Lectura directa del valor analógico en formato crudo (0–1023).
    • Diseño modular para facilitar la reutilización en otros proyectos.

    Aplicaciones

    El sistema está pensado para proyectos de riego automático, monitoreo de jardines o cultivos, y cualquier implementación que requiera reducir el consumo y prolongar la vida útil de sondas de humedad

  • Bicicleta que hace los cambios automáticamente

    Bicicleta que hace los cambios automáticamente

    📍 Barcelona

    Trabajo realizado por Alumno de Tutoría

    Incluye Sensor PAS, Placa Arduino Uno, Módulo de LCD OLED, Switch, Bicicleta.

  • Brazo robótico

    📍Barcelona 2022

    Proyecto de programación de acciones e iteraciones en Software para ubicar las esferas en diferentes posiciones.

    Un brazo robótico es un dispositivo mecánico controlado por computadora que se utiliza para manipular objetos de manera similar a un brazo humano. Estos brazos robóticos se pueden programar para realizar una variedad de tareas, desde simples movimientos hasta operaciones más complejas. La programación de acciones e iteraciones en software es fundamental para controlar y coordinar los movimientos del brazo robótico.

    Arduino es una plataforma electrónica de código abierto que se utiliza ampliamente en proyectos de robótica, incluidos los brazos robóticos. Proporciona una forma fácil de controlar y programar componentes electrónicos, lo que permite a los ingenieros y aficionados crear sus propios sistemas robóticos.

    La ingeniería mecatrónica es una disciplina que combina elementos de ingeniería mecánica, electrónica y de control para diseñar y construir sistemas automatizados. Los brazos robóticos son un ejemplo común de aplicación de la ingeniería mecatrónica, ya que requieren conocimientos en estas áreas para su diseño y programación.

  • Conectar dos placas ESP32 con Bluetooth

    Creado:: 22 de marzo de 2023

    Ultima actualización: 7/5/2025

    Primeros pasos con ESP32 Bluetooth Low Energy (BLE) en Arduino IDE – Bluetooth de Bajo Consumo de Energía

    El ESP32 cuenta con con Bluetooth Clásico y Bluetooth Low Energy (BLE)

    Esta publicación es una introducción a BLE con el ESP32.

    En esta sección: ¿Qué es BLE y para qué se puede usar?

    También algunos ejemplos con el ESP32 usando Arduino IDE.

    ¿Qué es Bluetooth de baja energía?


    Bluetooth Low Energy, BLE para abreviar, es una variante de ahorro de energía de Bluetooth. La aplicación principal de BLE es la transmisión a corta distancia de pequeñas cantidades de datos (bajo ancho de banda).

    A diferencia de Bluetooth Clásico, que siempre está activado, BLE permanece en modo de suspensión constantemente, excepto cuando se inicia una conexión.

    Comparado con Bluetooth clásico, Bluetooth Low Energy está diseñado para proporcionar un bajo consumo de energía, manteniendo un rango de alcance de comunicación similar.

    Esto hace que consuma muy poca energía. BLE consume aproximadamente 100 veces menos energía que Bluetooth (según el caso de uso).

    Además, BLE admite no solo la comunicación punto a punto, sino también el modo de transmisión y la red de malla.

    Servidor y cliente BLE

    Con Bluetooth Low Energy, hay dos tipos de dispositivos: el servidor y el cliente.

    El ESP32 puede actuar como cliente o como servidor. El servidor anuncia su existencia, por lo que otros dispositivos pueden encontrarlo y contiene datos que el cliente puede leer. El cliente escanea los dispositivos cercanos y, cuando encuentra el servidor que está buscando, establece una conexión y escucha los datos entrantes. Esto se llama comunicación punto a punto.

    Hay otros modos de comunicación posibles, como el modo de transmisión y la red de malla.

    GATT

    GATT significa Atributos Genéricos y define una estructura de datos jerárquica que está expuesta a los dispositivos BLE conectados. Esto significa que GATT define la forma en que dos dispositivos BLE envían y reciben mensajes estándar. Comprender esta jerarquía es importante porque facilitará la comprensión de cómo usar BLE con el ESP32.

    Perfil: colección estándar de servicios para un caso de uso específico;

    Servicio: recopilación de información relacionada, como lecturas de sensores, nivel de batería, frecuencia cardíaca, etc.;

    Característica: es donde se guardan los datos reales en la jerarquía (valor);

    Descriptor: metadatos sobre los datos;

    Propiedades: describe cómo se puede interactuar con el valor característico. Por ejemplo: leer, escribir, notificar, difundir, indicar, etc.

    En nuestro ejemplo, crearemos un servicio con dos características.

    Uno para la temperatura y otro para la humedad.

    Las lecturas reales de temperatura y humedad se guardan en el valor bajo sus características. Cada característica tiene la propiedad de notificación, de modo que notifique al cliente cada vez que cambien los valores.

    UUI

    Cada servicio, característica y descriptor tiene un UUID (Universally Unique Identifier). Un UUID es un número único de 128 bits (16 bytes).

    Por ejemplo:

    55072829-bc9e-4c53-938a-74a6d4c78776

    Hay UUID abreviados para todos los tipos, servicios y perfiles especificados en el SIG (Bluetooth Special Interest Group).

    Si su aplicación necesita su propio UUID, puede generarlo utilizando este sitio web generador de UUID.

    En resumen, el UUID se utiliza para identificar información de manera única. Por ejemplo, puede identificar un servicio particular proporcionado por un dispositivo Bluetooth.

    Conectando el ESP32

    Este ejemplo funcionaría para cualquier placa de desarrollo actual con ESP-32. En este caco se utilizaron las siguientes placas:

    Heltec ESP32 Lora V2, LolinD32, NodeMCU ESP32S

    Sketch para Servidor BLE

    #define LED_BUILTIN 2
    #include <BLEDevice.h>
    #include <BLEServer.h>
    #include <BLEUtils.h>
    #include <BLE2902.h>
    
    #define temperatureCelsius
    #define BLE_server "ESP32_Server"
    
    #define SERVICE_UUID "huecat23-6d3c-4a17-a71f-ece2e6075f9b"
    
    BLECharacteristic dhtTemperatureCelsiusCharacteristics("huecat23-c85e-4596-9bd9-015e2eaa4888", BLECharacteristic::PROPERTY_NOTIFY);
    BLEDescriptor dhtTemperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902));
    
    BLECharacteristic dhtHumidityCharacteristics("huecat23-4a2f-4cf3-96e6-38b79be71a61", BLECharacteristic::PROPERTY_NOTIFY);
    BLEDescriptor dhtHumidityDescriptor(BLEUUID((uint16_t)0x2903));
    
    
    bool device_connected = false;
    
    class MyServerCallbacks: public BLEServerCallbacks {
        void onConnect(BLEServer* pServer) {
          device_connected = true;
        };
    
        void onDisconnect(BLEServer* pServer) {
          device_connected = false;
        }
    };
    
    void setup() {
    
      Serial.begin(115200);
    
      BLEDevice::init(BLE_server);
      BLEServer *pServer = BLEDevice::createServer();
      pServer->setCallbacks(new MyServerCallbacks());
      BLEService *dhtService = pServer->createService(SERVICE_UUID);
    
    
      dhtService->addCharacteristic(&dhtTemperatureCelsiusCharacteristics);
      dhtTemperatureCelsiusDescriptor.setValue("DHT Temperature (Celsius)");
      dhtTemperatureCelsiusCharacteristics.addDescriptor(new BLE2902());
    
      dhtService->addCharacteristic(&dhtHumidityCharacteristics);
      dhtHumidityDescriptor.setValue("DHT humidity");
      dhtHumidityCharacteristics.addDescriptor(new BLE2902());
      dhtService->start();
      pServer->getAdvertising()->start();
      Serial.println("Esperando a Cliente Bluetooth");
    }
    void loop() {
    
    
      //Timer cada 5 segundos: envía la info por bluetooth
      static unsigned long enviaDato;
      if (millis() > enviaDato + 5000) {
        enviaDato = millis();
    
        ///////////////////////////////// 
          if (device_connected) {
    
        //Datos de prueba
        float temp = 25;
        float hum = 88;
        
        static char temperature_celsius[7];
        dtostrf(temp, 6, 2, temperature_celsius);
        dhtTemperatureCelsiusCharacteristics.setValue(temperature_celsius);
        dhtTemperatureCelsiusCharacteristics.notify();
        Serial.print("Temperatura: ");
        Serial.print(temp);
        Serial.print(" *C");
    
        static char humidity[7];
        dtostrf(hum, 6, 2, humidity);
        dhtHumidityCharacteristics.setValue(humidity);
        dhtHumidityCharacteristics.notify();
        Serial.print("  Humedad: ");
        Serial.print(hum);
        Serial.println(" %");
      }
    
    
    
        
      }
    
      
    
      //Parpadeo del LED
      static unsigned long parpadeo;
      if (millis() > parpadeo + 80) {
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
        parpadeo = millis();
      }
    
    }
    

    Sketch para el Cliente BLE

    #include "BLEDevice.h"
    #include "heltec.h"
    #include "Arduino.h"
    
    
    SSD1306Wire display(0x3c, SDA_OLED, SCL_OLED, RST_OLED); //128_64
    
    #define SCREEN_WIDTH 128
    #define SCREEN_HEIGHT 64
    
    #define temperatureCelsius
    #define BLE_server "ESP32_Server"
    
    
    // Generador de UUIDs:
    // https://www.uuidgenerator.net/
    
    //***********************************
    //BLE ID UNICO PARA SERVICIO
    static BLEUUID                dhtServiceUUID("huecat23-6d3c-4a17-a71f-ece2e6075f9b");
    //***********************************
    
    //BLE ID UNICO PARA CARACTERÍSTICA (TEMPERATURA)
    static BLEUUID temperatureCharacteristicUUID("huecat23-c85e-4596-9bd9-015e2eaa4888");
    
    //BLE ID UNICO PARA CARACTERÍSTICA (HUMEDAD)
    static BLEUUID    humidityCharacteristicUUID("huecat23-4a2f-4cf3-96e6-38b79be71a61");
    
    
    /*
    
      //***********************************
      //BLE ID UNICO PARA SERVICIO
      static BLEUUID dhtServiceUUID("d29181ad-6d3c-4a17-a71f-ece2e6075f9b");
      //***********************************
    
      //BLE ID UNICO PARA CARACTERÍSTICA (TEMPERATURA)
      static BLEUUID temperatureCharacteristicUUID("ea4963df-c85e-4596-9bd9-015e2eaa4888");
    
      //BLE ID UNICO PARA CARACTERÍSTICA (HUMEDAD)
      static BLEUUID humidityCharacteristicUUID("b61decbb-4a2f-4cf3-96e6-38b79be71a61");
    
    
    */
    static boolean bleConectado = false;
    static boolean connected = false;
    
    static BLEAddress *pServerAddress;
    static BLERemoteCharacteristic* temperatureCharacteristic;
    static BLERemoteCharacteristic* humidityCharacteristic;
    
    const uint8_t notificationOn[] = {0x1, 0x0};
    const uint8_t notificationOff[] = {0x0, 0x0};
    
    
    bool conectarAServidor(BLEAddress pAddress) {
      BLEClient* pClient = BLEDevice::createClient();
    
      pClient->connect(pAddress);
      Serial.println("Conectado al Servidor");
    
      BLERemoteService* pRemoteService = pClient->getService(dhtServiceUUID);
    
      if (pRemoteService == nullptr) {
        Serial.print("Failed to find our service UUID: ");
        Serial.println(dhtServiceUUID.toString().c_str());
        return (false);
      }
    
      temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
      humidityCharacteristic = pRemoteService->getCharacteristic(humidityCharacteristicUUID);
    
      if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {
        Serial.print("Failed to find our characteristic UUID");
        return false;
      }
      Serial.println(" Characteristics Found!");
    
      temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
      humidityCharacteristic->registerForNotify(humidityNotifyCallback);
    }
    
    class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
        void onResult(BLEAdvertisedDevice advertisedDevice) {
          if (advertisedDevice.getName() == BLE_server) {
            advertisedDevice.getScan()->stop();
            pServerAddress = new BLEAddress(advertisedDevice.getAddress());
            bleConectado = true;
            Serial.println("Dispositivo encontrado. Conectando...");
          }
        }
    };
    
    static void temperatureNotifyCallback(BLERemoteCharacteristic*pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify)
    {
    
      String informarTemperatura = "";
      informarTemperatura = "Temperatura: ";
      informarTemperatura += (char*)pData;
      informarTemperatura += " *C";
    
      imprimirConAltura(informarTemperatura, 20); ////// IMPRIME OLED Y SERIAL //////
    
    }
    
    static void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
    
      String informarHumedad = "Humedad: ";
      informarHumedad += (char*)pData;
      informarHumedad += " %";
    
      //imprimirConAltura(informarHumedad, 28); ////// IMPRIME OLED Y SERIAL //////
    
      Serial.println(informarHumedad);
    }
    
    void setup()
    {
      Serial.begin(115200);
      Serial.println("\nESP-32--B-BLE-CLIENTE");
    
      ///////////////////////////////////////// PARA PANTALLA OLED
      initHeltecEsp32(); //Inicializaciones correspondientes a modelo Pantalla OLED elegido.
    
      imprimirConAltura("Comenzando conexión BLE ( Cliente)", 0); ////// IMPRIME OLED Y SERIAL //////
    
      BLEDevice::init("");
    
      BLEScan* pBLEScan = BLEDevice::getScan();
      pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
      pBLEScan->setActiveScan(true);
      pBLEScan->start(30);
    
    
    }
    void loop() {
    
      if (bleConectado == true) {
    
        if (conectarAServidor(*pServerAddress)) {
    
          String conectando = "Conectado servidor BLE.";
          imprimirConAltura(conectando, 8); ////// IMPRIME OLED Y SERIAL //////
    
          temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
          humidityCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
          connected = true;
        } else {
          String conectando_error = "Falló conexión Servidor BLE";
          imprimirConAltura(conectando_error, 8); ////// IMPRIME OLED Y SERIAL //////
        }
        bleConectado = false;
      }
      delay(1000);
    }
    
    
    
    //Basado en ejemplo Heltec OLED_rotate.ino
    void VextON(void)
    {
      pinMode(Vext, OUTPUT);
      digitalWrite(Vext, LOW);
    }
    
    void VextOFF(void) //Vext default OFF
    {
      pinMode(Vext, OUTPUT);
      digitalWrite(Vext, HIGH);
    }
    
    void initHeltecEsp32() {
    
      VextON();
      delay(100);
    
      display.init();
      display.clear();
      display.display();
    
      display.setContrast(1);
    
      display.setTextAlignment(TEXT_ALIGN_CENTER);
      display.clear();
      display.display();
      display.screenRotate(ANGLE_0_DEGREE);
      display.setFont(ArialMT_Plain_16);
      display.drawString(64, 32 - 16 / 2, "HUE CAT"); //ROTATE_0
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_90_DEGREE);
      display.setFont(ArialMT_Plain_10);
      display.drawString(32, 64 - 10 / 2, "HUE CAT"); //ROTATE_90
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_180_DEGREE);
      display.setFont(ArialMT_Plain_16);
      display.drawString(64, 32 - 16 / 2, "HUE CAT"); //ROTATE_180
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_270_DEGREE);
      display.setFont(ArialMT_Plain_10);
      display.drawString(32, 64 - 10 / 2, "HUE CAT"); //ROTATE_270
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_0_DEGREE);
      display.setFont(ArialMT_Plain_16);
      display.drawString(64, 32 - 16 / 2, "HUE CAT"); //ROTATE_0
      display.display();
      delay(500);
    
      display.clear();
      display.display();
    
      display.setTextAlignment(TEXT_ALIGN_LEFT);
      display.setFont(ArialMT_Plain_10);
    
    }
    
    
    void imprimirConAltura(String stringToPrint, int alturaAImprimir) {
      //Imprime en monitor serie y display
      Serial.print("OLED->" + stringToPrint);
      display.drawString(0, alturaAImprimir, stringToPrint);
      display.display();
    }
    

  • Melange 5411: Lámpara de luz puntual

    Melange 5411: Lámpara de luz puntual

    Diseñada y fabricada por Hue

    para instlación -articulable-

    Más info aquí