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: