Aufzugsteuerung Modell

Hallo,
unzwar bin ich gerade dabei einen kleinen Aufzug mit einem Arduino Mega zu steuern und hänge schon seid Stunden an einem Problem, was ich nicht lösen kann, weshalb ich eure hilfe benötige.
Problem :
Ich möchte gerne für die Türen zwei Servomotoren nutzen und die so steuern, dass die Türen ersteinmal aufgehen und entweder nach einem ablauf einer Zeit von 5s automatisch wieder zu gehen oder in der Zeit mit einem Taster geschlossen werden können?.
Vielleicht gibt es eine Möglichkeit mit einem interrupt??? Würde mich freuen wenn mir jemand da weiter helfen kann.
Danke schonmal im Vorraus.:grinning:

Kein Interrupt.
Zeitintervalle mit millis() realiesieren und nicht mit delay().
Nachtwächtererklährung: BlinkwithoutDelay - Die Nachtwächtererklärung

Danke, aber wie kann ich wissen wie lange er bis zu dem Zeitpunkt braucht, da zuvor im Programmcode ersteinmal ein Ablauf passiert?. Und in dem Programmcode von dem Nachtwächter erklährung passiert das direkt und da weiß ich das millis()-...>5000 diese 5s sind aber wie bilde ich diese Zeitabschnitte ? Damit er genau 5 sec wartet und dann die Türen öffnet ?
Zur Verfügung habe ich zwei Methoden:
open_doors();
close_doors();
Und den button
bt_close;

Dann nochmal ein Ablauf (Automat, finite state machine) für die Türen. Als Zustände (enum) Closed, Opening, Open, Closing oder auch was auf Deutsch. Wenn Closed der Normalzustand ist dann warten auf ein Signal zum Öffnen aus der Aufzugsteuerung. Dann die Tür öffnen und in Opening warten bis die Tür offen ist. Dann Zeit merken und in Open warten bis entweder die Zeit abgelaufen ist oder der Schließen Knopf gedrückt wird. Dann die Tür schließen und in Closing warten bis die Tür geschlossen ist und weiter in Closed oder wenn der Sicherheitsschalter anspricht (etwas eingeklemmt) die Tür wieder öffnen und weiter In Opening.

Die Aufzugsteuerung liefert dafür ein Signal zum Öffnen der Tür und darf den Aufzug nur bewegen wenn die Tür gschlossen (Closed) ist.

Ja, gibt es!
millis() wird alle ca 1ms von einem Timer Interrupt weiter gesetzt.
Dieses kannst du nutzen.

In dem du dir Zeitpunkte merkst und dann von der Jetztzeit subtrahierst. So weißt du jederzeit, wieviel Zeit seit dem letzten Merken vergangen ist.

Siehe dazu das BlinkWithoutDelay Beispiel.

Beim Tür öffnen die Zeit merken und dann wenn die Tür offen ist, entweder auf Zeitablauf oder den Zu-Taster abfragen.

Einfache Statemachine mit "Blink without Delay" Anteilen

//https://forum.arduino.cc/t/aufzugsteuerung-modell/1006327
//code duplicated - deleteable

#include <Servo.h>
Servo myservo;

constexpr byte openPin = 4;    //  open door
constexpr byte closePin = 3;   // force close
constexpr byte servoPin = 8;   // GPIO des Servos

enum class State {DOOR_CLOSED, DOOR_OPENED} state = State::DOOR_CLOSED;

uint32_t previousMillis = 0; // time management
constexpr uint16_t intervalDoorOpen = 5000; // wie lange soll die Tür offen bleiben


void setup() {
  Serial.begin(115200);
  myservo.attach(servoPin);
  pinMode(openPin, INPUT_PULLUP);
  pinMode(closePin, INPUT_PULLUP);
  doorClose();
}

void doorOpen()
{
  myservo.write(90);
  state = State::DOOR_OPENED;
}

void doorClose()
{
  myservo.write(0);
  state = State::DOOR_CLOSED;
}

void showRestInterval()
{
  static uint32_t previousMillisShow = 0;
  if (millis() - previousMillisShow > 1000)
  {
    previousMillisShow = millis();
    Serial.print(F("remaining interval in sec:"));
    Serial.println((intervalDoorOpen - (millis() - previousMillis)) / 1000);
  }
}

void loop() {

  switch (state)
  {
    case State::DOOR_CLOSED :

      if (digitalRead(openPin) == LOW)
      {
        previousMillis = millis();
        Serial.println(F("Tür auf"));
        doorOpen();
      }
      break;
    case State::DOOR_OPENED :
      if (digitalRead(closePin) == LOW)
      {
        Serial.println(F("Tür zu forced"));
        doorClose();
      }
      if (millis() - previousMillis > intervalDoorOpen)
      {
        Serial.println(F("Tür zu timeout"));
        doorClose();
      }
      showRestInterval();
      break;
  }
}

Vielen Dank hat mir sehr weitergeholfen :+1:

Ich habe mir den Code angeschaut, doch verstehe nicht ganz wie ich den Code auf meinen Code ändern muss, denn in meinem Programm gibt es keinen Taster zum öffnen , nur zum schließen der Türen und nachdem die Kabine ein Stockwerk erreicht hat öffnen sich die Türen automatisch ohne Betätigung eines Tasters und können dann durch bt_close geschlossen werden oder nach 5s, deshalb verstehe ich das nicht ganz wie ich dies anpassen muss, denn nach dem Türablauf soll die Methode get_pos_and_act_to_goal() aufgerufen werden, dass ist sozusagen der sich immer wiederholende Grundschritt ?
würde mich sehr freuen wenn sie mir hier auch nochmal weiterhelfen könnten, da ich noch relativ frisch in der Programmierung von Arduinos bin ?

Programmcodeauschnitt:

#include <Servo.h>
//Deklarationen
//Taster
const int btn_S1 = 51    ;// Aufruftaster Stockwerk 1
const int btn_S2 = 46    ;   // Aufruftaster Stockwerk 2
const int btn_S3 = 45     ;   // Aufruftaster Stockwerk 3
const int btn_stop = 18   ;   // NOT-halt taster an Pin 18 angeschlossen wo die Interrupt service Routine ausgeführt werden kann
const int btn_close = 19 ;  // Türen schließen taster 
const int b_1 = 28         ;   // Magnetendlagensensor(mitte) Stockwerk  1
const int b_2 = 26        ;   // Magnetendlagensensor (mitte) Stockwerk 2
const int b_3 = 24       ;   // Magnetendlagensensor(mitte) Stockwerk  3
// Zustand der Aufruf,-Endlagentaster
int ZS_btn_S1;
int ZS_btn_S2;
int ZS_btn_S3;
int ZS_btn_stop;
int ZS_btn_close;
int ZS_btn_open;
int ZS_b_1, ZS_b_2, ZS_b_3;
//ansteuerung 7-Segment Anzeige
int PinP = 9, PinA = 2, PinB = 3, PinC = 4, PinD = 5, PinE = 6, PinF = 7, PinG = 8 ;
// ansteuerung von Pfeil-LEDs
int LED_UP = 30;
int LED_DOWN = 31;
//Motor Kontrolle mit IC-kontrollchip
int dir1 = 12      ;   // direction 1 => Richtung 1 (Motor) -linkslauf, auf arduino
int dir2 = 11         ;   // direction 2 => Richtung 2 (Motor) -rechtslauf, auf arduino
// Servo Motor linke Tür
int servoPin1 = 36    ;    // Pin an dem der Servomotor 1 angeschlossen wird, auf arduino
int servo_ap1 = 180  ; // Position des Servomotors 1 in Arbeitspos
int servo_gp1 = 0;  // Position des Servomotors 1 in Grundpos
Servo servo1     ;    // Name des Servomotors 1 an der linken Türe
// Servo Motor rechte Tür
int servoPin2 = 38  ;    // Pin an dem der Servomotor 2 angeschlossen wird, auf arduino
int servo_ap2 = 0  ; // Position des Servomotors 2 in Arbeitsposition
int servo_gp2 = 180;     // Position des SM 2 in Grundposition
Servo servo2     ;    // Name des Servomotors 2 an der rechten Türe

void setup() {
  pinMode(btn_S1, INPUT); // Taster/Sensoren als Eingänge deklarieren
  pinMode(btn_S2, INPUT);
  pinMode(btn_S3, INPUT);
  pinMode(btn_stop, INPUT);
  pinMode(btn_close, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(btn_stop), isrNotHalt, LOW); // wenn Not-Halt (Öffner) Pegel von high nach low fällt ,
  pinMode(b_1, INPUT);                                       //wird die isr ununterbrochen ausgeführt bis der Not-Halt wieder entrastet ist.
  pinMode(b_2, INPUT);
  pinMode(b_3, INPUT);
  pinMode(dir1, OUTPUT);
  pinMode(dir2, OUTPUT);
  pinMode(PinP, OUTPUT);
  pinMode(PinA, OUTPUT);
  pinMode(PinB, OUTPUT);
  pinMode(PinC, OUTPUT);
  pinMode(PinD, OUTPUT);
  pinMode(PinE, OUTPUT);
  pinMode(PinF, OUTPUT);
  pinMode(PinG, OUTPUT);
  pinMode(LED_UP, OUTPUT);
  pinMode(LED_DOWN, OUTPUT);



  servo1.attach(servoPin1);
  servo2.attach(servoPin2);
  Serial.begin(9600);       // fürs debugging
  
}

void loop() {
  get_pos_and_act_to_goal();
}

//Unterprogramme
void isrNotHalt()  // Interrupt Service Routine die sofort an jeder Stelle im Programm ausgeführt wird, wenn der Not-Halt(Öffner) betätigt wird
{ // sie wird solange ausgeführt bis der Not-Halt wieder eingerastet ist
  motor_stopp();
}


void get_pos_and_act_to_goal()
{
  ZS_btn_S1 = digitalRead(btn_S1);    // Zustände der Buttons/Endlagentaster einlesen
  ZS_btn_S2 = digitalRead(btn_S2);
  ZS_btn_S3 = digitalRead(btn_S3);
  ZS_btn_stop = digitalRead(btn_stop);
  ZS_b_1 = digitalRead(b_1);
  ZS_b_2 = digitalRead(b_2);
  ZS_b_3 = digitalRead(b_3);
  Serial.println("Positionsbestimmung und Zielauswahl");


  if (ZS_b_1 && ZS_btn_S2 && ZS_btn_stop == HIGH)
  {
    act_from_SW1_to_SW2();
  }
  if (ZS_b_1 && ZS_btn_S3 && ZS_btn_stop == HIGH)
  {
    act_from_SW1_to_SW3();
  }
  if (ZS_b_2 && ZS_btn_S1 && ZS_btn_stop == HIGH)
  {
    act_from_SW2_to_SW1();
  }
  if ( ZS_b_2 && ZS_btn_S3 && ZS_btn_stop == HIGH)
  {
    act_from_SW2_to_SW3();
  }
  if (ZS_b_3 && ZS_btn_S2 && ZS_btn_stop == HIGH)
  {
    act_from_SW3_to_SW2();
  }
  if (ZS_b_3 && ZS_btn_S1 && ZS_btn_stop == HIGH)
  {
    act_from_SW3_to_SW1();
  }
}


void servo_1_act_to_gp()      // act to Grundposition vom servo 1 (linke Tür)
{
  servo1.write(servo_gp1); // Servo 1 wird angesteuert in Richtung Grundposition
  delay(250);
  servo1.write(90); // Servo 1 stoppen 
  delay(25);
}

void servo_1_act_to_ap()   // act to Arbeitsposition vom  Servo 1 (linke Tür)
{
  servo1.write(servo_ap1); // Servo 1 bewegt sich zur Arbeitsposition
  delay(250);
  servo1.write(90); // Servo 1 stoppen
  delay(25);
}

void servo_2_act_to_gp()      // act to Grundposition vom servo 2 (rechte Tür)
{
  servo2.write(servo_gp2); // Servo 2 bewegt sich zur Grundposition
  delay(250);
  servo2.write(90); // Servo 2 stoppen
  delay(25);

}

void servo_2_act_to_ap()      // act to Arbeitsposition vom servo 2 (rechte Tür)
{
  servo2.write(servo_ap2); // Servo 2 bewegt sich zur Arbeitsposition
  delay(230);
  servo2.write(90); // Servo 2 stoppen
  delay(25);
}

void close_doors()
{
  servo_1_act_to_gp();
  servo_2_act_to_gp();
  Serial.println("TÜREN ZU");
}

void open_doors()
{
  servo_1_act_to_ap();
  servo_2_act_to_ap();
  Serial.println("TÜREN AUF");
}

void motor_rechtslauf()
{
  digitalWrite(dir2, LOW);     // Rechtslauf(HIGH), Kabine bewegt sich hoch
  digitalWrite(dir1, HIGH);      // Linkslauf(LOW)
  Serial.println("MOTOR RECHTSLAUF !");
}

void motor_linkslauf()
{
  digitalWrite(dir2, HIGH);       // Rechtslauf(LOW)
  digitalWrite(dir1, LOW);      // Linkslauf(HIGH), Kabine bewegt sich runter
  Serial.println("MOTOR LINKSLAUF !");
}

void motor_stopp()
{
  digitalWrite(dir2, HIGH);       // Rechtslauf(LOW)
  digitalWrite(dir1, HIGH);      // Linkslauf(LOW), Kabine bleibt stehen
  Serial.println("MOTOR STOPP !");
}


void segment_SW1()
{
  digitalWrite(PinA , LOW); // ergebnis der aktiven pins ist eine "1."
  digitalWrite(PinB , HIGH);
  digitalWrite(PinC , HIGH);
  digitalWrite(PinD , LOW);
  digitalWrite(PinE , LOW);
  digitalWrite(PinF , LOW);
  digitalWrite(PinG , LOW);
  digitalWrite(PinP , HIGH);
  delay(2000);                  // 2.Sekunde warten, dann in den Türablauf gehen
  doors_ablauf();
}

void segment_SW2()
{
  digitalWrite(PinA , HIGH);
  digitalWrite(PinB , HIGH);   // ergebnis der aktiven pins ist eine "2."
  digitalWrite(PinC , LOW);
  digitalWrite(PinD , HIGH);
  digitalWrite(PinE , HIGH);
  digitalWrite(PinF , LOW);
  digitalWrite(PinG , HIGH);
  digitalWrite(PinP , HIGH);
  delay(2000);                  // 2.Sekunde warten, dann in den Türablauf gehen
  doors_ablauf();
}
void segment_SW3()
{
  digitalWrite(PinA , HIGH); // ergebnis der aktiven pins ist eine "3."
  digitalWrite(PinB , HIGH);
  digitalWrite(PinC , HIGH);
  digitalWrite(PinD , HIGH);
  digitalWrite(PinE , LOW);
  digitalWrite(PinF , LOW);
  digitalWrite(PinG , HIGH);
  digitalWrite(PinP , HIGH);
  delay(2000);                  // 2.Sekunde warten, dann in den Türablauf gehen
  doors_ablauf();
}

void segment_aus()
{
  digitalWrite(PinA , LOW); // alle Pins LOW , 7-Segment Anzeige ist aus
  digitalWrite(PinB , LOW);
  digitalWrite(PinC , LOW);
  digitalWrite(PinD , LOW);
  digitalWrite(PinE , LOW);
  digitalWrite(PinF , LOW);
  digitalWrite(PinG , LOW);
  digitalWrite(PinP , LOW);
}

void doors_ablauf()
{

  **//Hier müsste der Code hin in dem die Türen direkt ohne Taster betätigung aufgehen und anschließend nach 5sec oder nach betätigung von bt_close**
**geschlossen werden und danach wieder in die Methode get_pos_and_act_to_goal() geht.**  

}

Man kann dort beliebig viele hintereinander hineinschreiben oder als Unterprogramme aufrufen.

du hast aktuell überwiegend die Ablauflogik im

get_pos_and_act_to_goal

also würde es Sinn machen, auch hier auf den Status abzufragen und gegebenenfalls im State::DOOR_OPENED eben die Tür wieder zuzuzumachen.

Ein Aufzug darf Türen nur im stielstand öffnen, nach der Aufzugsverordnung sogar nur bis 20cm vor und nach Bündig, Ok ist bei dir nur Spielzeug Aufzug :wink:
sind es 2Türen? Wen nein reicht einer, und muss nicht Servo sein, reicht normaler Gleichstrommotor (Bürstenmotor), oder Spindelantrieb vom CD / DVD Laufwerk.
Zeige mal dein Sketch.

habs mal so probiert und nach betätigung des Tasters bt_close funktioniert schonmal aber irgendwie der Timer von 5s nicht mehr, obwohl ich als Bedingung sage, dass er wenn die Zeit kleiner als die 5 s zum Überlaufen wiederholen soll und wenn diese Zeit größer als 5s ist nicht wiederholen soll aber irgendwie zählt es hier bis 4002030 hoch.
scrren

Programmtest:

int closePin = 2;   // force close
int bt = 8;
int LED = 13;


uint32_t previousMillis = 0; // time management
constexpr uint16_t intervalDoorOpen = 5000; // wie lange soll die Tür offen bleiben


void setup() {
  Serial.begin(9600);
  pinMode(closePin, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  pinMode(bt, INPUT_PULLUP);
}

void doorOpen()
{
  digitalWrite(LED, HIGH);
 }

void doorClose()
{
  digitalWrite(LED, LOW);
  
}

void showRestInterval()
{
  static uint32_t previousMillisShow = 0;
  if (millis() - previousMillisShow > 1000)
  {
    previousMillisShow = millis();
    Serial.print(F("remaining interval in sec:"));
    Serial.println((intervalDoorOpen - (millis() - previousMillis)) / 1000);
  }
}

void loop() {
  auswahl();
}
void auswahl () {
  Serial.println("bt gedrückt?");
  if (digitalRead(bt) == LOW) {
    ablauf();
  }
}
void ablauf() {
  previousMillis = millis();
  Serial.println(F("Tür auf"));
  doorOpen();
  while (millis() - previousMillis <intervalDoorOpen | digitalRead(closePin) == HIGH) {
    digitalRead(closePin);
    showRestInterval();
  }
  doorClose();
  auswahl();
}```

da willst vermutlich nicht ein | sondern ein ||

imho hat aber so das ganze wenig Sinn weil du dich mit while in der Schleife aufhältst und somit andere CodeTeile nicht mehr abgearbeitet werden.

Daher mein Vorschlag das über einen Status zu machen und abhängig vom Status eben auf Tastendruck oder Zeitablauf reagieren - ohne anderen Code zu blockieren.

Wie müsste ich den Code dann ändern ??

was passierte nachdem du das oder richtig gestellt hast?
Serial output posten ( geht auch besser als text in code tags) sowie neuen Sketch.

irgendwie klappt das mit der Taster bt_close Betätigung nur wenn die schleifen Bedingung so ist:

void ablauf() {
  previousMillis = millis();
  Serial.println(F("Tür auf"));
  doorOpen();
  while (millis() - previousMillis > intervalDoorOpen || digitalRead(closePin) == HIGH) {
    digitalRead(closePin);
    showRestInterval();
  }
  doorClose();
  auswahl();
}

Nach richtigem oder passiert leider immer noch dasselbe und nach der abgelaufenden Zeit funktioniert es mit der Taster Betätigung nicht mehr

andersrum genauso es funktioniert mit diesem Code erst nach dem Ablauf dieser 5s mit der Taster bt_close Betätigung:

void ablauf() {
  previousMillis = millis();
  Serial.println(F("Tür auf"));
  doorOpen();
  while (millis() - previousMillis < intervalDoorOpen || digitalRead(closePin) == HIGH) {
    digitalRead(closePin);
    showRestInterval();
  }
  doorClose();
  auswahl();
}

Du als Fragesteller IMMER kompletten Code posten.
Wenn jemand nach Serial Output frägt - Serial Output posten!

durch das oder digitalRead(closePIN) == HIGH hebelst dir den Zeitablauf aus.

die Zeit läuft ab, die Bedingung bleibt aber true weil der Button eben HIGH ist.

da kannst gleich ein true machen und AUS DEM BLOCKIERENDEN WHILE mit break ausbrechen.

  while (true) {
    if (digitalRead(closePin) == LOW) break;
    if (millis() - previousMillis > intervalDoorOpen) break;
    showRestInterval();
  }

Kleiner quickhack...

https://wokwi.com/projects/335530765910540882

So wird das nix. Mach einen switch für die einzelnen Teile von auswahl() und danach noch einen für die Türen.

Dankeschön hat funktioniert :smiley: