PROYECTOS

PROYECTOS

GIRASOL SOLAR





Con dos LDR y un servo construiremos un girasol que gire siguiendo una fuente de luz.



CÓDIGO
 

#include <servo.h>
servo miservo;
#define pinLdrDcha 4
#define pinLdrIzda 5
#define pinServo 3
#define zonaCero 20  //margen parado
int pos=90;  //angulo de posición 

void setup() {
   pinMode(pinLdrDcha, INPUT);
   pinMode(pinLdrIzda,INPUT);
   miservo.attach(pinServo);
   miservo.write(pos); // iniciamos el servo en 90º


void loop() {     //leemos la luz que recogen los dos LDRs
     int luzDcha=analogRead(pinLdrDcha);
     int luzIzda=analogRead(pinLdrIzda);
     if (luzDcha>luzIda + zonaCero) {
          girarDcha();
     }
     if (luzIzda>luzDcha + zonaCero) {
          girarIzda();
     }
}

void girarDcha() {
  if (pos<180) {
    pos++;
    miservo.write(pos);
    delay(20);
  }


void girarIzda() {
  if (pos>0) {
    pos--;
    miservo.write(pos);
    delay(20);
  }
}



 

PARKING CON BARRERA

portada-parkingEn esta práctica vamos a simular el siguiente escenario.Queremos controlar el acceso a un garaje con 3 plazas de aparcamiento. Para acceder al garaje hay una barrera controlada electrónicamente. Unas luces nos indican las plazas libres que hay en el garaje. Cuando hay plazas libres, el sistema deber permitir la entrada al garaje abriendo la barrera y modificando las luces de indicación. Si no hay ninguna plaza libre, la barrera no se abrirá hasta que no haya salido algún vehículo. Usaremos los 3 leds de Edubásica para señalizar el número de plazas libres. Un servo conectado al pin digital 7 accionará la barrera. 2 sensores (dentro y fuera del garaje) nos indicarán cuándo hay un vehículo intentando salir/entrar. Los sensores pueden ser de ultrasonidos, de infrarrojos, etc.


Colocaremos el servo con la barrera entre los sensores de entrada y salida. 
Las conexiones con Edubásica son simples:
  • Servo: mediante las 3 conexiones del JP3 que lo enlazan al pin7.
  • Sensores: Conexiones de alimentación y tierra a las clemas de Edubásica y el cable de señal a las entradas analógicas A4 y A5.
  • Leds: Los incluidos en Edubásica en los pines digitales 3, 4 y 5.
sensores-servobarrera



El algoritmo del programa se basa en ir monitorizando cuándo se activa el sensor de entrada o de salida. En nuestro caso los sensores son 2 Sharp GPD2D12 de infrarrojos. Tenemos una variable entera: coches que nos indica los vehículos que hay dentro del garaje.Se incluye una sencilla función que enciende las luces de aviso según el contenido de la variable coches.
// Barrera para parking This example code is in the public domain.

#include <Servo.h> 

int led1=3, led2=4, led3=5; //Declaramos los leds de indicacion
int in=A4, out=A5; //Sensor entrada pinA4, salida pinA5
int In, Out; //Para almacenar los valores que devuelve cada sensor
Servo barrera; //Creamos un objeto tipo servo
int coches=0; //numero de coches dentro

void setup() { //Configuracion de pines y servo (pin7)

  pinMode(led1, OUTPUT);     
  pinMode(led2, OUTPUT);     
  pinMode(led3, OUTPUT);  
  barrera.attach(7);  
  barrera.write(0); 

}

void loop() {

  indicador(coches); //función que según los coches enciende leds
  In = analogRead(in);
  Out = analogRead(out);

 

  if (In>300)        //Coche quiere entrar

  {

    if(coches<3){    //Si hay plaza libre

      coches=coches+1;
      barrera.write(90);  //Sube barrera
      indicador(coches);

      while (In>300 || Out >300){ //Espera que pase el coche

        In = analogRead(in);
        Out = analogRead(out);

      } 

      delay(1500);
      barrera.write(0);    //Baja barrera
      delay(3000);

    }

  }

if (Out>300){    //Coche quiere salir

      coches=coches-1;
      barrera.write(90);    //Sube barrera
      indicador(coches);

      while (In>300 || Out >300){ //Espera que pase el coche

        In = analogRead(in);
        Out = analogRead(out);

      } 

      delay(1500);
      barrera.write(0);    //Baja barrera
      delay(3000);

    }

void indicador(int coches){

  switch (coches){

    case 0:

      digitalWrite(led1, HIGH); 
      digitalWrite(led2, HIGH); 
      digitalWrite(led3, HIGH); 
      break;

    case 1:

      digitalWrite(led1, HIGH); 
      digitalWrite(led2, HIGH); 
      digitalWrite(led3, LOW); 
      break;

    case 2:

      digitalWrite(led1, HIGH); 
      digitalWrite(led2, LOW); 
      digitalWrite(led3, LOW); 
      break;

    case 3:

      digitalWrite(led1, LOW); 
      digitalWrite(led2, LOW); 
      digitalWrite(led3, LOW); 
      break;

  }

}

Pregunta Verdadero-Falso

Para controlar la barrera del parking es mucho mejor utilizar un motor de rotación continua (motor DC) que un servo.
 

El sensor de infrarrojos es un sensor que detecta la presencia de un objeto pero no ofrece una medida en centímetros de la distancia a la que se encuentra.  
 

La instrucción barrera.write(90); gira el servo 90 grados.
 


TACÓMETRO


Mediante esta práctica se pretende medir las revoluciones por minuto (RPM) del rotor de una maqueta que simula el movimiento de un aerogenerador. Se han utilizado dos modelos para realizar las pruebas. Uno es el modelo didáctico comercial de CEBEK y el otro aerogenerador corresponde a un modelo construido por alumnos de tercero de ESO con materiales del aula taller. Hay que tener en cuenta que  la maqueta no realiza la función de generación de energía mediante la fuerza de viento, como corresponde a un aerogenerador, sino que simplemente provoca el movimiento del rotor para simular el efecto del viento, suministrándose la corriente necesaria al motor eléctrico bien mediante una una placa solar o bien mediante una pila en cada caso.
Para realizar la detección de cada vuelta se utiliza un imán adherido a una de las palas que gira solidario a ella y un detector magnético, en este caso un relé Reed. Cada vez que el imán se posiciona frente al relé, debido a su campo magnético, provoca el contacto de los terminales del relé  poniendo en conexión un canal de lectura digital de la tarjeta Arduino con un voltaje de 5 voltios. Esta acción hace que la tarjeta reconozca un nivel lógico alto que, mediante la un sencillo programa, realizará un conteo de vueltas y la medida de las revoluciones por minuto del rotor.
rotor
Se ubica el relé Reed sobre la parte superior y el imán se pega a una de las palas del aerogenerador, de forma que cuando pase la pala por la parte superior del aerogenerador el imán y el relé queden enfrentados de forma que el campo magnético del imán permita cerrar los contactos del relé Reed, según se aprecia en la imagen.
Las conexiones eléctricas se realizarán con el apoyo de la placa protoboard según el esquema que se adjunta. Se conecta la resistencia en configuración “pull-down”, es decir, cuando el imán está enfrentado al relé éste se cierra (ON) y conecta la entrada digital a +5 V. En ausencia de imán el relé permanece abierto (OFF) y la entrada digital quedará conectada a masa (GND) a través de la resistencia de 10KOhm.
Esquema-reed

El programa, una vez configurados el pin 2 como entrada digital y la comunicación serie para poder monitorizar la salida, realiza de forma cíclica una lectura del puerto de entrada. Mediante una sentencia condicional comprueba si el estado ha cambiado. En el caso de que el cambio sea a un nivel alto (HIGH) incrementa en una unidad la variable que cuenta las vueltas. Con la instrucción millis() se puede calcular el tiempo que trascurre en dar una vuelta completa (tiempo_una_rev), por lo que mediante un sencillo cálculo podremos conocer la velocidad del rotor en revoluciones por minuto (rpm).conexiones
El programa, una vez configurados el pin 2 como entrada digital y la comunicación serie para poder monitorizar la salida, realiza de forma cíclica una lectura del puerto de entrada. Mediante una sentencia condicional comprueba si el estado ha cambiado. En el caso de que el cambio sea a un nivel alto (HIGH) incrementa en una unidad la variable que cuenta las vueltas. Con la instrucción millis() se puede calcular el tiempo que trascurre en dar una vuelta completa (tiempo_una_rev), por lo que mediante un sencillo cálculo podremos conocer la velocidad del rotor en revoluciones por minuto (rpm).

// Cuenta las vueltas de un rotor de aerogenerador.

const int  releReedPin = 2;
int vueltas = 0;
int estadoRele = 0;         
int ultimoEstadoRele = 0;   
long tiempo_anterior = 0;
long tiempo_una_rev = 0;
unsigned long tiempo_ahora;
long rpm;

void setup() 

{

  pinMode(releReedPin, INPUT);
  Serial.begin(9600);

}

void loop() {

  // Lee el estado del rele

  estadoRele = digitalRead(releReedPin);

  // Compara el estado del rele con el estado previo

  if (estadoRele != ultimoEstadoRele) {

    // Si el estado ha cambiado incrementa el contador

    if (estadoRele == HIGH) 

    {

      vueltas++;
      tiempo_ahora =millis();
      tiempo_una_rev = tiempo_ahora - tiempo_anterior;
      rpm = 60000 / tiempo_una_rev; // 1 minuto = 60000 ms
      Serial.println("Rele ON");
      Serial.print("vuelta ");
      Serial.println(vueltas);
      Serial.print("Tiempo por revolucion: ");
      Serial.println(tiempo_una_rev);
      Serial.print("Revoluciones por minuto: ");
      Serial.println(rpm);

    } 

    else {    

      // Si el estado actual es LOW pasa de ON a OFF 
      Serial.println("Rele OFF"); 
      tiempo_anterior = tiempo_ahora;    

    }

  }

  // Guarda el estado actual como ultimo estado
  ultimoEstadoRele = estadoRele; 

}



Pregunta Verdadero-Falso


Un relé Reed tiene dos contactos únicamente. 
 

El relé Reed es un interruptor NA que se cierra mediante la aplicación de un campo magnético.
 

Una revolución por minuto (rpm) son 2*PI / 60 radianes.
 

La instrucción millis() devuelve la hora actual del sistema
 


DOMÓTICA

En los hogares hoy en día contamos con infraestructuras necesarias para tener una vida medianamente confortable. El agua corriente, la calefacción, el sistema eléctrico, desagües y muchas más instalaciones permiten que realicemos nuestras tareas cotidianas de una manera fácil y segura. Dentro de este módulo vamos a incluir dos prácticas. Una que tiene que ver con una casa domótica y otra que incluya el manejo de un panel didáctico de neumática. En la primera práctica simularemos condiciones reales para el control básico de las instalaciones de una casa; mediremos temperatura y humedad, detectaremos intrusos y aprovecharemos la luz solar que incide sobre la casa. En cuanto al sistema neumático, veremos de qué manera podemos realizar un automatismo mezclando la tecnología del aire y la electrónica. Gobernaremos desde Arduino un cilindro neumático que realizará un movimiento de vaivén ininterrumpido.



portada-casa-inteligente
Como has podido comprobar con las prácticas anteriores Arduino es una controladora muy fácil de programar y seguro que se te han ocurrido ya algunas aplicaciones para la que podrías utilizarla. En esta práctica vas a tener la oportunidad de comprobar su potencial, implementando una casa inteligente.
Cuando termines está práctica dejará de sorprenderte esos anuncios de edificios inteligentes, coches inteligentes, etc... Verás que en realidad tu también puedes hacerlo y es posible que incluso mejor. Como las posibilidades son infinitas en este caso vamos a indicarte los elementos y un funcionamiento básico, pero sobre todo deja volar tu imaginación y siéntete libre para cambiar, añadir y modificar lo que quieras.



Tabla de elementos y funcionalidades:
tabla-funciones









Puede que en el taller encuentres estos sensores, o no, al igual que elementos como bombas u otros objetos. No te preocupes si no encuentras todos los componentes necesarios, simplemente simúlalos con lo que tengas. La motobomba puede ser un pequeño motor de CC o incluso un LED, el PIR puede ser un pulsador al igual que el detector de humedad, tu imaginación y los elementos de los que dispongas serán suficientes para crear tu casa inteligente. 
Dedícale unos minutos a pensar por qué vas a sustituir cada uno de los elementos y plásmalos en una tabla. Incluye también en qué pines de la placa estarán conectados y la lógica a seguir. Como ves en la tabla siguiente hay un ejemplo, el cual debes ajustar a los elementos que puedas conseguir y añadir aquellos que se te ocurran.
tabla-sustitutos
casa
Haz la maqueta de una casa de cartón, con sus habitaciones y sobre ella incluye todos los elementos. Recuerda dejar suficiente cable para conectarlos luego en la placa Arduino sin problemas. Una buena opción es llevarlos todos hacia el mismo lado de la casa y etiquetarlos para evitar errores. Aquí tienes un ejemplo de programación basado en la tabla anterior, aunque seguro que te gustará modificar cosas y sobre todo mejorarla. El programa es largo porque no está optimizado para que sea sencilla su interpretación.




El programa a realizar será el siguiente:
/* defino algunas variables por comodidad y mejor entendimiento del programa

mirando la tabla se ve a que elemento  corresponde cada variable*/

int LDR, MB, SH, PIR, LE, A, C, MP, T;

//guarda el estado de la persiana

boolean persiana_subida=true;

void setup() {   

  // inicializamos las variables

  LDR = 1;
  MB = 1;
  SH = 2;
  PIR = 4;
  LE = 5;
  A = 6;
  C = 7;
  MP = 8; 
  T = 3; 

 //activamos el puerto serial para la depuracion

  Serial.begin(9600);
  pinMode(MB, OUTPUT);   
  pinMode(LE, OUTPUT); 
  pinMode(A, OUTPUT); 
  pinMode(C, OUTPUT);  
  pinMode(MP, OUTPUT);
  pinMode(SH, INPUT);  
  pinMode(PIR, INPUT); 
  pinMode(T, INPUT);   
 
}

void loop() {

  //programamos logica LDR       

  if (analogRead(1)> 900) { //indica que es de noche

    if (persiana_subida){//La persiana est´ subida y por tanto la bajamos

     digitalWrite(MP,HIGH); //Baja persianas
     delay(5000); //suponemos que las persianas tardan en bajar 5 segundos
     digitalWrite(MP,LOW);//para motor persianas
     persiana_subida=false; //para saber que la persiana esta abajo

    }

    digitalWrite(LE, HIGH); //enciende luces exteriores

  }

  else {

   if(! persiana_subida){//La periana esta bajada y por tanto la subimos

     digitalWrite(MP,HIGH); //Sube persianas 
     delay(5000); //suponemos que las persianas tardan en bajar 5 segundos     digitalWrite(MP,LOW);//para motor persianas

    persiana_subida=true;//para saber que la persiana esta arriba

   }

    digitalWrite(LE,LOW);//apagamos luces

  }

  //programamos logica detector humedad

  if (digitalRead(SH)==1) {//Hay humedad

   digitalWrite(MB, HIGH);//arranca la motobomba 

  }

  else {

    digitalWrite(MB, LOW);//para la motobomba 

  }

//programamos logica detector presencia

  if (digitalRead(PIR==1) && analogRead(LDR) >900){//Se detecta presencia y es de noche

    digitalWrite(A, HIGH);//Activa alarma

  }

  else {

  digitalWrite(A,LOW);

 }

 //programamos logica sensor temperatura

 if (digitalRead(T)==1){

  digitalWrite(C,HIGH); //enciende la caldera

 }

 else {

  digitalWrite(C,LOW); //apaga la caldera 

 }

 //mostramos lo que ocurre por monitor serial para poder depurar problemas

  Serial.print("LDR=");
  Serial.println(analogRead(1));
  Serial.print("Detector Humedad=");
  Serial.println(digitalRead(SH));
  Serial.print("Detector Presencia=");
  Serial.println(digitalRead(PIR));
  Serial.print("Termostato=");
  Serial.println(digitalRead(T));
  delay (2000); //esperamos 2 segundos

}




Pregunta Verdadero-Falso

Un sensor PIR utiliza infrarrojos para detectar movimiento en su zona de influencia.
 

Mediante un potenciómetro se puede simular el efecto de un LDR
 

¿Podríamos sustituir el motor de corriente continua utilizado para subir la persiana por un servo de rotación continua (modificando también el programa)?
 



EL ACELERÓMETRO


Realizar una montaje que utilice el acelerómetro/giroscopio MPU 6050 de tal manera que cuando lo giremos horizontalmente el eje de un servomotor siga el movimiento del sensor.
Para ello conectaremos el servo al pin 10 y realizaremos las conexiones con Arduino del sensor MPU 6050 indicadas en la tabla indicada en la sección de Montaje.
También es necesario instalar la librería para MPU 6050 (desarrollo de Jeff Rowberg) disponible en internet. Un enlace para su descarga lo encontramos enhttp://diyhacking.com/projects/MPU6050.zip
Otra librería necesaria es I2Cdev: http://diyhacking.com/projects/I2Cdev.zip
Vamos a ver el resultado de la demostración en el siguiente vídeo:

ESQUEMA:

ARDUINOMPU 6050
5VVCC
GNDGND
A4SDA
A5SCL
D2INT
ARDUINOSERVO
5V+Vcc
GNDGND
D10SEÑAL

PROGRAMA A CARGAR EN ARDUINO:


// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0)
// 6/21/2012 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
//      2013-05-08 - added seamless Fastwire support
//                 - added note about gyro calibration
//      2012-06-21 - added note about Arduino 1.0.1 + Leonardo compatibility error
//      2012-06-20 - improved FIFO overflow handling and simplified read process
//      2012-06-19 - completely rearranged DMP initialization code and simplification
//      2012-06-13 - pull gyro and accel data from FIFO packet instead of reading directly
//      2012-06-09 - fix broken FIFO read sequence and change interrupt detection to RISING
//      2012-06-05 - add gravity-compensated initial reference frame acceleration output
//                 - add 3D math helper file to DMP6 example sketch
//                 - add Euler output and Yaw/Pitch/Roll output formats
//      2012-06-04 - remove accel offset clearing for better results (thanks Sungon Lee)
//      2012-06-01 - fixed gyro sensitivity to be 2000 deg/sec instead of 250
//      2012-05-30 - basic DMP initialization working

/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2012 Jeff Rowberg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
===============================================
*/

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"

#include "MPU6050_6Axis_MotionApps20.h"
//#include "MPU6050.h" // not necessary if using MotionApps include file

// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high

/* =========================================================================
   NOTE: In addition to connection 3.3v, GND, SDA, and SCL, this sketch
   depends on the MPU-6050's INT pin being connected to the Arduino's
   external interrupt #0 pin. On the Arduino Uno and Mega 2560, this is
   digital I/O pin 2.
 * ========================================================================= */

/* =========================================================================
   NOTE: Arduino v1.0.1 with the Leonardo board generates a compile error
   when using Serial.write(buf, len). The Teapot output uses this method.
   The solution requires a modification to the Arduino USBAPI.h file, which
   is fortunately simple, but annoying. This will be fixed in the next IDE
   release. For more info, see these links:

   http://arduino.cc/forum/index.php/topic,109987.0.html
   http://code.google.com/p/arduino/issues/detail?id=958
 * ========================================================================= */



// uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual
// quaternion components in a [w, x, y, z] format (not best for parsing
// on a remote host such as Processing or something though)
//#define OUTPUT_READABLE_QUATERNION

// uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles
// (in degrees) calculated from the quaternions coming from the FIFO.
// Note that Euler angles suffer from gimbal lock (for more info, see
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER

// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_YAWPITCHROLL

// uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration
// components with gravity removed. This acceleration reference frame is
// not compensated for orientation, so +X is always +X according to the
// sensor, just without the effects of gravity. If you want acceleration
// compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead.
//#define OUTPUT_READABLE_REALACCEL

// uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration
// components with gravity removed and adjusted for the world frame of
// reference (yaw is relative to initial orientation, since no magnetometer
// is present in this case). Could be quite handy in some cases.
//#define OUTPUT_READABLE_WORLDACCEL

// uncomment "OUTPUT_TEAPOT" if you want output that matches the
// format used for the InvenSense teapot demo
//#define OUTPUT_TEAPOT



#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };



// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================

volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

#include "Servo.h"
Servo servo1;
// ================================================================
// ===                      INITIAL SETUP                       ===
// ================================================================

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    // (115200 chosen because it is required for Teapot Demo output, but it's
    // really up to you depending on your project)
    Serial.begin(115200);
    while (!Serial); // wait for Leonardo enumeration, others continue immediately

    // NOTE: 8MHz or slower host processors, like the Teensy @ 3.3v or Ardunio
    // Pro Mini running at 3.3v, cannot handle this baud rate reliably due to
    // the baud timing being too misaligned with processor ticks. You must use
    // 38400 or slower in these cases, or use some kind of external separate
    // crystal solution for the UART timer.

    // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();

    // verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

    // wait for ready
    Serial.println(F("\nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available());                 // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again

    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        // set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }

    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
    servo1.attach(10);
}



// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;

    // wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
        // other program behavior stuff here
        // .
        // .
        // .
        // if you are really paranoid you can frequently test in between other
        // stuff to see if mpuInterrupt is true, and if so, "break;" from the
        // while() loop to immediately process the MPU data
        // .
        // .
        // .
    }

    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

        #ifdef OUTPUT_READABLE_QUATERNION
            // display quaternion values in easy matrix form: w x y z
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            Serial.print("quat\t");
            Serial.print(q.w);
            Serial.print("\t");
            Serial.print(q.x);
            Serial.print("\t");
            Serial.print(q.y);
            Serial.print("\t");
            Serial.println(q.z);
        #endif

        #ifdef OUTPUT_READABLE_EULER
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetEuler(euler, &q);
            Serial.print("euler\t");
            Serial.print(euler[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(euler[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(euler[2] * 180/M_PI);
        #endif

        #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            Serial.print("ypr\t");
            Serial.print(ypr[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(ypr[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(ypr[2] * 180/M_PI);
        #endif

        #ifdef OUTPUT_READABLE_REALACCEL
            // display real acceleration, adjusted to remove gravity
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            Serial.print("areal\t");
            Serial.print(aaReal.x);
            Serial.print("\t");
            Serial.print(aaReal.y);
            Serial.print("\t");
            Serial.println(aaReal.z);
        #endif

        #ifdef OUTPUT_READABLE_WORLDACCEL
            // display initial world-frame acceleration, adjusted to remove gravity
            // and rotated based on known orientation from quaternion
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
            Serial.print("aworld\t");
            Serial.print(aaWorld.x);
            Serial.print("\t");
            Serial.print(aaWorld.y);
            Serial.print("\t");
            Serial.println(aaWorld.z);
        #endif
    
        #ifdef OUTPUT_TEAPOT
            // display quaternion values in InvenSense Teapot demo format:
            teapotPacket[2] = fifoBuffer[0];
            teapotPacket[3] = fifoBuffer[1];
            teapotPacket[4] = fifoBuffer[4];
            teapotPacket[5] = fifoBuffer[5];
            teapotPacket[6] = fifoBuffer[8];
            teapotPacket[7] = fifoBuffer[9];
            teapotPacket[8] = fifoBuffer[12];
            teapotPacket[9] = fifoBuffer[13];
            Serial.write(teapotPacket, 14);
            teapotPacket[11]++; // packetCount, loops at 0xFF on purpose
        #endif

        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);

        servo_yaw();
    }
}


void servo_yaw(){

  if (ypr[0] > 0) servo1.write(ypr[0] * 180/M_PI);
  

}

ALARMA VIVIENDA

Gracias a la lógica programable podemos programar alarmas muy complejas y mucho más eficientes que las alarmas convencionales. Las alarmas convencionales usan finales de carrera y, en definitiva, interruptores que activan una alarma. En nuestro caso vamos a dotar a la alarma de cierta lógica que nos proporcione mejores y más cómodos resultados. Las posibilidades son ilimitadas y depende de tu imaginación . En esta práctica y sólo como ejemplo vamos a suponer algunas cosas que, si bien no tienen por qué ajustarse a la realidad, si que sirven como ejemplo para mostrar y dar a entender las posibilidades de la alarma. puerta, encender la luz y cerrar la puerta. Partimos de las siguientes premisas :
  1. El ladrón puede entrar sólo por la ventana o por la puerta. Fíjate en las puertas y ventanas de los comercios de tu localidad. Seguro que has visto más de uno.
  2. Como la ventana de la casa da a una calle principal muy transitada el ladrón no intentará entrar nunca por la ventana cuando sea de día.
  3. La entrada de nuestra casa es oscura y no tiene ventanas al exterior, por lo tanto nuestro comportamiento habitual es abrir la puerta, encender la luz y cerrar la puerta.
  4. Sólo abrimos las ventanas de día, nunca por la noche.


Como detector de apertura de puerta y de ventana vamos a usar dos pulsadores, uno de la placa y otro que montaremos sobre la protoboard. Sabremos si es de día o de noche gracias al LDR de la EduBásica. Monta el pulsador sobre la protoboard y conéctalo entre 5V y la patilla digital 7. Usa para ello las clemas de la EduBásica tal y como muestra la imagen. Ten en cuenta que los interruptores podrían sustituirse en un caso real con relé un Reed conocido también como interruptor magnético. Son elementos económicos y de muy fácil instalación. Vamos a realizar la práctica en dos pasos para que lo puedas entender sin problemas.


Primero carga este programa:
void setup() {                
    pinMode(7, INPUT); //Pin correspondiente al interruptor de la PROTOBOARD
pinMode(2,INPUT); //Pin correspondiente al interruptor de la placa 
 Serial.begin(9600); 
}

void loop() {
  Serial.print( " VENTANA "); 
  Serial.print(digitalRead(7));//interruptor de la PROTOBOARD
  Serial.print( " PUERTA ");
  Serial.print(digitalRead(2));  //interruptor de la placa
  Serial.print( " LUZ ");
  Serial.println(analogRead(1)); //Nos muetra el valor del LDR 
  delay(1000);              // wait for a second

Abre el “monitor serial” y prueba a activar los pulsadores. Verás que cuando están activos el valor obtenido es 1 y cuando están desactivados su valor es 0. Comprueba qué interruptor se corresponde con la ventana y cual con la puerta. Tapa ahora el LDR y observa el valor que obtienes cuando no recibe luz (será el mismo valor que si es de noche). Atendiendo a los supuestos anteriores carga este programa y observa su funcionamiento. Si el led rojo se enciende es que la alarma se ha disparado.

int ventana, puerta, luz;//definimos variables 
void setup() {                
 pinMode(7, INPUT); 
 pinMode(5,OUTPUT); //led rojo
 pinMode(2,INPUT);  
 Serial.begin(9600); 
}
void loop() {
  ventana=digitalRead(7); //guardamos el estado de la ventana
  Serial.print( " VENTANA ");
  Serial.print(ventana);
  puerta=digitalRead(2); //guardamos estado de puerta
  Serial.print( " PUERTA ");
  Serial.print(puerta);
  luz=analogRead(1); //guardamos estado de LUZ
  Serial.print( " LUZ ");
  Serial.println(luz);
  //implementamos la logica de la puerta
  if (puerta==1) {//la puerta esta abierta
    delay(3000); //esperamos hasta que encienda la luz
    if (luz > 1000) {//no han encendido la luz
      digitalWrite(5,HIGH); //Se activa la alarma
    }
  }
  //implementamos logica de ventana
  if (ventana==1 && luz < 1000){
   digitalWrite(5,HIGH); 
  }

Actividad

Como comprobarás una vez que la alarma se activa permanece en ese estado. Para desactivarla debes reiniciar la placa quitándole la alimentación. Piensa en una solución para poder desactivar la alarma, por ejemplo abriendo la ventana y la puerta a la vez.

Actividad

Ampliación:
Usamos EduBásica porque dispone de elementos hardware ya instalados, como led y pulsador, pero piensa que sin EduBásica tu Arduino dispone de 13 entradas digitales y 6 analógicas. Piensa en un sistema más completo de alarma en el que puedas conectar sensores de humo o de movimiento (PIR).

Actividad

Proyecto propuesto:
Realiza todo el proceso para implementar, mediante funciones lógicas, el siguiente sistema:
Se trata de una máquina de control de una cinta transportadora. Tenemos un sensor de temperatura basado en un termistor que nos dirá si se ha producido un sobrecalentamiento en la máquina. También hay un sensor de presión que detecta la presencia de un objeto sobre la cinta transportadora. Por último, la cinta transportadora sólo estará en funcionamiento si el operario mantiene apretado un pulsador. Tendremos un led que avisará si hay sobrecalientamiento y detendrá la cinta si está en movimiento. Un zumbador avisará cuando la cinta esté en movimiento.