Diagrama Dado Sencillo Neopixel

Descripción:

En esta práctica trabajamos valores aleatorios usando el generador pseudo aleatorio de las librerías de Arduino.

Para mostrar los valores generados se utiliza la plataforma Arduino y una serie de NeoPixeles formando un dado sencillo.


Contenido/Competencias:

  • Despliegue de información en interfaces sencillas (NeoPixel)
  • Generación de Números Aleatorios
  • Despliegue de información por terminal serial
  • Programa aplicaciones para sistemas automatizados.
  • CE9 Diseña modelos o prototipos para resolver problemas, satisfacer necesidades o
    demostrar principios científicos
  • CG6.1 Elige las fuentes de información más relevantes para un propósito específico y
    discrimina entre ellas de acuerdo a su relevancia y confiabilidad
  • OM1 Actualizarse respecto a las mejores prácticas en su especialidad o área de
    trabajo

El Plan:

  • Arma y programa el circuito.
  • Registrar varias corridas por semilla inicial y los resultados analizalos para buscar patrones.
  • (Opcional) analiza las secuencias en alguna aplicación de hoja de cálculo.
  • Documenta tus resultados

Hardware:

Descripción Cantidad Notas
Arduino UNO 1 Compatible
Cables Varios
Boton 1 Para control de Dado
DIP Switch 1 Para control de la semilla
NeoPixel 7 Conectados en serie

Software:

  • Arduino IDE o Editor de preferencia
  • Librerías Adafruit_NeoPixel.h
  • Arduino UNO o Simulador (Proteus VSM, TinkerCAD)

Recursos:


Diagrama:

Diagrama Dado Sencillo Neopixel


Codigo:

// Carlos Francisco Alvarez Salgado
// Tijuana B.C. Enero 2021
// Generador de Numeros pseudo-aleatorios
// El Plan:
// Vamos a generar múltiples repeticiones con la secuencia de números pseudo-aleatorios
// usando una semilla fija, registrándolos para compararlos con repeticiones con 
// una semilla obtenida aleatoriamente por la entrada análoga flotante o no conectada.

// Desarrollo:
// Arma y programa el circuito.
// Registrar varias corridas por semilla inicial y los resultados analizalos para buscar patrones.
// (Opcional) analiza las secuencias en alguna aplicación de hoja de cálculo.
// Documenta tus resultados

#include <Adafruit_NeoPixel.h>

#define NUM_LEDS 7 // 7 Pixeles por dado
#define PIN_Dados 3 // Pin conectado a la tira de Neopixeles
#define pinBoton 2 // PushBotton
#define btnModo 8 // Selecciona modo de Semilla
#define BRIGHTNESS 255
#define TIROS 10 // Cantidad de tiros por presion de boton

Adafruit_NeoPixel luces = Adafruit_NeoPixel(NUM_LEDS, PIN_Dados, NEO_GRB + NEO_KHZ800);

// Configuracion de Neopixeles
int8_t Intencidad=255;
// Color neopixel
int8_t cR=250;
int8_t cG=50;
int8_t cB=10;
int8_t dado1=0;

// Semilla inicial para Random
int8_t semilla=4;

int8_t dibujo[7][7]{
  {0,0,0,0,0,0,0}, //Apagado
  {0,0,0,1,0,0,0}, // 1
  {1,0,0,0,0,0,1}, // 2
  {1,0,0,1,0,0,1}, // 3
  {1,0,1,0,1,0,1}, // 4
  {1,0,1,1,1,0,1}, // 5
  {1,1,1,0,1,1,1}  // 6
};

void setup() {  
  luces.setBrightness(BRIGHTNESS);
  luces.begin();
  luces.show(); // inicia luces apagadas
  //Activar interrupcion en boton
  pinMode(btnModo, INPUT_PULLUP);
  pinMode(pinBoton, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(pinBoton), isrBoton, FALLING );
  // Activar monitor serial
  Serial.begin(9600);
}

// Vector de interrupciones para boton
void isrBoton(){
  while(!digitalRead(pinBoton));
  // Se activo dado
  // Usando entrada analoga sin conectar como semilla
  if (!digitalRead(btnModo)) semilla=analogRead(0); 

  randomSeed(semilla); // Usando semilla

  Serial.print("Boton Presionado... tirando ");
  Serial.print(TIROS);
  Serial.print(" veces con semilla ");
  Serial.println(semilla);
  for(int8_t i=1;i<=TIROS;i++){
    dado1=random(1,7);
    iluminaLuces();
    Serial.print(dado1);
    Serial.print((i<TIROS) ? "," : "\n"); // Poner comas a valores intermedios
    delay(100); // Para ver el resultado por un corto tiempo
  }
}

// Dibuja el o los dados sobre los NeoPixeles
void iluminaLuces(){
  // Dibujar dado 1
  // recorre puntos del dado
  for (int8_t i=0; i<=7;i++){
    int x=dibujo[dado1][i];
    luces.setPixelColor(i,luces.Color(x*cR,x*cG,x*cB));
  }
  // Dibujar dado 2 si deseas extender a mas dados
  //for (int8_t i=0; i<=7;i++){
    //int x=dibujo[dado2][i];
    //luces.setPixelColor(i+7,luces.Color(x*cR,x*cG,x*cB));
  //}

  luces.show();
}

void loop() {

}

Desarrollo:

Numeros aleatorios en Arduino

Cuando usamos el generador de números aleatorios de Arduino, se genera una secuencia usando una ecuación matemática y un valor inicial. A este valor inicial se le conoce como semilla.

randomSeed(semilla);

una vez inicializada la función de números pseudo aleatorios, se extraen y distribuyen los números generados con la llamada de:

dado1=random(1,7);

los parámetros de la función es el rango de números que va a devolver la función, es importante hacer notar, que el segundo numero no va a ser incluido dentro de las respuestas de la función, en este ejemplo nos entregara números aleatorios del 1 al 6, el 7 está excluido.

Una semilla casi aleatoria

Si usamos la misma semilla, siempre será la misma secuencia de números, es necesario que esta semilla cambie para cada secuencia generada.

Una forma sencilla de tomar valores aleatorios con un patrón con caos, es usar la entrada análoga mientras no esta conectado a nada, esto hará que la entrada registre los campos electromagnéticos del exterior y devuelva un valor de lectura entre 0 y 1023. Este valor de lectura también sigue un patrón, el del ambiente, esto es mas impredecible que una secuencia conocida, así que esta podría servir como una semilla para generar una secuencia diferente cada que se inicializa la semilla.

Probando la aleatoriedad

Vamos a generar múltiples repeticiones con la secuencia de números pseudo-aleatorios usando una semilla fija, registrándolos para compararlos con repeticiones con una semilla obtenida aleatoriamente por la entrada análoga flotante o no conectada.

Con el circuito armado y programado observamos la posición del control que selecciona que semilla vamos a utilizar cuando generemos los números aleatorios. Si el control esta desactivado usara el mismo numero como semilla, ya sea el inicial o el ultimo valor que utilizo.

Si el control esta activado, cada llamada de randomSeed toma un valor de la entrada análoga, y este cambiara cada que se llame la función. Si el control regresa a desactivado se usará el ultimo valor usado, se fija para las siguientes corridas.

Control Dado

El selector de semilla se fija en 4, y se realizan varias corridas de 10 tiros.

Resultado Semilla Fija

Como vemos en los resultados, todas las secuencias de la semilla 4 son las mismas cada vez que se llama.

Si cambiamos el control de semilla a activado y hacemos varias corridas

Resultados Entrada Analoga

podemos observar que cada llamada tiene una semilla diferente, por lo tanto las secuencias son distintas.

Si desactivamos el control de semilla, veremos que el ultimo valor es fijado y se reutiliza en las siguientes secuencias.

Resultados Entrada analoga fija

como la semilla se fija en un valor, las secuencias producidas seran las mismas.

Conclusiones:

La generación de números aleatorios en un sistema programable requiere de funciones matemáticas que proporcionan números dentro de un rango seleccionado. en Arduino la función Random es la que genera estos números, pero esta función es lineal y basadas en formulas estáticas, se requiere que esta función estática tenga algún dato variable, esta es la semilla inicial.

El generar números aleatorios con semillas fijas produce la misma secuencia cada vez que inicia el generador, es necesario cambiar la semilla inicial cada vez que se utiliza el Random.

Hay varias formas que podríamos tomar un numero al azar para determinar la semilla, un método sencillo es tomar los datos de una terminal abierta como la de la entrada análoga A0, que depende del ambiente, acercándose a lo mas aleatorio que un sistema cerrado puede tomar.