Projektvorstellung: Hühnerstallklappensteuerung/ Großes Problem

Ein freundliches Hallo an Alle :slight_smile:
Ich habe heute ein Projekt fertiggestellt, was gut zu laufen scheint. Aber gerade auf lange Sicht bin ich mir bei solchen Dingen meist unsicher, daher wäre es mir recht, wenn Code und Schaltplan nicht nur von meinen Augen begutachtet sind.
Zum Projekt: Mein Vater hat einen Hühnerstall, und die Klappe hängt an einem Garagentoröffner, dessen Elektronik versagt hat. Daher sollte ich die Elektronik ersetzen.
Funktionen: Der Schlitten betätigt 2 Endlagenschalter, so ist die Position i.d.R. bekannt. Eine RG-LED zeigt an, ob die Klappe oben (Grün), unten (rot), in Bewegung (gelb) ist, oder ob ein Fehler vorliegt (rot blinkend). Eine Zeitschaltuhr wird 2x am Tag für eine Minute aktiviert. Einerseits versorgt sie den Motor mit Strom, andererseits gibt sie über Spannungsteiler ein Signal an den Arduino, welcher dann die Klappe hoch- oder runterfährt.

Hier der Code:

//Stand: 21.06.2017
//Programm zur Steuerung einer Klappe am Hühnerstall
//geschrieben von Carsten Lehmann (DerLehmi)

#include <Bounce2.h>

//#define DEBUG

#define ledG 5                                            //Grüne LED
#define ledR 6                                            //Rote LED
#define tasterO 11                                        //Endpositionstaster Oben
#define tasterU 12                                        //Endpositionstaster Unten
#define relaisA 4                                         //Klappe runterfahren
#define relaisB 3                                         //Klappe hochfahren
#define eingang A3                                        //Eingang für Startsignal
bool flanke=false;                                        //wenn Eingang neu erkannt
bool beheben=false;                                       //wenn Taster zum Beheben der Fehlerposition betätigt

Bounce TasterO=Bounce();
Bounce TasterU=Bounce();

int state=0;                                              //Statusvariable (0=Wartestatus; 1=Betriebsmodus; 2=Blockiermodus; 3=Fehlermodus)
unsigned long actual_Milliseconds=0;
unsigned long zeitspeicher_notAus=0;
unsigned long zeitspeicher_signal=4294787295;

void setup() {
  #ifdef DEBUG
    Serial.begin(9600);
    while(!Serial);
    Serial.println("Start: Hühnerklappe");
  #endif
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

  pinMode(ledG, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(relaisA, INPUT_PULLUP);                         //verhindert ungewollte Initialisierung auf LOW (HIGH-aktiv)
  pinMode(relaisA, OUTPUT);
  pinMode(relaisB, INPUT_PULLUP);                         //verhindert ungewollte Initialisierung auf LOW (HIGH-aktiv)
  pinMode(relaisB, OUTPUT);

  pinMode(tasterO, INPUT_PULLUP);
  TasterO.attach(tasterO);
  TasterO.interval(15);
  pinMode(tasterU, INPUT_PULLUP);
  TasterU.attach(tasterU);
  TasterU.interval(15);
  pinMode(eingang, INPUT);

  TasterO.update();
  TasterU.update();
  fehlerTest();
  if(state!=3){                                           //Anzeige der Klappenposition
    if(TasterO.read()){
      digitalWrite(ledR, HIGH);                           //Klappe unten (Rot)
      #ifdef DEBUG
        Serial.println("Klappe ist unten");
      #endif
    }else{
      digitalWrite(ledG, HIGH);                           //Klappe oben (Grün)
      #ifdef DEBUG
        Serial.println("Klappe ist oben");
      #endif
    }
    emptyCap();
  }
  #ifdef DEBUG
    Serial.println("Ende des Setups");
  #endif
}

void loop() {
  actual_Milliseconds=millis();
  TasterO.update();
  TasterU.update();
  if(state==0){                                           //Wartestatus
    stopMotor();
    fehlerTest();
    if(actual_Milliseconds-zeitspeicher_signal>30000){    //im Wartestatus Abfrage aller 30 Sekunden
      if(digitalRead(eingang)){
        state=1;                                          //Betriebsstatus setzen
        #ifdef DEBUG
          Serial.println("Status --> 1");
        #endif
        flanke=true;
      }
      zeitspeicher_signal=actual_Milliseconds;
    }
  }else if(state==1){                                     //Betriebsstatus
    if(flanke){                                           //wenn Startvorgang
      if(!TasterO.read()){
        digitalWrite(relaisA, LOW);                       //Klappe runterfahren
        digitalWrite(ledR, HIGH);                         //in Betrieb: LED Gelb
        #ifdef DEBUG
          Serial.println("Klappe wird heruntergefahren");
        #endif
      }else{
        digitalWrite(relaisB, LOW);                       //Klappe hochfahren
        digitalWrite(ledG, HIGH);                         //in Betrieb: LED Gelb
        #ifdef DEBUG
          Serial.println("Klappe wird hochgefahren");
        #endif
      }
      flanke=false;                                       //Schlitten in Betrieb
      zeitspeicher_notAus=actual_Milliseconds;
    }else{                                                //wenn Motor läuft
      if(!digitalRead(relaisA)){
        if(TasterU.fell()){                               //Zielposition (unten) erreicht
          state=2;
          #ifdef DEBUG
            Serial.println("Status --> 2 (Unten erreicht)");
          #endif
          digitalWrite(ledG, LOW);
        }
      }else{
        if(TasterO.fell()){                               //Zielposition (oben) erreicht
          state=2;
          #ifdef DEBUG
            Serial.println("Status --> 2 (Oben erreicht)");
          #endif
          digitalWrite(ledR, LOW);
        }
      }
      if((actual_Milliseconds-zeitspeicher_notAus)>6000){ //wenn Schlitten blockiert
        state=3;
        #ifdef DEBUG
          Serial.println("Status --> 3 (Schlitten blockiert)");
        #endif
      }
    }
  }else if(state==2){                                     //Blockiermodus (keine Flankenerkennung)
    stopMotor();
    fehlerTest();
    if(actual_Milliseconds-zeitspeicher_signal>80000){    //wenn Blockierzeit vorbei
      emptyCap();
      state=0;
      #ifdef DEBUG
        Serial.println("Status --> 0");
      #endif
    }
  }else if(state==3){                                     //Fehlermodus
    if(TasterO.fell() || TasterU.fell()){
      beheben=true;
    }
    if(!beheben){
      stopMotor();
      if(digitalRead(ledG))
        digitalWrite(ledG, LOW);
      if((actual_Milliseconds-zeitspeicher_notAus)>300){  //LED blinkt rot
        digitalWrite(ledR, !digitalRead(ledR));
        zeitspeicher_notAus=actual_Milliseconds;  
      }
    }else if(TasterO.fell() && digitalRead(relaisB) && digitalRead(relaisA)){     //Zielposition oben anfahren
      digitalWrite(relaisB, LOW);
      #ifdef DEBUG
        Serial.println("Oben wird angefahren");
      #endif
    }else if(TasterU.fell() && digitalRead(relaisA) && digitalRead(relaisB)){     //Zielposition unten anfahren
      digitalWrite(relaisA, LOW);
      #ifdef DEBUG
        Serial.println("Unten wird angefahren");
      #endif
    }else if(TasterO.fell() && !digitalRead(relaisB)){    //Zielposition oben erreicht
      digitalWrite(relaisB, HIGH);
      state=0;
      beheben=false;
      if(digitalRead(ledR))
        digitalWrite(ledR, LOW);
      digitalWrite(ledG, HIGH);
      delay(5000);                                        //Wartezeit zum Abklemmen der Versorgung für Motor
      emptyCap();
      #ifdef DEBUG
        Serial.println("Oben erreicht");
      #endif
    }else if(TasterU.fell() && !digitalRead(relaisA)){    //Zielposition unten erreicht
      digitalWrite(relaisA, HIGH);
      state=0;
      beheben=false;
      digitalWrite(ledR, HIGH);
      delay(5000);                                        //Wartezeit zum Abklemmen der Versorgung für Motor
      emptyCap();
      #ifdef DEBUG
        Serial.println("Unten erreicht");
      #endif
    }
  }
}

void fehlerTest(){
  if(TasterO.read()==TasterU.read()){                     //Test, ob Schlitten eindeutige Lage hat
    state=3;                                              //Fehlerstatus
    #ifdef DEBUG
      Serial.println("Status --> 3 (Fehler gefunden)");
    #endif
    zeitspeicher_notAus=actual_Milliseconds;
  }
}

void stopMotor(){                                         //Motor stoppen
  if(!digitalRead(relaisA)){
    digitalWrite(relaisA, HIGH);
  }
  if(!digitalRead(relaisB)){
    digitalWrite(relaisB, HIGH);
  }
}

void emptyCap(){                                          //kurzzeitiges Ansteuern des Motors, um Kondensator zu entladen
  digitalWrite(relaisA, HIGH);
  digitalWrite(relaisB, LOW);
  delay(200);
  digitalWrite(relaisB, HIGH);
  #ifdef DEBUG
    Serial.println("Kondensator entladen");
  #endif
}

Und hier der Schaltplan:

Hallo,

in Kurzform.

Etwas unvorteilhaft gezeichneter Schaltplan und zu klein. Man kann kaum bis nichts lesen. Hängen die Taster oben an den 38V oder nicht? Masseverbindung beider Spannungsquellen fehlt. Sind die 38V und 7,5V die Spitzenspannung nach Gleichrichtung? Welche Nennspannung hat der Motor? Statt LM2596 würde ich einen Festspannungs-Schaltregler. Entweder die 3 Pin Platinchen von Pololu oder die 3 Pin Schaltregler von Recom oder Traco. Die Relais möchtest du wirklich direkt anklemmen? 20mA sind ausreichend? Freilaufdioden fehlen.

Danke für Deine Antwort

Etwas unvorteilhaft gezeichneter Schaltplan und zu klein. Man kann kaum bis nichts lesen.

-->Das hat der Beitragseditor aus dem Bild gemacht, für das Vollbild Rechtsklick auf das kleine Bild-->Grafik anzeigen; oder hier klicken

Hängen die Taster oben an den 38V oder nicht?

-->Nein, eine Seite am Arduino-Pin, die andere an GND

Masseverbindung beider Spannungsquellen fehlt.

-->Die Masseverbindung nach dem Spannungsregler an die 38V-Quelle reicht also nicht aus?

Sind die 38V und 7,5V die Spitzenspannung nach Gleichrichtung?

-->Die 7,5V kommen durch ein ungeregeltes Netzteil, dieses hier Die 38V messe ich nach dem Gleichrichter. Der Motor wird mit 24VDC (Einhell VC820) angegeben, muss aber zusammenpassen, da Trafo und Gleichrichter original vor diesem Motor geschaltet waren.

Statt LM2596 würde ich einen Festspannungs-Schaltregler.

-->Ist das im Grunde ein Schaltregler, mit dem man nicht über einen Poti die Spannung einstellen kann? Also einfach Poti raus und durch festen Widerstand ersetzen?

Die Relais möchtest du wirklich direkt anklemmen? 20mA sind ausreichend? Freilaufdioden fehlen.

-->Um Gottes Willen nein^^ Auf dem Schaltplan habe ich nur eine grobe Skizze des Relaisboards eingefügt, ist also kein nacktes Relais.... Auf dem Board wird das Relais durch einen Transistor geschalten und mit einer Schutzdiode versehen.

DerLehmi: -->Die Masseverbindung nach dem Spannungsregler an die 38V-Quelle reicht also nicht aus?

Minus vom LM2596 hängt am linken Arduino GND, Plus führt zur Relaiskarte und von dort über LEDs vom Optokoppler (oder was auch immer) zurück zum rechten Arduino GND. Es fließt also ein Strom vom rechten zum linken Arduino GND. Wahrscheinlich ist der Strom klein genug, keinen Schaden anzurichten, aber gefallen würde es mir nicht.

  pinMode(13, OUTPUT);

Wenn Du die anderen benennst, solte auch 13 benannt werden, sonst ist das eine potentielle Fehlerquelle.

int state=0;

Da reicht auch byte.

state könntest Du mittels switch/case abfragen.

Zumindest lange delays würde ich versuchen zu vermeiden.

Du hattest ja nach sowas gefragt :)

Hallo,

jetzt sehe ich besser. Die Taster sind dennoch unglücklich positioniert. Musste zugeben! Hätte man unterhalb der 38V Masse platzieren können.

[u]Masse:[/u] Jetzt sehe ich das. Ich empfehle dennoch die Massen beider Quellen erst direkt zusammenzuschließen, auf kurzem Wege, davon dann als eine Masse für die folgende Schaltung zuverwenden. Beide Massepins vom µC dennoch verbinden. Aber eben nicht das sich die Quellen Massen erst dort treffen.

[u]Spannung:[/u] Gut, dann sind die 38V die Spitzenspannung. Ich hoffe unbelastet gemessen. Das wollte ich wissen, wegen dem Spannungsteiler. Die Spitzenspannung musste auch bei der Kondensator Spannungsfestigkeit beachten. 50V besser 63V Typen. An A3 liegen dann 3,4V an. Der 24V Motor bekommt zu viel Spannung. Wenn dir das bewusst ist, ist okay, ich sage es nur.

Spannungsregler. Das Poti wird sich mit der Zeit verstellen. Ausmessen? Warum umständlicher machen wie nötig? Musste selber wissen, ich mache nur Vorschläge.

Wenn die Relaiskarte alles drauf hat, gut.

Die Motorbeschaltung ist hoffentlich nur auf die schnelle gezeichnet. Im Relais-Ruhezustand würde ich immer Masse an Motor legen.

Ansonsten nach Besten Wissen und Gewissen okay.

Danke für Eure Vorschläge. Also werde ich das Teil die Tage nochmal abbauen und soweit berichtigen.

Wenn Du die anderen benennst, solte auch 13 benannt werden, sonst ist das eine potentielle Fehlerquelle.

-->Jup, könnte ich eigentlich auch mit der Systemvariable (LED_BUILTIN) machen. Pin13 hat hier keine sonderliche Bedeutung, ich schalte den nur auf Low, damit die Onboard-LED nicht unnötig leuchtet.

Da reicht auch byte.

-->Stimmt, mach ich.

Zumindest lange delays würde ich versuchen zu vermeiden.

-->Die 5s Wartezeit? An dieser Stelle meine ich, das würde den Mehraufwand nicht rechtfertigen. Diese Stelle betrifft einen Eingriff des Nutzers, wo nur noch Zeit gebraucht wird, um die Motorversorgung abzuklemmen. Sonst sollen in der Zeit keine Werte erfasst werden oder sonstige Rechenoperationen erfolgen.

Minus vom LM2596 hängt am linken Arduino GND, Plus führt zur Relaiskarte und von dort über LEDs vom Optokoppler (oder was auch immer) zurück zum rechten Arduino GND. Es fließt also ein Strom vom rechten zum linken Arduino GND. Wahrscheinlich ist der Strom klein genug, keinen Schaden anzurichten, aber gefallen würde es mir nicht.

-->Steht auf der Liste

jetzt sehe ich besser. Die Taster sind dennoch unglücklich positioniert. Musste zugeben! Hätte man unterhalb der 38V Masse platzieren können.

-->Jup, hab den Plan abgeändert.

Jetzt sehe ich das. Ich empfehle dennoch die Massen beider Quellen erst direkt zusammenzuschließen, auf kurzem Wege, davon dann als eine Masse für die folgende Schaltung zuverwenden. Beide Massepins vom µC dennoch verbinden. Aber eben nicht das sich die Quellen Massen erst dort treffen.

-->Der Übersicht wegen mach ich es noch etwas anders: ich lege einfach Masse des (noch) LM auf die Gesamtmasse, welche dann zum GND des Arduino geht. Den anderen GND-Pin nutz ich dann nicht mehr.

Gut, dann sind die 38V die Spitzenspannung. Ich hoffe unbelastet gemessen. Das wollte ich wissen, wegen dem Spannungsteiler. Die Spitzenspannung musste auch bei der Kondensator Spannungsfestigkeit beachten. 50V besser 63V Typen. An A3 liegen dann 3,4V an.

-->Ja, unbelastet. An der 38V-Quelle hängt ein 50V, 470uF-Cap, an der 7,5V-Quelle ein 16V, 1000uF-Cap. Übrigens habe ich auf dem Schaltplan vergessen, eine Diode einzuzeichnen, welche vor dem analogen Eingang sitzt.

Der 24V Motor bekommt zu viel Spannung. Wenn dir das bewusst ist, ist okay, ich sage es nur.

-->Jop, find es auch komisch...ist aber nicht auf meinem Mist gewachsen.

Spannungsregler. Das Poti wird sich mit der Zeit verstellen. Ausmessen? Warum umständlicher machen wie nötig? Musste selber wissen, ich mache nur Vorschläge.

-->Wäre das dann sowas hier?

Die Motorbeschaltung ist hoffentlich nur auf die schnelle gezeichnet. Im Relais-Ruhezustand würde ich immer Masse an Motor legen.

-->Darauf habe ich gar nicht geachtet... eben nachgeprüft, leider im Ruhezustand auf der +Seite. Muss also auch noch geändert werden, und damit auch die Relais-Pins im Programm.

Hier der Schaltplan, wie ich es abändern möchte(die Masseverbindungen sehen hier alle der Übersichtlichkeit wegen verteilt aus, bei der richtigen Schaltung habe ich da einen zentralen Massepunkt) Außerdem wird wohl noch der Spannungsregler ausgetauscht, sobald ich das richtige Modul gefunden und bestellt habe. |500x266

DerLehmi: -->Die 5s Wartezeit? An dieser Stelle meine ich, das würde den Mehraufwand nicht rechtfertigen. Diese Stelle betrifft einen Eingriff des Nutzers, wo nur noch Zeit gebraucht wird, um die Motorversorgung abzuklemmen. Sonst sollen in der Zeit keine Werte erfasst werden oder sonstige Rechenoperationen erfolgen.

Bei automatisch motorischen Bewegungen gehört für mich die Frage geklärt, was passiert, wenn ein armes Huhn eingeklemmt wird. Der Bauer antwortet: Hühmersuppe!

Du hast weder NotAus noch manuelle Bewegungen vorgesehen, daher stört blockierende Programmierung nicht. Für mich, aus der Entfernung, gehört sowas aber dazu. Ob es eine mechanische Entriegelung gibt, sehe ich ja nicht.

Auf jeden Fall solltest Du mich einladen, wenn es zu häufig Hühnersuppe gibt :)

Auf jeden Fall solltest Du mich einladen, wenn es zu häufig Hühnersuppe gibt :)

-->Lässt sich einrichten xD

Bei automatisch motorischen Bewegungen gehört für mich die Frage geklärt, was passiert, wenn ein armes Huhn eingeklemmt wird.

-->Wenn man das nur erfassen könnte.... der Schlitten bewegt sich auf einer Schiene, an dem Schlitten hängt ein Seil, an welchem wiederum die Klappe hängt. Ein eingeklemmtes Huhn ließe sich schlecht erkennen, das fällt dann wohl unter die natürliche Auslese. Die Tiere gehen von selbst wie ein Uhrwerk in den Stall. Von daher kann man leicht die Zeitschaltuhr danach anpassen ;)

Du hast weder NotAus noch manuelle Bewegungen vorgesehen, daher stört blockierende Programmierung nicht. Für mich, aus der Entfernung, gehört sowas aber dazu. Ob es eine mechanische Entriegelung gibt, sehe ich ja nicht.

-->Nicht ganz, NotAus wäre ja, wenn der Schlitten nicht in einem bestimmten Zeitraum den anderen Taster erreicht. Manuell kann man das Teil bedienen, indem man den nicht betätigten Taster drückt...das System geht in den Fehlermodus. Nun den Motorstrom anschalten, den Taster betätigen, wo der Schlitten hinsoll.... dann fährt der Schlitten dahin, man schaltet innerhalb 5s die Versorgung für den Motor ab und schon ist das System wieder im normalen Modus.

Mir wäre es auch schöner gewesen, das System mit einem Display und Tastern sowie einer RTC zu versehen, wo man dort dann die Zeiten einstellen kann (ähnlich meinem Uhrprojekt fürs Auto).... aber das war halt nicht so erwünscht^^

Ein Tip für einfache Debug Ausgaben:

#define DEBUG

#ifdef DEBUG
  #define debugBegin(...) Serial.begin(__VA_ARGS__)
  #define debugPrint(...) Serial.print(__VA_ARGS__)
  #define debugPrintln(...) Serial.println(__VA_ARGS__)
#else
  #define debugBegin(...)
  #define debugPrint(...)
  #define debugPrintln(...)
#endif

Wenn du dann das #define DEBUG auskommentierst sind keine Ausgaben enthalten, da die Makros mit “nichts” ersetzt werden. So muss man nicht überall im Code abfragen

Ein Tip für einfache Debug Ausgaben:

-->Sehr schön, dankefein dafür....das macht die Sache noch spaßiger :)

DerLehmi: ... an der 7,5V-Quelle ein 16V, 1000uF-Cap. Übrigens habe ich auf dem Schaltplan vergessen, eine Diode einzuzeichnen, welche vor dem analogen Eingang sitzt.-->Jop, find es auch komisch...ist aber nicht auf meinem Mist gewachsen. -->Wäre das dann sowas hier?

der Regler passt nicht. Mindesteingangsspannung 9V. Zudem was willste mit 5A? Deine 7,5V sind auch etwas zu niedrig dafür. Und deine 38V leider zu hoch. Wenn das 24V wären könnte man daraus 5V generieren.

Zudem ich den ungeregelten 7,5V nicht traue. Was machen die 7,5V unter Last?

Wenn du es damit probieren möchtest, kann man einen Recom R-785.0-0.5 nehmen. 0,5A sollte doch ausreichen? Der erwartet mindestens 6,5V. Oder einen Traco TSR 1-2450 ... min 6,5V. Pololu D24V5F5, 5V, 500mA ... min 5,6V bei max. Last Pololu D24V10F5, 5V, 1A ... min 5,8V bei max. Last

Wenn du ein 9V oder 12V Steckernetzteil nehmen könntest, hätte man mehr Auswahl, dann könnte man einen Recom R-78E5.0-0.5 nehmen, wäre billiger wie der obige. Mindesteingangsspannung 7V. Pololu D24V6F5, 5V, 600mA ... min 7V bei max. Last

Such dir was aus. Wenn du andere Regler raussuchst, achte auf den Eingangsspannungsbereich.

Die Diode soll eine Verpolschutzdiode sein? Dann besser an den Spannungseingang, damit wäre auch der erste Kondensator geschützt.

DerLehmi: -->Lässt sich einrichten xD ... Die Tiere gehen von selbst wie ein Uhrwerk in den Stall.

dummes Huhn => Hühnersuppe kluges Huhn => viele Eier

Bei mir hat sich noch ein weiterer Gast angemeldet, sollte ich es alleine nicht schaffen, aber da wird es wohl nichts mit der Hühnersuppe.

Wenn Du die Hühner mal übernimmst, kannst Du ja auf RTC umstellen. Da könnte man bei Nichterreichen des Endschalters nach einer Zeit die Klappe wieder automatisch hochfahren, um das Huhn freizugeben und dann nach einer Wartezeit den Schließvorgang wiederholen. Wenn auch die Wiederholung scheitert, könnte eine manuelle Korrektur zur Beseitigung des Fremdkörpers per App angefordert werden.

Aber der gute Bauer schaut eh bei einem Rundgang nach seinen Viechern. Der hat ein Gefühl, wenn was nicht stimmt.

Die Diode soll eine Verpolschutzdiode sein? Dann besser an den Spannungseingang, damit wäre auch der erste Kondensator geschützt.

-->Mein Gedanke an dieser Stelle war eher, dass sich der Motor unter keinen Umständen aus dem analogen Eingang Versorgung holt, und damit das Board beschädigt.

Such dir was aus. Wenn du andere Regler raussuchst, achte auf den Eingangsspannungsbereich.

-->Hab mich mal umgeschaut, diese Teile sind mir bisher gar nicht groß aufgefallen^^ Der Pololu dürfte dieser hier sein... Dann finde ich noch den hier recht interessant... Den Recom gibts auch in billigerer Form (wenn auch ohne genauere Beschreibung oO)

Der hier dürfte auch passen, allerdings hat er doppelte Pins, und auf dem Schaltplan dazu sind noch 2 22uF-Caps an Ein- und Ausgang dran....müsste man noch nachträglich einfügen, oder?

Zudem ich den ungeregelten 7,5V nicht traue. Was machen die 7,5V unter Last?

-->Grade im laufenden System gemessen, direkt am Eingang des Step-Down-Wandlers....der bekommt 13,7V :o

dummes Huhn => Hühnersuppe kluges Huhn => viele Eier

-->So in etwa^^

Aber der gute Bauer schaut eh bei einem Rundgang nach seinen Viechern. Der hat ein Gefühl, wenn was nicht stimmt.

-->Das sowieso, deshalb auch die Indikator LED, welche man vom Haus aus sehen kann. Bauern sind wir übrigens nicht ;)

Da könnte man bei Nichterreichen des Endschalters nach einer Zeit die Klappe wieder automatisch hochfahren, um das Huhn freizugeben und dann nach einer Wartezeit den Schließvorgang wiederholen

-->Bei mir geht die Schaltung dann in den Fehlermodus, da dann nur der Schlitten blockiert sein kann. Mit einem eingeklemmten Huhn hat das nix zu tun, dann würde das Seil, woran die Klappe hängt, einfach nur an Spannung verlieren. Der Schlitten würde trotzdem weiterfahren...

Hallo,

überlege nochmal, wie will man einen Eingang durch “Spannungsdiebstahl” beschädigen. Da würde auch keine Diode helfen. Es muss nur sichergestellt werden das max. Ub am Eingang anliegt. Also max. 5V in deinem Fall. Alles andere ist dem analogen Eingang egal. Setze die Diode vorn an den Schaltungseingang, damit ist alles Verpol geschützt. Wobei die Diode den Motorstrom und etwas mehr aushalten muss. Ist dir überlassen. Wenn du alles richtig anklemmst passiert ohne auch nichts.

Der China Recom ist eine Fälschung. “Eckstein ebay” kannste laut meines Wissens vertrauen. Ich würde auch in deinem Fall den Pololu nehmen, wegen dem nach unten größeren Eingangsspannungsbereich.

Edit: übrigens, so sieht ein original Recom aus
Recom_a.png Recom_b.png Recom_c.jpg

Hallo,

wenn du ganz sicher gehen möchtest, wegen den 38V, dann nimm einen Optokoppler statt Spannungsteiler. Zum Bsp. SFH610 oder ähnliche. Damit bekommste gleichzeitig ein sauberes digitales Signal, low aktiv. R1 1W. Den Rest bekommste sicherlich selbst hin.

Optokoppler.png

Danke für Eure Tipps..... mit den Optokopplern behalt ich mal im Hinterkopf. Das Projekt läuft momentan zuverlässig, wie es soll... Noch warte ich auf den Wandler, dann passe ich die Schaltung nochmal richtig an. Also nochmals Danke für Eure Hinweise, das vermindert meine Sorgen um die Steuerung enorm (y)

So ich muss doch nochmal zurückmelden... und zwar ist heute die Steuerung ausgefallen, und der Motor lief, obwohl er mechanisch blockiert war. Den Motor habe ich wieder gängig gemacht (Kontakt zur Kohlebürste hatte sich "losgelötet"), jetzt bleibt mir die Frage, wie es dazu kommen konnte. :'( Der Arduino lief, die Anzeige-LED hat nicht geleuchtet... Also kann die Steuerung nur in den Fehlermodus gegangen sein, hat irgendwo eine Flanke im Schalter erkannt, den Schlitten in Bewegung gesetzt, und den Taster nicht erneut registriert. Momentan hab ich die Steuerung auf dem Tisch liegen, und versuche den Fehler irgendwie zu reproduzieren...ohne Erfolg. Egal ob ich Kontaktprobleme am Taster annehme, oder einen Taster, der klemmt. Kann die Kabellänge zu den Tastern eine Rolle spielen? Die Leitung ist ca. 1m lang und führt am Motor vorbei. Außerdem habe ich habe die Spannung am analogen Eingang beim Schaltvorgang gemessen (Multimeter, Maximalwerterfassung)-->maximal 3,8V... also kann dort auch nix passieren. Falls es hilft: ich habe den Fehler schonmal gehabt, bei der vorherigen Version... da hatte ich das ungeregelte Netzteil direkt an Vin des Arduino.... und dachte, dass das Board dadurch Schaden genommen hat. Den Nano aus dieser Schaltung kann ich zwar noch programmieren, allerdings sind die Pins 11 und 12 hinüber (wo damals die Taster dran waren)... ein Pin wird dabei stets als LOW, der andere stets als High registriert. -->Wie können diese Pins an normalen Tastern Schaden nehmen, und kann dies die Ursache für den erneuten Ausfall sein? Die aktuelle Schaltung macht auf dem Versuchsstand wieder, was sie soll....

1m am Moror vorbei klingt nach großem Problem.

Evtl solltest Du auf eine Stromsteuerung übergehen, so dass im Steuerstromkreis immer ca. 20 mA fließen müssen, damit High erkannt wird. Also etwa (ohne INPUT_PULLUP) 5V - Schalter - Pin - 150 Ohm - GND

Da muss sich die Störung schon anstrengen, auf HIGH zu kommen.

Gruß Tommy

Evtl solltest Du auf eine Stromsteuerung übergehen, so dass im Steuerstromkreis immer ca. 20 mA fließen müssen, damit High erkannt wird.
Also etwa (ohne INPUT_PULLUP)
5V - Schalter - Pin - 150 Ohm - GND

Da muss sich die Störung schon anstrengen, auf HIGH zu kommen.

–>Danke für Deine Antwort. Hardwaretechnisch also nur den Widerstand zwischen GND und dem Pin löten? Und dies beschädigt den Pin nicht auf Dauer?
Kann ich sonst noch was Sinnvolles tun, um die Störung zu unterdrücken?

Habe auch das Programm weiter angepasst, man kann die Position nur noch berichtigen, wenn er vom Setup aus in den Fehlermodus gegangen ist… geht er im normalen Modus in den Fehlermodus, so ist ein Neustart des Controllers zwingend erforderlich… damit ist sichergestellt, dass nur ein Nutzer die Position berichtigen kann, und nicht die Störung:

//Stand: 29.06.2017
//Programm zur Steuerung einer Klappe am Hühnerstall
//geschrieben von Carsten Lehmann (DerLehmi)

#include <Bounce2.h>

//#define DEBUG
#ifdef DEBUG
  #define debugBegin(...) Serial.begin(__VA_ARGS__);while(!Serial)
  #define debugPrint(...) Serial.print(__VA_ARGS__)
  #define debugPrintln(...) Serial.println(__VA_ARGS__)
#else
  #define debugBegin(...)
  #define debugPrint(...)
  #define debugPrintln(...)
#endif

#define ledG 5                                            //Grüne LED
#define ledR 6                                            //Rote LED
#define tasterO 11                                        //Endpositionstaster Oben
#define tasterU 12                                        //Endpositionstaster Unten
#define relaisA 4                                         //Klappe runterfahren
#define relaisB 3                                         //Klappe hochfahren
#define eingang A3                                        //Eingang für Startsignal
bool flanke=false;                                        //wenn Eingang neu erkannt
bool beheben=false;                                       //wenn Taster zum Beheben der Fehlerposition betätigt

Bounce TasterO=Bounce();
Bounce TasterU=Bounce();

byte state=5;                                             //Statusvariable (0=Wartestatus; 1=Betriebsmodus; 2=Blockiermodus; 3=Fehlermodus; 4=Setup-Fehler; 5=Setup)
unsigned long actual_Milliseconds=0;
unsigned long zeitspeicher_notAus=0;
unsigned long zeitspeicher_signal=4294787295;

void setup() {
  debugBegin(9600);
  debugPrintln("Start: Hühnerklappe");
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  pinMode(ledG, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(relaisA, INPUT_PULLUP);                         //verhindert ungewollte Initialisierung auf LOW (HIGH-aktiv)
  pinMode(relaisA, OUTPUT);
  pinMode(relaisB, INPUT_PULLUP);                         //verhindert ungewollte Initialisierung auf LOW (HIGH-aktiv)
  pinMode(relaisB, OUTPUT);

  pinMode(tasterO, INPUT);
  TasterO.attach(tasterO);
  TasterO.interval(15);
  pinMode(tasterU, INPUT);
  TasterU.attach(tasterU);
  TasterU.interval(15);
  pinMode(eingang, INPUT);

  TasterO.update();
  TasterU.update();
  fehlerTest();
  if(state!=4){                                           //Anzeige der Klappenposition
    state=0;                                              //Start ohne Fehler
    if(TasterO.read()){
      digitalWrite(ledR, HIGH);                           //Klappe unten (Rot)
      debugPrintln("Klappe ist unten");
    }else{
      digitalWrite(ledG, HIGH);                           //Klappe oben (Grün)
      debugPrintln("Klappe ist oben");
    }
    emptyCap();
  }
  debugPrintln("Ende des Setups");
}

void loop() {
  actual_Milliseconds=millis();
  TasterO.update();
  TasterU.update();
  if(state==0){                                           //Wartestatus
    stopMotor();
    fehlerTest();
    if(actual_Milliseconds-zeitspeicher_signal>30000){    //im Wartestatus Abfrage aller 30 Sekunden
      if(digitalRead(eingang)){
        state=1;                                          //Betriebsstatus setzen
        debugPrintln("Status --> 1");
        flanke=true;
      }
      zeitspeicher_signal=actual_Milliseconds;
    }
  }else if(state==1){                                     //Betriebsstatus
    if(flanke){                                           //wenn Startvorgang
      if(!TasterO.read()){
        digitalWrite(relaisA, LOW);                       //Klappe runterfahren
        digitalWrite(ledR, HIGH);                         //in Betrieb: LED Gelb
        debugPrintln("Klappe wird heruntergefahren");
      }else{
        digitalWrite(relaisB, LOW);                       //Klappe hochfahren
        digitalWrite(ledG, HIGH);                         //in Betrieb: LED Gelb
        debugPrintln("Klappe wird hochgefahren");
      }
      flanke=false;                                       //Schlitten in Betrieb
      zeitspeicher_notAus=actual_Milliseconds;
    }else{                                                //wenn Motor läuft
      if(!digitalRead(relaisA)){
        if(TasterU.fell()){                               //Zielposition (unten) erreicht
          state=2;
          debugPrintln("Status --> 2 (Unten erreicht)");
          digitalWrite(ledG, LOW);
        }
      }else{
        if(TasterO.fell()){                               //Zielposition (oben) erreicht
          state=2;
          debugPrintln("Status --> 2 (Oben erreicht)");
          digitalWrite(ledR, LOW);
        }
      }
      if((actual_Milliseconds-zeitspeicher_notAus)>6000){ //wenn Schlitten blockiert
        state=3;
        debugPrintln("Status --> 3 (Schlitten blockiert)");
      }
    }
  }else if(state==2){                                     //Blockiermodus (keine Flankenerkennung)
    stopMotor();
    fehlerTest();
    if(actual_Milliseconds-zeitspeicher_signal>80000){    //wenn Blockierzeit vorbei
      emptyCap();
      state=0;
      debugPrintln("Status --> 0");
    }
  }else if(state==3){                                     //Fehlermodus--> Neustart erforderlich
    stopMotor();
    if(digitalRead(ledG))
      digitalWrite(ledG, LOW);
    if((actual_Milliseconds-zeitspeicher_notAus)>200){    //LED blinkt rot
      digitalWrite(ledR, !digitalRead(ledR));
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
      zeitspeicher_notAus=actual_Milliseconds;
    }
  }else if(state==4){                                     //Setup-Fehlermodus
    if(TasterO.fell() || TasterU.fell()){
      beheben=true;
    }
    if(!beheben){
      stopMotor();
      if(digitalRead(ledG))
        digitalWrite(ledG, LOW);
      if((actual_Milliseconds-zeitspeicher_notAus)>500){  //LED blinkt rot
        digitalWrite(ledR, !digitalRead(ledR));
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
        zeitspeicher_notAus=actual_Milliseconds;  
      }
    }else if(TasterO.fell() && digitalRead(relaisB) && digitalRead(relaisA)){     //Zielposition oben anfahren
      digitalWrite(relaisB, LOW);
      digitalWrite(ledR, LOW);
      digitalWrite(LED_BUILTIN, HIGH);
      debugPrintln("Oben wird angefahren");
    }else if(TasterU.fell() && digitalRead(relaisA) && digitalRead(relaisB)){     //Zielposition unten anfahren
      digitalWrite(relaisA, LOW);
      digitalWrite(ledR, LOW);
      digitalWrite(LED_BUILTIN, HIGH);
      debugPrintln("Unten wird angefahren");
    }else if(TasterO.fell() && !digitalRead(relaisB)){    //Zielposition oben erreicht
      stopMotor();
      state=0;
      beheben=false;
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(ledG, HIGH);
      delay(5000);                                        //Wartezeit zum Abklemmen der Versorgung für Motor
      emptyCap();
      debugPrintln("Oben erreicht");
    }else if(TasterU.fell() && !digitalRead(relaisA)){    //Zielposition unten erreicht
      stopMotor();
      state=0;
      beheben=false;
      digitalWrite(LED_BUILTIN, LOW);
      digitalWrite(ledR, HIGH);
      delay(5000);                                        //Wartezeit zum Abklemmen der Versorgung für Motor
      emptyCap();
      debugPrintln("Unten erreicht");
    }
  }
}

void fehlerTest(){
  if(TasterO.read()==TasterU.read()){                     //Test, ob Schlitten eindeutige Lage hat
    if(state==5){
      state=4;                                            //Setup-Fehlermodus
      debugPrintln("Status --> 4 (Fehler gefunden)");
    }else{
      state=3;                                            //Fehlermodus
      debugPrintln("Status --> 3 (Fehler gefunden)");
    }
    zeitspeicher_notAus=actual_Milliseconds;
  }
}

-->Leider funktioniert das so nicht... Das System reagiert zu träge, der Motor schaltet zu spät ab und der Schlitten fährt deshalb über den Taster hinaus.... wie kann man das beheben? Was ich gemacht habe: -alle GND zusammen und auf einen Pin gelegt -Relais anders verschaltet, Motor ist im Ruhezustand auf Minus/ im Programm die Relais vertauscht -Taster wie empfohlen verdrahtet (5V zu Taster, Taster zu Pin, zwischen Pin und GND 150 Ohm Widerstand)/ im Programm für die Taster statt INPUT_PULLUP--> INPUT