Pseudo-Random, Not Random
When you call random() on an Arduino, you are not getting a truly random number. You are getting the next number in a very long, predetermined sequence. Think of it like a massive book with millions of numbers. Every time you call random(), the Arduino reads the next number from the book.
The catch: it always starts on the same page. Same starting page means same sequence. Every time you restart the Arduino, you get the same "random" numbers in the same order.
The Two Forms of random()
random(max)
Returns a number from 0 up to, but not including, max.
int val = random(6); // returns 0, 1, 2, 3, 4, or 5. Never 6.
random(min, max)
Returns a number from min up to, but not including, max.
int val = random(1, 7); // returns 1, 2, 3, 4, 5, or 6. Never 7.
The max value is always excluded. This is the number one source of bugs with random(). If you want 1 to 6 (a die roll), you need random(1, 7), not random(1, 6).
| What you want | What to write | |---------------|---------------| | 0 to 255 | random(256) | | 1 to 10 | random(1, 11) | | 0 to 180 (servo) | random(181) | | 0 or 1 (coin flip) | random(2) |
The Same Sequence Every Time
Run this sketch, note the five numbers, then restart the Arduino. Same five numbers. Every time.
void setup() {
Serial.begin(9600);
for (int i = 0; i < 5; i++) {
Serial.println(random(100));
}
}
void loop() {}
During one run, the numbers look random because you are reading different positions in the sequence. But across restarts, the starting position is identical.
randomSeed(): Picking a Different Starting Page
randomSeed() sets the starting position. Different seeds produce different sequences.
The classic trick to get a different seed each time: read an unconnected analog pin.
void setup() {
randomSeed(analogRead(A0)); // noise from a floating pin
}
An unconnected pin picks up tiny amounts of electrical noise that differ each time. It gives you a number between 0 and 1023, which means up to 1024 different starting positions.
Important: This only works if the pin is truly unconnected. If you have a sensor on A0, use a different analog pin.
Call randomSeed() once in setup(). Never in loop().
When You WANT the Same Sequence
Sometimes predictable "randomness" is useful:
- Debugging: Need to reproduce a bug? Use a fixed seed so the same inputs happen every time.
- Testing:
randomSeed(1)gives you a reproducible sequence.
Practical Ranges
| Project | Call | Why | |---------|------|-----| | LED brightness | random(256) | PWM is 0-255 | | Candle flicker delay | random(20, 151) | Looks like a flame | | Random tone | random(200, 2001) | Audible, sounds good on a small buzzer | | Servo position | random(181) | Full sweep: 0 to 180 | | RGB color channel | random(256) | Full color range per channel | | Dice roll (1-6) | random(1, 7) | Max is excluded, remember |
Common Mistakes
| Mistake | What Happens | Fix | |---------|-------------|-----| | Calling randomSeed() in loop() | Resets the sequence every iteration; barely-changing output | Call it once in setup() | | Off-by-one on max | random(255) never returns 255 | Use random(256) to include 255 | | Not seeding at all | Same pattern after every restart | Use randomSeed(analogRead(A0)) | | Expecting true randomness | Sequence is deterministic, not secure | Fine for projects, not for security |