The (minimalised) code below delivers results that do not seem anything approaching 'random' IMO.
Here's an example, where each comma was a fresh upload:
8, 8, 8, 22, 1, 15, 22, 15, 8, 15, 22, 15
BTW, I was unable to copy/paste the frozen serial monitor text. (Sometimes I can!) I wanted to show this quirk: I expected to see pairs of lines, with 'MB-59-RandomProblemTesting' the first. But oddly that only occurred once, after the second '22'.
I need the first dozen or so numbers to be reliably pseudo-random, as my project will play MP3 files in the folder of that number. It will quickly get boring unless I can improve the result!
int randNumber; // A randomly chosen number from 1 to 28
void setup()
{
Serial.begin(9600);
Serial.println(F("MB-59-RandomProblemTesting"));
randomSeed(analogRead(0)); // 20 cm wire attached
randNumber = random(1, 29); // Choose random number 1-28
Serial.print(F("randomNumber = "));
Serial.println(randNumber);
}
void loop()
{
}
Maybe the atmospherics picked up by the analog pin aren't very active where you are.
You could put some code in setup() to force you to press a button to release the code from setup() to loop() and just before that seed the random number with millis(). Then sit around for a few random seconds before pressing the button.
randomSeed() is only as good as the number used to seed it. How random is the value being read from A0 ?
An interesting technique to get more variation from the randomSeed() function that was recently suggested in the forum is to add the value from the analogRead() to a value read from an EEPROM location and to save the result back to the same location ready for when the sketch is next run. This way the seed can never be the same on consecutive runs
random() is working as designed. Your expectations are incorrect.
Please explain what you mean by "reliably pseudo-random".
Any random number generator will occasionally return repeats, so if you want to avoid that for your application, you have to build in a mechanism to do so.
You can try adding a length of wire (maybe coiled) to the analog input to possibly pick-up more noise. (That won't work very well if everything is in a metal case.)
Or if there is human input, you can run the random number generator continuously in the background and "grab" a number when a button is pushed, etc. Normally, you only need to do that once to start the pseudo-random number at an unknown (random) point in the sequence.
And/or, you could save a "random" number in EEPROM periodically, maybe every time a new song starts. Then use that as your seed the next time your program starts. It's not truly random but you'll get a different sequency each time.
And... If you are not doing this already you probably want to use "random selection without replacement" (AKA "shuffling") so a song doesn't get repeated until all songs have been played.
Forget about reading A0. Then you will gain an I/O pin. Instead, every minute or so, store the current value of random() in EEPROM. Then, at boot time, read it and use it as a seed.
For maximum randomness, store a high resolution seed, e.g.
long futureSeed = random( 2147483647L );
Or even simpler, just increment an EEPROM location every minute. Then the run time of the previous program operation becomes a seed for the next operation.
Do you really think that sequence looks pseudo random? I didn't post another batch but the results were very similar. And I think most here will know what "reliably pseudo-random" means. If you need a statistical explanation try a google search.
You are right, the deviation of initial values using an analog input value is not great enough by itself. It will always repeat a small subset of sequences after seeding.
Thanks, I'll explore the EEPROM suggestion (also made by @DVDdoug), although I've not so far used EEPROM in any project.
I was again frustrated by being unable to copy/paste from the serial monitor, so here's a screenshot of the run taken a few minutes ago. At a glance identical to the earlier one.
I resolved the (unrelated) puzzle over the inconsistent printing by adding a 500 ms delay before each pair of print lines. Probably could be less, but 100 ms was inadequate.
I saw another poster reporting repetition of 7, 14, 21, which is interesting as mine is 8, 15, 22.
Could also switch the ADC to a higher frequency clock and lower bit resolution which might give more random results, but the code would be specific to your MCU.
Thanks. As commented in my earlier code I am using a wire on A0, having seen that recommended quite widely. Same with the 'hidden' A6 and A7 inputs I also tried. Clearly unsatifactory so I'll abandon it and read up about EEPROM and try those suggestions.
Or perhaps generate a string of say 10 two-digit numbers 01-28 very simply. With an average play time per folder of about 5 hours, and assuming frequent switching, I'm confident that will do!
And, yes, once I have satisfactory randomness I'll add conditional code to ignore 'too early' repetition.
There's a lot of button pressing in the project already
Thanks for both replies. As you've probably seen, I agree and have abandoned the analog pin approach. (I had the impression it was widely used, which now puzzles me.)
And on reflection I'll probably postpone experiments with EEPROM (a new area for me) and use a much simpler method, as my application needs only a few random numbers at each startup.
Bear in mind the Park-Miller algorithm used in AVR Libc has some deficiencies. Think of it as a good choice for entertainment purposes, an OK choice for games of chance in which the outcome is nothing more than bragging rights, and a terrible choice for scientific simulations or games of chance that have real stakes.