Random Funktion

Möchte für mein Aquarium eine Zufällige Strömung erzeugen. Benutzen will ich dafür 4 Pumpen.
Zum testen lass ich mir auf dem LCD auf den ersten 4 Felder für High oder Low 1/0 anzeigen!
Ich will per Zufall Zwischen 1 und 3 Stunden meine Zufallszahl ändern!
Ich bin noch Anfänger, bitte um Hilfe.
Vielen Dank schonmal und einen schönen Abend,
Grüße Timo

int Zufallszahl; // Pumpenkombination
int Pumpenwechselzeit; // alle 1-3h
unsigned long Pumpenzeit = millis()+Pumpenwechselzeit100060*60;

void setup(void)
{
randomSeed(Zufallszahl);
randomSeed(Pumpenwechselzeit);
}

void loop(void)
Pumpenwechselzeit = random(3);

if (Pumpenzeit > Pumpenwechselzeit)
{Zufallszahl = random(12);}

//Pumpenkomibnationen
// immer 1 oder 2 an
//rest ist zufall
//p1 0-1
//p1,p2 1-2
//p1,p3 2-3
//p1,p4 3-4
//p1,p2,p3 4-5
//p1,p2,p4 5-6
//p1,p3,p4 6-7
//p1,p2,p3,p4 7-8
//p2 8-9
//p2,p3 9-10
//p2,p4 10-11
//p2,p3,p4 11-12

if (Zufallszahl >= 0 && Zufallszahl <= 1)
{digitalWrite(Pumpe_1, HIGH);
lcd.setCursor(0, 0);
lcd.print("1000");}
else
{digitalWrite(Pumpe_1, LOW);}

if (Zufallszahl > 1 && Zufallszahl <= 2)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_2, HIGH);
lcd.setCursor(0, 0);
lcd.print("1100");}
else
{digitalWrite(Pumpe_1, LOW);}
digitalWrite(Pumpe_2, LOW);

if (Zufallszahl > 2 && Zufallszahl <= 3)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_3, HIGH);
lcd.setCursor(0, 0);
lcd.print("1010");}
else
{digitalWrite(Pumpe_1, LOW);
digitalWrite(Pumpe_3, LOW);}

if (Zufallszahl > 3 && Zufallszahl <= 4)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_4, HIGH);
lcd.setCursor(0, 0);
lcd.print("1001");}
else
{digitalWrite(Pumpe_1, LOW);
digitalWrite(Pumpe_4, LOW);}

if (Zufallszahl > 4 && Zufallszahl <= 5)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_2, HIGH);
digitalWrite(Pumpe_3, HIGH);
lcd.setCursor(0, 0);
lcd.print("1110");}
else
{digitalWrite(Pumpe_1, LOW);
digitalWrite(Pumpe_2, LOW);
digitalWrite(Pumpe_3, LOW);}

if (Zufallszahl > 5 && Zufallszahl <= 6)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_2, HIGH);
digitalWrite(Pumpe_4, HIGH);
lcd.setCursor(0, 0);
lcd.print("1101");}
else
{digitalWrite(Pumpe_1, LOW);
digitalWrite(Pumpe_2, LOW);
digitalWrite(Pumpe_4, LOW);}

if (Zufallszahl > 6 && Zufallszahl <= 7)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_3, HIGH);
digitalWrite(Pumpe_4, HIGH);
lcd.setCursor(0, 0);
lcd.print("1011");}
else
{digitalWrite(Pumpe_1, LOW);
digitalWrite(Pumpe_3, LOW);
digitalWrite(Pumpe_4, LOW);
}

if (Zufallszahl > 7 && Zufallszahl <= 8)
{digitalWrite(Pumpe_1, HIGH);
digitalWrite(Pumpe_2, HIGH);
digitalWrite(Pumpe_3, HIGH);
digitalWrite(Pumpe_4, HIGH);
lcd.setCursor(0, 0);
lcd.print("1111");}
else
{digitalWrite(Pumpe_1, LOW);
digitalWrite(Pumpe_2, LOW);
digitalWrite(Pumpe_3, LOW);
digitalWrite(Pumpe_4, LOW);}

if (Zufallszahl > 8 && Zufallszahl <= 9)
{digitalWrite(Pumpe_2, HIGH);
lcd.setCursor(0, 0);
lcd.print("0100");}
else
{digitalWrite(Pumpe_2, LOW);}

