Pecera Autorregulada

Introducción

La libertad que se nos ha ofrecido para la realización de este proyecto ha sido ventajoso a la vez que complejo, pues hay incontables opciones a elegir a la hora de hacer un diseño con Arduino por lo que decidirse por uno ha sido difícil. Se nos ocurrieron miles de posibles modelos para construir, pero el que más interesante causó a todos los integrantes del grupo fue una casa domótica. Como primer proyecto decidimos que se trataba de algo muy completo y con dificultades para poder presentarlo en clase, por lo que decidimos hacer algo parecido pero en una versión mas manejable, es ahí cuando llegamos a una conclusión; una pecera autoregulada.

Se trataría de una pecera con distintas funcionalidades y con la posibilidad de poder personalizarla al gusto de quien lo posea. En un principio tendría un dispensador de comida automático, un sensor de temperatura sumergible, un sensor de nivel de agua y una mini bomba de agua para filtrar el agua. 

La metodología que hemos llevado a cabo a sido bastante intuitivo, pues al desconocer la mayoría de los componentes usados primero los hemos investigado individualmente con sus respectivos códigos y posteriormente hemos juntado todo en la pecera. A continuación detallaremos los materiales usados y el código de cada uno respectivamente.

Materiales

MaterialCoste
Placa Arduino Uni R3Incluido en el material
ProtoboardIncluido en el material
Cables (Male to Male)Incluido en el material
Sensor de temperatura para líquidos (DS18B20)2,79€
BuzzerIncluido en el material
Sensor de nivel de agua3,93€
Servomotor2,42€
Mini bomba de motor sumergible0,93€
LCD (16×2) + I2C10€
Coste Total: 20,07€

Servomotor

Hardware

Un servomotor o servo (Micro Servo 9g SG90 de Tower Pro) es un motor eléctrico con dos características.

  • Permite mantener una posición que indiquemos. El rango que alcanza este modelo es de 180º. 
  • Permite controlar la velocidad de giro, podemos hacer que antes de que se mueva a la siguiente posición espere un tiempo.

Puede moverse con una resolución máxima de 1 grado, debido a la limitación de la señal PWM que es capaz de generar Arduino UNO. Funcionan con una señal PWM, con un pulso de trabajo entre 1 ms y 2 ms y con un periodo de 20 ms (50 Hz), es decir, la velocidad máxima a la que podemos cambiar de posición será cada 20 ms. Tendrá 3 cables e irán de la siguiente manera; uno irá a tierra, otro a la alimentación de 5 Voltios y el tercero a un pin PWM (en este caso el 3).

Software

Para poder controlar el servo desde Arduino tenemos que hacer uso de la librería “Servo” de la biblioteca del propio IDE.

El código necesario para poder girar el Servo de 0º a 180º (grado a grado) es la siguiente. De la librería Servo.h hemos declarado un objeto o variable ServoMotor y hacemos uso de dos métodos. Por un lado el “attach()”, para indicar en que pin tenemos conectado nuestro servo, y por otro lado el “write()”, donde indicamos en qué ángulo queremos posicionar nuestro servomotor. En los bucles for se realizara el giro de 180º, para ello habrá un delay de 15ms por cada grado que sume a su posición actual. Para hacer el giro más rápido o lento se deberá regular el delay de dentro del bucle. Finalmente en la demostración individual se pone un delay de 2 segundos para comenzar de nuevo el giro.

En la practica el delay seria de 43200000ms, es decir de 12h, que es el tiempo que debe transcurrir para alimentar a los peces.

#include <Servo.h>

Servo ServoMotor;

int pos = 0;

void setup() {
  Serial.begin(9600);
  ServoMotor.attach (3); 
  ServoMotor.write(pos);
}

void loop() {
  
  for (pos = 0; pos < 180; pos += 1) {
    ServoMotor.write(pos);
    delay(15); 
  }
  for (pos = 180; pos >= 1; pos -= 1) {
    ServoMotor.write(pos);
    delay(15); 
  }

  delay(2000);
}

Sensor de Nivel de Agua con Buzzer

Hardware

Este sensor esta diseñado para detectar agua, y es útil para detectar fugas de agua, lluvia, desbordamiento de un tanque, o simplemente para medir el nivel, presencia o volumen de agua.

Este sensor tiene 3 pines:

  • S (signal): Es el pin que proporciona una salida analógica. Por lo tanto usaremos el pin S como entrada analógica en el Arduino. El valor que da será variable en función de la superficie cubierta. El valor estará comprendido entre VCC y GND.
  • + (VCC): Es el pin de alimentación capaz de soportar entre 3,3V y 5V.
  • – (GND): Es el pin conectado a tierra.

En nuestro caso lo usaremos para saber cuándo se esta dando una fuga producido por algún daño en la pecera. De modo que colocaremos el sensor de nivel de agua rozando la superficie del agua, y en el momento en el que no detecte agua se emitirá una alarma mediante un buzzer.

El buzzer (Mono Enclosed Speaker) usado solamente dispone de dos pines; uno para conectarlo a un puerto no digital (no PWM), y otra para conectarlo a tierra.

Software

Para el uso de ambos dispositivos no es necesaria ninguna librería adicional. Primero se declaran las variables y mediante la función pinMode() se declara el sensor como entrada y el buzzer como salida.  

La función de loop() estará comprobando constantemente que el sensor este detectando agua mediante la función digitalRead(), de lo contrario cuando el sensor devuelva un LOW llamara a la función sonarAlarma() donde se generara un tono de 500Hz durante 500ms y se detendrá por otros 500ms. Debido a que no hay ningún delay el buzzer seguirá emitiendo el mismo sonido hasta que el sensor vuelva detectar agua.

int sensorNv = 7;
int buzzer = 8;

int valorSensor;

void setup() {
  Serial.begin(9600);
  pinMode(sensorNv, INPUT);
  pinMode(buzzer, OUTPUT);
}

void loop() {
  
  if (digitalRead(sensorNv) == LOW) {
    Serial.println ("CUIDADO, esta perdindo agua.");
    sonarAlarma();
  } else {
    Serial.println ("BIEN");
  }
}

void sonarAlarma() {
  tone(buzzer, 500, 300);
  delay(500);
}

Sensor de Temperatura Sumergible

Hardware

El dispositivo que hemos usado para medir la temperatura del agua es el sensor de temperatura DS18B20. Este puede medir temperaturas desde -55ºC hasta los 125ºC, con una precisión de 0,5º. Es un sensor digital que utiliza el protocolo One-Wire, es decir, necesita solo un pin de datos para comunicarse y permite conectar más de un sensor en el mismo bus.

Dispone de 3 pines:

  • VDD: es la tensión de alimentación puede soportar desde 3V a 5,5V
  • GND: es la toma de tierra
  • DQ: es el pin de datos por donde se recibirán todos los datos en el protocolo One-Wire

Los pines VDD y GND se conectaran a sus valores respectivamente, sin embargo el pin DQ es más complejo. Para su montaje deberemos usar una resistencia pull-up para controlar el bus de comunicaciones, de esta forma, cuando el sensor conectados al bus One-Wire no envíe datos, la línea de datos será igual a HIGH o la tensión que suministremos (en nuestro caso de 5V). En el momento que un sensor empieza a transmitir, la línea cambia de estado y ya sabemos que hay un sensor transmitiendo datos. El valor de la resistencia dependerá de la longitud del cable, el mas optimo seria uno de 4,7K Ohms, pero al no disponer de este valor hemos usado uno de 330 Ohms.

Primero debemos incluir las librerías OneWire y DallasTemperature. El primero se puede encontrar en el Gestor de Librerías de Arduino, el segundo lo tendremos que buscar en GitHub.

Mediante la variable pinDatosDQ indicaremos el pin donde estará conectado el sensor. En las posteriores dos lineas declaramos los objetos de las clases OneWire y DallasTemperature. Solo utilizaremos este último que es el que nos da acceso a los sensores de temperatura DS18B20. Usaremos el símbolo & para pasar la variable por referencia

En la función setup iniciamos el bus One-Wire llamando a la función .begin(). En la funcion loop, llamamos a la función .requestTemperatures() para enviar comandos para la toma de temoeratura. Una vez que el sensor ha recibido el comando, y ha tomado la temperatura en Celsius se solicitara la información con la función .getTempCByIndex(indice_sensor). Al usar únicamente un sensor, el valor de las paréntesis será de 0, si de lo contrario tuviésemos n sensores conectados en serie el valor seria de 0 a n-1.

#include <OneWire.h>
#include <DallasTemperature.h>

int pinDatosDQ = 2;
 
OneWire oneWireObjeto (pinDatosDQ);
DallasTemperature sensorDS18B20 (&oneWireObjeto);

void setup() {
    Serial.begin(9600);
    sensorDS18B20.begin(); 
}

void loop() {
    sensorDS18B20.requestTemperatures();
    Serial.print("Temperatura sensor: ");
    Serial.print(sensorDS18B20.getTempCByIndex(0));
    Serial.println("º C");
    delay(1000);
} 

Mini Bomba de Agua

Hardware

Una bomba de agua es un dispositivo capaz de generar un caudal de líquido usando energía cinética. Para su funcionamiento dispone de 3 elementos básicos:

  • Entrada: por donde se absorbe el líquido.
  • Motor+Hélice: el encargado de generar la energía cinética
  • Salida: es la toma por donde saldrá el líquido propulsado por la potencia generada

Nuestra idea para este dispositivo es el de filtración de agua, por lo tanto no hemos querido usar un interruptor MOSFET para controlar su encendido ya que no se detendrá en ningún momento, y por lo tanto no precisará de ningún código, solamente de una fuente de alimentación. Ésta será mediante los puertos GND y la entrada de 5V del Arduino.

LCD + I2C

Hardware

Para poder mostrar los valores recogidos con el sensor de temperatura u otros mensajes usaremos una Pantalla de Cristal Liquido (LCD) 16×02, es decir 16 columnas y 2 lineas. Dispone de 16 pines:

  • Un pin de selección de registro (RS): que controla en qué parte de la memoria está escribiendo datos
  • Un pin de lectura/escritura (R/W) 
  • Un pin Habilitar que permite escribir en los registros
  • 8 pines de datos (D0 -D7)
  • Un pin display de contraste (Vo)
  • Un pin de fuente de alimentación (+5V and GND) 
  • Un LED para controlar la iluminación del fondo

Para poder conectarlo al Arduino necesitaríamos usar 6 pines digitales ademas de  un potenciometro. Para hacerlo más simple y legible hemos usado un controlador I2C que es un expansor de entradas y salidas digitales, ademas lleva un potenciometro integrado para controlar el contrastar. Ya que tiene los pines ordenados, debemos soldarlo al propio LCD, por lo tanto habremos reducido los pines de datos de 6 a 2. El I2C proporciona 4 pines:

  • 2 pines de alimentación; uno será la toma a tierra y el otro conectado a los 5V.
  • 2 pines SDA y SCL que estarán conectados a los puertos analógicos A4 y A5 respectivamente.
LCD
I2C
LCD sin I2C
LCD con I2C

Primero debemos incluir las librerías LiquidCrystal_I2C y Wire (accesible desde el propio Arduino). Declararemos el objeto de LiquidCrystal_I2C, para ello necesitaremos conocer su modulo (esto se puede hacer desde un sketch), en nuestro caso el 0x27, y también deberemos definir las columnas y filas que contiene.

En el setup usaremos la función .init() para inicializar el modulo I2C y el LCD, y el .backlight() para encender la luz del fondo del LCD. El resto de funciones que se usaran son similares a las de la librería incluida en el Arduino LiquidCrystal que son las siguientes:

  • .clear(): Borra la pantalla LCD y posiciona el cursor en la esquina superior izquierda (0,0)
  • .setCursor(x,y): Posiciona el cursor del LCD en la posición indicada por columna y fila
  • .print(): Escribe un texto o mensaje en el LCD, similar a escribir en el Serial 
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27,16,2);  

long tiempo;

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  tiempo = millis()/1000;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("TIEMPO: ");
  lcd.print(tiempo);
  delay(1000);
}

Problemas

El primer problema que hemos encontrado al realizar la practica ha sido el propio agua, pues cualquier contacto de esta con algún dispositivo no sumergible podría estropearlo o en el mejor de los casos esperar a que se secase para volver a utilizarlo.

Por otro lado, debido a que los componentes usados no son del todo óptimos, la durabilidad de estos ha supuesto problemas. Primeramente el sensor de nivel de agua la primera vez que lo usamos media, aunque no con mucha exactitud, el porcentaje del sensor que estaba cubierto por el agua, sin embargo con el uso se deterioró y únicamente detectaba agua desde la mitad para arriba. Por lo que nos vimos obligados a cambiar el código, pues en un principio estaba pensado para medir el porcentaje cubierto. En la versión final su función es la detección de agua. El sensor de temperatura también nos dio problemas, por un lado para encontrar las librerías precisas para poder usarlos, debido a que uno de ellos no se encontraba en la biblioteca de Arduino y algunas de GitHub estaban anticuadas. Y por otro lado conectarlo con Arduino también resultó difícil, debido a que no se podía conectar directamente al pin de entrada, sino que se necesitaba usar una resistencia pull-up. Finalmente, pese a que el día de la presentación pudimos hacer un a demostración sin problemas, para el día de la grabación general del proyecto la mini bomba de agua dejo de funcionar, por lo tanto en la grabación final la fuente no esta activada.

Asimismo pensamos en la posibilidad de poder conectar la pecera al móvil para poder controlar desde la distancia las funcionalidades de esta. No obstante tiene más complejidad de la que pueda aparentar.  Buscamos servidores ya creados para poder entablar una conexión entre estas y nuestro Arduino, pudimos encontramos dos; Blynk y la nube de la propia organización Arduino. La primera de estas tenia variedad de opciones para establecer conexión entre el software y la placa. Una de ellas era por Bluetooth, pero al comprar un modulo HC-05 nos dimos cuenta que era incompatible con los dispositivos iOS, por lo tanto tuvimos que devolverlo, pues no disponíamos de dispositivos Android. Otra opción era la conexión de Serie, para ello había que descargarse una librería el cual no estaba disponible en la propia biblioteca de Arduino y las de GitHub estaban anticuadas. La ultima opción era mediante conexión Wifi, sin embargo el Arduino Uno no dispone de esta funcionalidad integrada por lo que tendríamos que comprar un modulo Wifi, como sería el ESP8266, no obstante se trata de otro microcontrolador, por lo que descartamos pues el objetivo del proyecto era familiarizarse con Arduino y este salía de nuestro alcance. El segundo servidor era la Arduino IoT Cloud, pero encontramos el mismo problema; la necesidad de un shield Wifi. Pues por ahora, únicamente puede entablar conexión Wifi con los modelos MKR, Nano o Portenta.

Finalmente vimos que al juntar todos los componentes había errores que individualmente no habíamos visto, por ejemplo el LCD dejaba de funcionar pasado un tiempo. Pensamos en la posibilidad de que el Arduino no pudiese proporcionar la alimentación suficiente a todos los pines, pero finalmente llegamos a la conclusión de que el uso de un Delay al final del loop causaba interrupciones, por lo tanto cambiamos el código del comedero para que funcionase con la función millis().

Casos de Uso

Dado que se trata de un dispositivo autoregulado, esto supone que necesita la interacción mínima posible. Por lo tanto no es preciso diseñar un diagrama de estados pues los componentes de esta función independientemente. A continuación se muestran las funciones de la pecera:

  • Visualizar temperatura del agua
  • Visualizar señal de alerta en caso de fuga
  • Filtrar agua
  • Dar de comer al pez

Si tuviésemos la posibilidad de disponer de más fondos y tiempo, proponemos los siguientes cambios a añadir para poder completar de personalizarlo.

  • RTC: para controlar el tiempo exacto y poder mostrarlo en el LCD.
  • Sensor de pH: para medir con exactitud el pH de la pecera
  • Sensor de Electro Conductividad: Devuelve una respuesta analógica proporcional al nivel de sal que contiene el agua
  • Bomba de CO2: Ayuda con la fotosíntesis de la flora que contiene la pecera
  • Lampara LED: para ambientar
  • Ventilador: Necesario para reducir la temperatura producido por la lampara o en verano. Estaría conectado al sensor de temperatura.
  • Calentador: Necesario para aumentar la temperatura y no se enfríe mediante la filtración de agua y mantenerla constante durante la noche.

Código Completo

#include <Servo.h> //Libreria del ServoMotor
#include <OneWire.h> //Libreria DS18B20
#include <DallasTemperature.h> //Libreria DS18B20
#include <LiquidCrystal_I2C.h> //Libreria LCD
#include <Wire.h> //Libreria LCD

Servo ServoMotor;
LiquidCrystal_I2C LCD(0x27,16,2);  
#define pinSensorTmp 2
#define sensorNv 6
#define buzzer 7

// Instancia a las clases OneWire y DallasTemperature
OneWire OWObjeto (pinSensorTmp);
DallasTemperature DTSensorDS18B20 (&OWObjeto);

const long TMPO_ALIMENTAR = 43200000; //se alimenta a los peces cada 12 horas

long tiempo; //contador millis
long tmpoAlimentar; //contador para alimentar
int pos = 0; //posición del servoMotor
int valorSensorNv; //valor leido por el sensor de nivel
int valorSensorTmp; //valor leido por el sensor de temperatura

void setup() {
  Serial.begin(9600);
  pinMode(sensorNv, INPUT);
  pinMode(buzzer, OUTPUT);
  DTSensorDS18B20.begin();
  ServoMotor.attach (3);
  ServoMotor.write(pos);
  tmpoAlimentar = TMPO_ALIMENTAR;
  LCD.init();
  LCD.backlight();
}

void loop() {
  
  tiempo = millis();
  if (digitalRead(sensorNv) == LOW) {
    sonarAlarma();
    LCD.clear();
    LCD.setCursor(0, 0);
    LCD.print("!CUIDADO FUGA!");
    Serial.println("¡CUIDADO! Esta perdindo agua");
  } else {
    LCD.clear();
    recogerTemperatura (valorSensorTmp);
  }

  if (esHoraDeComer()) {
    girarServoMotor();
    tmpoAlimentar += TMPO_ALIMENTAR;
  }
  Serial.println (tiempo);
}

boolean esHoraDeComer() {
  // sera true cuando el tiempo(millis) sea proximo (1s de diferencia) 
  // al tiempo establecido para alimentar (43200000*n) 
  // (n= las veces que se ha alimentado desde el inicio del programa)

  if ((tiempo <= tmpoAlimentar+1000) && (tiempo >= tmpoAlimentar-1000)){
    return true;
  } else {
    return false;
  }
}

void girarServoMotor() {
  // Girar gradualmente de 0º a 180º
  for (pos = 0; pos < 180; pos += 1) {
    ServoMotor.write(pos);
    delay(15); 
  }
  for (pos = 180; pos >= 1; pos -= 1) {
    ServoMotor.write(pos);
    delay(15); 
  }
}

void sonarAlarma() {
  //generar tono de 523Hz durante 500ms, y detenerlo durante 500ms.
  tone(buzzer, 500, 300);
  delay(500);
}

void recogerTemperatura (int val) {
  // Mandamos comandos para toma de temperatura a los sensores
  DTSensorDS18B20.requestTemperatures();     

  // Mostrar por el LCD
  LCD.setCursor(0, 0);
  LCD.print("Temperatura: ");
  LCD.setCursor(0,1);
  LCD.print(DTSensorDS18B20.getTempCByIndex(0));
  LCD.print(" C");
  
  // Mostrar por el puerto Serial
  Serial.print("Temperatura: ");
  Serial.print(DTSensorDS18B20.getTempCByIndex(0));
  Serial.println("º C");
}

Video Complementario

También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *