Hi... bin ein N00b, daher erstmal Hallo in die Runde.
Das Christkind brachte mir ein Arduino-Starter-Kit und ich spiele nun etwas damit herum.
Gefallen hat mir das im Projektbuch beschriebene Projekt 11, also die Kristallkugel.
Soweit so gut, die Sache funktioniert und alles...
Nun dachte ich mir, das wäre ein lustiges Bürogadget...
Bis mir aufgefallen ist, dass sich die Antworten immer exakt gleich ergeben.
Beispiel:
"Kaffepause" - "Ablehnen!" - "frueher Schluss"...
Dann schalte ich das Ding ab (oder drücke Reset) und es kommt:
"Kaffepause" - "Ablehnen!" - "frueher"...
Mit anderen Worten: die Zufallsantworten sind keine...
Irgendwelche Ideen, wie der Arduino bei jedem Neustart sich eine andere Reihenfolge ausdenkt?
Hier der Sketch (1:1 aus dem Netz kopiert/aus dem Buch abgeschrieben und nur die Antworten verändert:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int switchPin = 6;
int switchState = 0;
int prevSwitchState = 0;
int reply;
void setup() {
lcd.begin(16, 2);
pinMode(switchPin,INPUT);
lcd.print("Frag das");
lcd.setCursor(0, 1);
lcd.print("Bueroorakel");
}
void loop() {
switchState = digitalRead(switchPin);
if (switchState != prevSwitchState) {
if (switchState == LOW) {
reply = random(8);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("das Orakel sagt:");
lcd.setCursor(0, 1);
switch(reply){
case 0:
lcd.print("Ablehnen!");
break;
case 1:
lcd.print("Ja");
break;
case 2:
lcd.print("Frueher Schluss");
break;
case 3:
lcd.print("Nein");
break;
case 4:
lcd.print("darueberschlafen");
break;
case 5:
lcd.print("Kaffepause");
break;
case 6:
lcd.print("Ungern");
break;
case 7:
lcd.print("Kekse!");
break;
}
}
}
// save the current switch state as the last state
prevSwitchState = switchState;
}
Das liegt daran, daß der Arduino keinen echten Zufallszahlengenerator besitzt, sondern einen sogenannten Pseudozufallsgenerator.
Dieser bekommt einen Startwert (Seed) und gibt anhand dieses Startwertes immer die gleiche Reihe an Zufallszahlen aus.
Ein echter Zufallsgenerator basiert zum Beispiel auf dem Rauschen eines Widerstandes, einer Diode oder anderen wirklich zufälligen Ereignissen, wie dem Zerfall radioaktiver Elemente, dem Rauschen von Bildsensoren oder anderen physikalischen Vorgängen. In Software kann man keine echten Zufallszahlen erzeugen.
Aber auf dem Arduino kann man mittels randomSeed() dem Zufallsgenerator einen Startwert übergeben. Um den zumindest quasizufällig zu bekommen, kann man einen offenen Analogeingang abfragen, da dieser immer etwas rauscht und somit bei jedem Auslesen andere Werte ausgibt.
Noch zufälliger wird es, wenn man an dem Analogeingang eine Art Antenne anschließt, die das Rauschen der Umgebung einfängt. Diese Antenne ist einfach nur ein ca. 5cm langes Stück Draht, welches man am Analogeingang ansteckt.
In der Arduino-Referenz ist beschrieben, wie man dem Pseudozufallsgenerator einen zufälligen Startwert übergibt.
Eher nicht. analogRead liefert nur 1024 verschiedene Werte, in der Praxis erheblich weniger.
Die Pseudo-Randomfolge liefert da erheblich besser gleichverteilte Werte.
Wenn man random eh mit interaktiven Sachen (Taster) kombiniert, hat man da eine gute randomSeed - Quelle. Aber auch hier besser randomSeed nur als Seed verwenden, nicht als random-Ersatz.
Die Verteilung der Zufallszahlen wird von einem geänderten Seed nicht beeinflusst weil der Pseudozufsallszahlengenerator beim Ändern des Seeds nicht neu gestartet wird, sondern nur eine andere Berechnungsgrundlage bekommt.
Dadurch wird die Zufallszahlenfolge noch weniger vorhersagbar, weil bei jedem Zyklus wieder ein zufälliges Element dazu kommt.
Einspruch Euer Ehren: Nach einem Aufruf von randomSeed ist das nächste Ergebnis von random fest vorgegeben, abhängig vom seed-Wert.
Die "Verteilung" wird in der Tat nicht beeinflusst, aber sie hat gar keine Chance, gleichverteilte Werte zu liefern, wenn du jedesmal mit randomSeed mit einer sehr begrenzten Zahl von Vorgabewerten dazwischenfunkst.
Stattgegeben.
Kurz mal getestet. Es kommen tatsächlich immer die gleichen Zahlen dabei raus.
Ich kenne andere Implementierungen, bei denen der Startwert nicht geändert wird. Bei der im Arduino verwendeten Implementierung ist es anscheinend anders.
Eine Variable, die innerhalb einer Funktion deklariert wird ohne sie zu initialisieren, hält doch den Wert, der bei einer zufälligen der nächst freien Adresse hinterlegt ist. Könnte man diesen Wert nicht einfach für randomseed nehmen?
Werde ich später mal ausprobieren.
Edit: Klappt nicht so super. Da habe ich bestimmt irgendwo wieder was falsches Aufgeschnappt.
Denn:
Nur weil man nicht (oder nur schwerlich) vorhersagen kann, was in einer solchen Zelle steht, heißt das doch nicht, dass sich der Inhalt von Geisterhand dauernd ändert.
Du hast Recht. Das stammt noch aus einem C++ Tutorial auf dem PC. Und dort, da auf dem Betriebssystem noch viel mehr den RAM beansprucht, ist der vergebene Adressbereich für diese Variable, sehr wahrscheinlich immer woanders bzw. der hinterlegte Wert, an der Adresse, inzwischen von etwas anderen, im Hintergrund laufenden, verändert wurden.
Bei dem kleinen Arduino passieren nicht so viel Nebenläufigkeiten, als das sich die nächst freie Adresse oder der dort hinterlegte Wert ständig ändert. Zumindest nicht bei diesen kleinen Beispielen.
Entstanden ist der Fundus aus kleinen Übungen.
(möglichst)Alles , was mir neu oder ungewohnt vorkommt, wird in kleinen Beispielen durchgearbeitet, bis es verstanden ist.
Ob Sprachdinge, Designpattern, Ideen aus dem Forum, usw.
Auch Irrtümer werden dort bis zum bitteren Ende ausgerollt.
Das meiste landet in der Versenkung, da es bessere Alternativen gibt, oder aus anderen Gründen. Aber ein paar Dinge sind schon recht wertvoll (zumindest für mich).