if (Zufallszahl > 9 && Zufallszahl <= 10)
{digitalWrite(Pumpe_2, HIGH);
digitalWrite(Pumpe_3, HIGH);
lcd.setCursor(0, 0);
lcd.print("0110");}
else
{digitalWrite(Pumpe_2, LOW);
digitalWrite(Pumpe_3, LOW);}

if (Zufallszahl > 10 && Zufallszahl <= 11)
{digitalWrite(Pumpe_2, HIGH);
digitalWrite(Pumpe_4, HIGH);
lcd.setCursor(0, 0);
lcd.print("0101");}
else
{digitalWrite(Pumpe_2, LOW);
digitalWrite(Pumpe_4, LOW);}

if (Zufallszahl > 11 && Zufallszahl <= 12)
{digitalWrite(Pumpe_2, HIGH);
digitalWrite(Pumpe_3, HIGH);
digitalWrite(Pumpe_4, HIGH);
lcd.setCursor(0, 0);
lcd.print("0111");}
else
{digitalWrite(Pumpe_2, LOW);
digitalWrite(Pumpe_3, LOW);
digitalWrite(Pumpe_4, LOW);}
}

Ist keine wirkliche Zufallszahl aber für normale Menschen nicht vorhersagbar.

unsigned char get_zufalls_zeit()
{
  return (millis() % 3) + 1;
}

Die Funktion liefert einen Wert zwischen 1 - 3 zurück mit dem du weiterarbeiten kannst.

Die Funktion sollte nur aufgerufen werden, wenn die Zufalls Zeit neu generiert werden soll.

Hallo Gerlitschka,
du machst es dir beim programmieren manchmal unnötig schwer.

bei den ganzen if Abfragen
"if (Zufallszahl > 2 && Zufallszahl <= 3)"
bedeutet das doch einfach nur if Zufallszahl=3
das geht doch eleganter mit switch

