Alarma de detección de robo, detección de perturbaciones y movimiento.
Nuestro proyecto consiste en un dispositivo de detección de perturbaciones en contenedores protegidos.
La forma de usarlo es muy simple, se enciende automáticamente cuando conectas la batería. Se debe dejar dentro de la mochila o contenedor, preferentemente encima de los contenidos a proteger, para que hubiese que mover la caja para acceder a ellos.
Al sentir desplazamiento, cambio de posición o de orientación se activa una alarma que permite detectar la posición de la caja y que no dejará de sonar hasta que se desconecte la batería del dispositivo. Al mismo tiempo, se envía una notificación al móvil del usuario para notificarle de que se ha detectado movimiento.
Código
Usamos C en el entorno de Arduino para programar el dispositivo. Necesitamos dos ficheros: uno para el arduino y otro para el módulo WiFi:
// ---------------------------------------------------- Librerías ------------------------------------------------------------------
#include "SoftwareSerial.h" // Comunicación con el módulo de sonido
#include "Wire.h" // Comunicación con el giroscopio (protocolo I2C)
// ---------------------------------------------------- Constantes del modulo de sonido --------------------------------------------
#define Start_Byte 0x7E
#define Version_Byte 0xFF
#define Command_Length 0x06
#define End_Byte 0xEF
#define Acknowledge 0x01
// ---------------------------------------------------- Variables del modulo de sonido ---------------------------------------------
SoftwareSerial mySerial(6, 7); // RX, TX, comunicación con el modulo de sonido
byte receive_buffer[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte volume = 0x00;
// ---------------------------------------------------- Variables del giroscopio-acelerómetro --------------------------------------
const int MPU_ADDR = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int offset[6] = {-3431, 1919, 1765, -9, 34, 71}; // Offset de calibracion para los valores del giroscopio-acelerometro
// ---------------------------------------------------- Funciones del modulo de sonido ---------------------------------------------
void execute_CMD(byte CMD, byte Par1, byte Par2) {
// Sends the command to the module
// Calculate the checksum (2 bytes)
word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);
// Build the command line
byte Command_line[10] = { Start_Byte, Version_Byte,
Command_Length, CMD, Acknowledge,
Par1, Par2, highByte(checksum),
lowByte(checksum), End_Byte};
// Send the command line to the module
for(byte k = 0; k < 10; k++) {
mySerial.write(Command_line[k]);
}
}
void set_eq(uint8_t eq) {
// Sets the state of EQ
execute_CMD(0x07, 0, eq); // Sets the EQ
delay(100);
}
void set_volume(uint8_t volume) {
// Sets the volume level
execute_CMD(0x06, 0, volume); // Set volume level
delay(100);
}
void module_init() {
// Resets the module and sets the EQ state,
// volume level, and plays first song on the
// storage device
execute_CMD(0x0C, 0, 0); // reset the module
delay(1000);
delay(100);
delay(100);
set_eq(0);
set_volume(0x19);
}
void play_first() {
// Plays first song on the storage device
execute_CMD(0x03, 0, 1); // Play first song
delay(100);
}
void loop_current() {
// loops current playing song
execute_CMD(0x19, 0, 0);
delay(100);
}
void activarModuloSonido(){
// Reproduce el sonido de alarma y lo pone en bucle
play_first();
loop_current();
}
// ---------------------------------------------------- Funciones del giroscopio-acelerómetro --------------------------------------
int * activarSensores(){
static int valores[6]; //Almacen de los valores del giroscopio y acelerómetro (Eje X, Eje Y, Eje Z de ambos sensores)
//Activación de los sensores
Wire.beginTransmission(MPU_ADDR);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
Wire.requestFrom(MPU_ADDR, 7*2, true); // request a total of 7*2=14 registers
//Valores del acelerometro
valores[0] = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
valores[1] = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
valores[2] = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
//Valores del giroscopio
valores[3] = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
valores[4] = Wire.read()<<8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
valores[5] = Wire.read()<<8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)
for(int i=0; i<6; i++){
valores[i] = valores[i] + offset[i];
}
//Retornamos el puntero
return valores;
}
bool hayMov (){
//hacer dos medidas y compararlas
bool movimientoDetectado = false;
int *p;
int i;
int medida1[6];
int medida2[6];
//primera medida
p = activarSensores();
for(i =0; i < 6; i++){ //guardamos los resultados en un array
medida1[i] = *(p+i);
}
delay(1000); //tiempo de espera entre medidas en ms
//segunda medida
p = activarSensores();
for(i =0; i < 6; i++){ //guardamos los resultados en un array
medida2[i] = *(p+i);
}
//comparamos ambos arrays
//teniendo en cuenta las respuestas de los sensores, 1500 parece un margen razonable para detectar movimiento
for(i =0; i<6; i++){
int diff = abs(medida1[i] - medida2[i]);
if (diff > 1000){ //el valor absoluto de la resta debe permanecer por debajo de n
movimientoDetectado = true;
}
}
return movimientoDetectado;
}
// ---------------------------------------------------- Funciones del modulo WiFi --------------------------------------------------
void activarModuloWiFi(){
// Se manda una señal al modulo WiFi para que mande notificaciones al movil. Se introduce un delay para asegurar la sincronización con el mismo
// al menos dos veces
digitalWrite(0, HIGH);
delay(3100);
digitalWrite(0, LOW);
}
void setup() {
// Inicialización del modulo WiFi
pinMode(0,OUTPUT);
digitalWrite(0,LOW);
// Inicialización del módulo de sonido y de su canal de comunicación
mySerial.begin(9600);
delay(1000);
module_init();
// Inicialización del giroscopio-acelerómetro
Wire.begin();
Wire.beginTransmission(MPU_ADDR); // Begins a transmission to the I2C slave (GY-521 board)
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
delay(5000);
}
void loop() {
// Si se detecta movimiento en el giroscopio-acelerómetro, se activan tanto el modulo de sonido (para activar el altavoz)
// como el módulo Wifi, y se bloquea el programa en un bucle infinito, ya que para terminarlo, hay que apagar el arduino
// por completo
if(hayMov()){
activarModuloSonido();
activarModuloWiFi();
while(true);
}
}
WiFi:
/************
GeeksTips.com
ESP8266 Arduino Tutorial - Push notification messages example
Arduino code example
www.geekstips.com
*/
#include <ESP8266WiFi.h>
// PushingBox scenario DeviceId code and API
String deviceId = "v316966B1F2622E0";
const char* logServer = "api.pushingbox.com";
const char* ssid = "MotorolaOneVision";
const char* password = "HolaMundo3";
bool primerAcceso = true;
void sendNotification(String message){
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
WiFiClient client;
if (client.connect(logServer, 80)) {
String postStr = "devid=";
postStr += String(deviceId);
postStr += "&message_parameter=";
postStr += String(message);
postStr += "\r\n\r\n";
client.print("POST /pushingbox HTTP/1.1\n");
client.print("Host: api.pushingbox.com\n");
client.print("Connection: close\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
}
client.stop();
}
void setup() {
pinMode(3,FUNCTION_3);
pinMode(1,FUNCTION_3);
}
void loop() {
while(true){
if(digitalRead(3) == HIGH){
if(!primerAcceso){
sendNotification("¡Te estan robando!");
} else{
primerAcceso = false;
}
delay(1500);
}
}
}
Hardware
Módulos y otros materiales:
- Placa Arduino Uno
- Módulo WiFi AZ-Delivery ESP8266-01S
- AZ-Delivery GY-521 MPU-6050 3-axis Gyroscope and Acceleration sensor module
- AZ-Delivery MP3 DFPlayer Mini Module
- Altavoz
- Tarjeta SD 32 GB
- Resistencia 1K
Esquema de conexiones:
Problemas encontrados
El datasheet del módulo WiFi no estaba documentado por completo: No se explicaba como subir nuevo código a través de Arduino (sí con módulos externos), además de que este se activaba en cuanto le llegaba corriente, y se tenía que activar cuando el giroscopio detectase movimiento.
El giroscopio no se conectaba bien hasta que lo soldamos, así que fue difícil hacer pruebas al principio.
Finalmente, todos los problemas se solucionaron a tiempo y estamos contentos con el resultado.
Documentación
Para más información, se puede consultar el siguiente archivo PDF: