Números pseudoaletorios, función random()
Primero vamos a ver como generar números pseudoaleatorios usando la función random() de Arduino. Su uso es muy sencillo primero, normalmente en la función setup, se fija la semilla del generador usando la función randomSeed() y un valor que se le pasa como parámetro y luego se invoca a la función random() usadon una de sus dos versiones:
random(max)
random(min, max)
La primera calcula un valor entre 0 y max, la segunda entre min y max.
La semilla fijada en radomSeed() se usa para generar una secuencia de números pseudoaleatorios. A diferencia de los números aleatorios, que son distintos cada vez, los pseudoaletaorios son siempre los mismos. Cada semilla genera una secuencia única de números aleatorios que es siempre la misma. Por lo que si queremos que cada vez que reiniciemos la placa la secuencia de números sea diferente, tenemos que establecer la semilla con un valor que cambie cada vez. Hay varias opciones:
- Tener un valor almacenado en la memoria EEPROM e incrementarlo en cada vez que se inicie el programa y usarlo como semilla.
- Usar la función micros() que devuelve el número de microsegundos desde que el software se inicio.
- El más habitual es usar el valor de de un puerto analógico donde no haya nada conectado.
El problema de usar estos tres métodos es que el primero es predecible y los otros dos no son realmente buenas fuentes de aleatoriedad. Sin embargo para la mayoría de los casos (que no se requieran números realmente aleatorios por seguridad) pueden ser suficientes.
Un ejemplo de uso:
long randNumber;
void setup() {
Serial.begin(9600);
randomSeed(analogRead(0));
}
void loop() {
//devuelve un número entre 0 y 300
randNumber = random(300);
Serial.println(randNumber);
//devuelve un número entre 10 y 200
randNumber = random(10, 20);
Serial.println(randNumber);
delay(2000);
}
Generar números realmente aleatorios con un trozo de cable y analogRead
Si buscas una manera de generar números realmente aleatorios con Arduino se suele aconsejar recurrir a leer el valor de un puerto analógico que no este conectado a nada. El problema es que realmente los valores obtenidos no son aleatorios. Suelen oscilar en torno a un valor sin alejarse demasiado de él. Es decir si el valor leído es el 150 los más probable es que el siguiente número sea cercano, es más probable que sea el 151 que el 3. Cómo generador de números aleatorios no solo no es ninguna maravilla, es que es en muchos casos peor que el generador de números pseudoaleatorios de random()
Hay montajes electrónicos que producen valores aleatorios a partir del ruido que sufren sus componentes, pero suelen ser complicados. (Además ya no sería con un Arduino y tengo que justificar que el articulo este en la sección de «Arduino»)
Volviendo a nuestra idea de leer valores del puerto analógico vemos que el problema es que los números que devuelven oscilan entorno a un valor, esto se debe a que lo que leemos es el ruido en el puerto analógico, el ruido actúa como función aleatoria, pero este ruido tienen una característica especial, que explicada breve y mal es: «A más fuerte sea el ruido menos probable es que ocurra». Por lo tanto variaciones grandes del valor del puerto analógico son poco probables. Sin embargo hay una parte muy pequeña de este valor que si que se ve sometida a variaciones, la parte más pequeña del valor del puerto y por tanto la que más fácilmente varia, el bit de menor peso. Vamos a tomar solo ese bit y con ocho de ellos componer un byte. Ese byte debería ser aleatorio.
Para obtener el bit de menor peso podemos usar el siguiente código:
analogRead(analogInput)%2
Veamos el ejemplo para obtener un byte leyendo el puerto 8 veces:
byte randomAnalog(int analogInput){
byte rnd = 0;
for(int i = 0; i <; 8; i++){
int aux = analogRead(analogInput)%2 << i;
rnd += aux;
delay(10);
}
return rnd;
}
El delay(10) lo añadí por que sin ninguna espera analogRead me devolvía el mismo valor varias veces.
¿Pero donde esta el cable? Os preguntareis. Para aumentar el ruido, nada mejor que conectar un cable suelto en el puerto que se va a leer, contra más largo y retorcido esté mejor.
Combinar varias fuentes
Si te fías poco de este sistema puedes usar dos fuentes, o más, de aleatoriedad obteniendo bytes de dos puertos analógicos distintos y luego combinándolos con un xor.
byte r0 = randomAnalog(A0);
byte r1 = randomAnalog(A1);
byte r = r1 ^ r0;
Puede encontrar el código en el repositorio de github de ArduTips.
Un problema que pueden tener estos sistemas es que generalmente cuando hablamos de números aleatorios nos referimos a que producen produce el bit 0 y el bit 1 con un 50% de probabilidades (lo que se denomina un sistema justo), pero en este caso no podemos estar seguros de que sea así, sin embargo hay una manera de convertir cualquier sistema aleatorio a justo se puede leer aquí.
Puedes ver la explicación en vídeo de como generar números pseudoaleatorios en mi canal de youtube:
También esta disponible el vídeo de como generar números aleatorios:
Pingback: Generador justo de números aleatorios en arduino | Construyendo a Chispas