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:

Prueba

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 *