jueves, 20 de marzo de 2014

Configuración Módulo Bluetooth HC-06

          Hasta ahora hemos visto como mandar comandos de dos formas: la primera es escribiendo una rutina en 'Loop' que se repite continuamente, esto es, haciendo siempre lo mismo una y otra vez; la segunda es mediante pulsadores simulando un mando conectado directamente al Arduino, con el cual y dependiendo del botón pulsado se hará una acción u otra. Pues bien, vamos a ver a partir de ahora una tercera opción, que será con la que controlemos MotorDroid, y no es otra que mediante Bluetooth.


          Para ello usaremos el módulo bluetooth HC-06 de cuatro pines, Vcc, Gnd, Txd y Rxd. Con ello tendremos un puerto serial adicional a nuestra disposición que será con el que nos comunicaremos con Arduino para mandar comandos que ejecuten acciones. Conectaremos el módulo en el Serial 3 de nuestro Arduino Mega como podéis ver en el prototipo.


      Importante, hay que conectar el pin RDX del BT con el TDX de Arduino y el TDX del BT con el TDX de Arduino, no os confundáis, que a mi me pasó la primera vez. Pues bien, para configurar sólo necesitamos escribir código en el 'Setup' del sketch. ES importante que antes de comenzar a ejecutar tengamos desconectado el módulo, y conectarlo en el momento en el que se va a pedir. Mediante comandos AT iremos configurando la velocidad de comunicación, nombre del dispositivo y contraseña.

//Función 'Setup'
void setup(){
  //Inicializamos el Serial
  Serial.begin(9600);
  //Inicializamos el Serial BT, que está conectado puerto 3 de comunicación
  Serial3.begin(9600);
  //Esperamos 5 segundos para conectar el BT a los pines
  Serial.println("CONECTE EL BT MODULE");
  delay(10000);
  //Mandamos el comando AT para comenzar a configurar
  Serial3.print("AT");
   Serial.println("CONFIGURANDO");
  //Siempre que mandemos un comando al BT tenemos que esperar un segundo
  delay(1000);
  //Cambiamos de nombre enviando AT+NAME seguido del nombre deseado
  Serial3.print("AT+NAMEMOTORDROID");
   Serial.println("Configurando Nombre");
  //Esperamos los cambios
  delay(1000);
  //Cambiamos la velocidad del módulo
  Serial3.print("AT+BAUD4");
   Serial.println("Configurando velocidad");
  //Esperamos los cambios
  delay(1000);
  //Cambiamos la contraseña enviando AT+PIN y la que queramos
   Serial.println("Configurando pin");
  Serial3.print("AT+PIN1990");
  //Esperamos los cambios
  delay(1000);
  //Mostramos por puerto serial la finalización de la configuración
  Serial.println("TERMINADO");
}

//Función 'Loop'
void loop(){
  //No hacemos nada
}

          Tal y como está comentado en el sketch, cada vez que mandemos un comando es necesario esperar un segundo para que este se ejecute correctamente y podamos escribir el siguiente. en el vídeo podéis ver como cambia la configuración antes y después de ejecutar el código. Y con esto empezamos a dejar de usar cables. =D


miércoles, 19 de marzo de 2014

BiRueda Pulsador (+Giro sobre sí mismo)

          Vamos a añadirle las funciones de giro en sentido horario y antihorario al vehículo BiRueda. Para ello necesitaremos un "mando" con más botones obviamente.


          Como podéis ver hay dos botones más. Los dos centrales son hacia adelante y hacia atrás, siendo los dos de los extremos el que gira en sentido horario y el otro el que gira en sentido antihorario. Para poder controlar el vehículo hay que añadir los eventos de pulsación de dichos pulsadores nuevos como veremos en el sketch.

//Importamos la libreria AFMotor.h
#include <AFMotor.h>
//Definimos los pines de los botones
#define ADELANTE    22
#define ATRAS       23
#define IZQUIERDA   24
#define DERECHA     25
//Creamos los dos motores que están conectados a M1 y M2 respectivamente con frecuencia 64KHZ
AF_DCMotor motor(2, MOTOR12_64KHZ); 
AF_DCMotor motor2(1, MOTOR12_64KHZ);

//variable para la velocidad
int velocidad;

//Función 'Setup'
void setup() {
  //Inicializamos Serial
  Serial.begin(9600);   
  Serial.println("BiRueda Pulsador (+Giro sobre sí mismo)");

  //Botones como entrada y abiertos
  pinMode(ADELANTE, INPUT);
  digitalWrite(ADELANTE, HIGH);
  pinMode(ATRAS, INPUT);
  digitalWrite(ATRAS, HIGH);
  pinMode(IZQUIERDA, INPUT);
  digitalWrite(IZQUIERDA, HIGH);
  pinMode(DERECHA, INPUT);
  digitalWrite(DERECHA, HIGH);
  
  //Le damos velocidad a los motores
  motor.setSpeed(255);
  motor2.setSpeed(255);
}

//Eventos de captura de los botones
//Botón adelante
boolean UP()
{
  //Si el pin está LOW quiere decir que está pulsado
  int up_pulsado = !digitalRead(ADELANTE);
  return up_pulsado;
}
//Botón atras
boolean DOWN()
{
  int down_pulsado = !digitalRead(ATRAS);
  return down_pulsado;
}
//Botón izquierda
boolean LEFT()
{
  int left_pulsado = !digitalRead(IZQUIERDA);
  return left_pulsado;
}
//Botón derecha
boolean RIGHT()
{
  int right_pulsado = !digitalRead(DERECHA);
  return right_pulsado;
}
 
//Función 'Loop'
void loop() {
  //Obtenemos los eventos de cada botón usando las funciones implementadas
  boolean ad = UP();
  boolean at = DOWN();
  boolean iz = LEFT();
  boolean de = RIGHT();
  
  //Si los dos pulsadores de velocidad están pulsados o no el BiRueda no se moverá  
  if ((ad == 1 && at==1) || (ad == 0 && at==0)){
    Serial.print(".");
    motor.run(RELEASE);
    motor2.run(RELEASE);
  }//Si sólo está pulsado ADELANTE
  else if(ad ==1){
    Serial.print("U");
    motor.run(FORWARD);
    motor2.run(FORWARD);
  }else if(at == 1){
    Serial.println("D");
    motor.run(BACKWARD);     
    motor2.run(BACKWARD);
  }
  
  //Si los dos pulsadores de dirección están pulsados o no seguirá con la misma velocidad
  if ((iz == 1 && de == 1)|| (iz == 0 && de == 0)){
    motor.setSpeed(255);
    motor2.setSpeed(255);
  }//Giro en sentido horario
  else if(iz == 0 && de == 1){
    Serial.println("R");
    motor.run(BACKWARD);
    motor2.run(FORWARD);
    motor.setSpeed(155);     
    motor2.setSpeed(155);
  }//Giro en sentido antihorario
  else if(iz == 1 && de == 0){
    Serial.println("L");
    motor.run(FORWARD);
    motor2.run(BACKWARD);
    motor.setSpeed(155);   
    motor2.setSpeed(155);
  }
  
  //Dejamos un retraso de 20 milisegundos
  delay(20);
}
          Como podemos apreciar en el código del sketch, si los dos botones de giro está pulsados o no simultáneamente mantendremos la dirección del vehículo. En cambio cuando pulsemos uno, invertirá el giro de uno de los motores (el conveniente para el giro en el sentido deseado) y reduce la velocidad de los motores para la realización del giro. Sin más os dejo con el funcionamiento.


martes, 18 de marzo de 2014

BiRueda Pulsador (Adelante y atrás)

          Muy bien, ya hemos visto como programar rutinas de movimiento (nada inteligentes) al vehículo BiRueda, pero lo que en principio nos interesa para el proyecto es poder mandar órdenes al vehículo. Para comenzar a enviar estos comandos vamos a usar una especie de mando con pulsadores sobre un breadboard que irá conectada directamente a Arduino.



          Como podéis ver, lo único que añadimos son las dos entradas de los pulsadores a Arduino, pines 22 y 23, con los que haremos que el BiRueda vaya Adelante o Atrás dependiendo de cual se pulse. En el caso de que no pulsemos ninguno o pulsemos los dos a la vez el vehículo permanecerá parado. Aquí podéis ver como es el sketh usado para este propósito:

//Importamos la libreria AFMotor.h
#include <AFMotor.h>
//Definimos los pines de los botones
#define ADELANTE    22
#define ATRAS       23
//Creamos los dos motores que están conectados a M1 y M2 respectivamente con frecuencia 64KHZ
AF_DCMotor motor(2, MOTOR12_64KHZ); 
AF_DCMotor motor2(1, MOTOR12_64KHZ);

//variable para la velocidad
int velocidad

//Función 'Setup'
void setup() {
  //Inicializamos Serial
  Serial.begin(9600);   
  Serial.println("BiRueda Pulsador (Adelante y atrás)");
  //Botones como entrada y abiertos
  pinMode(ADELANTE, INPUT);
  digitalWrite(ADELANTE, HIGH);
  pinMode(ATRAS, INPUT);
  digitalWrite(ATRAS, HIGH);
  //Le damos velocidad a los motores
  motor.setSpeed(255);
  motor2.setSpeed(255);
}

