Asustando a mBot

Introducción

La idea con este juego que realizaremos con nuestro robot mBot es experimentar las características del sensor de luz integrado dentro de la placa mCore y el módulo adicional de sensor de sonido.

Por otro lado también experimentaremos con la matriz de LEDs de 8×16 que nos permitirá poner caras divertidas a nuestro robot.

También utilizaremos otros componentes integrados en la placa como el zumbador y los LEDs RGB.

Operativa del juego:

    • Pondremos un umbral de luminosidad en el cual consideramos que es de día y el robot está “despierto”. Si no se supera este umbral querrá decir que es de noche y por tanto el robot estará “dormido”.
    • Si está “despierto” el robot mostrará una serie de secuencia de gestos de ojos en la matriz de LEDs que cambiará si se encuentra “dormido”.
    • Cuando se detecte un sonido que supere un cierto umbral el robot se “asustará” y se iniciará una secuencia de gestos en la matriz de LEDs (ojos de sorpresa) acompañados de sonidos.
    • Si se considera que es de noche y por tanto está “dormido” esta secuencia se acompañará con la iluminación de los dos LEDs que se encuentran integrados en la placa por el contrario si consideramos que es de día y por tanto está “despierto” en vez de encender los LEDs haremos que realice unos pequeños movimientos a izquierda y derecha. Durante la noche el umbral de sonido será más sensible que durante el día.

Para ver el funcionamiento de lo anteriormente descrito aquí os dejo el video demostrativo del juego:

Listado de componentes

    • Robot mBot.
    • Matriz de LEDs.
    • Pack de estructuras para mBot.
    • 2 x Cable RJ25 20cm.

Montaje de componentes

Para poder realizar el juego necesitaremos instalar el módulo de sensor de sonido mediante el pack de estructuras para mBot.

También instalaremos la matriz de LEDs en la parte frontal del robot.

La conexiones de los diferentes módulos a los puertos de la placa mCore serán:

    • Módulo sensor de sonido: Puerto 4.
    • Matriz de LEDs: Puerto 3.

Programación

Antes de mostrar el sketch con toda la programación del juego hay que tener en cuenta la siguiente observación:

En la función secuenciaCara() no podemos utilizar instrucciones como el delay o permanecer en un bucle  ya que pararía la ejecución en un punto concreto.

Para ello se ha utilizado la instrucción millis() : if (millis() – t > intervalo)  que nos permite ejecutar cada “x” tiempo ciertas instrucciones sin detenerse en un punto.

De esta manera no paramos la ejecución en ningún punto concreto y el hilo de ejecución podrá detectar si se produce un sonido mientras se está ejecutando una secuencia de la cara y por tanto iniciar la secuencia de alerta lo antes posible.

Por otro lado para la realización de las caras he utilizado el entorno de programación mBlock de Makeblock que tiene una herramienta visual para realizar esta tarea de un modo fácil.

Por último os dejo el sketch con toda la programación:

// ---------------------------------------------------------------------------
// mBot (asuntando al mBot) - v1.0 - 04/02/2018
//
// AUTOR/LICENCIA:
// Creado por Angel Villanueva - @avilmaru
// Copyright 2018 Licencia: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
//
// LINKS:
// Blog: https://mecatronicalab.es
//
//
// HISTORICO:
// 04/02/2018 v1.0 - Release inicial.
//
// ---------------------------------------------------------------------------

#include <MeMCore.h>

MeLEDMatrix ledMx(PORT_3);
MeSoundSensor sensorSonido(PORT_4);

MBotDCMotor motor(PORT_1);
MeLightSensor sensorLuz(PORT_6);
MeRGBLed rgbLed(PORT_7,2);
MeBuzzer buzzer;

const int UMBRAL_LUZ  = 300;
const int UMBRAL_SONIDO_DIURNO = 500;
const int UMBRAL_SONIDO_NOCTURNO = 300;

unsigned char *cara;
String ultimoModo = "";

unsigned int luminosidad;
unsigned int sonido;
unsigned long t0 = 0;
uint8_t secuencia = 0;

void setup()
{

  ledMx.setBrightness(6);
  ledMx.setColorIndex(1);
  ledMx.clearScreen();

  motor.move(1,0);
  
  rgbLed.setColor(0,0,0,0);
  rgbLed.show();

}

void loop()
{

    luminosidad = sensorLuz.read();
    if (luminosidad > UMBRAL_LUZ)
    {
        sonido = sensorSonido.strength();
        if (sonido > UMBRAL_SONIDO_DIURNO)
            secuenciaAlerta("DESPIERTO");
        else
            secuenciaCara(1000,"DESPIERTO");
      
    }else{
      
        sonido = sensorSonido.strength();
        if (sonido > UMBRAL_SONIDO_NOCTURNO)
           secuenciaAlerta("DORMIDO");
        else
            secuenciaCara(1000,"DORMIDO");
    }

}
     

/*
 
En esta función no podemos utilizar instrucciones como el delay o permanecer en un bucle  ya que pararía la ejecución en un punto concreto.
Para ello se ha utilizadola instrucción millis()  (Ej:. if (millis() - t > intervalo) ) que nos permite ejecutar cada x tiempo ciertas instrucciones sin detenerse 
en un punto.
De esta manera no paramos la ejecución en ningún punto concreto y el hilo de ejecución podrá detectar si se produce un sonido mientras se está ejecutando una secuencia
de la cara y por tanto iniciar la secuencia de alerta lo antes posible

*/  
void secuenciaCara(unsigned long intervalo, String modo)
{

  if (millis() - t0 > intervalo)
  {

    t0 = millis();
    
    if (ultimoModo != modo)
      secuencia = 0;

    secuencia++;  

    if (modo == "DESPIERTO")
    {
          switch (secuencia)
          {
            case 1:
                cara = new unsigned char[16]{0,60,66,74,74,66,60,0,0,60,66,74,74,66,60,0};
                break;
            case 2:
                cara = new unsigned char[16]{0,60,66,66,66,90,60,0,0,60,66,66,66,90,60,0};
                break;
            case 3:
                cara = new unsigned char[16]{0,60,90,66,66,66,60,0,0,60,90,66,66,66,60,0};
                secuencia=0;
                break;    
          }
          
    }else if (modo == "DORMIDO")
    {
        switch (secuencia)
        {
            case 1:
                cara = new unsigned char[16]{0,16,8,8,8,16,0,0,0,0,16,8,8,8,16,0};
                break;
            case 2:
                cara = new unsigned char[16]{0,0,16,8,8,8,16,0,0,0,0,16,8,8,8,16};
                secuencia=0;
                break;
        }
        
    }
 
    mostrarCara(cara);
    ultimoModo = modo;
    
  }

}

/* 

En esta función si que utilizaremos delays ya que nos interesa que se ejecute entera y no tenga en cuenta si existe o no un sonido mientras se ejecuta
a diferencia de la función anterior.

*/

void secuenciaAlerta(String modo)
{

  bool activaMovimiento = false;
  rgbLed.setColor(0,0,0,0); 
  rgbLed.show();

  if (modo == "DESPIERTO")
  {
     activaMovimiento = true;
  }
  else
  {
    rgbLed.setColor(0,0,0,255); // Azul
    rgbLed.show();
    
  }
   
  
  cara = new unsigned char[16]{60,66,129,153,153,129,66,60,60,66,129,153,153,129,66,60};
  mostrarCara(cara);
  buzzer.tone(784, 500); // esto ya produce delay
  
  cara = new unsigned char[16]{60,66,129,129,129,129,66,60,60,66,129,129,129,129,66,60};
  mostrarCara(cara);
  
  if (activaMovimiento)
      motor.move(3,255);

  delay(300);
  
  cara = new unsigned char[16]{60,66,129,153,153,129,66,60,60,66,129,153,153,129,66,60};
  mostrarCara(cara);
  
  if (activaMovimiento)
    motor.move(4,255);

  buzzer.tone(330, 300);  // esto ya produce delay


  cara = new unsigned char[16]{60,66,129,129,129,129,66,60,60,66,129,129,129,129,66,60};
  mostrarCara(cara);

  if (activaMovimiento)
    motor.move(3,255);

  delay(300);
  
  cara = new unsigned char[16]{60,66,129,153,153,129,66,60,60,66,129,153,153,129,66,60};
  mostrarCara(cara);

  if (activaMovimiento)
    motor.move(4,255);

  buzzer.tone(330, 300);  // esto ya produce un delay

  motor.move(1,0);
  rgbLed.setColor(0,0,0,0);
  rgbLed.show();
    
  delay(400);
        
}

void mostrarCara(unsigned char *cara)
{

  unsigned char drawBuffer[16];

  memcpy(drawBuffer,cara,16);
  free(cara);
  ledMx.drawBitmap(0,0,16,drawBuffer);
  
}