miércoles, 8 de abril de 2015

Desbloqueo PC

Quería construir un dispositivo que me permitiese desbloquear el ordenador fácilmente. Finalmente lo he hecho mediante un Arduino UNO por su facilidad para emular un teclado conectado al ordenador mediante el puerto USB (a la vez que le sirve de alimentación).
He diseñado la caja mediante Autodesk 123D y la he impreso con mi impresora 3D.

Componentes:
  • Arduino Leonardo
  • Altavoz
  • Grabador-reproductor de un sonido
  • Sensor de distancia
  • Tarjeta inhalámbrica RFID
  • LCD Nokia 
    • piezzo-buzzer
    • sensor temperatura
    • teclado
Funcionalidades:
    • Desbloqueo del ordenador al aproximar tarjeta RFID o mediante teclado
    • Sensor de distancia (hasta 51cm.).
    • Temperatura
    • Humedad
    • Sonidos de aviso
    • Cronómetro para usar la técnica del pomodoro.
















    miércoles, 30 de abril de 2014

    Cíclope: detección y seguimieno de rostros o Top Codes

    En este proyecto he preparado una aplicación java que mediante la librería OpenCv permite detectar rostros humanos o Top Codes mediante una cámara web y comunicándose con una placa Arduino UNO  mediante el puerto serie con la librería java-simple-serial-connector. La imagen que capta la cámara se visualiza en una ventana en la pantalla del ordenador con el rostro o el Top Code detectado recuadrado. Según las coordenadas en las que se encuentra el recuadro dentro de la ventana se mueven los servos de la base donde se encuentra la cámara para que el recuadro quede centrado. De este modo conseguiremos que la cámara siga constantemente al objetivo.


    La base con servos sobre la que descansa la cámara la he diseñado mediante Autodesk 123D y la he impreso mediante mi impresora 3D UP! Mini aquí podéis descargaros los ficheros .123d y .stl para imprimirla o modificarlos a vuestro gusto.

    El arduino lo he encerrado en una caja también creada con la impresora 3D







    Para el aprendizaje de OpenCv he comprado el libro Vision-based User Interface Programming in java. Aquí está la web del libro que contiene el código fuente de sus ejemplos.

    Para configurar eclipse para usarlo con OpenCv este es un buen tutorial.

    Aquí incluyo un extracto de las funcionalidades que ofrecen los Top Codes:
    The TopCode computer vision library is designed to quickly and easily identify and track tangible objects on a flat surface. Just tag any physical object with a TopCode (a circular black and white symbol) and the system will return:
    • An ID number
    • Location of the tag
    • Angular orientation of the tag
    • Diameter of the tag

    The TopCode library will identify 99 unique codes and can accurately recognize codes as small as 25 x 25 pixels. The image processing algorithms work in a variety of lighting conditions without the need for human calibration. The core TopCode library is 100% Java (with a C++ port now available). An additional library is provided to grab high-resolution images from a webcam using Microsoft's DirectShow API. This library is written in C++ but contains native hooks to Java. 

    Top Code recocido y recuadrado por la aplicación


    El código fuente de la aplicación Cíclope, tanto java para el PC como el sketch del Arduino podés encontrarlo aquí.

    domingo, 29 de diciembre de 2013

    ArduinoBluetoothCar controlado con aplicación Android desde el móvil

    Prueba de comunicación entre Arduino y un teléfono Android con una aplicación hecha con AppInventor

    Me he basado en  http://www.instructables.com/id/How-control-arduino-board-using-an-android-phone-a/
    La conexión física de la tarjeta bluetooth con el arduino la he tomado de: http://www.instructables.com/id/Cheap-2-Way-Bluetooth-Connection-Between-Arduino-a/?ALLSTEPS
    y de http://www.instructables.com/id/Androino-Talk-with-an-Arduino-from-your-Android-d/?ALLSTEPS

    Versión v1: Mediante botones en el teléfono controlo el coche
    Versión v2: Añado control por movimiento del teléfono sin necesidad de pulsar botones
    Versión v3: Añado control por voz y sensor de distancia

    IMPORTANTE: Para evitar el error avrdude: stk500_getsync(): not in sync: resp=0x00 cuando se sube el programa al arduino hay que desconectar el cable que va al pin 0 (RX): "DISCONNECT ANY WIRES going to pin 0 (RX) while you do the upload. The sketch upload function uses the RX pin".

    El código Android está programado con la versión 1 de appinventor.mit.edu

    Sincronización
    Control por teclado
    Control por voz
    Control por gestos
    Código de la aplicación desarrollada con appInventor para el teléfono:


    Código fuente del Arduino:

    
    //Prueba de comunicación entre Arduino y un teléfono Android con una aplicación hecha con AppInventor
    // Tomado de http://www.instructables.com/id/How-control-arduino-board-using-an-android-phone-a/
    // la conexión física de la tarjeta bluetooth con el arduino la he tomado de:
    // http://www.instructables.com/id/Cheap-2-Way-Bluetooth-Connection-Between-Arduino-a/?ALLSTEPS
    // y de http://www.instructables.com/id/Androino-Talk-with-an-Arduino-from-your-Android-d/?ALLSTEPS
    // Versión v1: Mediante botones en el teléfono controlo el coche
    // Versión v2: Añado control por movimiento del teléfono sin necesidad de pulsar botones
    // Versión v3: Añado sensor de distancia
    
    // IMPORTANTE: Para evitar el error avrdude: stk500_getsync(): not in sync: resp=0x00 cuando se sube el programa al arduino hay que
    // DISCONNECT ANY WIRES going to pin 0 (RX) while you do the upload. The sketch upload function uses the RX pin. 
    
    #include 
    
    AF_DCMotor motor1(1, MOTOR12_64KHZ);
    AF_DCMotor motor2(2, MOTOR12_64KHZ);
    
    const uint8_t SPEED_INCREMENT = 50;
    byte serialA;
    
    uint8_t speed = 255;
    
    uint8_t distanceStatus=1; //1 Far, 2 Middle, 3 Near
    //uint8_t oldDistanceStatus=1;
    //uint8_t greenDistance=100;
    int yellowDistance=250;
    int redDistance=530;
    
    int distanceSensorPin = A0;
    int distanceSensorValue;
    
    int read1, read2, read3, readMedia, readDiference1, readDiference2, readDiference3;
    const int TOLERABLE_READ_ERROR = 30;
    
    void setup()
    {
      // initialize the serial communication:
      Serial.begin(9600); //baud rate - make sure it matches that of the module you got:
      
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      }
    
    void loop() {
      if (Serial.available() > 0) {
        serialA = Serial.read();
    //    Serial.println(serialA);
        processCommand(serialA);
      }
      processDistance();
    }
    
    void processCommand(byte command){
      switch (command) {
      case 1:
    //    Serial.println("********Recived 1 *******");
        left();
        break;
      case 2:
    //    Serial.println("********Recived 2 *******");
        right();
        break;
      case 3:
    //    Serial.println("********Recived 3 *******");
        forward();
        break;
      case 4:
    //    Serial.println("********Recived 4 *******");
        backward();
        break;
      case 5:
    //    Serial.println("********Recived 5 *******");
        fullStop();
        break;   
      case 6:
    //    Serial.println("********Recived 6 *******");
        increaseSpeed();
        break;  
      case 7:
    //    Serial.println("********Recived 7 *******");
        decreaseSpeed();
        break;      
      default:
    //    Serial.print("********Recived unexpected command: ") + Serial.println(command);
        break;
      }
    }
    
    void right(){
    //  Serial.println("Turning right...");
      motor1.run(FORWARD);
      motor1.setSpeed(speed);
      motor2.run(RELEASE);
    }
    
    void left(){
    //  Serial.println("Turning left...");
      motor2.run(FORWARD);
      motor2.setSpeed(speed);
      motor1.run(RELEASE);
    }
    
    void forward(){
    //  Serial.println("Forward...");
      motor1.run(FORWARD);
      motor2.run(FORWARD);  
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
    }
    
    void backward(){
    //  Serial.println("Backward...");
      motor1.run(BACKWARD);
      motor2.run(BACKWARD);  
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
    }
    
    void fullStop(){
    //  Serial.println("FullStop...");  
      motor1.run(RELEASE);
      motor2.run(RELEASE);  
    }
    
    void increaseSpeed(){
    //  Serial.println("IncreaseSpeed...");  
      if ((speed + SPEED_INCREMENT) > 255){
        speed = 255;
      }else{
        speed += SPEED_INCREMENT;
      }
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
    }
    
    void decreaseSpeed(){
    //  Serial.println("DecreaseSpeed...");    
      if ((speed - SPEED_INCREMENT) < 0){
        speed = 0;
      }else{
        speed -= SPEED_INCREMENT;
      }
      motor1.setSpeed(speed);
      motor2.setSpeed(speed);
    }
    
    void processDistance(){
       // read the value from the sensor:
      distanceSensorValue = readDistance();
      
    //  Serial.print("distanceSensorValue=");
    //  Serial.println(distanceSensorValue);
      
    //  Serial.print("distanceStatus=");
    //  Serial.println(distanceStatus);
      
      if (distanceSensorValue == 999){
        //error in read
        return;
      }
      
      if (distanceSensorValue < yellowDistance && distanceStatus != 1){
    //   Serial.println("distanceStatus_1"); 
       distanceStatus=1; 
       Serial.print("1"); //Sending to phone
      }else if (distanceSensorValue >= yellowDistance && distanceSensorValue < redDistance && distanceStatus != 2){
    //   Serial.println("distanceStatus_2");   
       distanceStatus=2; 
       Serial.print("2"); //Sending to phone
      }else if (distanceSensorValue >= redDistance && distanceStatus != 3){
    //   Serial.println("distanceStatus_3");
       distanceStatus=3; 
       Serial.print("3"); //Sending to phone
       fullStop();
      }
    }
    
    // return media of to 3 reads  or 999 if there is error
    int readDistance(){
        read1=analogRead(distanceSensorPin);
        delay(50); //delay between readings to avoid errors because of erratic reading
        read2=analogRead(distanceSensorPin);
        delay(50); //delay between readings to avoid errors because of erratic reading
        read3=analogRead(distanceSensorPin);
        delay(50);
    
        readMedia = (read1 + read2 + read3)/3;
        
        //we need to use readDiferenceX variables due to abs() limitations (read Reference Documentation)
        readDiference1 = read1 - readMedia;
        readDiference2 = read2 - readMedia;
        readDiference3 = read3 - readMedia;
        
        if ((abs(readDiference1) > TOLERABLE_READ_ERROR) || (abs(readDiference2) > TOLERABLE_READ_ERROR) || (abs(readDiference2) > TOLERABLE_READ_ERROR)){
          // the 3 reads have too many differences
          return 999;
        }
        return (read1 + read2 + read3)/3; //media of the 3 reads
    }
    
    

    martes, 19 de febrero de 2013

    Enterprise TrekDuino

    En este proyecto he hackeado con un Arduino Mega una maqueta de la nave Enterprise de la serie Star Trek para añadirle muchas funcionalidades como luces ambientales con leds blancos, leds rojos para la alerta roja, leds RGB (de colores) para los motores, leds rojos y verdes para las luces de posición, led rojo para el deflector, un laser real para el disparo faser, efecto visual de disparo de torpedo de fotones, reconocimiento de voz con easyVR, efectos de sonidos de la nave original, sensor de temperatura y humedad, pantalla TFT para mostrar imágenes y mensajes, sensor PIR para detección de movimiento...



    Tras pintar cada una de las partes de la maqueta coloqué en su interior los múltiples leds, junto con el laser y pasé todo el cableado por el interior hasta llevarlo a la base donde, tal y como se puede apreciar en las fotos está todo el sistema de control.


    El interruptor lateral corta la corriente para dejarlo apago o encendido completamente. Cuando está encendido es el sensór PIR de la parte frontal el que activa todo cuando detecta movimiento.
    En el lateral, el logotipo de la Federación de Planetas oculta un botón de modo que al oprimirlo se pone a la espera (apareciendo la imagen de Standby en el monitor). Tras pulsarlo pueden introducirse comandos (previamente registrados) de voz en dos etapas. Primero (al igual que en la serie) diremos la palabra Ordenador. Al reconocerla el sistema emite un beep y aguarda el comando de voz concreto. Este puede ser:
    • Alerta roja: Se escucha el sonido de alarma, en el monitor aparece la imagen de alerta roja, se cambia la iluminación interior a rojo, se emite el sonido de levantar escudos, se disparan el laser y el torpedo de fotones con su sonidos asociados, tras lo cual pasados unos segundos se pasa a alerta amarilla y posteriormente a verde con el sonido de bajar escudos y se retorna a la normalidad.
    • Levanta escudos: Emite el sonido apropiado.
    • Dispara torpedo fotones: Enciende el led que emula esta función y emite el sonido.
    • Dispara faser: Dispara el faser con su sonido
    Pulsando dos veces consecutivas el pulsador también se provoca una alerta roja.

    En situación normal el monitor alterna una imagen con la temperatura y humedad ambiental.








    La verdad es que he disfrutado haciendo la maqueta y reuniendo en ella diversos componentes que había utilizado en anteriores proyectos junto con otros nuevos.

    Estuve sopesando la posibilidad de crear la caja sobre la que se asienta la maqueta con un diseño propio más estilizado e imprimirla con una impresora 3d. Para ello aprendí a diseñar objetos tridimensionales con el programa Autodesk 123D que ofrece unas enormes posibilidades. Finalmente descarté el modelo que había preparado por el excesivo coste de su impresión. De este modo aproveché una sencilla caja de madera que perforé y pinté.

    Código fuente

    Puedes descargarte todo el código:
    • Mediante subversion:  
    svn checkout http://trekduino.googlecode.com/svn/trunk/ trekduino-read-only
    • Navegador web: 
    https://code.google.com/p/trekduino/source/browse/
    • Proyecto googlecode: 
    https://code.google.com/p/trekduino/


    Listado de materiales:
    • Maqueta Revell 1/600 U.S.S. Enterprise NCC-1701:



    martes, 12 de junio de 2012

    Mando a distancia universal sin manos o con múltiples adaptadores

    Sustituye cualquier mando a distancia de infrarrojos: televisión, aire acondicionado, radio... Puede ser usado sin contacto físico, únicamente pasando la mano por encima lo que permite que personas con graves limitaciones de movimiento puedan utilizarlo. Para otras personas que puedan utilizar un joystick se le pueden instalar un mando de la WII y así tener más funcionalidades.

    Está dirigido a todas aquellas personas con problemas motores a quienes sea difícil utilizar un mando a distancia convencional.

    La finalidad es que al estar diseñado de forma modular se le pueden conectar diferentes accesorios como el sensor sin contacto físico, el mando de la wii, botones grandes, sensores de presión... dependiendo de las necesidades de cada usuario.

    Uso sin manos, con el sensor de distancia: cada vez que se pasa la mano por encima se cambia el canal.

    Uso mediante el joystick del Nunchuck de la WII. De esta manera se pueden enviar 4 códigos diferentes. Podrían utilizarse también los 2 botones que tiene.



     Para cargar el dispositivo con los 4 códigos que deseemos del mando a distancia (este número puede cambiarse en el programa) pulsaremos los dos botones simultáneamente, comenzará a parpadear el led rojo y entonces pulsaremos los botones del mando a distancia. Cada vez que se recibe un código parpadea una vez el led. Tras recibir el cuarto código vuelve a parpadear varias veces  y ya está listo para su uso. Estos códigos se almacenan en la memoria EEPROM de modo que aunque se le quite la corriente no se borrarán.

    En la versión actual cuando se pasa la mano por encima se pone en pausa o en play. Si se para la mano encima suena un pitido (no he reflejado el buzzer en las fotos ni en el esquema) y entonces si se sube la mano se hace fastforwar (avance rápido) y si se baja backforward (retroceso rápido).



    Nota: En las fotos no aparecen ni el capacitor ni el MAX IRLed (si figuran en el esquema)




    Lo envolvemos todo con una cajita hecha con Lego



    Esquema original:





    Esquema mejorado:

    Para aumentar el alcance de la señar infrarroja que en el esquema origina no llegaba a los 2 metros he sustituido el led infrarrojo y la correspondiente resistencia por el Max Power IR LED Kit de SparkFun.com Otra mejora es añadir un capacitor de 100μF/25v entre la toma de corriente (positivo del capacitor) y la tierra del lector de distancia de infrarrojo para estabilizar las lecturas tal y como se indica en su datasheet de especificaciones.
     No es necesario ningún cambio en el programa.




    Materiales:

    Si se quiere usar pasando la mano por encima:
    Si se quiere usar con el Nunchuku de la WII:
    Puedes descargarte todo el código:

    martes, 10 de enero de 2012

    CocheNunchuk el coche controlado con Nunchuk

    He preparado la base de un coche con dos motores de Lego Mindstorm RCX conectados al Arduino UNO mediante el Motor Shield de Adafruit.com. Gracias al Wiichuck Adapter conectamos el Nunchuk y utilizando esta librería preparo el programa con el que controlaremos los motores.

     En el Nunchuk he configurado lo siguiente:
    • botón de parada
    • botón de arranque
    • girandole sobre el eje X giro a derecha o izquierda
    • levantándole o bajándole sobre el eje Y se regula la velocidad
    • con el joystick que lleva integrado controlo la marcha atrás




    Código:

    /*
     * CocheNunchukV2 Coche con ArduinoNunchuk y motores Lego
     * Mediante un nunchuk conectado mediante el cable puedo manejar un coche hecho con dos motores Lego
     * En el Nunchuk he configurado lo siguiente:
     * - botón de parada
     * - botón de arranque
     * - girandole sobre el eje X giro a derecha o izquierda
     * - levantándole o bajándole sobre el eje Y se regula la velocidad
     * - con el joystick que lleva integrado controlo la marcha atrás
     *
     * Copyleft 2011 Antonio Garcia Figueras
     *
     * Usando libreria de Gabriel Bianconi,  http://www.gabrielbianconi.com/projects/arduinonunchuk/
     *
     */

    #include <Wire.h>
    #include "ArduinoNunchuk.h"
    #include <AFMotor.h>

    #define BAUDRATE 19200
    #define PORCENTAJE_MARGENX 20
    #define PORCENTAJE_MARGENY 20
    ArduinoNunchuk nunchuk = ArduinoNunchuk();

    //Servo myservo;

     int minX;
     int maxX;
     int minY;
     int maxY;
     int minZ;
     int maxZ;
     float centroX;
     float margenX;
     int contador;
     float razonY;
     int posXServo;
     boolean swStop;
     int velocidad;

     AF_DCMotor motorIz(1, MOTOR12_64KHZ); // create motor izquierda, 64KHz pwm
     AF_DCMotor motorDe(2, MOTOR12_64KHZ); // create motor derecha, 64KHz pwm

    void setup() {
      Serial.begin(BAUDRATE);

      pinMode(13, OUTPUT);    //Iniciamos el led

      Serial.println("Inicio incializacion");
      nunchuk.init();
      Serial.println("Final incializacion"); 

      calibraAccel();
     
      // Averiguamos cual es el valor del punto medio
      centroX = (float)(minX + (maxX -minX)/2);
      Serial.print("centroX:");
      Serial.println(centroX, DEC);

      // Daremos este margen desde el centro para considerar que va recto
      margenX =  (float)PORCENTAJE_MARGENX * (maxX -minX)/100;
      Serial.print("margenX:");
      Serial.println(margenX, DEC); 

    //Calculo de la razon para calcular el valor del velocidad (70-255=185)
    //en funcion del movimiento del nunchucku en el eje Y
      razonY = (float)185/(maxX - minX); 
      Serial.print("RazonY:");
      Serial.println(razonY, DEC);
     
      swStop = true;
    }

    void loop() {
         nunchuk.update();
        
         imprimeValoresNunchuk();
    //     delay(2000);
        
         if (nunchuk.zButton==1){
          swStop=true;
         }else if (nunchuk.cButton==1){
          swStop=false;
         }    
        
         if (swStop){
           para();
           Serial.println("swStop es true");
         }else{
           determinaMovimiento();
           Serial.println("swStop es false");
         }
    //     Serial.println("***************************************");
    //     Serial.print("accelX:");
    //     Serial.println(nunchuk.accelX, DEC);
        


    }

    void parpadea(){
      for (int cont = 0; cont < 3; cont++){
        digitalWrite(13, HIGH);   // set the LED on
        delay(500);              // wait for a second
        digitalWrite(13, LOW);    // set the LED off
        delay(500); 
      }
    }
     
    void determinaVelocidad(){
         // Al multiplicar la posicion Y del nunckuk por la razon
         // lo convertimos a valores entre 70 y 255 para la velocidad del motor
         velocidad = (int)((nunchuk.accelY - (maxY - minY)) * razonY)+70;
        
         motorIz.setSpeed(velocidad);   
         motorDe.setSpeed(velocidad);   
         Serial.print("accelY:");
         Serial.println(nunchuk.accelY, DEC); 
         Serial.print("Velocidad");
         Serial.println(velocidad, DEC);     
    }

    void determinaMovimiento(){
         determinaVelocidad();
         if (nunchuk.accelX > (centroX + margenX)){
           giroDerecha();
         }else if(nunchuk.accelX < (centroX - margenX)){
           giroIzquierda();
         }else{
           recto();
         } 
    }

    void giroDerecha(){
      Serial.print("giroDerecha");
      motorDe.run(RELEASE);
      if (nunchuk.analogY < 100){ 
        motorIz.run(BACKWARD);
      }else{
        motorIz.run(FORWARD);
      }   
    }

    void giroIzquierda(){
      Serial.print("giroIzquierda");
      motorIz.run(RELEASE);
      if (nunchuk.analogY < 100){ 
        motorDe.run(BACKWARD);
      }else{
        motorDe.run(FORWARD);
      }   
    }

    void recto(){
      Serial.print("recto");
      if (nunchuk.analogY < 100){
        motorIz.run(BACKWARD);
        motorDe.run(BACKWARD);
      }else{
        motorIz.run(FORWARD);
        motorDe.run(FORWARD);
      }


    void para(){
      motorIz.run(RELEASE);
      motorDe.run(RELEASE);


    // Calibra todos los acelerometros para saber sus
    // valores minimos y maximos
    void calibraAccel()  {
     parpadea(); // parpadea cuando va a comenzar la calibración
     nunchuk.update();
     minX = nunchuk.accelX;
     maxX = nunchuk.accelX;
     minY = nunchuk.accelY;
     maxY = nunchuk.accelY;
     minZ = nunchuk.accelZ;
     maxZ = nunchuk.accelZ;
     contador=0;
     
     Serial.println("Inicio calibracion");
     
     while (contador<=200){
         Serial.print("Paso=");
         Serial.println(contador);
         nunchuk.update();
         if (nunchuk.accelX < minX){
           minX=nunchuk.accelX;
         }
         if (nunchuk.accelX > maxX){
           maxX=nunchuk.accelX;
         }
        
         if (nunchuk.accelY < minY){
           minY=nunchuk.accelY;
         }
         if (nunchuk.accelY > maxY){
           maxY=nunchuk.accelY;
         }

         if (nunchuk.accelZ < minZ){
           minX=nunchuk.accelZ;
         }
         if (nunchuk.accelZ > maxZ){
           maxZ=nunchuk.accelZ;
         }    
         delay(10);
         contador++;
     }
     Serial.print("Resultado calibracion X. MinX=");
     Serial.print(minX, DEC);
     Serial.print(" MaxX=");
     Serial.print(maxX, DEC);
     Serial.print(" Diferencia=");
     Serial.println(maxX - minX);
     
     Serial.print("Resultado calibracion Y. MinY=");
     Serial.print(minY, DEC);
     Serial.print(" MaxY=");
     Serial.print(maxY, DEC);
     Serial.print(" Diferencia=");
     Serial.println(maxY - minY);
     
     Serial.print("Resultado calibracion Z. MinZ=");
     Serial.print(minZ, DEC);
     Serial.print(" MaxZ=");
     Serial.print(maxZ, DEC);
     Serial.print(" Diferencia=");
     Serial.println(maxZ - minZ);
     
     parpadea();// parpadea al finalizar la calibración
    }


    void imprimeValoresNunchuk(){
      Serial.print(nunchuk.analogX, DEC);
      Serial.print(' ');
      Serial.print(nunchuk.analogY, DEC);
      Serial.print(' ');
      Serial.print(nunchuk.accelX, DEC);
      Serial.print(' ');
      Serial.print(nunchuk.accelY, DEC);
      Serial.print(' ');
      Serial.print(nunchuk.accelZ, DEC);
      Serial.print(' ');
      Serial.print(nunchuk.zButton, DEC);
      Serial.print(' ');
      Serial.println(nunchuk.cButton, DEC);
    }

    viernes, 30 de diciembre de 2011

    Detector de mentiras conArduinoNunchuk y servo

    Este proyecto sirve para probar el manejo del Nunchuk de la Wii. Según se gire en el aire el Nunchukse le envía al servo la orden de giro.

    La chorradita del cartel de Mentira y Verdad ha sido para divertir a mi hija pequeña y a una amiga suya.

    Estuve sopesando algunas librerías para manejar el Nunchuk y al final me he decantado por http://www.gabrielbianconi.com/projects/arduinonunchuk/

    Como adaptador para conectar el nunchuk a Arduino he usado el WiiChuck http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/



    Código fuente:

    /*
     * Detector de mentiras conArduinoNunchuk y servo
     *
     * Copyleft 2011 Antonio Garcia Figueras
     *
     * Usando libreria de Gabriel Bianconi, http://www.gabrielbianconi.com/
     *
     * Project URL: http://www.gabrielbianconi.com/projects/arduinonunchuk/
     *
     */

    #include <Wire.h>
    #include "ArduinoNunchuk.h"
    #include <Servo.h>

    #define BAUDRATE 19200

    ArduinoNunchuk nunchuk = ArduinoNunchuk();

    Servo myservo;

     int minX;
     int maxX;
     int minY;
     int maxY;
     int minZ;
     int maxZ;
     int contador;
     float razonX;
     int posXServo;

    void setup() {
      Serial.begin(BAUDRATE);
      myservo.attach(9);  // attaches the servo on pin 9 to the servo object
      myservo.write(90);  // lo colocamos centrado
      Serial.println("Inicio incializacion");
      nunchuk.init();
      Serial.println("Final incializacion");
      calibraAccel();
     
    //Calculo de la razon para calcular el valor del servo (0-180)
    //en funcion del movimiento del nunchucku
      razonX = (float)180/(maxX - minX);
      Serial.print("Razon:");
      Serial.println(razonX, DEC);
    }

    void loop() {
         nunchuk.update();
       
         // Al multiplicar la posicion del nunckuk por la razon
         // lo convertimos a valores entre cero y 180 para el servo
         posXServo = (int)(nunchuk.accelX - (maxX - minX)) * razonX;
         Serial.print("accelX:");
         Serial.println(nunchuk.accelX, DEC);
       
         Serial.print("posXServo:");
         Serial.println(posXServo, DEC);
         if (posXServo > 180) posXServo=180; //por si por los decimales da un valor superior
         if (posXServo < 0) posXServo=0;
       
         myservo.write(posXServo);
       
         delay(10); //Para dar tiempo a que se coloque el servo
     
     
     
    //  nunchuk.update();
    //
    //  Serial.print(nunchuk.analogX, DEC);
    //  Serial.print(' ');
    //  Serial.print(nunchuk.analogY, DEC);
    //  Serial.print(' ');
    //  Serial.print(nunchuk.accelX, DEC);
    //  Serial.print(' ');
    //  Serial.print(nunchuk.accelY, DEC);
    //  Serial.print(' ');
    //  Serial.print(nunchuk.accelZ, DEC);
    //  Serial.print(' ');
    //  Serial.print(nunchuk.zButton, DEC);
    //  Serial.print(' ');
    //  Serial.println(nunchuk.cButton, DEC);
    }


    // Calibra todos los acelerometros para saber sus
    // valores minimos y maximos
    void calibraAccel()  {
     nunchuk.update();
     minX = nunchuk.accelX;
     maxX = nunchuk.accelX;
     minY = nunchuk.accelY;
     maxY = nunchuk.accelY;
     minZ = nunchuk.accelZ;
     maxZ = nunchuk.accelZ;
     contador=0;

     Serial.println("Inicio calibracion");

     while (contador<=200){
         Serial.print("Paso=");
         Serial.println(contador);
         nunchuk.update();
         if (nunchuk.accelX < minX){
           minX=nunchuk.accelX;
         }
         if (nunchuk.accelX > maxX){
           maxX=nunchuk.accelX;
         }
       
         if (nunchuk.accelY < minY){
           minY=nunchuk.accelY;
         }
         if (nunchuk.accelY > maxY){
           maxY=nunchuk.accelY;
         }

         if (nunchuk.accelZ < minZ){
           minX=nunchuk.accelZ;
         }
         if (nunchuk.accelZ > maxZ){
           maxZ=nunchuk.accelZ;
         }   
         delay(10);
         contador++;
     }
     Serial.print("Resultado calibracion X. MinX=");
     Serial.print(minX, DEC);
     Serial.print(" MaxX=");
     Serial.print(maxX, DEC);
     Serial.print(" Diferencia=");
     Serial.println(maxX - minX);

     Serial.print("Resultado calibracion Y. MinY=");
     Serial.print(minY, DEC);
     Serial.print(" MaxY=");
     Serial.print(maxY, DEC);
     Serial.print(" Diferencia=");
     Serial.println(maxY - minY);

     Serial.print("Resultado calibracion Z. MinZ=");
     Serial.print(minZ, DEC);
     Serial.print(" MaxZ=");
     Serial.print(maxZ, DEC);
     Serial.print(" Diferencia=");
     Serial.println(maxZ - minZ);
    }