Buzón inteligente
Autores
- Mohibul Alom
- Cristofer Tamaral Martín
- Adrián Martín Martín
Objetivo
Tenemos como objetivo desarrollar un proyecto de un sistema empotrado o embebido. Estos sistemas están orientados en cubrir una necesidad en concreto. En nuestro caso, hemos optado por integrar funciones nuevas a nuestro buzón que todos tenemos en nuestras casas. Además, tenemos como finalidad aportar seguridad de saber en todo momento el contenido introducido en nuestras casillas casi a diario.
Tareas
- Tarea 1: ver el contenido del buzón desde cualquier sitio.
- Tarea 2: detectar cuando se introducido nuevo contenido: cartas, revistas, etc.
- Tarea 3: tomar una foto del contenido del buzón después de detectar dicho evento.
- Tarea 4: enviar la foto tomada a nuestra red social, por ejemplo, Telegram.
- Tarea 5: tener un mecanismo para extraer el contenido del buzón mediante un comando.
Materiales y costes
Placa Arduino Mega: 13.99 €
Módulo wifi: placa ESP32 Y módulo de cámara: OV2640: 11.99 €
Sensor: 1.80 €
Motores: 6.99 €
Driver para el motor L298N: 6.90 €
Madera MDF, bisagra, cerrojo y clavos: 9.90 €
Rueda: 0 € (fabricada con restos de madera).
Total: 51.57 €
Diseño
Conexiones
Montaje
Para realizar la construcción primero se dibujó un boceto en el cual quedaban establecidas las medidas y como iban a ser cada una de las partes de nuestro buzón, quedando los lados con las siguientes medidas:
- Laterales 25×50 cm.
- Techo y suelo 30×20 cm.
- Parte anterior y posterior 30×25 cm.
- Rampa 32×20 cm.
Estas partes fueron cortadas y posteriormente se procedió a trabajar sobre cada una de ellas. En el techo se realizó una hendidura que actúa como hueco para introducir las cartas. En la cara frontal del buzón se realizó una segunda hendidura la cual actuará como salida de las cartas. En una de las partes laterales se colocaron unas bisagras y un cerrojo para que este lateral actuara como puerta para poder acceder al interior del buzón. En el otro lateral se colocó un motor el cual sujeta una “puerta” la cual se abre y se cierra imitando el mecanismo de un peaje para dejar salir las cartas o mantenerlas dentro. En la rampa se colocó otro motor conectado a una rueda fabricada con madera, esto serviría para impulsar las cartas hacia el exterior, a la rampa también se le colocaron unos bordes laterales para que las cartas si se movían hacia los lados no cayeran ni se quedaran enganchadas en el interior del buzón. La protoboard, la placa de Arduino y el resto de los componentes necesarios para el correcto funcionamiento del buzón fueron colocados en la parte interior del techo fijados con tornillos.
Código
Código de la placa Arduino Mega:
1
2 //Boton
3 const int buttonPIN = 30;
4
5
6 //Tapa
7 int IN1 = 5; // IN1 de L298N a pin digital 5
8 int IN2 = 6; // IN2 de L298N a pin digital 6
9 int ENA = 7; // ENA de L298N a pin digital 7
10 int VELOCIDAD = 200; // variable para almacenar valor de velocidad
11
12 //rampa
13 int IN3 = 8; // IN1 de L298N a pin digital 8
14 int IN4 = 9; // IN2 de L298N a pin digital 9
15 int ENB = 10; // ENA de L298N a pin digital 10
16 int VELOCIDAD_RAMPA = 200; // variable para almacenar valor de velocidad
17
18
19 //***********************************************************
20
21 int op = 100;
22 int opB = 0;
23
24 //pin para el sensor de infrarrojo debe ser PWM (pines con simbolo "~")
25 const int sensorPIN = 4;
26
27 void setup() {
28 pinMode(sensorPIN, INPUT);
29 Serial.begin(115200); // opens serial port, sets data rate to 9600 bps
30
31 pinMode(buttonPIN, INPUT); //pin
32
33 pinMode(12, OUTPUT); //pin led
34 pinMode(13, OUTPUT); //pin led
35
36 pinMode(IN1, OUTPUT); // pin 5 como salida
37 pinMode(IN2, OUTPUT); // pin 6 como salida
38 pinMode(ENA, OUTPUT); // pin 7 como salida
39
40 pinMode(IN3, OUTPUT); // pin 8 como salida
41 pinMode(IN4, OUTPUT); // pin 9 como salida
42 pinMode(ENA, OUTPUT); // pin 10 como salida
43
44 }
45
46 void loop() {
47
48 int button = digitalRead(buttonPIN);
49 int sensor = digitalRead(sensorPIN);
50
51 if (sensor != HIGH) {
52 Serial.write(op);
53 digitalWrite(12, HIGH);
54 delay(500);
55 } else {
56 digitalWrite(12, LOW);
57 }
58
59
60 if (button == HIGH) {
61 Serial.println(button);
62 expulsarcarta();
63 digitalWrite(13, HIGH);
64 } else {
65 digitalWrite(13, LOW);
66 }
67 }
68
69
70 void expulsarcarta() {
71 //subimos tapa arriba
72 analogWrite(ENA, VELOCIDAD);
73 digitalWrite(IN1, HIGH);
74 digitalWrite(IN2, LOW);
75 delay(1000);
76
77 //paramos el motor de la tapa
78 digitalWrite(ENA, LOW);
79
80 //Iniciamos el motor de la rampa hacia adelante
81 analogWrite(ENB, VELOCIDAD_RAMPA);
82 digitalWrite(IN3, LOW);
83 digitalWrite(IN4, HIGH);
84 delay(5000);
85
86 //paramos el motor de la rampa
87 digitalWrite(ENB, LOW);
88
89 //bajamos la tapa hacia abajo
90 analogWrite(ENA, VELOCIDAD);
91 digitalWrite(IN1, LOW);
92 digitalWrite(IN2, HIGH);
93 delay(1000);
94
95 //paramos el motor de la tapa
96 digitalWrite(ENA, LOW);
97
98 }
Código de la placa ESP32CAM:
1 #include <Arduino.h>
2 #include <WiFi.h>
3 #include <WiFiClientSecure.h>
4 #include "soc/soc.h"
5 #include "soc/rtc_cntl_reg.h"
6 #include "esp_camera.h"
7 #include <UniversalTelegramBot.h>
8 #include <ArduinoJson.h>
9
10 const char* ssid = "MiFibra-F929-24G";
11 const char* password = "FcoVnHm9";
12
13 // Initialize Telegram BOT
14 String BOTtoken = "1539204514:AAE1ezuvj1cLQ8W3PbbLAR3LvGc9Ciwv00U"; // your Bot Token (Get from Botfather)
15
16 // Use @myidbot to find out the chat ID of an individual or a group
17 // Also note that you need to click "start" on a bot before it can
18 // message you
19 String CHAT_ID = "1529030408";
20
21 bool sendPhoto = false;
22
23 WiFiClientSecure clientTCP;
24 UniversalTelegramBot bot(BOTtoken, clientTCP);
25
26 #define FLASH_LED_PIN 4
27 bool flashState = LOW;
28
29 //Checks for new messages every 1 second.
30 int botRequestDelay = 1000;
31 unsigned long lastTimeBotRan;
32
33 //CAMERA_MODEL_AI_THINKER
34 #define PWDN_GPIO_NUM 32
35 #define RESET_GPIO_NUM -1
36 #define XCLK_GPIO_NUM 0
37 #define SIOD_GPIO_NUM 26
38 #define SIOC_GPIO_NUM 27
39
40 #define Y9_GPIO_NUM 35
41 #define Y8_GPIO_NUM 34
42 #define Y7_GPIO_NUM 39
43 #define Y6_GPIO_NUM 36
44 #define Y5_GPIO_NUM 21
45 #define Y4_GPIO_NUM 19
46 #define Y3_GPIO_NUM 18
47 #define Y2_GPIO_NUM 5
48 #define VSYNC_GPIO_NUM 25
49 #define HREF_GPIO_NUM 23
50 #define PCLK_GPIO_NUM 22
51
52
53 void configInitCamera() {
54 camera_config_t config;
55 config.ledc_channel = LEDC_CHANNEL_0;
56 config.ledc_timer = LEDC_TIMER_0;
57 config.pin_d0 = Y2_GPIO_NUM;
58 config.pin_d1 = Y3_GPIO_NUM;
59 config.pin_d2 = Y4_GPIO_NUM;
60 config.pin_d3 = Y5_GPIO_NUM;
61 config.pin_d4 = Y6_GPIO_NUM;
62 config.pin_d5 = Y7_GPIO_NUM;
63 config.pin_d6 = Y8_GPIO_NUM;
64 config.pin_d7 = Y9_GPIO_NUM;
65 config.pin_xclk = XCLK_GPIO_NUM;
66 config.pin_pclk = PCLK_GPIO_NUM;
67 config.pin_vsync = VSYNC_GPIO_NUM;
68 config.pin_href = HREF_GPIO_NUM;
69 config.pin_sscb_sda = SIOD_GPIO_NUM;
70 config.pin_sscb_scl = SIOC_GPIO_NUM;
71 config.pin_pwdn = PWDN_GPIO_NUM;
72 config.pin_reset = RESET_GPIO_NUM;
73 config.xclk_freq_hz = 20000000;
74 config.pixel_format = PIXFORMAT_JPEG;
75
76 //init with high specs to pre-allocate larger buffers
77 if (psramFound()) {
78 config.frame_size = FRAMESIZE_UXGA;
79 config.jpeg_quality = 10; //0-63 lower number means higher quality
80 config.fb_count = 2;
81 } else {
82 config.frame_size = FRAMESIZE_SVGA;
83 config.jpeg_quality = 12; //0-63 lower number means higher quality
84 config.fb_count = 1;
85 }
86
87 // camera init
88 esp_err_t err = esp_camera_init(&config);
89 if (err != ESP_OK) {
90 Serial.printf("Camera init failed with error 0x%x", err);
91 delay(1000);
92 ESP.restart();
93 }
94
95 // Drop down frame size for higher initial frame rate
96 sensor_t * s = esp_camera_sensor_get();
97 s->set_framesize(s, FRAMESIZE_CIF); // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
98 }
99
100 void handleNewMessages(int numNewMessages) {
101 Serial.print("Handle New Messages: ");
102 Serial.println(numNewMessages);
103
104 for (int i = 0; i < numNewMessages; i++) {
105 String chat_id = String(bot.messages[i].chat_id);
106 if (chat_id != CHAT_ID) {
107 bot.sendMessage(chat_id, "Unauthorized user", "");
108 continue;
109 }
110
111 // Print the received message
112 String text = bot.messages[i].text;
113 Serial.println(text);
114
115 String from_name = bot.messages[i].from_name;
116 if (text == "/start") {
117 String welcome = "Welcome , " + from_name + "\n";
118 welcome += "Use the following commands to interact with the ESP32-CAM \n";
119 welcome += "/photo : takes a new photo\n";
120 welcome += "/flash : toggles flash LED \n";
121 bot.sendMessage(CHAT_ID, welcome, "");
122 }
123 if (text == "/flash") {
124 flashState = !flashState;
125 digitalWrite(FLASH_LED_PIN, flashState);
126 Serial.println("Change flash LED state");
127 }
128 if (text == "/photo") {
129 sendPhoto = true;
130 Serial.println("New photo request");
131 }
132 }
133 }
134
135 String sendPhotoTelegram() {
136 const char* myDomain = "api.telegram.org";
137 String getAll = "";
138 String getBody = "";
139
140 camera_fb_t * fb = NULL;
141 fb = esp_camera_fb_get();
142 if (!fb) {
143 Serial.println("Camera capture failed");
144 delay(1000);
145 ESP.restart();
146 return "Camera capture failed";
147 }
148
149 Serial.println("Connect to " + String(myDomain));
150
151
152 if (clientTCP.connect(myDomain, 443)) {
153 Serial.println("Connection successful");
154
155 String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + CHAT_ID + "\r\n--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
156 String tail = "\r\n--RandomNerdTutorials--\r\n";
157
158 uint16_t imageLen = fb->len;
159 uint16_t extraLen = head.length() + tail.length();
160 uint16_t totalLen = imageLen + extraLen;
161
162 clientTCP.println("POST /bot" + BOTtoken + "/sendPhoto HTTP/1.1");
163 clientTCP.println("Host: " + String(myDomain));
164 clientTCP.println("Content-Length: " + String(totalLen));
165 clientTCP.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
166 clientTCP.println();
167 clientTCP.print(head);
168
169 uint8_t *fbBuf = fb->buf;
170 size_t fbLen = fb->len;
171 for (size_t n = 0; n < fbLen; n = n + 1024) {
172 if (n + 1024 < fbLen) {
173 clientTCP.write(fbBuf, 1024);
174 fbBuf += 1024;
175 }
176 else if (fbLen % 1024 > 0) {
177 size_t remainder = fbLen % 1024;
178 clientTCP.write(fbBuf, remainder);
179 }
180 }
181
182 clientTCP.print(tail);
183
184 esp_camera_fb_return(fb);
185
186 int waitTime = 10000; // timeout 10 seconds
187 long startTimer = millis();
188 boolean state = false;
189
190 while ((startTimer + waitTime) > millis())
191 {
192 Serial.print(".");
193 delay(100);
194 while (clientTCP.available())
195 {
196 char c = clientTCP.read();
197 if (c == '\n')
198 {
199 if (getAll.length() == 0) state = true;
200 getAll = "";
201 }
202 else if (c != '\r')
203 getAll += String(c);
204 if (state == true) getBody += String(c);
205 startTimer = millis();
206 }
207 if (getBody.length() > 0) break;
208 }
209 clientTCP.stop();
210 Serial.println(getBody);
211 }
212 else {
213 getBody = "Connected to api.telegram.org failed.";
214 Serial.println("Connected to api.telegram.org failed.");
215 }
216 return getBody;
217 }
218
219 void setup() {
220 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
221 // Init Serial Monitor
222 Serial.begin(115200);
223
224 // Set LED Flash as output
225 pinMode(FLASH_LED_PIN, OUTPUT);
226 digitalWrite(FLASH_LED_PIN, flashState);
227
228 // Config and init the camera
229 configInitCamera();
230
231 // Connect to Wi-Fi
232 WiFi.mode(WIFI_STA);
233 Serial.println();
234 Serial.print("Connecting to ");
235 Serial.println(ssid);
236 WiFi.begin(ssid, password);
237 while (WiFi.status() != WL_CONNECTED) {
238 Serial.print(".");
239 delay(500);
240 }
241 Serial.println();
242 Serial.print("ESP32-CAM IP Address: ");
243 Serial.println(WiFi.localIP());
244 }
245
246 void loop() {
247
248 int men = 0;
249
250 if (Serial.available()) {
251 men = Serial.read();
252 if (men == 100) {
253 bot.sendMessage(CHAT_ID, "DETECTADO PRESENCIA", "");
254 digitalWrite(FLASH_LED_PIN, HIGH);
255 sendPhotoTelegram();
256 digitalWrite(FLASH_LED_PIN, LOW);
257 }
258 }
259
260
261 if (sendPhoto) {
262 Serial.println("Preparing photo");
263 digitalWrite(FLASH_LED_PIN, HIGH);
264 sendPhotoTelegram();
265 digitalWrite(FLASH_LED_PIN, LOW);
266 sendPhoto = false;
267 }
268 if (millis() > lastTimeBotRan + botRequestDelay) {
269 int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
270 while (numNewMessages) {
271 Serial.println("got response");
272 handleNewMessages(numNewMessages);
273 numNewMessages = bot.getUpdates(bot.last_message_received + 1);
274 }
275 lastTimeBotRan = millis();
276 }
277 }
Dificultades y soluciones
Una de las dificultades que se nos presenta es la falta de ruedas para realizar el mecanismo de la rampa. Esto se solucionó cortando una madera con el diámetro requerido de madera la cual se recubrió con una cinta de impresora para que no resbalaran las cartas por ella.
Otra complicación que surgió tras la construcción del buzón fue que el motor que permitía que las cartas salieran no era capaz de levantar esta pieza que cerraba el buzón por lo que hubo que sustituirla por otro material más ligero.
Además, hemos tenido muchos problemas al intentar enviar una señal desde telegram a la placa de Arduino para que una vez llegada la señal activara el proceso de extracción de las cartas.
La solución que encontramos a este contratiempo fue poner un botón que sustituyera la señal enviada por telegram.
Conclusiones
Nos hacía bastante ilusión hacer un proyecto de este tipo entre nuestro grupo de compañeros, era nuestra primera vez con este tipo de materiales. Es una asignatura que nos despierta gran interés al ser muy visual e interactuar físicamente con los componentes.
Durante la realización del proyecto hemos tenido bastantes problemas con la logística al tener un integrante del grupo sin poder desplazarse por problemas de salud, también con la entrega de los componentes por parte de amazon y con la comunicación de diferentes módulos, hemos usado módulos bastante complejos y hemos tenido ideas muy ambiciosas como usar el buzón mediante una red social como telegram.
Esto nos ha llevado bastante tiempo y nos ha dado bastantes problemas. A pesar de ello hemos intentado hacerlo lo mejor posible dentro de nuestros conocimientos.