Random function not randomising after reset

I just started using the Arduino IDE a day or two ago, I understand quite a lot already since I have some small experience with other programming languages. I was doing a small project where I have a potentiometer, three LED's (green, yellow and red) and a buzzer connected to my UNO. The idea was to write some code so that I would get more knowledgeable of the Arduino specific functions. I want the three LED's to light up but never at the same time using the potentiometer, making it random somehow I stumbled accross the random function. But when I reset the code the random number stays the same no matter how many times i reset it. Here is my code:

const int led_yellow = 5;
const int led_red = 3;
const int buzzer = 9;
byte chance = random(255);
void setup() {
 // put your setup code here, to run once:
 Serial.begin(9600);
 pinMode(led_green, OUTPUT);
 pinMode(led_yellow, OUTPUT);
 pinMode(led_red, OUTPUT);
 pinMode(buzzer, OUTPUT);
}

void loop() {
 // put your main code here, to run repeatedly:
 int data = analogRead(A0);
 float voltage = data * (5.00 / 1023.00);
 int percentage = map(data, 0, 1023, 0, 100);
 Serial.print("Potentiometer at ");
 Serial.print(voltage);
 Serial.print("V or ");
 Serial.print(percentage);
 Serial.println("%");
 Serial.print("The random number is: ");
 Serial.println(chance);
 Serial.println("------------------------------");
 delay(250);

 int brightness = map(data, 0, 1023, 0, 255);
 int sound = map(data, 0, 1023, 0, 255);
 if (chance >= 0 & chance <= 83) {
   analogWrite(led_green, brightness);
 }
 else if (chance >= 84 & chance <= 167) {
   analogWrite(led_yellow, brightness);
 }
 else {
   analogWrite(led_red, brightness);
   analogWrite(buzzer, sound);
   }
}

Does anyone know a fix for this or if it is just a fault in the function?

Look at the documentation of random(). random() doesn't really generate random numbers, but a sequence of pseudo random numbers. If you always use the same 'starting point' you will always get the same sequence.
From the documentation;

> If it is important for a sequence of values generated by random() to differ, on subsequent executions of a sketch, use randomSeed() to initialize the random number generator with a fairly random input, such as analogRead() on an unconnected pin.

4 Likes

Move this...

...inside the loop function.

The compiler will help you decide where the line belongs.

You can use randomSeed() to add a little more randomness. Or you can dig through The reliable but not very sexy way to seed random; I'm not sure which post contains the latest iteration of the code.

1 Like

That randomizes it every 0.25 seconds though, I tried this and it just keeps switching between the LED's which is not what I want it to do.

So basically, I have to use random seed() instead of just random and it'll change numbers every reset?

You have to use a different random seed every time. This can be done by storing the seed in EEPROM and by incrementing it in setup(). This will give you a different pseudorandom sequence after every reboot. E.g.,

#include <EEPROM.h>

void setup() {
  Serial.begin(9600);

  size_t const address {0};
  unsigned int seed {};
  EEPROM.get(address, seed);
  randomSeed(seed);
  EEPROM.put(address, seed + 1);
}

void loop() {
  Serial.println(random());
  delay(1000);
}
1 Like

You use randomSeed() to seed the random number generator with a different value; that will give a different start value for the random() function.

Does it?

Maybe you should post the new version.

Welcome to the forum.

The most common way is to use one or more analog inputs, regardless if something is connected or not. That is good enough for toys and games.

If you want to choose between 3 options, then you can do "random(3);" for 0, 1 or 2.

The tone() function is often used for a buzzer.

With those changes, I get:

// Forum: https://forum.arduino.cc/t/random-function-not-randomising-after-reset/1161545
// Sketch by: maagdappel
// Changes by: Koepel, 24 August 2023.

const int led_green = 4;
const int led_yellow = 5;
const int led_red = 3;
const int buzzer = 9;

