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

Registrado
5 Sep 2019
Mensajes
127
Ubicación
Leioa
Provincia
Bizkaia
Hola a tod@s,

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.
 

Archivos adjuntos

  • [TodoMarino.com] Control de nivel con arduino (histéresis y protección de inundación)
    IMG_20190905_092849.webp
    22,6 KB · Visitas: 335
  • [TodoMarino.com] Control de nivel con arduino (histéresis y protección de inundación)
    IMG_20190906_093007.webp
    45,8 KB · Visitas: 345
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 10ms 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:
**EDITADO -> el sistema se apagaba cada cierto tiempo porque estaba conectado a un enchufe inteligente y se apagaba durante las paradas de bombas cuando alimento, por lo que no había problemas, pero en sistemas que nunca reinician puede ocurrir un problema de sobrerellenado debido a un overflow del LONG de los millis. Modificado para que no haya problemas por saturación del tiempo.
He eliminado el control de tiempo por ciclo para evitar problemas con el delay().

C++:
//definición de pines
#define boya  11
#define onboard_led 13
#define pwm_out 14

#define t_bomba_lock 10000 //tiempo máximo bombeando (ms)
#define t_on 1000 //tiempo con el detector a on (ms)
#define t_off 1000 //tiempo con el detector a off (ms)


uint32_t miliseconds,milis_ant,milis_on_ant,milis_off_ant,milis_bomba_ant;
bool bomba_locked=false,bomba_on=false;
unsigned int pwm_value;


void setup() {
  //configuración de entradas/salidas digitales
  pinMode(boya,INPUT);
  pinMode(onboard_led,OUTPUT);
  pwm_value=0;
}

void loop() {
  miliseconds=millis();

  if(miliseconds<milis_ant)//en caso de que haya un overflow del uint32_t del millis(), valor ha pasado a 0 reseteo todo
  {
    milis_on_ant=miliseconds;
    milis_off_ant=miliseconds;
    milis_bomba_ant=miliseconds;
    bomba_on=false;
  }
  milis_ant=miliseconds;

  if (digitalRead(boya)==HIGH)//bajo nivel tanque (reseteamos el temporizador de parada)
    milis_off_ant=miliseconds;
  else//alto nivel tanque (reseteamos el temporizador de marcha)
    milis_on_ant=miliseconds;

  if (!bomba_on)//si la bomba está parada, reseteamos el temporizador de seguridad
    milis_bomba_ant=miliseconds;

  if((miliseconds-milis_on_ant>t_on) && !bomba_on && !bomba_locked)//ha pasado el tiempo configurado con nivel bajo si la bomba está parada, la arrancamos
  { 
    bomba_on=true;
    pwm_value=127;
  }

  if((bomba_on && (miliseconds-milis_off_ant>t_off)) || bomba_locked)//estando la bomba arrancada ha pasado el tiempo configurado con el detector arriba, se para la bomba
    bomba_on=false;

  if(miliseconds-milis_bomba_ant>t_bomba_lock)//si la bomba ha estado arrancada durante más tiempo del tiempo de seguridad, se para y se bloquea el proceso de rellenado
  {
    bomba_locked=true;
    bomba_on=false;
  }

  if(bomba_locked && (miliseconds-milis_off_ant>t_off))//si el detector de nivel vuelve a detectar nivel lleno, se quita el bloqueo de bomba.
    bomba_locked=false;

  if (bomba_on)//bomba en marcha, subimos el pwm desde 127 hasta 255 en pasos de a 1/10ms
    pwm_value+=1;
  else
    pwm_value=0;
    
  //limito la salida pwm a 255
  if(pwm_value>255)
    pwm_value=255;

  if (bomba_locked)//si la bomba está bloqueada, led de error parpadea y bomba parada
  {
    pwm_value=0;
    blink_led(onboard_led);
  }

  analogWrite(pwm_out,pwm_value);//escribo la salida pwm
    
 delay(10);
}

//parpadeo de led para mostrar bloqueo de bomba.
void blink_led(int pin)
{
  static uint32_t tiempo=millis();
  static bool value=false;

  if(miliseconds-tiempo>500 || miliseconds<tiempo)
  {
    tiempo=miliseconds;
    value=!value;
  }
  digitalWrite(pin,value);
}
 
Última edición:
Atrás
Arriba