Pavlov’s Feeder. Un dispensador automático de comida para mascotas con Arduino
Contenidos
Introducción
El proyecto consiste en un dispensador automático de comida para mascotas que incluye un reloj para poder programar la dispensa de comida en un horario determinado. Cuando se ha rellenado el bol, el dispensador emite un sonido que intenta emular el de una campana para avisar a la mascota.
Autoría
Proyecto realizado por el grupo 4 de la asignatura Sistemas Empotrados y Tiempo Real del curso 2018/2019 en el Campus de Móstoles de la URJC, formado por:
- Marina Cabeza González
- Patricia Sánchez Fernández
- Celia Velasco Martínez
Componentes utilizados
Los componentes de los que no se indica el precio son aquellos que ya teníamos o hemos reciclado.
Componentes electrónicos
- Placa de Arduino Uno (proporcionada por el profesor)
- Servomotor (9,99€)
- Pantalla LCD 16×2 con botones de Keyestudio (8,99€)
- RTC DS3231 (7,09€)
- Altavoz
- Cables de puente hembra a hembra (3,90€)
- Cables macho a macho
- Protoboard
Componentes no electrónicos
- Tubo de PVC (3,08€)
- Codo de PVC (0,52€)
- Botella de agua de 2,5L (0,49€)
- Cuenco de plástico (0,75€)
- Caja de madera
- Bridas y cinta aislante
- Placa de metacrilato
- Clip
Montaje
Diseño inicial
En el diseño inicial teníamos pensado poner una báscula que pesara
la comida necesaria para la mascota. En el diseño final no incluimos báscula y
la cantidad de comida se mide en el tiempo que se deja abierto el paso de esta
por el tubo (que se bloquea y desbloquea mediante una pestaña accionada por el
servomotor). También se disponía de ledes para indicar el estado del
dispensador, que finalmente no se incluyeron al realizar la pantalla LCD la
misma función.
Componentes electrónicos
Hemos montado el circuito de nuestro proyecto como se indica en el siguiente diagrama de conexiones realizado en la herramienta Fritzing (puedes hacer click en la imagen para verla más de cerca).
Estructura del dispensador
En cuanto a la estructura del dispensador, hemos reciclado una caja de madera que hemos pintado de blanco y a la que hemos realizado los agujeros necesarios para incluir una garrafa de 3L que almacena el pienso y un bol, ambos comunicados mediante un tubo y un codo de PVC. La caja incluye una tapa extraíble que permite acceder al resto de componentes con facilidad.
En el siguiente GIF se muestra el funcionamiento del servomotor.
Aspecto final del proyecto:
Problemas encontrados
En un principio pensamos incluir una báscula para comprobar
la cantidad de pienso que se vertía al bol y también la que quedaba en la
garrafa, pero nos encontramos con que la construcción de una báscula para
Arduino casi requería de un proyecto paralelo por su complejidad. Por lo tanto,
decidimos no incluirla y controlar el pienso dispensado mediante el tiempo de
apertura de la trampilla controlada por el servomotor.
hora de llevar a cabo nuestro proyecto definitivo ha sido el de almacenar la
hora actual en el RTC. Nos llevó un tiempo dar con la librería adecuada para el chip que adquirimos y conseguir que el tiempo no se inicializase cada vez a la hora en la que
se compiló nuestro programa.
servomotor porque se movía descontroladamente. Al principio pusimos un alambre
para conectar el servo a la placa, pero este se acababa doblando y terminamos
poniendo un clip más resistente.
Posibles mejoras
Nuestro dispensador es compacto y de un tamaño reducido
porque está pensado para mascotas de talla pequeña o mediana. En el caso de
necesitarse para una mascota más grande, se podría sacar el cuenco fuera de la
caja, alargar el tubo y sujetar el cuenco a la caja mediante un soporte para
que no se mueva.
para comprobar si la mascota ha comido o si por el contrario queda pienso en el
cuenco. Incluso se podría utilizar IoT y enviar un mensaje al móvil del dueño
indicándole que su mascota no se ha terminado el pienso.
cambiar la hora actual sin tener que cargar en la placa el sketch para inicializar la hora en el RTC, lo que convertiría el producto en algo más usable para personas sin conocimientos de informática.
Código
La explicación de nuestro código podéis encontrarla en los comentarios dentro del mismo y en el vídeo que se incluye más arriba. El código lo hemos implementado y subido a la placa mediante el IDE oficial de Arduino para Windows.
Librerías utilizadas
Hemos utilizado las librerías Arduino.h, LiquidCrystal.h, Wire.h y Servo.h, incluidas por defecto en el IDE de Arduino, y también la librería RTClib.h, que puede encontrarse en el siguiente repositorio de GitHub: https://github.com/adafruit/RTClib.
Sketch principal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
#include <Arduino.h> #include <LiquidCrystal.h> /* Library for the LCD */ #include <Wire.h> #include "RTClib.h" #include <Servo.h> /* Initialize the library with interface pins numbers: */ LiquidCrystal lcd(8, 9, 4, 5, 6, 7); int val; /* Speaker (buzzer): */ int speakerPin = 13; /* Real time clock: */ RTC_DS3231 rtc; /* Servo: */ Servo myservo; int pos = 0; /* Variable to store the servo position */ int servoPin = 10; DateTime now; byte hour, minute; String h, m; int feedHour = 14; int feedMin = 0; boolean foodTime = true; void setup() { /* Set speaker pin as an output pin: */ pinMode(speakerPin, OUTPUT); /* Set up LCD's number of columns and rows: */ lcd.begin(16, 2); /* Start RTC: */ rtc.begin(); } void loop() { now = rtc.now(); printTime(now); /* LCD buttons are all connected to A0 pin with this values: * 0-50: UP * 50-150: RIGHT * 150-300: DOWN * 300-500: LEFT * 500-750: SELECT */ val = analogRead(A0); if ((val >= 500) && (val <= 750)) { // SELECT setFeedHour(); delay(1000); } now = rtc.now(); printTime(now); delay(2000); if ((feedHour == now.hour()) && (feedMin == now.minute()) && foodTime) { feed(); } /* We use 'foodTime' so food doesn't get served twice * if the feed routine ends in less than a minute. */ if (feedMin != now.minute()) { foodTime = true; } } void feed() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Sirviendo comida"); /* Food gets served: */ /* Attach servo on pin 10 (We attach servo only when * we need it and detach it afterwards to stop it * from shaking) */ myservo.attach(servoPin); /* Servo moves to open lid for food to fall through. * 'pos' goes from 0 to 180 degrees in steps of 1 degree * and then gets written to servo*/ for (pos = 0; pos <= 120; pos += 1) { myservo.write(pos); /* Wait 15ms for the servo to reach the position */ delay(15); } delay(1000); /* Go back from 180 to 0 degrees to close the lid: */ for (pos = 120; pos >= 0; pos -= 1) { myservo.write(pos); delay(15); } delay(3000); /* Detach servo: */ myservo.detach(); bell(); foodTime = false; } void bell() { for (int i=0; i<6; i++) { /* Bell sound: */ tone(speakerPin, 1915); delay(700); tone(speakerPin, 1700); delay(700); tone(speakerPin, 1519); delay(700); noTone(speakerPin); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Hora de la"); lcd.setCursor(0, 1); lcd.print("comida!!!!"); delay(5000); now = rtc.now(); printTime(now); delay(5000); } } /* Prints actual time and feed time. * If hour or minute is just one digit, a zero * will be added for formatting purposes */ void printTime(DateTime t) { /* Actual time */ lcd.setCursor(0, 0); lcd.print("H. actual: "); hour = t.hour(); if (hour < 10) { h = "0" + String(hour); } else { h = String(hour); } lcd.print(h); lcd.print(':'); minute = t.minute(); if (minute < 10) { m = "0" + String(minute); } else { m = String(minute); } lcd.print(m); /* Feed hour */ lcd.setCursor(0, 1); lcd.print("H. comida: "); if (feedHour < 10) { h = "0" + String(feedHour); } else { h = String(feedHour); } lcd.print(h); lcd.print(':'); if (feedMin < 10) { m = "0" + String(feedMin); } else { m = String(feedMin); } lcd.print(m); return; } void setFeedHour() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Cambiar hora de"); lcd.setCursor(0, 1); lcd.print("comida: "); int hourAux = feedHour; while(true) { lcd.setCursor(8, 1); if (hourAux < 10) { lcd.print("0"); lcd.print(hourAux); } else { lcd.print(hourAux); } lcd.setCursor(10, 1); lcd.print(':'); lcd.setCursor(11, 1); if (feedMin < 10) { m = "0" + String(feedMin); } else { m = String(feedMin); } lcd.print(m); delay(200); /* We check which button is being pressed */ val=analogRead(A0); if ((val>=50) && (val<=150)) { /* UP + 1 hour */ hourAux = (hourAux + 1) % 24; } else if ((val>=150) && (val<=300)) { /* DOWN - 1 hour */ hourAux = hourAux - 1; if (hourAux < 0) { hourAux = 23; } } else if ((val>=300)&&(val<=500)) { /* LEFT cancel */ break; } if ((val>=0)&&(val<=50)) { /* RIGHT save */ feedHour = hourAux; setFeedMin(); break; } } return; } void setFeedMin() { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Cambiar min. de"); lcd.setCursor(0, 1); lcd.print("comida: "); int minAux = feedMin; while(true) { lcd.setCursor(8, 1); if (feedHour < 10) { h = "0" + String(feedHour); } else { h = String(feedHour); } lcd.print(h); lcd.setCursor(10, 1); lcd.print(':'); lcd.setCursor(11, 1); if (minAux < 10) { m = "0" + String(minAux); } else { m = String(minAux); } lcd.print(m); delay(200); /* We check which button is being pressed */ val = analogRead(A0); if((val>=50) && (val<=150)) { /* UP + 1 min */ minAux = (minAux + 1) % 60; } else if((val>=150) && (val<=300)) { /* DOWN - 1 min */ minAux = minAux - 1; if (minAux < 0) { minAux = 59; } } else if((val>=300) && (val<=500)) { /* LEFT cancel */ break; } else if((val>=500) &&( val<=750)) { /* SELECT save */ feedMin = minAux; break; } } return; } |
Sketch auxiliar para poner el reloj en hora
Este código solo necesita ejecutarse una vez para inicializar el chip RTC con la hora actual. El chip RTC mantendrá la hora gracias a la pila que lleva incorporada.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <Wire.h> #include "RTClib.h" RTC_DS3231 rtc; void setup() { rtc.begin(); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); /* The rest of the code is not necessary to set the time, * we're just making sure it was set correctly: */ Serial.begin(9600); DateTime now = rtc.now(); printDate(now); } void loop() { } void printDate(DateTime date) { Serial.print(date.year(), DEC); Serial.print('/'); Serial.print(date.month(), DEC); Serial.print('/'); Serial.print(date.day(), DEC); Serial.print(" "); Serial.print(date.hour(), DEC); Serial.print(':'); Serial.print(date.minute(), DEC); Serial.print(':'); Serial.print(date.second(), DEC); Serial.println(); } |
Conclusiones
Este proyecto nos ha servido para familiarizarnos con Arduino y su entorno de desarrollo, así como todas las posibilidades que ofrece.
Anexo: Manual de funcionamiento
Este dispositivo es un dispensador automático de comida de
mascotas que incorpora un reloj programable. Para utilizar este producto siga
los siguientes pasos:
- Enchufe el producto a la corriente.
- Se iluminará la pantalla, en la que aparecerá la hora actual y la hora de la comida predeterminada (las 14:00).
- Para modificar dicha hora pulse el botón SELECT durante 1-2 segundos.
- Una vez pulsado aparecerá un mensaje pidiendo el cambio de hora. Mediante los botones UP y DOWN puede incrementar o disminuir la hora.
- Cuando haya modificado la hora pulse RIGHT para cambiar los minutos igual que en el paso 4.
- Puede cancelar cualquiera de estas acciones pulsando LEFT.
- Para guardar la nueva hora de la comida pulse SELECT.
- Espere a la hora programada y el dispensador echará la comida para su mascota.
- Recuerde rellenar el dispositivo con el pienso favorito de su mascota.
Hola buen día , me parece perfecto su proyecto.
El los diagramas e imágenes ya no aparecen
Habrá posibilidad que me los puedan compartir al correo
carlosgs.trejo@gmail.com
Arreglado. Ya se pueden ver de nuevo.
Un saludo
hola que tal, habrá manera que me puedas pasar el proyecto en .ino de tu código?
No he puedo ejecutarlo correctamente, si es así por correo, ya que me pareció un proyecto importante y me gustaría mejorarlo
Hola, ustedes me podrían ayudar con una duda tengo la ultima versión del IDE del Arduino eso no afectara la libreria RTClib que ustedes me proporcionan en el link? O Es Algún Otro Error?…. Por que lo que sucede es que cuando compilo la progra me aparece»error compilando para la tarjeta arduino uno» porfavooor necesito de su ayuda!!!!
Hola, podrian ayudarme con el codigo lo que pasa es que al reescribirlo en Arduino IDE no me permite añadir la libreria Arduino.h asi como otras librerias, al momento de ejecutar el codigo me aparece error