random returning same value every cycle until reset

I am having an issue with my project it is a simple traffic light with the yellow set to four seconds however I have the red and green sent to random times I noticed that the red and green always return the same value (number of seconds) until reset and then it comes up with a different number instead of just returning a random number every cycle. does anyone have any ideas how I can get it to come up with a random number upon every cycle instead of just of just coming up with the random number and sticking to it until reset.

I can post my code if that would help

by the way I am not using the delay function

Here is the code, I'm sure it would help to see what is going on.

const int greenPin = 0;
const int yellowPin = 1;
const int redPin = 2;
const int buttonPin = 8;

enum color {
  GREEN, YELLOW, RED, OFF} 
lightState = OFF;  

int lightMode = 0;  

unsigned long lastButtonPressTime;
bool lastButtonState;
const unsigned long buttonDebounceInterval = 100; 
bool blinkerOn = false;             
unsigned long previousMillis = 0;        

unsigned long blinkInterval = 533;  
unsigned long greenInterval = (random(10000, 48000));
unsigned long yellowInterval = 4000;  
unsigned long redInterval = (random(16000, 55000));

void setup()
{
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}


void setColor(int newColor)
{

  digitalWrite(greenPin, LOW);
  digitalWrite(yellowPin, LOW);
  digitalWrite(redPin, LOW);

  switch (newColor)
  {
  case GREEN:  
    digitalWrite(greenPin, HIGH); 
    break;
  case YELLOW: 
    digitalWrite(yellowPin, HIGH); 
    break;
  case RED: 
    digitalWrite(redPin, HIGH); 
    break;
  }
}

void loop(){
  bool buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState && millis() - lastButtonPressTime > buttonDebounceInterval)
  {
    lastButtonState = buttonState;
    lastButtonPressTime = millis();
    if (buttonState == LOW)  
      lightMode++;
  }

  switch (lightMode)
  {
  case 0: 
    lightState = OFF;  
    flash(YELLOW); 
    break;
  case 1: 
    lightState = OFF;  
    flash(RED); 
    break;
  case 2: 
    threelight(); 
    break;
  default: 
    lightMode = 0;
  }
}


void flash(int flashColor){

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > blinkInterval) {
    
    previousMillis = currentMillis;   

    blinkerOn = !blinkerOn; 

    if (blinkerOn)
      setColor(flashColor);
    else
      setColor(OFF);
  }
}

void threelight(){
  unsigned long currentMillis = millis();
  switch (lightState)
  {
  case GREEN: 
    if (currentMillis - previousMillis > greenInterval)
    {
      previousMillis = currentMillis; 
      lightState = YELLOW;
      setColor(YELLOW);
    }
    break;

  case YELLOW:
    if (currentMillis - previousMillis > yellowInterval)
    {
      previousMillis = currentMillis; 
      lightState = RED;
      setColor(RED);
    }
    break;

  case RED:
    if (currentMillis - previousMillis > redInterval)
    {
      previousMillis = currentMillis;  
      lightState = GREEN;
      setColor(GREEN);
    }
    break;

  default: 
    lightState = GREEN;
    previousMillis = currentMillis;
    setColor(GREEN);
  }
}

Look at where you are calling random(). You only call it twice - when the Arduino first boots up. Of course the value never changes while the sketch is running.

Get the green and yellow lights off the hardware serial port pins so you can debug your code.

This code was actually set up to run on my attiny84 that I'm programing through my arduino. Thats why I am using those pins for the yellow and green.

I was suspisuous that was something to do with since it was only being called one time. can I move those times from the setup to the loop to get it to work as intended?

Yes you will need to have those random() values in the loop somewhere otherwise they will never change as you know. :)

So I moved my random code from setup to void loop thinking that would solve the issue and it is still happening. Anyone have any ideas why?

// Define the pins we are using
const int greenPin = 0;
const int yellowPin = 1;
const int redPin = 2;
const int buttonPin = 8;

enum color {
  GREEN, YELLOW, RED, OFF} 
lightState = OFF;  //  State of the three-light traffic light

int lightMode = 0;  // Blinking yellow, Blinking red, or full color

unsigned long lastButtonPressTime;
bool lastButtonState;
const unsigned long buttonDebounceInterval = 100;  // One peress per 1/10th second

bool blinkerOn = false;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated

unsigned long blinkInterval = 533;  
unsigned long yellowInterval = 4000;  


void setup()
{
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

// NOTE: The argument here would normally be 'enum color' but the way Arduino does things
// (it puts all function declarations at the top) it tries to declare the function before
// the declaration of the enum and gets and error.  Fortunately enums work a lot like 
// integers.
void setColor(int newColor)
{
  // Turn all colors off to start
  digitalWrite(greenPin, LOW);
  digitalWrite(yellowPin, LOW);
  digitalWrite(redPin, LOW);

  switch (newColor)
  {
  case GREEN:  
    digitalWrite(greenPin, HIGH); 
    break;
  case YELLOW: 
    digitalWrite(yellowPin, HIGH); 
    break;
  case RED: 
    digitalWrite(redPin, HIGH); 
    break;
  }
}

void loop(){
  bool buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState && millis() - lastButtonPressTime > buttonDebounceInterval)
  {
    lastButtonState = buttonState;
    lastButtonPressTime = millis();
    if (buttonState == LOW)  //  Button is 'active low'?
      lightMode++;
  }

  switch (lightMode)
  {
  case 0: 
    lightState = OFF;  // Re-start at GREEN
    flash(YELLOW); 
    break;
  case 1: 
    lightState = OFF;  // Re-start at GREEN
    flash(RED); 
    break;
  case 2: 
    threelight(); 
    break;
  default: 
    lightMode = 0;
  }
}

// NOTE: The argument here would normally be 'enum color' but the way Arduino does things
// (it puts all function declarations at the top) it tries to declare the function before
// the declaration of the enum and gets and error.  Fortunately enums work a lot like 
// integers.
void flash(int flashColor){

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > blinkInterval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    blinkerOn = !blinkerOn;  //  Toggle blinker

    if (blinkerOn)
      setColor(flashColor);
    else
      setColor(OFF);
  }
}

void threelight(){
  unsigned long currentMillis = millis();
  switch (lightState)
  {
  case GREEN: 
    if (currentMillis - previousMillis > (random(10000, 48000)))
    {
      previousMillis = currentMillis; //Re-start timer
      lightState = YELLOW;
      setColor(YELLOW);
    }
    break;

  case YELLOW:
    if (currentMillis - previousMillis > yellowInterval)
    {
      previousMillis = currentMillis; //Re-start timer
      lightState = RED;
      setColor(RED);
    }
    break;

  case RED:
    if (currentMillis - previousMillis > (random(16000, 55000)))
    {
      previousMillis = currentMillis;  //Re-start timer
      lightState = GREEN;
      setColor(GREEN);
    }
    break;

  default: 
    lightState = GREEN;
    previousMillis = currentMillis;
    setColor(GREEN);
  }
}

You are calling the random() function but not assigning the value it returns to a variable. What do you expect the call to random() to do ?

Well I am still fairly new to arduino and I'm having trouble understanding the Random code, I have spent a lot of time trying to find answers online without much success. is there anyway you could help me figure out how to get random working in my code here or at least point me in the right direction?

I would appriciate any help you could provide me

You just call random to get a new random number and put it in the variable where you want it. There's no trick at all.

This code will print random numbers from 0 to 9 on the monitor.

int var = random(10);

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

void loop(void){

     Serial.println(var);
     var = random(10);   // This line gets a new random number and puts it in var.
}

thanks for your help, however I'm not sure how to get that to work when I have two separate random times, one for the red and another for the green. How do I differentiate one from the other?

Look, calling random() returns you a value. You can call it as many times as you want, and it will give you a new random number each time. You store that number in a variable and use it wherever you want. There's nothing that links the random function to any one variable. The random function simply returns a number.

If you want two variables then:

int redvar;
int greenvar;

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

void loop(void){
     redvar = random(10);   // This line gets a new random number and puts it in redvar.
     greenvar = random(10);   // This line gets another new random number and puts it in greenvar.
     
     Serial.print("redvar = ");
     Serial.println(redvar);
     Serial.print("greenvar = ");
     Serial.println(greenvar);
     
}

I have now plugged all my random times in the way they were in the example you showed me and now I'm only getting the minimum time for the red and green times that is in my random command. ( my random calls for a time of 10 to 48 seconds and every time it comes up I'm getting only 10 seconds. Why would that be happening?

// Define the pins we are using
const int greenPin = 9;
const int yellowPin = 10;
const int redPin = 11;
const int buttonPin = 8;
int redvar;
int greenvar;


enum color {
  GREEN, YELLOW, RED, OFF} 
lightState = OFF; 

int lightMode = 0;  

unsigned long lastButtonPressTime;
bool lastButtonState;
const unsigned long buttonDebounceInterval = 100; 

bool blinkerOn = false;            
unsigned long previousMillis = 0;       

unsigned long blinkInterval = 533;  

unsigned long yellowInterval = 4000;  


void setup()
{
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  redvar = random(10);
  greenvar = random(10);
}


void setColor(int newColor)
{

  digitalWrite(greenPin, LOW);
  digitalWrite(yellowPin, LOW);
  digitalWrite(redPin, LOW);

  switch (newColor)
  {
  case GREEN:  
    digitalWrite(greenPin, HIGH); 
    break;
  case YELLOW: 
    digitalWrite(yellowPin, HIGH); 
    break;
  case RED: 
    digitalWrite(redPin, HIGH); 
    break;
  }
}

void loop(){
  
  redvar = random(16000,55000);
   greenvar = random(10000,48000);
  bool buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState && millis() - lastButtonPressTime > buttonDebounceInterval)
  {
    lastButtonState = buttonState;
    lastButtonPressTime = millis();
    if (buttonState == LOW)  
      lightMode++;
  }

  switch (lightMode)
  {
  case 0: 
    lightState = OFF;  
    flash(YELLOW); 
    break;
  case 1: 
    lightState = OFF;  
    flash(RED); 
    break;
  case 2: 
    threelight(); 
    break;
  default: 
    lightMode = 0;
  }
}


void flash(int flashColor){

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > blinkInterval) {
    
    previousMillis = currentMillis;   

    
    blinkerOn = !blinkerOn;  

    if (blinkerOn)
      setColor(flashColor);
    else
      setColor(OFF);
  }
}

void threelight(){
  unsigned long currentMillis = millis();
  switch (lightState)
  {
  case GREEN: 
    if (currentMillis - previousMillis > greenvar)
    {
      previousMillis = currentMillis; 
      lightState = YELLOW;
      setColor(YELLOW);
    }
    break;

  case YELLOW:
    if (currentMillis - previousMillis > yellowInterval)
    {
      previousMillis = currentMillis; 
      lightState = RED;
      setColor(RED);
    }
    break;

  case RED:
    if (currentMillis - previousMillis > redvar)
    {
      previousMillis = currentMillis;  
      lightState = GREEN;
      setColor(GREEN);
    }
    break;

  default: 
    lightState = GREEN;
    previousMillis = currentMillis;
    setColor(GREEN);
  }
}

Note that you are trying to squeeze 55000 into an int which can hold no more than 32,767. Make that unsigned int.

It looks like you've written some great non-blocking code to blink and move your LEDs. SO now what is happening is that each time the code hits the top of loop you are getting a new random number. If it hasn't been that long yet, then when you hit the top of loop you grab yet another random number. This whole process will happen over and over really fast until random returns a number that is short enough to trip your if statement. Since it is happening so fast, it won't take long before it guesses a number close to the minimum and it has been longer than the minimum time.

What I think you want to do is, pick a random number and hold the light on for that length of time. So maybe it would make more sense to get a random number and hold onto it and keep checking against the same number. Then inside the if statement, when the time has passed, only then do you go get a new random number.

What you are doing now:

Get a random time between 10 and 48 sec
IF the light has been on that long, then turn it off
If the light hasn't been on that long then guess a new number.

What I think you want to do:

get a random time between 10 and 48 seconds.
keep checking against that number until the light has been on that long
turn the light off and get a new random number.

Shpaget: Note that you are trying to squeeze 55000 into an int which can hold no more than 32,767. Make that unsigned int.

Actually random() returns a long. It doesn't specifically say in the reference what the arguments are, but if it returns a long it wouldn't make much sense for them to be anything other than long.

So what exactly is causing it only to hold my minimum times on my randoms, what am I missing that it completely ignores my random and goes to my minimum. I am confused how random works and I don’t see many explanations online for picking random times of lights

But redvar and greenvar are ints. This code

int ranNum;
void setup() {
  Serial.begin(9600);
}
void loop() {
  ranNum = random (30000, 55000);
  Serial.println(ranNum);
  delay(500);
}

prints out this:

-18729
30249
30073
-16878
-26606
-24264
32544
30878
-32613
-22827
-21096
-22371

Microprocessor very quickly goes through the loop. Many thousands times each second. On every pass it picks a new random number and checks if it is greater than the number of milliseconds since the last change. Once the code gets past 10 seconds since the last change, the new random number that is generated will quickly be just above 10000, since many different ones are generated quickly. Chances are very high that it will generate something that is very close to 10000 in what appears to your naked eye as a fraction of a second after 10 seconds.

Generate a new random number only after you change the state of the LEDs (once per change, not once per loop iteration).

It isn't ignoring anything. Try printing out the random numbers you get. What is happening is that each time you get a random number and it hasn't been that long yet, you don't wait until it is that long but instead just grab a new random number. This is happening thousands of times a second. At some point shortly after the minimum time has passed, one of those return values is coming out close to the minimum time and clears the if.

At some point, about 10 seconds in, one of those values you're getting is near the minimum of 10 seconds. If it isn't, then you are just getting a new random number.

What you need to do is only get a new random number when you have reached the time specified by the last one. Put the code to get a new random number in the if statement with the code that gets run when the time has passed. Right now it is at the beginning of the loop. So it is getting a new number every time.

Random isn't hard to understand.

You can understand this right?

someVariable = 4;

It sets a variable equal to 4.

someVariable = random();

does exactly the same thing. It sets that variable equal to something. It sets it equal to whatever number random returns. Some random number.

If you'll print out the values of redvar and greenvar you'll see that they keep picking new random numbers thousands of times a second. You don't want that. You want it to only get a new random number when the time from the last one is up.

the code right now reads:

get a random number, lets say its 30 seconds
hasn't been 30 seconds yet so get a new one, 23
hasn't been 23 seconds yet get a new one 42
hasn't been 42 seconds yet get a new one 21

...  until we get to about the 10 second mark.

hasn't been 38 seconds yet get a new number it's 26
hasn't been 26 seconds yet get a new number it's 32
hasn't been 32 seconds yet get a new number it's 10
It has been 10 seconds so let's go.

Whaqt you want is:

Get a random number:  it's 25

hasn't been 25 seconds loop again
hasn't been 25 seconds loop again
hasn't been 25 seconds loop again

...  after 25 seconds

it has been 25 seconds let's go do the thing we were waiting to do

Now get a new random number (redvar = random()) 

And do it all again.

Thanks, I now understand what is happening to cause my minimum time to keep coming up. So where would I instruct my program to wait for the random time it came up with to be over before moving on, and what commands would I use? I'm trying to search online to see if I can get some examples or ideas but I'm not having any luck.