Probleme mit Zeitverarbeitung

Hallo zusammen,

ich bin Anfänger mit einem Arduino Uno R3 und würde einmal ein paar Ratschläge benötigen.

Folgendes habe ich vor:
Ich möchte eine Torsteuerung für einen Mähroboter bauen.
Bisherige Umsetzung (derzeit noch über einfache Relaisschaltung):
Am Roboter befindet sich ein Endlagenschalter (NC/NO), der jeweils ein Signal an die dazu in Reihe geschalteten Endlagentaster (beide NC) für Tor auf / Tor zu gibt - am Arduino würde also jeweils ein Signal für "Roboter startet, Tor nicht offen" bzw. "Roboter an Ladestation, Tor nicht geschlossen" ankommen. Sobald einer der beiden Input-Pins bestromt wird, gibt der Arduino wie gewünscht ein Signal auf den jeweiligen Output-Pin für "Tor schließen" bzw. "Tor öffnen" solange, bis der jeweilige Endlagentaster das Signal unterbricht, das habe ich mit if-Anweisungen soweit hinbekommen.
Was mir fehlt ist eine Sicherheitsabschaltung, die den Motor nach einigen Sekunden abschaltet falls z.B. das Tor mal klemmt und der Endlagentaster nicht erreicht wird.
Ich habe versucht mit millis zu arbeiten - allerdings bewirkt die von mir erstellte Anweisung rein garnichts.
Die LED, die den Motor simuliert, wird nicht wie erwartet nach einer Sekunde wieder abgeschaltet wenn das Eingangs-Signal bestehen bleibt.
Mir scheint ich habe da einen grundsätzlichen Denkfehler eingebaut.
Kann mir jemand sagen, wo mein Denkfehler liegt?

Programmcode (hier nur für ersten Schalter, der zweite würde ja -mit Ausnahme der Pinbelegung- genauso aussehen)

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long during = 1000;

void setup()
{
  
  // einmalige Ausfuehrung beim Start (Pinkonfig)
  
  pinMode (2, INPUT); // Input Roboter in, Tor auf
  
  pinMode (5, INPUT); // Input Roboter out, Tor zu
  
  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen
  
  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
  }

void loop() {
    {
     if
      (digitalRead(2)==HIGH) //Signal Roboter startet, Tor zu
      { 
       startMillis = millis();
       digitalWrite(8,HIGH); //Tor oeffnen
       {currentMillis = millis();
       if
       (currentMillis - startMillis >= during)  //Zeitmessung fuer Sicherheitsabschaltung
        {digitalWrite(8,LOW); //Sicherheitsabschaltung
        }
       }
      }
    else
      {
      digitalWrite(8, LOW);
      }
      startMillis = currentMillis;
      }

drück mal STRG-T in deiner IDE und schmeiss mal alle unnötigen Klammern raus vieleicht erkennst du es dann leichter.

Serial-Ausgaben zeigen dir, was dein Code wirklich macht.

StefanK75:
ich bin Anfänger mit einem Arduino Uno R3 und würde einmal ein paar Ratschläge benötigen.
...

Der Tipp von noiasca ist schon echt gut.

Gewöhne Dir grundsätzlich an, „schönen Code“ zu schreiben. Bei der Fehlersuche ist das Gold wert. Evtl. ist bei meinem Geschreibsel auch anderes interessant.

Gruß

Gregor

startMillis = millis();
digitalWrite(8, HIGH); //Tor oeffnen
{ currentMillis = millis();
if
(currentMillis - startMillis >= during) //Zeitmessung fuer Sicherheitsabschaltung
{ digitalWrite(8, LOW); //Sicherheitsabschaltung
}

startMillis und currentMillis sind bei dir immer nahezu gleich
versuch es mal so

uint32_t long startMillis, currentMillis;
const unsigned long during = 1000;

void setup()
{
  // einmalige Ausfuehrung beim Start (Pinkonfig)
  pinMode (2, INPUT); // Input Roboter in, Tor auf
  pinMode (5, INPUT); // Input Roboter out, Tor zu
  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen
  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
}

void loop()
{
  if
  (digitalRead(2) == HIGH) //Signal Roboter startet, Tor zu
  {
    currentMillis = millis();
      if
      (currentMillis - startMillis >= during)  //Zeitmessung fuer Sicherheitsabschaltung
      { digitalWrite(8, LOW); //Sicherheitsabschaltung
         startMillis = millis();
      }
  }
  else
    digitalWrite(8, LOW);
}

Solltes eher beim Überschreiten einer bestimmten Leistungsaufnahme schalten als wie nach "einer Zeit".

Erst einmal vielen Dank für Eure Ratschläge.
Den Fehler habe ich bisher allerdings noch nicht gefunden.
Die serielle Ausgabe geht bei mir im Moment auch noch nicht - da werde ich mich jetzt wohl als erstes drum kümmern, damit ich eine Idee bekomme was der Arduino da eigentlich treibt.

Natürlich habt Ihr völlig Recht dass sauberes Arbeiten die Fehlersuche erleichtert.
Nun ich bin als Optimist davon ausgegangen dass es zumindest ansatzweise funktioniert und ich mich danach um "schöner Wohnen" kümmern kann. :wink:

Zum Thema Leistungsaufnahme:
Das ist ein guter Hinweis, habe ich aber schon über eine Sicherung und zusätzlich eine Rutschkupplung umgesetzt.
Diese Art der Abschaltung würde auch zumindest bei "Tor zu" zu spät greifen.
Das Tor schließt durch sein Eigengewicht - der Motor funktioniert hier eigentlich nur als "Bremse", muss aber bestromt werden, da er selbshemmend ausgeführt ist.
Wenn er weiterläuft würde er einfach den Seilzug abwickeln.

StefanK75:
Die serielle Ausgabe geht bei mir im Moment auch noch nicht - da werde ich mich jetzt wohl als erstes drum kümmern, damit ich eine Idee bekomme was der Arduino da eigentlich treibt.

das ist essential dass du das hinbekommst. Es gibt fast keine Debug-Möglichkeiten außer Serial Ausgaben am Arduino Uno.
Funktionieren die Beispiele aus der IDE? Wenn nein, was passiert genau, dass es bei dir nicht klappt?
"geht bei mir nicht" ist KEINE Fehlerbeschreibung!

StefanK75:
Natürlich habt Ihr völlig Recht dass sauberes Arbeiten die Fehlersuche erleichtert.
Nun ich bin als Optimist davon ausgegangen dass es zumindest ansatzweise funktioniert und ich mich danach um "schöner Wohnen" kümmern kann. :wink:

Der Punkt ist, dass mit „schönerem Code“ der Durchblick zunimmt. Das mit dem „schöner Wohnen“ bekommst Du gratis dazu :slight_smile:

Is vielleicht blöd, aber isso.

Gruß

Gregor

Vl. Hilft dir das weiter.. Habe deine Möglichkeiten an Endschaltern nicht ganz durchschaut, deshalb muss du die Kommentare ersetzten!

unsigned long startOpeningDoor;
unsigned long currentMillis;
const unsigned long during = 1000;

void setup()
{
  
  // einmalige Ausfuehrung beim Start (Pinkonfig)
  
  pinMode (2, INPUT); // Input Roboter in, Tor auf
  
  pinMode (5, INPUT); // Input Roboter out, Tor zu
  
  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen
  
  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
  }

void loop() {
    

if(/*roboter startet*/ && /*Tor zu*/ )
{
  startOpeningDoor=millis();
     Do
     {
 digitalWrite(8,HIGH); //tor öffnen starten
     }while((millis()-startOpeningDoor<during)  || /*Tor geöffnet*/ ); //solange bis during überschritten oder Tor geöffnet ist

   digitalWrite(8,LOW);//Tor öffnen beenden
}
}

Das könnte klappen!
Vielen Dank....ich glaube das war der Schubs in die richtige Richtung!
Teste ich morgen abend...heute wird's nix mehr.

Einen schönen Rest-Dienstag an alle!

Reiter:
Vl. Hilft dir das weiter.. Habe deine Möglichkeiten an Endschaltern nicht ganz durchschaut, deshalb muss du die Kommentare ersetzten!

unsigned long startOpeningDoor;

unsigned long currentMillis;
const unsigned long during = 1000;

void setup()
{
 
  // einmalige Ausfuehrung beim Start (Pinkonfig)
 
  pinMode (2, INPUT); // Input Roboter in, Tor auf
 
  pinMode (5, INPUT); // Input Roboter out, Tor zu
 
  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen
 
  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
  }

void loop() {

if(/roboter startet/ && /Tor zu/ )
{
  startOpeningDoor=millis();
    Do
    {
digitalWrite(8,HIGH); //tor öffnen starten
    }while((millis()-startOpeningDoor<during)  || /Tor geöffnet/ ); //solange bis during überschritten oder Tor geöffnet ist

digitalWrite(8,LOW);//Tor öffnen beenden
}
}

Ich habe es jetzt mal mal mit do / while versucht.
Ich glaube der Weg ist grundsätzlich richtig.
Im Moment führt die Funktion dazu dass der Motor (bzw. die Simulations-Diode) bei HIGH-Signal eine Sekunde an bleibt.
Der Plan war dass sie bei längerem HIGH-Signal als vorgegeben (during) ausgeht, auch wenn das HIGH-Signal weiterhin bestehen bleibt.
Ich habe die Funktion do/while wohl noch nicht vollständig verstanden.
....da werde ich wohl noch ein bißchen suchen und probieren müssen.
Aufgabe für morgen :wink:

Euch allen einen schönen Abend!

Im Moment sieht der Code so aus:

unsigned long startOpeningDoor;
unsigned long currentMillis;
const unsigned long during = 1000;

void setup()
{

  // einmalige Ausfuehrung beim Start (Pinkonfig)

  pinMode (2, INPUT); // Input Roboter in, Tor auf

  pinMode (5, INPUT); // Input Roboter out, Tor zu

  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen

  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
}

void loop() {


  if (digitalRead(2) == HIGH)
  {
    startOpeningDoor = millis();
    do
    { digitalWrite(8, HIGH); //tor öffnen starten
    } while (millis() - startOpeningDoor < during) ; //solange bis during überschritten oder Tor geöffnet ist
    digitalWrite(8, LOW); //Tor öffnen beenden
  }
  else 
  {digitalWrite(8, LOW);
  }
}

ich hab mir gedacht ich nutze deine Leerzeilen für ein paar Debug-Ausgaben und ein paar Konstanten um die Magic-Numbers zu ersetzen

unsigned long startOpeningDoor;
unsigned long currentMillis;
const unsigned long during = 1000;
const int pinInputIn = 2;     // Input Roboter in, Tor auf
const int pinInputOut = 5;    // Input Roboter out, Tor zu
const int pinOutputIn = 8;    // Output Roboter in, Tor schliessen
const int pinOutputOut = 11;  // Output Roboter out, Tor öffnen

void setup()
{
  Serial.begin(115200);
  // einmalige Ausfuehrung beim Start (Pinkonfig)
  pinMode (pinInputIn, INPUT); 
  pinMode (pinInputOut, INPUT); 
  pinMode (pinOutputIn, OUTPUT); 
  pinMode (pinOutputOut, OUTPUT); 
  Serial.println(F("Setup abgeschlossen")); // irgendwas damit du siehst dass deine Serial-Ausgabe funktioniert
}

void loop() 
{
  if (digitalRead(pinInputIn) == HIGH)
  {
    Serial.println(F("D25 pinInputIn == HIGH"));
    startOpeningDoor = millis();
    Serial.println(F("D27 pinOutputIn -> HIGH"));
    do
    { 
      digitalWrite(pinOutputIn, HIGH); //tor öffnen starten
    } 
    while (millis() - startOpeningDoor < during); //solange bis during überschritten oder Tor geöffnet ist
    Serial.print(F("D33 pinOutputIn -> LOW"));
    digitalWrite(pinOutputIn, LOW); //Tor öffnen beenden
    Serial.println();
  }
  else
  { 
    if (digitalRead(pinOutputIn)) Serial.print(F("D39 pinOutputIn -> LOW")); // nur beim ersten mal wenn das else zutrifft Debug Ausgabe ausgeben
    digitalWrite(pinOutputIn, LOW);
  }
}

inhaltlich macht es noch nichts anderes als dein Sketch, aber vieleicht siehst du nun was dein Programm eigentlich macht. Vieleicht hilft es auch wenn du deine Schalter mit entsprechenden Pullups/Pulldowns versiehst

Ich habe es jetzt doch noch mal mit if / if&& probiert.
Diesmal mit Ausgabe und ich denke ich habe den Fehler gefunden, weiß allerdings noch nicht wie ich ihn beheben kann. Dazu barauch ich wohl nochmal Eure Hilfe.

Kurze Erklärung (jedenfalls nach meinem Verständnis):
Die Differenz zwischen millis und startMillis ist immer 0.
Das heißt die Abbruchbedingung wird nie erreicht, weil startMillis sozusagen fortgeschrieben wird.

Jetzt kommt die Frage:

Hat jemand eine Idee, wie ich beim drücken des Tasters (also Pin2 HIGH) millis auslesen und solange quasi als temporäre konstante speichern kann, bis der Schalter wieder geöffnet wird?

Hier nochmal der Code, mit dem ich es zum Schluss probiert habe:

unsigned long startMillis;
const unsigned long during = 10000;

void setup()
{
  Serial.begin(9600);
  // einmalige Ausfuehrung beim Start (Pinkonfig)

  pinMode (2, INPUT); // Input Roboter in, Tor auf

  pinMode (5, INPUT); // Input Roboter out, Tor zu

  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen

  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
}
void loop() {
  //startMillis = currentMillis;
  if
  (digitalRead(2) == HIGH) //Signal Roboter startet, Tor zu
  {
    startMillis = millis();
    if ((digitalRead(2) == HIGH) && (millis() - startMillis < during)); //Zeitmessung fuer Sicherheitsabschaltung
    { digitalWrite(8, HIGH); //Sicherheitsabschaltung
      Serial.print (millis() - startMillis);
      delay(1000);
    }
  }
  else
  { digitalWrite(8, LOW);
  }
}

Verschiebe mal das

startMillis = millis();

in den else-Zweig.

Gruß Tommy

Hallo zusammen und sorry dass ich mich einige Zeit nicht gemeldet hab, ich bin die letzten Tage einfach nicht dazu gekommen ein bisschen rum zu probieren.

@Tommy56 startMillis in den Else-Zweig zu verschieben funktiniert tatsächlich.
Die Serielle Ausgabe spuckt jetzt tatsächlich die Zeitdifferenz aus, solange der Schalter gedrückt ist.
Vielen Dank für den Hinweis.
Irgendwo habe ich allerdings noch einen Fehler eingebaut - die LED bleibt nach wie vor an, solange der Schalter gedrückt ist. Vielleicht hat ja noch jemand eine Idee?

unsigned long startMillis;
const unsigned long during = 6000;

void setup()
{
  Serial.begin(9600);
  // einmalige Ausfuehrung beim Start (Pinkonfig)

  pinMode (2, INPUT); // Input Roboter in, Tor auf

  pinMode (5, INPUT); // Input Roboter out, Tor zu

  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen

  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
}
void loop() {
  //startMillis = currentMillis;
  if
  (digitalRead(2) == HIGH) //Signal Roboter startet, Tor zu
  {
    if ((digitalRead(2) == HIGH) && ((millis() - startMillis) < during)); //Zeitmessung fuer Sicherheitsabschaltung
    { digitalWrite(8, HIGH); //Sicherheitsabschaltung
      Serial.print (millis() - startMillis);
      delay(1000);
    }
  }
  else
  { startMillis = millis();
    digitalWrite(8, LOW);
  }
}

.

Überleg mal ob du das delay überhaupt brauchst, zum Debuggen ok, aber der gesamte Ablauf ist dadurch auch jeweils für eine Sekunde blockiert, d.h. die LED leuchtet minimum 1 Sekunde. Drückst du den Taster länger als eine Sekunde?

Das Delay ist nur zum Debuggen.
Das fliegt raus sobald der Sketch läuft.

Den Taster drücke ich länger als 6 Sekunden - das Ziel ist ja dass die LED nach 6 Sekunden von alleine ausgeht, auch wenn der Tater gedrückt bleibt.

    if ((digitalRead(2) == HIGH) && ((millis() - startMillis) < during)); //Zeitmessung fuer Sicherheitsabschaltung
    { digitalWrite(8, HIGH); //Sicherheitsabschaltung
      Serial.print (millis() - startMillis);
      delay(1000);
    }

Logisch, hier schaltest du die LED ein, aber nicht wieder aus während der Taster noch gedrückt ist. Die LED geht erst wieder aus, sobald du den Taster los lässt. Hier fehlt noch ein else.

Stimmt, aber bei "IF && ..." meldet der Sketch "else without an if"

unsigned long startMillis;
const unsigned long during = 6000;

void setup()
{
  Serial.begin(9600);
  pinMode (2, INPUT); // Input Roboter in, Tor auf
  pinMode (5, INPUT); // Input Roboter out, Tor zu
  pinMode (8, OUTPUT); // Output Roboter in, Tor schliessen
  pinMode (11, OUTPUT); // Output Roboter out, Tor öffnen
}
void loop()
{
  if ((digitalRead(2) == HIGH) && ((millis() - startMillis) < during)); //Signal Roboter startet, Tor zu
  { digitalWrite(8, HIGH);                                            //zeitbegrenztes Einschalten
    Serial.print (millis() - startMillis);
    delay(1000);
  }
  else
  { digitalWrite(8, LOW);
    startMillis = millis();
  }
}

Ja, weil du einen Fehler eingebaut hast:

if ((digitalRead(2) == HIGH) && ((millis() - startMillis) < during));

Mach das ; weg, dann sollte es laufen, zumindest bis zum nächsten möglichen Fehler. :wink: