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:

lunes, 24 de febrero de 2014

Parpadeo Led con Delay

          Vamos a ver como hacer parpadear un led haciendo uso de la función delay. Esta función hace a Arduino esperar un número especificado de milisegundos antes de continuar ejecutando la siguiente línea de código. Sabiendo que hay 1000 milisegundos en un segundo, el código 'delay(1000);' crea un retraso de un segundo.

          El circuito que montaremos es sencillo, simplemente tendremos un led con una resitencia que lo conecta a tierra y el otro pin lo conectamos al pin 12 de Arduino. Aquí podéis ver el prototipo:


          Realmente podríamos hacer uso del pin 13 de Arduino para no usar la breadboard ya que en la mayoría de las placas Arduino tienen una resistencia de un KOhm en ese pin permitiendo conectar un Led directamente. Pero para ir haciendo uso de componentes lo conectamos a otro pin (cómo el 12 en nuestro caso) añadiéndole la resistencia. Los LEDs tiene polaridad, es decir, sólo se encenderán si los orientamos correctamente. Lo usual es que la patilla más larga sea el positivo y el que tengamos que conectar al pin debido, siendo la patilla corta la que debe de ir a tierra (GND).

          A continuación el código que hace nuestro propósito, que como veis es muy sencillo:

//Definimos el pin para el led
#define led   12
// Función 'Setup'
void setup() {              
  // Inicializamos el pin 'led' como salida
  pinMode(led, OUTPUT);    
}
// Función 'Loop'
void loop() {
  // encendemos el LED (Ponemos el voltaje a 'HIGH')
  digitalWrite(led, HIGH);
  // esperamos medio segundo
  delay(500);        
  // apagamos el LED (Ponemos el voltaje a 'LOW')
  digitalWrite(led, LOW);
  // esperamos medio segundo 
  delay(500);              
}

          Para entender un poco más como funcionan los Sketch, voy a hablar de otras dos funciones básicas usadas para programar Arduino. pinMode como podéis imaginar configura un pin de Arduino como entrada o salida. Para usarla, pasamos como argumento el número del pin que vamos a configurar y la constante INPUT o OUTPUT. Como input podemos manejar estados de sensores, como un botón , y como salida podemos manejar entre otras cosas Leds, como vimos en el Simple Boton Led. Por otra parte, la función digitalWrite envía un valor a un pin. Como podemos ver, si escribimos 'digitalWrite(led, HIGH)' modificamos el pin 12 como HIGH o 5 voltios.

          Y esto es todo por esta vez, os dejo que veáis como funciona:



         

sábado, 22 de febrero de 2014

Simple Boton Led

          Comenzamos con los Mini-Proyectos que irán formando parte del TFG, con los cuáles iremos avanzando en el estudio de Arduino y Android para la realización exitosa del proyecto. Comenzaré siempre haciendo una breve descripción de lo que quiero hacer, continuando con imágenes de los prototipos usados, Sketches con su explicación, vídeos demostrativos, etc... dependiendo del Mini-Proyecto que esté afrontando. Comenzamos.

         Vamos a hacer que un led se encienda cuando pulsemos un botón y se apague cuando no lo hagamos. Así vamos a ver el funcionamiento básico de la placa Arduino, cómo diseñar un prototipo en Fritzing y cómo programar y cargar un Sketch.

          En primer lugar vamos a hacer el diseño del prototipo con Fritzing. Es tan simple como abrir el programa, guardar el proyecto con un nombre y a continuación ir añadiendo a la ventana principal todos los componentes que vamos a utilizar para el prototipo. En nuestro caso: placa Arduino, breadboard, led, botón y resistencia.


          Colocamos y conectamos los componentes de la forma que aparece en la imagen. Simplemente pinchamos en un "agujero", arrastramos y soltamos en otro "agujero" para realizar una conexión. La resistencia la usamos para no fundir el led, disminuyendo la intensidad de corriente que pasa por él. Conectamos el botón al PIN de Arduino 2 y el led en el PIN de Arduino 12. Posteriormente lo montamos.

          La programación de un Sketch es relativamente sencilla: Tiene dos métodos principales que son setup y loop. En setup realizamos la configuración de los pines y de los componentes y variables que vamos a utilizar. Loop es el bucle principal que se repite continuamente y es donde tendremos que realizar las acciones. A continuación os muestro el Sketch explicado utilizado para hacer que Arduino capture la pulsación del botón y así encender o no el led:

//Definimos los pines para el led y el botón
#define  boton  2
#define  led    12
//Definimos una variable para saber el estado del botón
int estadoBoton = 0;
//Método 'Setup'
void setup(){
  //Inicializamos el pin 'led' como salida
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);
  //Inicializamos el pin 'botón' como entrada
  pinMode(boton, INPUT);
  //Modo 'pull up'
  digitalWrite(boton, HIGH);
}
//Método 'Loop'
void loop(){
  //Lee el valor del estado de 'boton'
  estadoBoton = digitalRead(boton);
  //Comprobamos si está pulsado
  if (estadoBoton == LOW){
    //Encendemos el led
    digitalWrite(led ,HIGH);
  }else{
    //Apagamos el led
    digitalWrite(led, LOW);
  }
}

          Para terminar os dejo un vídeo demostrativo de como funciona correctamente. Espero que os haya gustado, esto sólo es el comienzo...



jueves, 20 de febrero de 2014

Fritzing

          Continuando con los entornos que voy a utilizar en el desarrollo de mi trabajo fin de grado (TFG), hoy os voy a hablar de una que me va a ser de mucha ayuda, ya que ando muy pegado en cuando a circuitos electrónicos (lo poco que recuerdo de las clases de tecnología del instituto con el gran Jorge y un tema de física de primero en la facultad, con sus problemas de circuitos y demás, pero poco práctico) y no es otro que Fritzing.


         Fritzing es un programa de código libre para el diseño y desarrollo de circuitos electrónicos cuyo software es usado por investigadores, ingenieros (lo que quiero ser), aficionados (lo que soy de momento) y artistas (sólo cuando me viene la inspiración). Fritzing fue creado bajo los principios de Processing y Arduino, y permite documentar los prototipos o maquetas basados en Arduino en mi caso y crear esquemas de circuitos impresos. Dispone de un conjunto de librerías con elementos electrónicos para poder diseñar circuitos, entre ellos las placas Arduino, leds, resistencias, condensadores, diodos, etc... Además de la librería básica en la que se encuentran casi todos los elementos necesarios para realizar los circuitos, podremos encontrar librerías de otros fabricantes de hardware libre.

También cuenta con un sitio web que ayuda a compartir y discutir diseños de prototipos y costa de una gran comunidad. Desde la propia página nos podemos descargar el programa con el que trabajaremos en los prototipos y que usare tanto para la documentación de los circuitos que implementaré en el proyecto como en los ejemplos que iré mostrando aquí. Os dejo una imagen de ejemplo de qué es lo que podemos hacer con Fritzing y un videotutorial.






martes, 18 de febrero de 2014

Arduino: entornos de programación

          Tal cómo dije en Hola Mundo!, mi PFG estará compuesto por un Arduino, y muchos os preguntaréis, ¿y qué es un Arduino?

          Arduino es una plataforma de hardware libre, basada en una placa con un microcontrolador, diseñada para facilitar el use de la electrónica en proyectos multidisciplinares. El hardware es una placa con un microcontrolador Atmel AVR y puertos de entrada/salida, muy sencillos y de bajo coste que permiten muchos diferentes diseños. El software consiste en un entorno de desarrollo que implementa el lenguaje de programación Processing/Wiring y el cargador de arranque que es ejecutado en la placa. Aparte de la placa, existe muchísimos módulos con los que trabajar (BT, IR, Servo, Leds,...) además de "Shields" que hacen trabajos específicos que frecuentemente vienen con sus propias librerías. Para más información está su web oficial



         Hay muchos tipos de Arduino, dependiendo del microcontrolador, voltajes, frecuencia de reloj, etc... En mi caso en haré uso del Arduino Uno - R3 cuyas características son:
  • Microcontrolador: ATmega328
  • Voltaje entrada/salida: 7-12V / 5V
  • Frecuencia de reloj: 16MHz
  • Digital I/O: 14
  • Entradas Analógicas: 6
  • PWM: 6
  • UART: 1
  • Memoria Flash: 32Kb
  • Cargador: Optiboot
  • Interfaz de Programación: USB via ATMega16U2
[EDITADO] Es muy probable que cambie de placa, puesto que estudiando el proyecto a realizar necesite algunos pines más de los que me ofrece el Arduino Uno - R3, así pues os dejo con las características también del modelo Arduino Mega 2560 R3:
  • Microcontrolador: ATmega2560
  • Voltaje entrada/salida: 7-12V / 5V
  • Frecuencia de reloj: 16MHz
  • Digital I/O: 54
  • Entradas Analógicas: 16
  • PWM: 14
  • UART: 4
  • Memoria Flash: 256Kb
  • Cargador: STK500v2
  • Interfaz de Programación: USB vía ATMega16U2



         Como entorno de programación tenemos el Arduino IDE, de código abierto y fácil de escribir código. Se ejecuta sobre Windows, MacOS y Linux. Está escrito en Java y está basado en Processing y algún que otro software abierto. Opcionalmente podremos usar una extensión para Visual Studio llamada "Visual Micro" con el que podremos escribir y cargar los programas para Arduino desde este IDE.. Podemos ver como es el funcionamiento fundamental de Arduino. Básicamente, escribimos programas o "Sketch" que harán que funcione un determinado circuito electrónico que tengamos implementado. Con el microcontrolador podemos hacer uso de Pines Digitales, Entradas Analógicas, PWM (modulación por ancho de pulso), etc...

         Hemos visto una pequeña introducción de Arduino, qué es y cómo funciona. Existe una gran comunidad detrás de este proyecto de hardware libre y podremos encontrar mucha información con relativa facilidad.