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);
}