Control de nivel con arduino (histéresis y protección de inundación)

Tema en 'Taller de Arduino' iniciado por carmamezo, 6 Sep 2019.

  1. carmamezo

    carmamezo

    Mensajes:
    5
    Registrado:
    5 Sep 2019
    Ubicación:
    Leioa
    Hola a [email protected],

    Acabo de llegar al foro y me gustaría poneros mi primer brico con arduino (es una chorrada), se trata de un rellenador automático... La idea de hacerlo con arduino es evitar inundaciones, está claro que un rellenador no necesita electrónica (el circuito puede ser eléctrico puro) pero me pareció peligroso poner un circuito eléctrico directo sin control por dos motivos:
    - El control de nivel todo/nada va a hacer que la bomba esté continuamente encendiendo/apagando cuando el nivel esté en el límite de detección de la boya.
    - El control de nivel todo/nada no detecta si estamos llenando durante demasiado tiempo el tanque (no tenemos agua de reposición o la boya ha fallado).
    Debido a estas dos condiciones, hice un circuito con un NANO donde trabaja con un control en histéresis y con un watchdog que pone el arduino en fallo (el led del arduino parpadea y el control de nivel se desactiva al cabo de un tiempo de llenado hasta resetear el arduino) para evitar que la bomba trabaje durante mucho tiempo (bien porque la boya está mal o bien porque no haya agua en el tanque de reposición).
    El control en histéresis funciona con la siguiente lógica:
    - Si el nivel está detectando bajo durante X segundos continuos, enciendo la bomba.
    - Si el nivel está detectando alto durante X xegundos continuos, apago la bomba.
    De esta forma siempre espero a que el nivel baje por debajo del límite del detector y suba por encima del límite. Se evitan encendidos/apagados continuos y breves y alargamos la vida de la bomba. Además realizo un arranque suave de la bomba mediante PWM (alargando su vida aún más). He utilizado una bomba de desplazamiento positivo de 12v, que a diferencia de las centrífugas es capaz de subir una columna de agua a más altura, pero como contra tiene que si se deja en vacío mucho tiempo se quema. Os pongo unas fotos, espero echaros una mano por aquí en lo que pueda. La placa la estaba usando para hacer pruebas y por eso veréis que tiene unas cuantas cosas conectadas que no estoy usando actualmente.
     

    Adjuntos:

    A MccNaxo y Ariel1980 les gusta esto.
  2. alvata

    alvata

    Mensajes:
    1
    Registrado:
    22 Ene 2020
    Ubicación:
    sevilla
    hola podrias poner el codigo que usas? para descargarlo, gracias
     
  3. carmamezo

    carmamezo

    Mensajes:
    5
    Registrado:
    5 Sep 2019
    Ubicación:
    Leioa
    Perdona por no haber respondido antes he estado liadillo (ahora tengo tiempo de sobra por desgracia), he limpiado el código porque tenía bastante kk por medio (lectura de temperaturas DS18B20, RTC...), basicamente empieza a llenar cuando pasan 10s con la boya abajo (aprox, depende del delay) y termina de llenar cuando pasan otros 10s con la boya arriba. La bomba se controla mediante PWM con rampas de arranque, se empieza con el 50% (127) y se va incrementando cada 100ms de uno a uno el PWM, hasta el máximo de 255 . Una vez que el PWM supera los 200 (78%) se empieza a contar tiempo de bomba en marcha, si está más tiempo que el configurado en el valor t_bomba_lock (en ms), la bomba se para y el código queda bloqueado al activar el flag "bomba_locked", haciendo que el led de la placa flashee. He usado un contador incremental que cada ciclo incrementa en 10ms la cuenta (teniendo en cuenta el delay del final), como verás es un método muy rudimentario, pero me aseguro de no tener problemas con la sobrecarga del contador milllis(), el tiempo es aproximado y los 10ms que incremento son "muy poco fiables" (en realidad serán algunos más), pero para esta aplicación sencilla es más que suficiente.


    Creo que ha quedado sólo lo importante:


    #include <Wire.h>
    //definición de pines
    #define boya 11
    #define onboard_led 13
    #define pwm_out 14
    #define t_bomba_lock 15000 //tiempo máximo bombeando (ms)
    int cuenta_on = 0, cuenta_off = 0;
    bool bomba_locked=false;
    void setup() {
    //configuración de entradas/salidas digitales
    pinMode(boya,INPUT);
    pinMode(onboard_led,OUTPUT);
    //configuración comunicación serie PC (debug)
    Serial.begin(9600);
    }
    void loop() {
    // put your main code here, to run repeatedly:
    uint32_t miliseconds;
    static int pwm_value=0;
    static unsigned int tiempo_bomba=0;
    static uint32_t tiempo_pwm=0;
    miliseconds=millis();
    if (digitalRead(boya)==HIGH)
    {
    if (cuenta_on<100)cuenta_on+=1;
    cuenta_off=0;
    }
    else
    {
    if(cuenta_off<100)cuenta_off+=1;
    cuenta_on=0;
    }
    //100 ciclos con la boya activa para rellenar
    if (cuenta_on==100)
    {
    if (tiempo_pwm==0)pwm_value=127;
    if(pwm_value>200)
    tiempo_bomba+=10;

    if ( ((miliseconds-tiempo_pwm)>100) || (tiempo_pwm>miliseconds))
    {
    tiempo_pwm=miliseconds;
    pwm_value++;
    }
    }
    //100 ciclos con la boya desactiva para parar de rellenar
    if (cuenta_off==100)
    {
    pwm_value=0;
    tiempo_bomba=0;
    }
    //bloqueo de seguridad de la bomba
    if ( (tiempo_bomba>t_bomba_lock) && !bomba_locked)// 15s bombeando, paro bomba por seguridad
    {
    bomba_locked=true;
    Serial.println("bomba bloqueada");
    }
    //limito la salida pwm a 255
    if(pwm_value>255)
    pwm_value=255;
    else if (pwm_value<0)
    pwm_value=0;
    if (bomba_locked)
    {
    pwm_value=0;
    blink_led(onboard_led);
    }
    analogWrite(pwm_out,pwm_value);//escribo la salida pwm

    delay(10);//espera de 10ms (OJO QUE EL TIEMPO de bloqueo de bomba SE CALCULA CON ESTO)
    }
    void blink_led(int pin)
    {
    static uint32_t tiempo=millis();
    static bool value=false;
    uint32_t milis;
    milis=millis();
    if(milis-tiempo>500 || milis<tiempo)
    {
    tiempo=millis();
    value=!value;
    }
    if (value)
    digitalWrite(pin,HIGH);
    else
    digitalWrite(pin,LOW);
    }
     
    Última edición: 20 Mar 2020