switch(Zufallszahl){
case 0: .......
case 1: .......
u.s.w.

bei den ganzen if Abfragen
"if (Zufallszahl > 2 && Zufallszahl <= 3)"
bedeutet das doch einfach nur if Zufallszahl=3
das geht doch eleganter mit switch

switch(Zufallszahl){
case 0: .......
case 1: .......
u.s.w.

Sprich, mein Random 12 gibt nur ganze Zahlen aus? Dachte, da kann auch eine z.B. 5,5 kommen.

Allerdings hab ich das noch nicht ganz kapiert, wie ich in meinem Fall diese Random 12(12 verschiede schaltzustaende) nur durch meine Random 3 (Zufall alle 1-3h) anpacke.
Dh, dass nur alle 1-3h, je nachdem was die Zufallszahl raus gibt meinen Schaltzustand ändere.

ich hab mich noch nie mit random u.s.w. beschäftigt,
aber da du "Zufallszahl" als Integer deklariert hast und "Pumpenzeit" als long können da
nur ganze Zahlen raus kommen, keine Kommazahlen.

so ganz hab ich auch noch nicht verstanden was du genau willst.
Pumpenzeit gibt ja immer eine riesig große Zahl, ( 10006060), allerdings nur, wenn du die auch im Programm berechnest.
Also ist die auch immer größer als Pumpenwechselzeit, denn die kann ja maximal 3 werden.

Also mein Ziel ist es alle 1-3 Stunden meine 4 Pumpen zufällig zu schalten. Also der erste Zufall soll die länge ausgeben, also wird sich die Strömung mal nach einer Stunde verändern, ein anderes mal nach zwei, ein anderes mal eben nach drei Stunden. Wenn über den Zufall die länge der Laufzeit ermittelt ist, soll er den Zufall für meine 12 Pumpenzufälle starten, bis die 1-3h wieder rum sind.
Leider bin ich mit meinem Latein am Ende!

Bitte um Hilfe
Grüße timo

ALso ich würde das einfach simpler machen:

Leg einen Timer an (so wie hier beschrieben: http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay)
Immer wenn der Timer abgelaufen ist, wird er auf Null gesetzt und das Intervall per Zufall neu bestimmt.
Also in der Funktion dann per Random das Intervall bestimmen also random(3600000, 10800000) //=> hier wird halt eine random zeit zwischen 1h und 3h berechnet
und per Random die jeweilige PUmpe: random (4) //=> 0 ist Pumpe 1, 1 ist Pumpe 2 und 2 ist Pumpe 3, 3 ist Pumpe4 ....kannst natürlich auch anders anlegen.

das ganze dann ungefähr so (nicht getestet, nicht vollständig):

if(millis() - millisStandLetzterStroemungswechsel > aktuellerStroemungstimer) {  
     millisStandLetzterStroemungswechsel=millis();
     aktuellerStroemungstimer=random(3600000, 10800000);
     zuaktivierendePumpe=random(4);

den letzten Teil würde ich sogar noch in eine eigene Funktion auslagern, in der die Pumpen an/aus geschaltet werden.
Dort kannst du dann auch besser die jeweiligen 12 Zufallsmöglichkeiten wählen lassen (hier habe ich einfach nur jeweils 1 Möglichkeit gegeben, aber vom Prinzip her dasselbe. Mach es dann wie von Maverick beschrieben, also random(12); und dahinter dann die 12 cases aufführen http://www.arduino.cc/en/Reference/SwitchCase , am besten per Arrays z.B. {0,1,1,0{ => Pumpe1=OFF 2=ON 3=ON 4=OFF, oder du baust die randomFUnktion direkt in das Array, dann musst du nicht mal die 12 cases definieren :wink: http://www.arduino.cc/en/Reference/Array
Mach es nicht so kompliziert :wink:

Gruß

So, getestet! Dachte anfangs es funktioniert, leider doch nicht ganz!

int Pumpe_1 = 28;
int Pumpe_2 = 29;
int Pumpe_3 = 30;
int Pumpe_4 = 31;
int Zufallszahl;
long millisStandLetzterStroemungswechsel = 0;
long aktuellerStroemungstimer = random(1000, 12000);

void setup(void)
{
pinMode(28,OUTPUT);
pinMode(29,OUTPUT);
pinMode(30,OUTPUT);
pinMode(31,OUTPUT);
}


void loop(void)
 {
unsigned long currentmillis = millis();

if(currentmillis - millisStandLetzterStroemungswechsel > aktuellerStroemungstimer)
{millisStandLetzterStroemungswechsel = currentmillis;
Zufallszahl = random(12);


if (Zufallszahl >= 0 && Zufallszahl <= 1)
{digitalWrite(Pumpe_1, HIGH);
lcd.setCursor(0, 0);
lcd.print("1000");}
else
{digitalWrite(Pumpe_1, LOW);}
  
usw.....

Ich werde das mit Switch Case ändern, sobald es so funktioniert =)
Leider hab ich das Problem, dass er nun
immer alle 6 Sekunden den Zustand ändert. Die Zufallsfunktion klappt so irgendwie nicht.
Es nimmt immer den mittleren Wert.
long aktuellerStroemungstimer = random(1000, 12000); 6 Sekunden
long aktuellerStroemungstimer = random(1000, 6000); 3 Sekunden

Noch eine Idee?

wie wäre es denn so:
hab ich nicht getestet aber sollte gehen
wenn ich richtig gerechnet habe sind 10800000 sec gleich 3 Stunden,
die Schleife wird also nur alle drei Stunden durchlaufen.
Dann wird eine Zufallszahl zwischen 0 und 12 generiert und ja nach Zahl die entsprechende Anzahl Pumpen geschaltet.

jetzt = millis();
 if(jetzt - vorher > 10800000){
   Zufallszahl = random(12);
   switch(Zufallszahl){
   case 0:  
     digitalWrite(Pumpe_1, HIGH);
     digitalWrite(Pumpe_2, LOW);
     digitalWrite(Pumpe_3, LOW);
     digitalWrite(Pumpe_4, LOW);
     break;
   case 1:  
     digitalWrite(Pumpe_1, HIGH);
     digitalWrite(Pumpe_2, HIGH);
     digitalWrite(Pumpe_3, LOW);
     digitalWrite(Pumpe_4, LOW);
     break;  
   case 2:  
     digitalWrite(Pumpe_1, HIGH);
     digitalWrite(Pumpe_3, HIGH);
     digitalWrite(Pumpe_2, LOW);
     digitalWrite(Pumpe_4, LOW);
     break;  
  .
  .
  .
  .
  .
  .
 }
  vorher=millis();
 }
 }

Danke Maverick, aber mir geht es ja darum, nicht immer alle 3h den Zustand zu ändern, sondern beliebig zwischen 1 und 3 Stunden. =)

ok dann vielleicht so:

void loop(void) 
{
Pumpenwechselzeit = random(3);
jetzt = millis();
 if(jetzt - vorher > 3600000 * Pumpenwechselzeit){
   Zufallszahl = random(12);
   switch(Zufallszahl){
   case 0:  
     digitalWrite(Pumpe_1, HIGH);
     digitalWrite(Pumpe_2, LOW);
     digitalWrite(Pumpe_3, LOW);
     digitalWrite(Pumpe_4, LOW);
     break;
   case 1:  
     digitalWrite(Pumpe_1, HIGH);
     digitalWrite(Pumpe_2, HIGH);
     digitalWrite(Pumpe_3, LOW);
     digitalWrite(Pumpe_4, LOW);
     break;  
   case 2:  
     digitalWrite(Pumpe_1, HIGH);
     digitalWrite(Pumpe_3, HIGH);
     digitalWrite(Pumpe_2, LOW);
     digitalWrite(Pumpe_4, LOW);
     break;  
  .
  .
  .
  .
  .
  .
 }
  vorher=millis();
 }
 }

Oke, danke für eure Hilfe, passt =)

sofern man +1 macht

Pumpenwechselzeit = random(3)+1;

Wenn ich jetzt den Arduino auf reset klicke, dauert es zwischen 1 und 3 Stunden, bis der erste Zustand der Pumpen Definiert wird. Da mach ich am besten über void Setup einen von Hand definierten Start oder?
int Pumpe_1 = 28,HIGH);
int Pumpe_2 = 29,HIGH);
int Pumpe_3 = 30,HIGH);
int Pumpe_4 = 31,HIGH);

es geht doch einfacher:
1 oder 2 von 4 Pumpen ein
Wechsel zwischen 1 und 3 Stunden.

// Steuerung Pumpen für Aquarium.

int PumpenAusgang[]={2,3,4,5}; //Ausggangspin an welchen die Pumptreiber hängen.
int NrPumpenEin =0; //anzahl der eingeschaltenen Pumpen.
unsigned long Pumpenwechselzeit = 0;  // Zeit nachder ein Wechsel stattfindet  
unsigned long vorher =0;
int k;

void setup()
{
Serial.begin(9600);  
for (int i=0; i<4;i++)
{
pinMode(PumpenAusgang[i],OUTPUT);  // definiert Pins als Ausgang.
digitalWrite(PumpenAusgang[i], LOW);  // Schaltet alle Ausgänge aus.
}
Serial.println ("initialisation gemacht ");
pumpenAuswaehlen();
}

void loop() 
{
  if(millis() - vorher > Pumpenwechselzeit)
  {    
    pumpenAuswaehlen ();
  }
}

void pumpenAuswaehlen (void)
{
Pumpenwechselzeit =1200000 + 1200000 * random(3);

//******************************************
Pumpenwechselzeit /=1000;  // Zeit verkürzen für Test;
//******************************************

NrPumpenEin = 1 + random (2);
Serial.print ("Pumpenwechselzeit= "); Serial.print (Pumpenwechselzeit,DEC);
Serial.print ("  |  Anzahl Pumpen eingeschaltet = "); Serial.print (NrPumpenEin,DEC); Serial.print ("  |  ");
for (int i=0; i<4;i++)
{
digitalWrite(PumpenAusgang[i], HIGH);  // Schaltet alle Pumpen ein damit nie keine Pumpe läuft.
}
for (int j=4; j>NrPumpenEin; j--)
{
  k = random(4); 
  if (digitalRead(PumpenAusgang[k]) == HIGH)
  {
  digitalWrite(PumpenAusgang[k], LOW);
  Serial.print (" Pumpe NR "); Serial.print (PumpenAusgang[k],DEC); Serial.print (" AUS; ");
  }
  else
  {
  j++;
  }
}
vorher = millis();
Serial.println ();
}

Für richtige Zeit Zeile

Pumpenwechselzeit /=1000;

auskommentieren.

Grüße Uwe

UWE du bist ein Pro =) Aber für mich als Anfänger lass ich lieber mal die lange Version :smiley:
trotzdem Danke, hab den Sketch trotzdem mal abgespeichert, Timo

Da ist eigentlich nichts besonders kompliziertes dran an meinem Sketch.
Grüße Uwe

Hi Gerlitschka,

Uwe hat dir quasi ähnlich wie von mir bereits vorgeschlagen (mit einigen Verbesserungen) den kompletten code programmiert.
Der ist auch nicht schwer zu durchschauen, geh ihn doch einfach mal step by step durch und mal dir auf papier auf, was jeweils passiert.
=> so kannst du den Code nachvollziehen und lernst außerdem dazu.
Auch wenn du lieber ne "lange" VErsion nutzt, weil sie dir einfacher erscheint, fang lieber frühzeitig an, Code so kurz und übersichtlich wie möglich zu gestalten.

EIne Frage an Uwe:

for (int j=4; j>NrPumpenEin; j--)
{
  k = random(4); 
  if (digitalRead(PumpenAusgang[k]) == HIGH)
  {
  digitalWrite(PumpenAusgang[k], LOW);
  Serial.print (" Pumpe NR "); Serial.print (PumpenAusgang[k],DEC); Serial.print (" AUS; ");
  }
  else
  {
  j++;
  }
}
vorher = millis();
Serial.println ();
}

"Rein Theoretisch" könnte das doch ne Endlosschleife geben, wenn k = random(4); immer den gleichen Wert zurückspielt oder?
Denn zunächst wird j einen runtergesetzt und dann wieder einen hoch.
Ich gehe davon aus, dass das praktisch nie passieren wird, kann man das daher vernachlässigen?
Oder habe ich grad einen Denkfehler?
Gruß

Hallo currymuetze

"Und ewig grüßet das Murmeltier."

Ja, dieser Spagetti-Code mit den switch-case schleife ist nicht die beste Art zu programmieren.

Ja, theoretisch könnte die Schleife durch das ewig gleiche Ergebnis hängen bleiben, aber die Random-Funktion ist ja so programmiert, daß sie zufällige Zahlen gibt die im gesamten gesehen möglichst gleichmäßig auf den gesamten Wertebereich aufgeteilt ist. Um da signifikante Zeiten herauskommen (einige Sekunden bis Minuten) muß schon einige hundert bis 1000 mal die gleiche Zahl hintereinender herauskommen und das ist unwahrscheinlich bis unmöglich.

Falls das wirklich passiert (daß eine Zahl immer wieder herauskommt) bleibt das Programm in dieser Schleife und es gehen konstant 3 Pumpen. Deshalb habe ich auch so programmiert daß zuerst alle pumpen eingeschaltet werden und dann die Zufallsfunktion die Pumpen ausschaltet und nicht zuerst alle ausschalten und dann einige einschalten.

Natürlich kann man einen Zähler einbauen und kontrollieren ob die Schleife zB 10 mal durchläuft ohne zu einen Ergebnis zu kommen und diesem Fall die Schleife abbricht und 2 Pumpen per default setzt.

int wiederholungen =0;
...
wiederholungen =0;
for (int j=4; j>NrPumpenEin; j--)
{
  k = random(4); 
  if (digitalRead(PumpenAusgang[k]) == HIGH)
  {
  digitalWrite(PumpenAusgang[k], LOW);
  Serial.print (" Pumpe NR "); Serial.print (PumpenAusgang[k],DEC); Serial.print (" AUS; ");
  }
  else
  {
  j++;
  }
  wiederholungen++;
 if(wiederholungen>=10)
{
digitalWrite(PumpenAusgang[0], LOW);
digitalWrite(PumpenAusgang[1], LOW);
}
}
vorher = millis();
Serial.println ();
}

Die Gefahr einer Fehlfunktion ist da sehr wahrscheinlicher im
Falls sich das System blockieren sollte ist es sehr wahrscheilicher daß es am Blockieren des Arduino, am Blockieren der Pumpe, am Fehlen der Netzspannung durch einen Schaden in der Energieverteilung; am Auslösen des FI-schutzes oder Magnetothermischen Sicherung in Verteiler des Hauses/Wohnung durch eine Schaden an einem anderen Gerät ecc. liegen wird.

Viele Grüße Uwe

So Uwe, ich denk ich habe das soweit alles verstanden, das mit den Zeiten läuft, musste nur ein wenig was abändern, allerdings wollte ich ein Schalter für die Fütterung einrichten, aufdem alle Pumpen gleichzeitig für 15 min ausgehen.

Es müsste doch funktionieren, wenn ich durch Taster betätigen meine "Fuetterung" aktiviere. Dann vergleich ich "vorher" mit "Fuetterung". Wenn "Vorher" größer ist, geht der normale random zustand wieder weiter. Vorher setze ich alle 4 Pumpen auf LOW? richtig?

int Fuetterung = 900000;
// 15 minuten sind 900000 millis

if(millis() - vorher > Pumpenwechselzeit)
{
pumpenAuswaehlen ();
}

Soll die Fütterung immer zulässig sein oder nur alle x Stunden möglich sein? Dies um eine Fehlfunktion entgegenzuwirken.
Grüße Uwe