void setup() 
{
  Serial.begin(9600);
  Serial.println("--------------------------------------");
  
  pinMode(led_green, OUTPUT);
  pinMode(led_yellow, OUTPUT);
  pinMode(led_red, OUTPUT);
  pinMode(buzzer, OUTPUT);

  // The values of analogRead are added, that is not ideal.
  // They could be multiplied or with XOR or something else.
  // Every "expert" about random tells something different. 
  unsigned long seed = 0;
  for(int i = A0; i <= A5; i++)
  {
    seed += analogRead(i); 
  }
  randomSeed(seed);
}

void loop() 
{
  int chance = random(3);

  int data = analogRead(A0);
  float voltage = data * (5.00 / 1023.00);
  int percentage = map(data, 0, 1023, 0, 100);

  Serial.print("Potentiometer at ");
  Serial.print(voltage);
  Serial.print("V or ");
  Serial.print(percentage);
  Serial.print("%. ");
  Serial.print("The random number is: ");
  Serial.print(chance);
  Serial.println();

  int brightness = map(data, 0, 1023, 0, 255);
  int sound = map(data, 0, 1023, 0, 255);

  switch(chance)
  {
    case 0:
      analogWrite(led_green, brightness);
      noTone(buzzer);
      break;
    case 1:
      analogWrite(led_yellow, brightness);
      noTone(buzzer);
      break;
    case 2:
      analogWrite(led_red, brightness);
      tone(buzzer, sound);
      break;
  }

  delay(500);      // slow down the sketch
}

You can try it in the Wokwi simulator:

Start the simulation with the green start button in the upper-middle of the screen. Then press the red reset button on the Arduino board to reset it. Check that the sequence of 0,1,2 is different every time.

+1 has some undesirable properties with the Park-Miller generator.

That's because the one person who actually analyzed using analogRead for creating seeds, the one actual expert, was able to demonstrate that it is always a bad choice.

Did you notice that pressing the reset button of a Arduino Uno in Wokwi simulation creates a new seed. That is so cool, even the random noise is simulated.

Moderator edit: perceived call to battle removed

I copied this code to my UNO, it still doesn't achieve what i want it to. A random number from 0 to 2 at the start of the script which remains te same and doesnt get overwritten during the loop. However i do want it to change after a reset.

Post your code.

I already did, I used the code Koepel sent in the thread which didn't work the way i wanted it to.

Post your new code.

The most common solution is to seed by reading a floating analog input. That's not a "great" method because the input is usually in limited range. But it's often "random enough" to make the results unpredictable (which is usually the goal).

I make a lot sound activated lighting effects with random variations and I use the audio input as the seed. That's more unpredictable, as long as there is audio when setup() and seed() runs.

If you have a real-time clock you can use the time for a seed. Of course, the clock should be independent of the processor.

If there is human input/interaction (like if you are pulling the lever on a slot machine) there's another good-easy method (which I haven't personally used) -

Run the pseudo-random generator continuously in a "fast loop" and then "grab" a number when the user pushes a button (or something like that). Depending on the application or user interaction, you can use that method to create a random seed, or every time you need a random number.

The script that I used uses the analog input to create a seed, and every time the function random() is called in the loop(), a new random number is generated.

The variable 'chance' with a number 0, 1 and 2 never stays the same. That is impossible. Can you try it again ?

If all your analog inputs are short circuit to GND, then every analogRead() returns zero. You can fix that by adding a LDR or NTC with a resistor to analog inputs.
If using the analog inputs always fails and there is no sensor or anything can be used, then you have to use the EEPROM. But that is only to create a different seed every time. Once a seed is set, the random() function returns a sequence of random numbers.

A little background story:
The Arduino random function and the 'C' and 'C++' random function keep internally a variable for the new random number. All you have to do is call "random()" and you get a new number every time.
It starts with a seed, and the rest is a mathematical calculating.
I changed your global variable 'chance' to a local variable, but that does not change the
"randomness".

Could you elaborate?