//Eventos de captura de los botones
//Botón adelante
boolean UP()
{
  //Si el pin está LOW quiere decir que está pulsado
  int up_pulsado = !digitalRead(ADELANTE);
  return up_pulsado;
}
//Botón atras
boolean DOWN()
{
  int down_pulsado = !digitalRead(ATRAS);
  return down_pulsado;
}
 
//Función 'Loop'
void loop() {
  //Obtenemos los eventos de cada botón usando las funciones implementadas
  boolean ad = UP();
  boolean at = DOWN();
  
  //Si los dos pulsadores están pulsados o no el BiRueda no se moverá  
  if ((ad == 1 && at==1) || (ad == 0 && at==0)){
    Serial.print(".");
    motor.run(RELEASE);
    motor2.run(RELEASE);
  }//Si sólo está pulsado ADELANTE
  else if(ad ==1){
    Serial.print("U");
    motor.run(FORWARD);
    motor2.run(FORWARD);
  }else if(at == 1){
    Serial.println("D");
    motor.run(BACKWARD);
    motor2.run(BACKWARD);
  }
  //Dejamos un retraso de 20 milisegundos
  delay(20);
}

          Como hemos visto en otros miniproyectos que usan pulsadores, necesitamos funciones para que capturen los eventos de pulsación de cada botón, que durante 'Loop' vamos comprobando para ver que comando debe ejecutar el BiRueda. Sin más os dejo con una demostración de su funcionamiento.


viernes, 14 de marzo de 2014

BiRueda Autónomo (+ Giro sobre sí mismo)

          Siguiendo con el BiRueda Autónomo (más bien podría llamarse programado, ya que lo que tiene es una rutina que repite continuamente) vamos a añadirle ahora dos funciones de giro nuevas a la rutina que se repite. Vamos a implementar el giro en sentido horario y el giro en sentido antihorario sobre sí mismo.


          Podemos observar como el prototipo diseñado y que vamos a utilizar es el mismo que el de la entrada anterior, por lo que no hay que explicar mucho más. Los giros se realizan de manera muy sencilla de esta forma: basta con invertir el sentido de una de las ruedas dependiendo de en que sentido queramos hacer el giro.

//Importamos la libreria AFMotor.h
#include <AFMotor.h>

//Creamos los dos motores que estan conectados al M1 y M2 respectivamente con una frecuencia de 64KHZ
AF_DCMotor motor(1, MOTOR12_64KHZ);
AF_DCMotor motor2(2, MOTOR12_64KHZ);

int velocidad;

//Función 'Setup'
void setup(){
  //Ajustamos la una velocidad
  velocidad = 150;
  //Lo iniciamos parados
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Inicializamos Serial
  Serial.begin(9600);
  Serial.println("Test Motor");
  
  //Le damos la velocidad a los motores
  motor.setSpeed(velocidad);
  motor2.setSpeed(velocidad);
  
}

//Función 'Loop'
void loop(){
  Serial.println("BiRueda Autonomo (Giro sí mismo Test)");
 
  //Movimiento hacia delante
  motor.run(FORWARD);
  motor2.run(FORWARD);
  
  //Dejamos 2 segundos de movimiento
  delay(2000);
  
  //Paramos
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Dejamos 1 segundos de parado
  delay(1000);
  
  //Un segundo de giro en un sentido
  motor.run(FORWARD);
  motor2.run(BACKWARD);
  delay(1000);
  
  //Paramos
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Dejamos 1 segundos de parado
  delay(1000);
  
  //Movimiento hacia atrás
  motor.run(BACKWARD);
  motor2.run(BACKWARD);
  
  //Dejamos 2 segundos de movimiento
  delay(2000);
  
  //Paramos
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Dejamos 1 segundos de parado
  delay(1000);
  
  //Un segundo de giro en un sentido
  motor.run(BACKWARD);
  motor2.run(FORWARD);
  delay(1000);
  
  //Paramos
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Dejamos 1 segundos de parado
  delay(1000);
}


          Podéis observar como funciona con el vídeo, recordando que aún las ruedas no están bien calibradas (de ahí la desviación que sufre)


jueves, 13 de marzo de 2014

BiRueda Autónomo (Adelante y Atrás)

          Vamos a empezar con el tema interesante, manejo de motores. Para Arduino existe un Shield Oficial para el control de motores, la Arduino Motor Shield:


          Como es un poco cara, me he decantado por una Shield no oficial para el control de motores, la Adafruit Motor Shield:


          Básicamente hace lo mismo, puede controlar motores DC, motores paso a paso y servomotores. Para ello hace uso de unas librerías que hay que meter en el IDE de Arduino. Para el caso en cuestión necesitaremos sólo la AFMotor.h con la que podremos controlar los dos motores DC uno para cada rueda del BiRueda que vamos a montar.

          El prototipo es realmente sencillo, tenemos que montar la Shield sobre la placa Arduino en los pines correspondientes (no hay peligro de equivocarnos, sólo encaja de una forma, no seáis brutos), enganchar los cables de cada motor en un módulo de control de motores de la Shield, colocando Vcc y Gnd en el lugar correspondiente. La alimentación se hará con una pila de 9V que conectaremos al Arduino, siendo necesaria ya que la potencia suministrada por el cable usb a Arduino es insuficiente la mayoría de las ocasiones para mover los motores.


          Una vez diseñado el prototipo lo montamos y le cargaremos el siguiente Sketch:



//Importamos la libreria AFMotor.h
#include <AFMotor.h>

//Creamos los dos motores que estan conectados al M1 y M2 respectivamente con una frecuencia de 64KHZ
AF_DCMotor motor(1, MOTOR12_64KHZ);
AF_DCMotor motor2(2, MOTOR12_64KHZ);

int velocidad;

//Función 'Setup'
void setup(){
  //Ajustamos la una velocidad
  velocidad = 150;
  //Lo iniciamos parados
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Inicializamos Serial
  Serial.begin(9600);
  Serial.println("Test Motor");
}

//Función 'Loop'
void loop(){
  Serial.println("BiRueda Autonomo (Adelante y Atras Test)");

  //Le damos la velocidad a los motores
  motor.setSpeed(velocidad);
  motor2.setSpeed(velocidad);
  
  //Movimiento hacia delante
  motor.run(FORWARD);
  motor2.run(FORWARD);
  
  //Dejamos 2 segundos de movimiento
  delay(2000);
  
  //Paramos
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Dejamos 1 segundos de parado
  delay(1000);
  
  //Movimiento hacia atrás
  motor.run(BACKWARD);
  motor2.run(BACKWARD);
  
  //Dejamos 2 segundos de movimiento
  delay(2000);
  
  //Paramos
  motor.run(RELEASE);
  motor2.run(RELEASE);
  
  //Dejamos 1 segundos de parado
  delay(1000);
}

          Podemos comprobar la sencillez de uso de la librería: comenzamos cargándola para usar sus funciones. Tendremos que crear una instancia de AF_DCMotor para cada motor, indicando en que módulo esta conectado y a que frecuencia va a trabajar. En 'Setup' inicializamos los motores como parados y la velocidad que les vamos a dar. Ya en 'Loop' le damos la velocidad a los motores y hacemos la rutina de movimiento que es: adelante dos segundo, paramos un segundo, atrás dos segundo y paramos un segundo. Para indicar los estados de los motores se usan las constantes 'RELEASE', 'FORDWARD' y 'BACKWARD'. En el vídeo demostrativo podéis apreciar como funciona y se aprecia como la potencia de los motores DC usados no están calibrados, por lo que no va en línea recta, sino que se gira sólo. De momento no es preocupante para nuestro objetivo, puesto que es muy probable que sólo use un sólo motor DC para la tracción de MotorDroid. Sin más aquí lo podéis ver. Hasta la próxima:


miércoles, 12 de marzo de 2014

Intermitentes Led Botón Estacionamiento

          A raíz del Mini-Proyecto de ayer y mientras lo publicaba por aquí me surgió la idea de añadir al coche sistema de señalización de estacionamiento, el botón con el triángulo con el que todos los intermitentes parpadean a la vez vamos. Lo dificil ya lo tenía hecho y sólo era cuestión de añadir un pulsador más al prototipo y hacer un if-else en el que el if sea el sistema de señalización de estacionamiento y el else el sistema de intermitentes ya implementado. Veamos el prototipo:


           Como podréis apreciar el nuevo pulsador va conectado al pin 40 de nuestro Arduino Mega, el resto del prototipo es exactamente igual. A continuación el infinito sketch con las funciones y cambios añadidos:


//Definimos los pines de los botones
#define IZQBOT  50
#define DERBOT  22
#define CENBOT  40
//Definimos los pines de los leds
#define IZQLED  51
#define DERLED  23

//Definimos estados para los botones
boolean izq_fue_pulsado;
boolean der_fue_pulsado;
boolean cen_fue_pulsado;

//Estados de los leds iniciados como apagados
int izqEstado = LOW;
int derEstado = LOW;

//Contadores de pulsaciones
int pulsacionesIzq;
int pulsacionesDer;
int pulsacionesCen;

//Tiempo de parpadeo
const long parpadeo = 600;

//Tiempos previos
unsigned long tiempoPrevioI = 0; 
unsigned long tiempoPrevioD = 0; 
unsigned long tiempoPrevioC = 0; 

//Función 'Setup'
void setup(){
  //Botones como entrada y abiertos
  pinMode(IZQBOT, INPUT);
  digitalWrite(IZQBOT, HIGH);
  
  pinMode(DERBOT, INPUT);
  digitalWrite(DERBOT, HIGH);
  
  pinMode(CENBOT, INPUT);
  digitalWrite(CENBOT, HIGH);
  
  //Leds como salida
  pinMode(IZQLED, OUTPUT);
  pinMode(DERLED, OUTPUT);
  
  //Inicialmente los botones no están pulsados
  izq_fue_pulsado = false;
  der_fue_pulsado = false;
  cen_fue_pulsado = false;
  
  //Número de pulsaciones
  pulsacionesIzq = 0;
  pulsacionesDer = 0;
  pulsacionesCen = 0;
  
  //Inicializamos el puerto Serial
  Serial.begin(9600);
}

//Funcion pulsar izquierda
boolean eventoPulsoIzq(){
  //Evento a devolver
  boolean evento;
  //Comprobamos estado actual del botón
  int izq_esta_pulsado = !digitalRead(IZQBOT);
  //Boton pulsado ahora y no estaba pulsado
  evento = izq_esta_pulsado & !izq_fue_pulsado;
  //Actualizamos el estado del boton
  izq_fue_pulsado = izq_esta_pulsado;
  //Devolvemos el evento
  return evento;
}

//Funcion pulsar derecha (Análogo a eventoPulsoIzq)
boolean eventoPulsoDer(){
  //Evento a devolver
  boolean evento;
  //Comprobamos estado actual del botón
  int der_esta_pulsado = !digitalRead(DERBOT);
  //Boton pulsado ahora y no estaba pulsado
  evento = der_esta_pulsado & !der_fue_pulsado;
  //Actualizamos el estado del boton
  der_fue_pulsado = der_esta_pulsado;
  //Devolvemos el evento
  return evento;
}

//Funcion pulsar derecha (Análogo a eventoPulsoIzq)
boolean eventoPulsoCen(){
  //Evento a devolver
  boolean evento;
  //Comprobamos estado actual del botón
  int cen_esta_pulsado = !digitalRead(CENBOT);
  //Boton pulsado ahora y no estaba pulsado
  evento = cen_esta_pulsado & !cen_fue_pulsado;
  //Actualizamos el estado del boton
  cen_fue_pulsado = cen_esta_pulsado;
  //Devolvemos el evento
  return evento;
}

//Funcion parpadeo de led izquierdo
void parpadeoLedIZQ(){
  //Obtenemos el tiempo actual
  unsigned long tiempoActualI = millis();
  //Si la diferencia es mayor que el intervalo de tiempo de parpadeo es cuando actualizamos el estado del led
  if(tiempoActualI - tiempoPrevioI >= parpadeo) {
    //Guardamos el instante de tiempo
    tiempoPrevioI = tiempoActualI;   
    //Si el led esta encendido lo apagamos y viceversa
    if (izqEstado == LOW)
      izqEstado = HIGH;
    else
      izqEstado = LOW;
  }
    // Actualizamos el led
    digitalWrite(IZQLED, izqEstado);
}

//Funcion parpadeo de led derecho
void parpadeoLedDER(){
  //Obtenemos el tiempo actual
  unsigned long tiempoActualD = millis();
  //Si la diferencia es mayor que el intervalo de tiempo de parpadeo es cuando actualizamos el estado del led
  if(tiempoActualD - tiempoPrevioD >= parpadeo) {
    //Guardamos el instante de tiempo
    tiempoPrevioD = tiempoActualD;   
    //Si el led esta encendido lo apagamos y viceversa
    if (derEstado == LOW)
      derEstado = HIGH;
    else
      derEstado = LOW;
  }
    // Actualizamos el led
    digitalWrite(DERLED, derEstado);
}

//Funcion parpadeo de leds
void parpadeoLedCEN(){
  //Obtenemos el tiempo actual
  unsigned long tiempoActualC = millis();
  //Si la diferencia es mayor que el intervalo de tiempo de parpadeo es cuando actualizamos el estado del led
  if(tiempoActualC - tiempoPrevioC >= parpadeo) {
    //Guardamos el instante de tiempo
    tiempoPrevioC = tiempoActualC;   
    //Si el led esta encendido lo apagamos y viceversa
    if (derEstado == LOW){
      derEstado = HIGH;
      izqEstado = HIGH;
    }else{
      derEstado = LOW;
      izqEstado = LOW;
    }
  }
    // Actualizamos el led
    digitalWrite(DERLED, derEstado);
    digitalWrite(IZQLED, izqEstado);
}

//Funcion que añade linea al Serial
void lineaSerial(){
    static int contador = 0;
  if((++contador & 0x3f)==0){
    Serial.println();
  }
}

//Función 'Loop'
void loop(){
  
  //Capturamos los eventos de los botones
  boolean izqpulsado = eventoPulsoIzq();
  boolean derpulsado = eventoPulsoDer();
  boolean cenpulsado = eventoPulsoCen();
  
  //Actualizamos las pulsaciones
  pulsacionesIzq += izqpulsado;
  pulsacionesDer += derpulsado;
  pulsacionesCen += cenpulsado;

  //Si pulsamos el estacionador reinicia los contadores de los intermitentes
  if((pulsacionesCen%2) == 1){
    pulsacionesIzq = 0;
    pulsacionesDer = 0;
    parpadeoLedCEN();
  }else{
  
    //Si el módulo 2 de las pulsaciones es 1 activamos el parpadeo
    if((pulsacionesIzq%2) == 1 && (pulsacionesDer%2) == 0){
      parpadeoLedIZQ();
    }
    if((pulsacionesDer%2) == 1 && (pulsacionesIzq%2) == 0){
      parpadeoLedDER();
    }
    //Si el módulo 2 de las pulsaciones es 0 apagamos los leds
    if((pulsacionesDer%2) == 0 && (pulsacionesIzq%2) == 0){
      digitalWrite(DERLED, LOW);
      digitalWrite(IZQLED, LOW);
    }//Si un led estaba en función parpadeo al pulsar el otro, le sumamos 1 y lo apagamos
      if((pulsacionesIzq%2) == 1 && (pulsacionesDer%2) == 1){
        if(izqpulsado == 1){
          pulsacionesDer += 1;
          digitalWrite(DERLED, LOW);
        }else if(derpulsado == 1){
          pulsacionesIzq += 1;
          digitalWrite(IZQLED, LOW);
        }
    }
  }
  
  //Mostramos el número de pulsaciones
  Serial.print(pulsacionesIzq);
  Serial.print(pulsacionesDer);
  Serial.print(pulsacionesCen);
  //Mostramos por Serial las pulsaciones
  Serial.print(izqpulsado ? "I" : ".");
  Serial.print(derpulsado ? "D" : ".");
  Serial.print(derpulsado ? "C" : ".");
  
  //Añadimos líneas cada cierto tiempo
  lineaSerial();
  
  //Imponemos un retraso en el loop
  delay(20);
}

          Básicamente hemos añadido lo necesario para que el pulsador nuevo sea independiente a los otros puesto que causaba fallos utilizar los parpadeos de cada led. Por lo tanto se implementa parpadeoLedCen() y el evento para capturar la pulsación. Ya en 'Loop' cuando se pulse el botón nuevo hacemos que los contadores izquierdo y derecho se pongan a 0 y activamos el parpadeo de todos los leds al unísono. Realmente son cambios sencillos con respecto al anterior programa, sólo se ve muy extenso y eso asusta a los inexpertos. Os dejo un vídeo de como funciona:


martes, 11 de marzo de 2014

Intermitentes Led Boton

          Como comenté en la última entrada, a partir de ahora los prototipos, pero sobre todo, los sketchs que vamos a implementar se van a complicar de manera considerable, resultando muy pesada la explicación pormenorizada de todo lo que hacemos. Por lo tanto, se dará una idea general de lo que queremos hacer, ver un poco como es el prototipo a implementar y el sketch vendrá bien comentado como siempre, pero dejaremos unas pinceladas de lo hecho. Comencemos con el Mini-Proyecto de hoy.

          Vamos a realizar el sistema de intermitentes que va a usar nuestro MotorDroid (que chulo suena... xD). De momento vamos a ir haciendo uso de pulsadores para el control de los comandos que va a tener el vehículo, posteriormente se hará mediante comandos desde un smartphone Android mediante bluetooth, intentando extrapolar las ideas básicas usadas con los pulsadores. En fin, no me adelanto y vamos a lo de hoy.


          Usaremos para el montaje del prototipo dos leds amarillos (estoy esperando los naranjas...) que realmente serán cuatro, dos por pulsador (los dos izquierdos y los dos derechos), dos resistencias de 1KOmn y dos pulsadores. Conectaremos el pulsador izquierdo al pin 50 y el led izquierdo al pin 51 con cables azules; y los derechos con verdes al pin 22 y 23 respectivamente. A continuación vemos el sketch infinito que cargaremos en nuestro Arduino Mega para que realice esta función.

//Definimos los pines de los botones
#define IZQBOT  50
#define DERBOT  22
//Definimos los pintes de los leds
#define IZQLED  51
#define DERLED  23

//Definimos estados para los botones
boolean izq_fue_pulsado;
boolean der_fue_pulsado;

//Estados de los leds iniciados como apagados
int izqEstado = LOW;
int derEstado = LOW;

//Contadores de pulsaciones
int pulsacionesIzq;
int pulsacionesDer;

//Tiempo de parpadeo
const long parpadeo = 600;

//Tiempos previos
unsigned long tiempoPrevioI = 0; 
unsigned long tiempoPrevioD = 0; 

//Función 'Setup'
void setup(){
  //Botones como entrada y abiertos
  pinMode(IZQBOT, INPUT);
  digitalWrite(IZQBOT, HIGH);
  
  pinMode(DERBOT, INPUT);
  digitalWrite(DERBOT, HIGH);
  
  //Leds como salida
  pinMode(IZQLED, OUTPUT);
  pinMode(DERLED, OUTPUT);
  
  //Inicialmente los botones no están pulsados
  izq_fue_pulsado = false;
  der_fue_pulsado = false;
  
  //Número de pulsaciones
  pulsacionesIzq = 0;
  pulsacionesDer = 0;
  
  //Inicializamos el puerto Serial
  Serial.begin(9600);
}

//Funcion pulsar izquierda
boolean eventoPulsoIzq(){
  //Evento a devolver
  boolean evento;
  //Comprobamos estado actual del botón
  int izq_esta_pulsado = !digitalRead(IZQBOT);
  //Boton pulsado ahora y no estaba pulsado
  evento = izq_esta_pulsado & !izq_fue_pulsado;
  //Actualizamos el estado del boton
  izq_fue_pulsado = izq_esta_pulsado;
  //Devolvemos el evento
  return evento;
}

//Funcion pulsar derecha (Análogo a eventoPulsoIzq)
boolean eventoPulsoDer(){
  //Evento a devolver
  boolean evento;
  //Comprobamos estado actual del botón
  int der_esta_pulsado = !digitalRead(DERBOT);
  //Boton pulsado ahora y no estaba pulsado
  evento = der_esta_pulsado & !der_fue_pulsado;
  //Actualizamos el estado del boton
  der_fue_pulsado = der_esta_pulsado;
  //Devolvemos el evento
  return evento;
}

//Funcion parpadeo de led izquierdo
void parpadeoLedIZQ(){
  //Obtenemos el tiempo actual
  unsigned long tiempoActualI = millis();
  //Si la diferencia es mayor que el intervalo de tiempo de parpadeo es cuando actualizamos el estado del led
  if(tiempoActualI - tiempoPrevioI >= parpadeo) {
    //Guardamos el instante de tiempo
    tiempoPrevioI = tiempoActualI;   
    //Si el led esta encendido lo apagamos y viceversa
    if (izqEstado == LOW)
      izqEstado = HIGH;
    else
      izqEstado = LOW;
  }
    // Actualizamos el led
    digitalWrite(IZQLED, izqEstado);
}

//Funcion parpadeo de led derecho
void parpadeoLedDER(){
  //Obtenemos el tiempo actual
  unsigned long tiempoActualD = millis();
  //Si la diferencia es mayor que el intervalo de tiempo de parpadeo es cuando actualizamos el estado del led
  if(tiempoActualD - tiempoPrevioD >= parpadeo) {
    //Guardamos el instante de tiempo
    tiempoPrevioD = tiempoActualD;   
    //Si el led esta encendido lo apagamos y viceversa
    if (derEstado == LOW)
      derEstado = HIGH;
    else
      derEstado = LOW;
  }
    // Actualizamos el led
    digitalWrite(DERLED, derEstado);
}

//Funcion que añade linea al Serial
void lineaSerial(){
    static int contador = 0;
  if((++contador & 0x3f)==0){
    Serial.println();
  }
}

//Función 'Loop'
void loop(){
  
  //Capturamos los eventos de los botones
  boolean izqpulsado = eventoPulsoIzq();
  boolean derpulsado = eventoPulsoDer();
  
  //Actualizamos las pulsaciones
  pulsacionesIzq += izqpulsado;
  pulsacionesDer += derpulsado;
  
  //Si el módulo 2 de las pulsaciones es 1 activamos el parpadeo
  if((pulsacionesIzq%2) == 1 && (pulsacionesDer%2) == 0){
    parpadeoLedIZQ();
  }
  if((pulsacionesDer%2) == 1 && (pulsacionesIzq%2) == 0){
    parpadeoLedDER();
  }
  //Si el módulo 2 de las pulsaciones es 0 apagamos los leds
  if((pulsacionesDer%2) == 0 && (pulsacionesIzq%2) == 0){
    digitalWrite(DERLED, LOW);
    digitalWrite(IZQLED, LOW);
  }//Si un led estaba en función parpadeo al pulsar el otro, le sumamos 1 y lo apagamos
    if((pulsacionesIzq%2) == 1 && (pulsacionesDer%2) == 1){
      if(izqpulsado == 1){
        pulsacionesDer += 1;
        digitalWrite(DERLED, LOW);
      }else if(derpulsado == 1){
        pulsacionesIzq += 1;
        digitalWrite(IZQLED, LOW);
      }
  }
  
  //Mostramos el número de pulsaciones
  Serial.print(pulsacionesIzq);
  Serial.print(pulsacionesDer);
  //Mostramos por Serial las pulsaciones
  Serial.print(izqpulsado ? "I" : ".");
  Serial.print(derpulsado ? "D" : ".");
  
  //Añadimos líneas cada cierto tiempo
  lineaSerial();
  
  //Imponemos un retraso en el loop
  delay(20);
}

          Básicamente, tenemos que capturar los eventos de pulsación de los botones, que serán los encargados de decir a los leds si están apagados o haciendo el parpadeo sin delay como vimos anteriormente. Contamos las pulsaciones para permutar el estado del led entre apagado o parpadeando, si el módulo 2 del número de pulsaciones es 1 entraremos en modo parpadeo, si es 0 se apagará. Además, cuando un led esta en función parpadeo y se pulse el botón del otro led se debe cambiar el estado del otro led además de poner en parpadeo el nuestro. Es decir, o están los dos leds apagados o sólo uno de los dos en modo parpadeo. Quizás en un futuro implemente con otro botón aparte la función estacionaria, haciendo que todos los leds parpadeen simultáneamente. Os dejo el vídeo de muestra para que veáis como funciona (que seguro no me habéis entendido... ^^'):


martes, 4 de marzo de 2014

Parpadeo Led sin Delay

          Ya hemos visto como hacer parpadear un led, ¿para que necesitamos entonces conocer otra forma de hacerlo? Pues muy simple. En ocasiones es necesario hacerlo parpadear mientras realizamos otra tarea. Este es el caso si hacemos unas luces intermitentes accionadas mediante botones, que será como comencemos a a manejar nuestro coche.

          El diseño del prototipo es exactamente el mismo que cuando usamos el delay, sólo que ahora estoy usando los componentes míos propios (ya me están llegando las piezas del puzzle) y por ello hacemos uso del Arduino Mega (me ha llegado antes que el Uno, no me lo creo ni yo) y un led ahora de color azul.


          La idea es muy sencilla, tendremos una variable con intervalo de tiempo y un instante inicial. Por cada vuelta por la función 'loop' comprobamos el tiempo actual y si la diferencia es mayor que el intervalo preestablecido pasamos a actualizar el estado del led, lo apagamos si estaba encendido o lo encendemos si estaba apagado.

//Definimos el pin para el led
#define led   12
//Estado del led
int estadoLed = LOW;
// Usamos unsined long vara variables de tiempo
// guarda el momento en el que el led fue //actualizado (es decir, cuando se apagó o //encendió por última vez)

unsigned long tiempoPrevio = 0;      
//Intervalo de tiempo del parpadeo
const long intervalo = 600;        
// Función 'Setup'
void setup() {
  // Inicializamos el pin 'led' como salida
  pinMode(led, OUTPUT);    
}
// Función 'Loop'
void loop(){
  //Obtenemos el tiempo actual
  unsigned long tiempoActual = millis();
  //Si la diferencia es mayor que el intervalo de //tiempo de parpadeo es cuando actualizamos el //estado del led
  if(tiempoActual - tiempoPrevio >= intervalo) {
    //Guardamos el instante de tiempo
    tiempoPrevio = tiempoActual;
    //Si el led esta encendido lo apagamos y //viceversa
    if (estadoLed == LOW)
      estadoLed = HIGH;
    else
      estadoLed = LOW;
    // actualizamos el led
    digitalWrite(led, estadoLed);
  }
}

          A partir de ahora comenzaré a hacer cosas un poco más complejas, haciendo uso de más componentes ya que me están llegando las piezas con las que montaré el coche completo. Os dejo el resultado en un video: