Probleme mit random() am ARDUINO
In der EDV gibt es keinen echten Zufallsgenerator, der Werte tatsächlich zufällig erzeugt, so auch beim Arduino. Das sollten Sie wissen in Projekten mit Zufallswerten.
Juli 17, 2023 - Lesezeit: 3 Minuten
Nutzt Ihr Projekt (ARDUINO Nano) die Erzeugung zufälliger Werte, dann stoßen Sie früher oder später auf den Befehl random() in der Arduino-Bibliothek. Dieser Befehl sorgt dafür, das ein zufälliger Wert (zwischen min und max) erzeugt wird. Die folgende Codezeile erzeugt einen zufälligen Wert der zwischen 1 und 100 liegt - nehmen wir mal 77 an.
Serial.println(random(1, 100));
Schalten Sie den Arduino aus und erneut ein, erzeugt der Generator allerdings wiederum die zufällige 77 - Sie bemerken bereits jetzt, das mit diesem Befehl etwas nicht stimmt - es ist immer die gleiche Zufallszahl. Bedingt ist dieser Effekt durch die implementierte Hardware die keinen echten Zufallsgenerator besitzt, denn Zufallsgeneratoren werden beispielsweise im Computerbereich mit Echtzeituhren oder Umdrehungswerten des Lüfters gekoppelt, um zufällige Werte generieren zu können - all dies hat der ARDUINO Nano nicht. Die Folge, es entsteht immer der selbe Wert der zwar zufällig irgendwo zwischen 1-100 liegt aber fortan unverändert bleibt.
randomSeed()
Es gäbe allerdings Alternativen, zunächst den Befehl randomSeed() der in der Lage ist zufällige Werte auszugeben, jedoch sind dies keine echten Zufallswerte. Der Befehl randomSeed() bedient sich einer fertigen Liste die zufällig angeordnete feste Zahlen beinhaltet und liest diese Schritt für Schritt aus, so entsteht der Eindruck zufälliger Werte. Dieser Befehl lieftert also ebenfalls keine echten Zufallszahlen.
analogRead()
Eine weitere Alternative wäre analogRead() der den analogen, freien Eingang (z.B.) A0 liest und den Wert zwischen 0...1024 ausgibt. Und tatsächlich erzeugt analogRead() echte zufällige Werte anhand dieses Verfahrens, jedoch hat auch diese Methode ein Problem. Die scheinbar zufälligen Werte an einem freien Analog-Pin werden aufgrund physikalischer Bedingungen erzeugt die in der unmittelbaren Umgebung des Pins herrschen, beispielsweise haben elektomagnetische Felder die im Raum stehen großen Einflus auf den Analogpin aber auch die simple Anwesenheit des Menschen kann dazu führen elektostatische Bedingungen in der Nähe zu verändern und folglich das Ergebnis zu verfälschen.
Wollten Sie analogRead() zur Erzeugung eines booleans ala True/False nutzen könnten Sie dies eventuell so machen:
if (analogRead(0) > 512) {
return true;
} else {
return false;
}
Pseudocode der zu 50% true und zu 50% false erzeugt
Zwar ist 512 exakt die Hälfte der Auflösung des Analaogpins mit maximal 1024, jedoch pendeln die gelesenen Werte eher um einen Bereich herum, der stark von den pyhsikalischen Bedingungen der Umgebung geprägt ist. In einem eigenen Versuch habe ich herausgefunden, das der Wert stark im Bereich 200-400 pendelte aber nie 0 oder 1024 angenommen hat. Eine echte Zufallsverteilung ist dies also nicht, eine Anpassung ist also nötig.
rnd = analogRead(0)
if (rnd%2 == 0) {
return true;
} else {
return false;
}
Pseudocode der der die Teilbarkeit nutzt um true oder fals zu erzeugen
Die obige Implementierung ist besser geeignet, da es ihr vollkommen egal ist ob der Wert in einem festen Bereich pendelt oder nicht. Das Coding nutzt den Modulo2 und ergibt 0 oder 1 wenn der Wert durch 2 teilbar ist. Denn Sie können durchaus unterstellen, das der Wert zwar in einem engen Rahmen pendeln wird abber dennoch gerade oder ungerade Zahlen in einer natürlichen Verteilung aufweisen wird.
Arduinos Empfehlung
Das ARDUINO Projekt selbst empfiehlt allerdings auch eine eigene Lösung, die aus einer Kombination aus randomSeed() und analogRead() besteht.
long randNumber;
void setup() {
Serial.begin(9600);
randomSeed(analogRead(0));
}
void loop() {
randNumber = random(300);
Serial.println(randNumber);
delay(50);
}
Zwar sind die wenigen Zeilen nicht sehr schwer zu verstehen, jedoch wird vielen Anwendern nicht klar, wie randomSeed(analogRead(0)); wohl mit randNumber = random(300); in Verbindung steht? Denn eine gemeinsame Variable nutzen sie nicht und tauschen auch keine Return-Variable aus. Der Witz liegt in der Hardwareimplementierung. in setup() wird der Zufallsgenerator mit einer Zufallsliste (Seed) initialisiert und im loop() nutzt random() eben genau diesen zuvor initialisierten Zufallsgeneraturs des Chips.
Der Zufallsgenerator eines großen Computers ist einfach zu verwenden, demgegenüber muss man ein wenig Hardwarekenntnis beim ARDUINO mitbringen, um ihn ähnlich wie am Computer nutzen zu können.
Schlagworte:
Random Zufall Seed rnd