Hilfe/Tipp bei Programm zur Licht-abhängige Steuerung mit Stepper (Hühnerklappe)

Hallo zusammen,

ich habe schon gegooglet leider nichts passendes gefunden…

Ich möchte mir eine von Licht/Helligkeit gesteuerte Hühnerklappe mit einem Schrittmotor bauen.

Dazu habe ich einen Code erstellt. Leider wird (logischerweise) die Loop immer ausgeführt sodass sich der Motor dauerhaft dreht. Er reagiert aber auf die LUX Änderung nur soll er das nur einmal am Tag tun…

Ich bräuchte hier eure Hilfe.

Was muss ich in meinem Code einbauen damit der Schrittmotor nur einmal die Funktion ausführt (wenn dunkel mach Klappe zu oder wenn Hell Klappe auf)

Wer kann mir hier Hilfestellung geben welchen Operator ich einbauen muss damit die Funktion erfüllt wird? Nach was muss ich Suchen?

Mir fehlt sowas wie eine Zustandsänderung die aber nicht zeitabhängig ist sondern LUX abhängig und dann erst wieder startet wenn ein andere LUX Wert erreicht wird.

#include <AFMotor.h>
#include <Wire.h>
#include <BH1750.h>
int x= 8 ;


AF_Stepper motor1(200,1);
//AF_Stepper motor2(200,2);
BH1750 lightMeter(0x23);


void setup() {
  
motor1.setSpeed(30);
//motor2.setSpeed(50);
Serial.begin(9600);
Wire.begin();
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
    Serial.println(F("BH1750 Advanced begin"));
  }
  else {
    Serial.println(F("Error initialising BH1750"));
  }
}



void loop() 
{
float lux = lightMeter.readLightLevel();
Serial.print("Light: ");
Serial.print(lux);
Serial.println(" lx");

if (lux >= 5)
  {
    x = 1;
  }
if (lux < 5)
  {
    x = 2;
  }

if (x == 1)
  {
  motor1.step(200,BACKWARD,DOUBLE);
  x = 3;
  delay(2000);
  }
  

if (x == 2)
{
  motor1.step(200,FORWARD,DOUBLE);
  x =4;
}


}

noch als Ergänzung:

Wenn LUX < 5 soll der Motor 1x die definierte Anzahl an Umdrehungen machen und dann nichts mehr bis LUX >5

wie kann ich es Umsetzten das der Motor nichts macht bis LUX wieder über den definierten Wert ist und dann die definiert Anzahl am Umdrehungen wieder nur 1x ausführt?

(deleted)

piper0931:
wie kann ich es Umsetzten ...

Zuerst solltest Du IMO einen Programmablaufplan zeichnen, der die einzelnen Schritte so weit „verfeinert“, dass Du den Plan quasi nur noch abtippen musst. Beim Programmieren solltest Du darauf achten, sinnvolle und einheitliche Einrückungen zu benutzen.

Dein if-Gedöns solltest Du in ein switch()/case-Konstrukt umbauen (falls das im Arduino-C-Dialekt möglich ist). Das ist meiner Erfahrung nach kürzer und v. A. besser lesbar.

Gruß

Gregor

@piper0938
Und was genau willst du mit der Variablen "x" erreichen ?
Das erkenne ich nicht.

Das was in der zusätzlichen (unnützen) Abfrage passiert, kann auch schon in der vorherigen if-Abfrage passieren.

piper0931:
noch als Ergänzung:

Wenn LUX < 5 soll der Motor 1x die definierte Anzahl an Umdrehungen machen und dann nichts mehr bis LUX >5

wie kann ich es Umsetzten das der Motor nichts macht bis LUX wieder über den definierten Wert ist und dann die definiert Anzahl am Umdrehungen wieder nur 1x ausführt?

Was denkst du, wie oft die Messung über / unter / über / unter 5 ist, wenn das Licht in dem Bereich ist. Du musst da z.B. bei kleiner 5 zumachen und dann erst bei größer 9 wieder öffnen. Sonst ist die Türe eine Ewigkeit nur beim auf und zu fahren, bis die Schwelle 5 Deutlich über- oder unterschritten ist.
Diese x Gaudi kannst du dann wieder rausschmeissen.

Hallo,

Am Anfang wirst Du auch irgendwie mal auf eine Referenz fahren müssen, damit es ab dieser Position dann losgeht. z.B oben oder auf. Das Kann z.B ein Endschalter sein.Wenn die Mechanik das ab kann könnte es auch ein Festanschlag sein. Aber das hängt davon ab wie das mechanisch aussieht. Die geschlossen Position dazu zu nehmen könnte einem Huhn eventell nicht gut tun wenn es dazwischen gerät. Obwohl die sind sicher schneller als die zufahrende Klappe. Eventuell Sirene und gelbe Rundumleuchte berücksichtigen :wink:

Heinz

Hallo zusammen,

vielen Dank für eure Tipps und Anregungen.

Habe hier nochmal einen Code der bisher ganz gut funktioniert bis auf ein Problem.

Es muss außerdem geprüft werden in welche “Richtung” sich der Lux Wert bewegt. Also ob es von hell zu dunkel geht oder anders rum. Wenn das fehlt würde es passieren das die Klappe sich 2x Mal am Tag z.B. öffnen will weil der definiert Lux Wert einmal frühs und einmal abend erreicht wird.

deshalb habe ich folgende Bedingung eingebaut welche aber leider nicht richtig funktioniert. Ohne diese klappt es aber sie ist halt erforderlich. Hat jemand einen Tipp was hier falsch ist?

es geht um den zweiten Teil : (lux-lux1 < 0) diese Bedingung wird anscheinden nicht geprüft?!

 if ((lux == 5 ) and ((lux-lux1) < 0))
#include <AFMotor.h>
#include <Wire.h>
#include <BH1750.h>
enum State {State1, State2};
int State;
int lux1;

BH1750 lightMeter(0x23);
AF_Stepper motor1(200,1);

void setup(){

  Serial.begin(9600);
  motor1.setSpeed(30);
  Wire.begin();
  // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3);

  if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
    Serial.println(F("BH1750 Advanced begin"));
  }
  else {
    Serial.println(F("Error initialising BH1750"));
  }

}


void loop() {

  int lux = lightMeter.readLightLevel();
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lx");
  Serial.print(lux1);
  Serial.println(" lux1");
  lux1 = lux;
  delay(1000);

  switch (State)
{
case State1:

  if ((lux == 5 ) and ((lux-lux1) < 0)) // hier noch einen Bereich definieren, evtl wird 5 lux nicht genau getroffen..
                                        // (lux-lux1) < 0) dient dazu zu prüfen ob es von hell nach dunkel gegangen ist um zu verhindern das die Klappe 2x am Tag auf geht. Da würde sie dann anschlagen und zu einem Fehler kommen.
                                        // deshalb die Prüfung weil der Lux Wert ja zweimal am Tag erreicht wird...
  {
  motor1.step(200,BACKWARD,DOUBLE);
  Serial.println(State);
  delay (3000); //(7200000); //20 min   // die 20 min Pause dienen dazu da sich innerhalb dieser Zeit der Lux Wert ändert damit wird verhindert das der Motor 2x dreht. Zu testzwecken 3 sec eigestellt.
  }
 else
 {
  State = State2;
 }
  break;
case State2:

  if ((lux == 40 ) and ((lux-lux1) > 0)) // hier noch einen Bereich definieren, evtl wird 12 lux nicht genau getroffen..
  {
  motor1.step(200,FORWARD,DOUBLE);
  Serial.println(State);
  delay  (3000); //(7200000); //20 min
  }
  else
  {
  State = State1;
  }
  break;
}

}

Hi

Einen analogen Wert auf == (und nur auf einen Punkt) abzufragen ist enthusiastisch - wenn der Wert 5 übersprungen wird, wird diese Zeile NIE ausgeführt.

Besser wird Es, wenn Du eine Schaltschwelle festlegst und ‘eine Ecke davon weg’ erst schaltest.
Z.B. Schwelle 500.
Bei steigender Helligkeit steigt auch dieser Wert, dann:
Bei >510 gilt es als ‘hell’
Bei <490 gilt es als ‘dunkel’.

Dann kannst Du noch eine Verzögerung einbauen, daß nicht jedes vorbeikommende Glühwürmchen die Klappe zum Dauerlauf animiert.

// https://forum.arduino.cc/index.php?topic=684241.msg4604105#msg4604105

bool wirdtag = 0; //Flags für die Abfragen
bool isttag = 0;
const uint16_t schwelle = 500;  //LDR-Wert zum gewünschten Schaltzeitpunkt
const uint16_t hysterese = 10;  //'Puffer', verhindert Takten
const byte ldrpin = A0;         //hier ist der LDR angeschlossen
uint32_t lastldr;               //letzte 'Schaltzeit' der Helligkeitserkennung
uint32_t wartezeit=60000;       //Wartezeit, bis die neue Helligkeit übernommen wird
void setup(void) {

}

void loop(void) {
  uint16_t wert = analogRead(ldrpin);
  if (wert >= hysterese && wert - hysterese > schwelle) { //Abfrage, ob's Tag wird
    if (!wirdtag) {   //durch 2 geteilte IF wird (wert - hysterese > schwelle) erst
      lastldr = millis(); //berechnet, wenn der Wert >= der Hysterese ist, kein Unterlauf
      wirdtag = true;
    } else if (millis() - lastldr > wartezeit) {
      isttag = 1;
    }
  }
  if (wert + hysterese < schwelle) { //Abfrage, ob's Nacht wird
    if (wirdtag) {
      lastldr = millis();
      wirdtag = false;
    } else if (millis() - lastldr > wartezeit) {
      isttag = 0;
    }
  }
  if (isttag) {
    //wenn Klappe nicht oben, hochfahren
  } else {
    //wenn Klappe nicht unten, runter fahren
  }
}
/* //Uno/Nano
Der Sketch verwendet 648 Bytes (2%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 14 Bytes (0%) des dynamischen Speichers, 2034 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
 */

MfG

Die Lux - Richtung ist uninteressant.

Wenn du sagst bei kleiner 5 mache ich zu und bei größer 10 mache ich auf, dann ist das auf jeden Fall richtig. Der Wert zum schließen muss nur weit genug weg sein vom Wert zum öffnen. Wenn der Wert <5 gemessen wurde, dann wird in der nächsten Zeit kein Wert mehr mit >10 gemessen. Der Wert >10 kann erst wieder kommen, wenn es hell wird, also am nächsten Morgen.

Oder wie vom Postmaster, bei >510 gilt es als ‘hell’ also auf - bei <490 gilt es als ‘dunkel’ also zu, das ist das selbe, nur mit anderen Helligkeits Werten.

Was nicht geht, ist das was du willst. Kleiner 5 ist zu, größer 5 ist auf. Das wäre ein ewiges auf und zu wenn das Licht so um die 5 ist. Ist doch logisch. Die Messung ist nicht so genau, jeder gemessene Wert ist wieder anders. Wenn er um die 5 ist, dann ist er dauernd mal größer 5 mal kleiner 5. Und die Türe macht auf / zu / auf / zu / u.s.w.

Deshalb mache bei <5 zu und bei >10 auf. Das einzige was dann noch ein Problem ist, das wäre zum Beispiel der Scheinwerfer eines Autos. Sagen wir mal die Türe macht zu, weil die Helligkeit <5 ist, dann bleibt die Türe zu bis zum nächsten Morgen, ausser ein Auto leuchtet mit seinem Scheinwerfer an deinen Sensor und sorgt für ein Licht >10. Dann würde es wieder aufmachen und erst wieder zu, wenn das Auto weg ist.

Franz

Hi

Dagegen hilft ja die Wartezeit, Die ich vorgesehen habe.
Ob's eine ganze Minute sein muß - kA.

MfG

Ja ich wollte eben auf so ein Problem hinweisen, das du da ansprichst, da der Themenstarter wohl Hinweise nur sehr langsam vesteht und sehr umständlich denkt.

Franz