Attiny 84 Servo Problem

Hallo an alle! mein Projekt bei dem das Problem auftritt besteht darin in einem Feuerwehrfahrzeugmodell (als DC-Car) Beleuchtung, Sound und eine Servo Bewegug zu realisieren. Angesteuert werden diese Funktionen abhänig vom Zustand zweier digitaler Inputs von einem anderen Decoder (DC-Car), die auf - schalten wenn eine Funktion ausgelöst werden soll. Die Stromversorgung des Attinys erfolgt über einen LiPo. Ich betreibe den Tiny mit 8mhz und für die Servoansteuerung nutze ich die SoftwareServo library.

Der Teil des Codes, welcher Probleme hervorruft ist die Servoansteuerung. Diese ist eigentlich ein sweep, der durch einen Input ausgelöst wird, einmal hin und herfahren soll, und zwischen drin eine gewisse Zeit pausieren soll. Das ganze muss ohne Delay erfolgen um die anderen Funktionen nicht zu behindern. Außerdem soll der Strom für den Servo über einen Transistor abgeschaltet werden, wenn dieser nicht seine Position verändert.

Das Problem besteht konkret darin, dass der Servo wenn der Input LOW ist nur bis zur Pause den Sweep korrekt ausführt, auch der Transistor schaltet richtig, danach aber nicht wieder zurück fährt, dies tritt auf mit oder ohne Überbrückung des Transistors auf. Getestet habe ich auch schon soviel, dass sich ausschließen lässt es sei ein Hardware Problem. Auch die Funktion, die das Servoausfahren und den Transistor steuert habe ich an einem anderen Arduino mit den beiden Komponenten getestet. Auch lässt sich ausschließen, dass die Inputs fehlerhaft funktionieren, da die anderen zwei Funktionen, die auf diese zugreifen einwandfrei funktionieren.

Meine Fragen (Lösungsansätze) sind nun: 1. Ist mein Sweep Programm eventuell für einen Attiny 84 gar nicht geeignet? 2. Hängt das Problem mit der Servo library vielleicht zusammen oder mit dem refresh Befehl? 3. Funktioniert die millis() Steuerung die ich versuche zu nutzen überhaupt in dieser Form?

#include <SoftwareServo.h>

SoftwareServo leiterDrehen;
int Transistor = 0;
int PotiPin = 5;
int PotiVal = 0;
int Drehposition = 72 ;

int GrundPosDrehen = 72;

int StandardEndPosDrehen = 35;
int EndPosDrehen = StandardEndPosDrehen;

boolean forward = true ;   //Richtung in die Servos verstellt werden

unsigned long ts = millis () ;   // time accounting.
int DELAY = 20;
boolean LeiterAusfahren = true;

int lautsprecher = 6;
int Hornzufall = 0;
int zufall = 1;

int Licht2I = 0; //Licht2 Input vom Decoder
int SoundI = 0; //Sound Input

void Leiter();
void Beleuchtung();
void Martinshorn();

boolean wechsel = false;
boolean signalwechsel = false;
boolean tonedirection = true;
unsigned long previousMillis = 0;
const long noteDuration = 620;
unsigned long wailpreviousMillis = 0;
const long wailnoteDuration = 20;
int hz = 310;
unsigned long ZpreviousMillis = 0;
const long ZnoteDuration = 12000;
unsigned long HpreviousMillis = 0;
const long HnoteDuration = 1000;
///////////////////////PIN/gesamtZeit/AnzahlZustände/AUS/AN/AUS/AN...//gilt für LOW=LED ein
int Leitersicherung_timing[]   = { 1, 500,  5, 50, 150, 50, 150, 100};
int LeiterBlaulicht_timing[]   = { 2, 600,  5, 0, 150, 50, 150, 250};

int HA3_timing[]   = { 10, 500,  5, 50, 150, 50, 150, 100};
int HA4_timing[]   = { 9, 500,  5, 50, 150, 50, 150, 100};
int HA5_timing[]   = { 8, 500,  5, 50, 150, 50, 150, 100};

//eigene Animationen für die Heckabsicherung

int HAinnenZ = HIGH;
int HAmitteZ = HIGH;
int HAaussenZ = HIGH;
unsigned long HApreviousM = millis();
int HAduration = 1;
int HAcount = 3;
int HAzufall = random(3);

int Heckabsicherung1[] = {8, 9, 10, 250, 10, 250, 10, 150, 100, 150, 10};
int Heckabsicherung2[] = {8, 9, 10, 150, 100, 150, 50, 150, 100, 150, 50};

void setup() {
  pinMode(Transistor, OUTPUT);
  pinMode(Leitersicherung_timing[0], OUTPUT);
  pinMode(LeiterBlaulicht_timing[0], OUTPUT);

  for (int i = 0; i < 3; i++) {
    pinMode(Heckabsicherung1[i], OUTPUT);
  }

  HAduration = Heckabsicherung1[HAcount];
  pinMode(3, INPUT);
  pinMode(4, INPUT);

  digitalWrite(Transistor, HIGH);

  leiterDrehen.attach(7);
  leiterDrehen.write(Drehposition);

  //LEDs auf HIGH also aus
  digitalWrite(Heckabsicherung1[0], HIGH);
  digitalWrite(Heckabsicherung1[1], HIGH);
  digitalWrite(Heckabsicherung1[2], HIGH);

  digitalWrite(Leitersicherung_timing[0], HIGH);
  digitalWrite(LeiterBlaulicht_timing[0], HIGH);

}
void BlaulichtStatus(int* Blaulichtdata)
{
  // Anfangs von eingeschaltetem Blinkstatus ausgehen
  boolean blinkStatusOn = true;
  // Zeit im Blinkzyklus per Modulo-Arithmetik
  // aus millis() und der Gesamt-Zykluszeit des Turms errechnen
  long inCycleTime = millis() % Blaulichtdata[1];
  int onoffCount = Blaulichtdata[2]; // Anzahl der ein/aus Schaltungen
  while (onoffCount > 0 && inCycleTime - Blaulichtdata[3 + Blaulichtdata[2] - onoffCount] > 0)
  {
    // bereits abgelaufene Blinkzeit abziehen
    inCycleTime -= Blaulichtdata[3 + Blaulichtdata[2] - onoffCount];
    onoffCount--; // Anzahl der ein/aus Schaltungen vermindert
    blinkStatusOn = !blinkStatusOn; // Blinkstatus wechselt
  }
  // wenn alles durch, dann den errechneten Blinkstatus setzen
  digitalWrite(Blaulichtdata[0], blinkStatusOn);

}
void loop() {
  Licht2I = digitalRead(3);
  SoundI = digitalRead(4);

  if (millis() <= 45000) {

    PotiVal = analogRead(PotiPin);
    PotiVal = map(PotiVal, 0, 1023, 0, 180);

    if (PotiVal >= 1 && PotiVal <= 90 && PotiVal <= GrundPosDrehen) {

      if (PotiVal == StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[2], LOW);
      } else {
        digitalWrite(Heckabsicherung1[2], HIGH);
      }
      if (PotiVal < StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[1], LOW);
      } else {
        digitalWrite(Heckabsicherung1[1], HIGH);
      }
      if (PotiVal > StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[0], LOW);
      } else {
        digitalWrite(Heckabsicherung1[0], HIGH);
      }
      if (StandardEndPosDrehen != PotiVal)
        EndPosDrehen = PotiVal;

    }

  } else {
    Leiter();
    Beleuchtung();
    Martinshorn();
  }
  SoftwareServo::refresh();
}

void Leiter() {
  if (millis () - ts >= DELAY) {
    ts = millis() ;   // setup timestamp for next time.

    if (Licht2I == LOW) {//LICHT2 schaltet am Decoder mit -
      if (LeiterAusfahren) {
        if (forward)
        {
          if (DELAY == 60)
            DELAY = 20;

          if (Drehposition != EndPosDrehen) {
            digitalWrite(Transistor, HIGH);
            Drehposition -= 1;
          } else {
            forward = false ;
            DELAY = 35000;
            digitalWrite(Transistor, LOW);
          }
        } else {
          if (DELAY == 35000)
            DELAY = 60;
          if (Drehposition != GrundPosDrehen) {
            digitalWrite(Transistor, HIGH);
            Drehposition += 1;
          } else { // test for reverse
            //forward = true ;
            Drehposition = GrundPosDrehen;
            LeiterAusfahren = false;
            digitalWrite(Transistor, LOW);
          }
        }
      }
    } else {
      
        LeiterAusfahren = true;
        forward = true;
      
        DELAY = 60;
        if (Drehposition != GrundPosDrehen) {
          digitalWrite(Transistor, HIGH);
          Drehposition += 1;
        } else { // test for reverse
          Drehposition = GrundPosDrehen;
        }

        digitalWrite(Transistor, LOW);
      
    }
  }
  leiterDrehen.write (Drehposition);
}

void Beleuchtung() {
...//gekürtzt
}
 
void Martinshorn() {
  //martinshorn mit wail unterbrechung
  int wailstep = 8;
  int ton = 0;

  //stadtsignal tonhöhen: 410 und 547 Landsignal:362 und 483
  if (SoundI == LOW) {//Sound schaltet mit - denke ich

    if (millis() - HpreviousMillis >= HnoteDuration) {
      HpreviousMillis = millis();
      Hornzufall = random(12);
    }

    if (millis() - ZpreviousMillis >= ZnoteDuration) {
      ZpreviousMillis = millis();
      zufall = random(4);
    }
    if (Hornzufall > 0) {
      if (zufall > 0) {
        if (millis() - previousMillis >= noteDuration) {
          previousMillis = millis();


          if (wechsel) {
            ton = 463;
            wechsel = false;
          } else {
            ton = 362;
            wechsel = true;
          }

          tone(lautsprecher, ton);


        }

      } else {
        if (millis() - wailpreviousMillis >= wailnoteDuration) {
          wailpreviousMillis = millis();
          if (tonedirection) {
            hz += wailstep;
            if (hz >= 1500) {
              hz = 1500;
              tonedirection = LOW;
            }
          } else {
            hz -= wailstep;
            if (hz <= 310) {
              hz = 310;
              tonedirection = HIGH;
            }
          }
          tone(lautsprecher, hz);
        }
      }
    } else {
      tone(lautsprecher, 200);
    }
  } else {
    noTone(lautsprecher);
  }
}

PS. Ich bin kein erfahrener Anwender von Arduino, das ist mein erstes Projekt mit einem Attiny.

Danke im voraus!

Grüße

Hi

So ganz ohne Kommentare, was wohl was da machen soll, ist der Sketch nicht sonderlich leicht zu lesen.
Auch scheinen die Einrückungen nicht ganz zu passen - werde den Sketch aber jetzt nicht selber zurecht rücken!
Auch wäre schön gewesen, daß man erkennt, wo der Sketch zwar in die eine Richtung dreht, aber eben nicht in die Andere - wird wohl in Leiter() sein.
Was mir auffiel: if (millis() <= 45000) {Soll Das so?
Ein Kommentar dort hätte diese Frage ggf. erübrigt.

MfG

Hi,
danke für die Antwort. Ich habe nun Kommentare in der Funktion Leiter(), die für die Servobewegung zuständig ist, ergänzt.

Soll Das so?

Ja, in den ersten 45s nur soll es möglich sein die Position, der ausgefahrenen Leiter, zu verändern.

#include <SoftwareServo.h>

SoftwareServo leiterDrehen;
int Transistor = 0;
int PotiPin = 5;
int PotiVal = 0;
int Drehposition = 72 ;

int GrundPosDrehen = 72;

int StandardEndPosDrehen = 35;
int EndPosDrehen = StandardEndPosDrehen;

boolean forward = true ;   //Richtung in die Servos verstellt werden

unsigned long ts = millis () ;   // time accounting.
int DELAY = 20;
boolean LeiterAusfahren = true;

int lautsprecher = 6;
int Hornzufall = 0;
int zufall = 1;

int Licht2I = 0; //Licht2 Input vom Decoder
int SoundI = 0; //Sound Input

void Leiter();
void Beleuchtung();
void Martinshorn();

//nicht relevant für das Servoausfahren
boolean wechsel = false;
boolean signalwechsel = false;
boolean tonedirection = true;
unsigned long previousMillis = 0;
const long noteDuration = 620;
unsigned long wailpreviousMillis = 0;
const long wailnoteDuration = 20;
int hz = 310;
unsigned long ZpreviousMillis = 0;
const long ZnoteDuration = 12000;
unsigned long HpreviousMillis = 0;
const long HnoteDuration = 1000;
///////////////////////PIN/gesamtZeit/AnzahlZustände/AUS/AN/AUS/AN...//gilt für LOW=LED ein
int Leitersicherung_timing[]   = { 1, 500,  5, 50, 150, 50, 150, 100};
int LeiterBlaulicht_timing[]   = { 2, 600,  5, 0, 150, 50, 150, 250};

int HA3_timing[]   = { 10, 500,  5, 50, 150, 50, 150, 100};
int HA4_timing[]   = { 9, 500,  5, 50, 150, 50, 150, 100};
int HA5_timing[]   = { 8, 500,  5, 50, 150, 50, 150, 100};

//eigene Animationen für die Heckabsicherung

int HAinnenZ = HIGH;
int HAmitteZ = HIGH;
int HAaussenZ = HIGH;
unsigned long HApreviousM = millis();
int HAduration = 1;
int HAcount = 3;
int HAzufall = random(3);

int Heckabsicherung1[] = {8, 9, 10, 250, 10, 250, 10, 150, 100, 150, 10};
int Heckabsicherung2[] = {8, 9, 10, 150, 100, 150, 50, 150, 100, 150, 50};

void setup() {
  pinMode(Transistor, OUTPUT);
  pinMode(Leitersicherung_timing[0], OUTPUT);
  pinMode(LeiterBlaulicht_timing[0], OUTPUT);

  for (int i = 0; i < 3; i++) {
    pinMode(Heckabsicherung1[i], OUTPUT);
  }

  HAduration = Heckabsicherung1[HAcount];
  pinMode(3, INPUT);
  pinMode(4, INPUT);

  digitalWrite(Transistor, HIGH);

  leiterDrehen.attach(7);
  leiterDrehen.write(Drehposition);

  //LEDs auf HIGH also aus
  digitalWrite(Heckabsicherung1[0], HIGH);
  digitalWrite(Heckabsicherung1[1], HIGH);
  digitalWrite(Heckabsicherung1[2], HIGH);

  digitalWrite(Leitersicherung_timing[0], HIGH);
  digitalWrite(LeiterBlaulicht_timing[0], HIGH);

}
void BlaulichtStatus(int* Blaulichtdata)
{
  // Anfangs von eingeschaltetem Blinkstatus ausgehen
  boolean blinkStatusOn = true;
  // Zeit im Blinkzyklus per Modulo-Arithmetik
  // aus millis() und der Gesamt-Zykluszeit des Turms errechnen
  long inCycleTime = millis() % Blaulichtdata[1];
  int onoffCount = Blaulichtdata[2]; // Anzahl der ein/aus Schaltungen
  while (onoffCount > 0 && inCycleTime - Blaulichtdata[3 + Blaulichtdata[2] - onoffCount] > 0)
  {
    // bereits abgelaufene Blinkzeit abziehen
    inCycleTime -= Blaulichtdata[3 + Blaulichtdata[2] - onoffCount];
    onoffCount--; // Anzahl der ein/aus Schaltungen vermindert
    blinkStatusOn = !blinkStatusOn; // Blinkstatus wechselt
  }
  // wenn alles durch, dann den errechneten Blinkstatus setzen
  digitalWrite(Blaulichtdata[0], blinkStatusOn);

}
void loop() {
  Licht2I = digitalRead(3);
  SoundI = digitalRead(4);

  if (millis() <= 45000) {// Innerhalb der ersten 45s soll die EndPos veränderbar sein

    PotiVal = analogRead(PotiPin);
    PotiVal = map(PotiVal, 0, 1023, 0, 180);//Werte werden auf 0 bis 180 Grad übertragen

    if (PotiVal >= 1 && PotiVal <= 90 && PotiVal <= GrundPosDrehen) {//Damit kein Schaden an der Leiter entsteht und das Programm ordentlich funktioniert
      // Ausgehend vom Richtwert StandardEndPos ist von außen erkennbar wie weit die Leiter ausfahren wird
      if (PotiVal == StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[2], LOW);
      } else {
        digitalWrite(Heckabsicherung1[2], HIGH);
      }
      if (PotiVal < StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[1], LOW);
      } else {
        digitalWrite(Heckabsicherung1[1], HIGH);
      }
      if (PotiVal > StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[0], LOW);
      } else {
        digitalWrite(Heckabsicherung1[0], HIGH);
      }
      if (StandardEndPosDrehen != PotiVal)
        EndPosDrehen = PotiVal;//neue EndPos

    }

  } else {
    Leiter();
    Beleuchtung();
    Martinshorn();
  }
  SoftwareServo::refresh();// Servo wird immer refresh
}

void Leiter() {
  if (millis () - ts >= DELAY) {
    ts = millis() ;   // setup timestamp for next time.

    if (Licht2I == LOW) {//LICHT2 schaltet am Decoder mit -
      if (LeiterAusfahren) {//Über diese Bedingung wird verändert, dass wenn Licht2I==LOW die Leiter nur einmal aus und einfährt
        if (forward)//Richtung wird hierrüber bestimmt// diese Drehrichtung funktioniert ohne Probleme
        {
          if (DELAY == 60)//schnelleres Ausfahren ist leichter für den Servo
            DELAY = 20;

          if (Drehposition != EndPosDrehen) {
            digitalWrite(Transistor, HIGH);//Transistor schaltet während der Bewegung den Strom für die Leiter an
            Drehposition -= 1;
          } else {
            forward = false ;
            DELAY = 35000;//Delay verlängert um die Leiter für eine gewisse Zeit ausgefahren zu lassen
            digitalWrite(Transistor, LOW);
          }
        } else {// Ab diesem Punkt scheint der Code nicht mehr richtig auf dem Attiny zu laufen
          if (DELAY == 35000)//Delay wieder kleiner nach der Pause
            DELAY = 60;
          if (Drehposition != GrundPosDrehen) {
            digitalWrite(Transistor, HIGH);
            Drehposition += 1;
          } else { // test for reverse
            //forward = true ;
            Drehposition = GrundPosDrehen;
            LeiterAusfahren = false;// damit nur einmal ausgefahren wird
            digitalWrite(Transistor, LOW);// kein unnötiger Stromverbrauch( LiPo wird genutzt)
          }
        }
      }
    } else {

      LeiterAusfahren = true;//Funktion des Leiterausfahrens wird zurückgesetzt für den nächsten Einsatz
      forward = true;

      DELAY = 60;
      if (Drehposition != GrundPosDrehen) {//als Kontrolle ob die Leiter eingefahren wurde
        digitalWrite(Transistor, HIGH);
        Drehposition += 1;
      } else { // test for reverse
        Drehposition = GrundPosDrehen;
      }

      digitalWrite(Transistor, LOW);// Strom für Servo aus

    }
  }
  leiterDrehen.write (Drehposition); //Positionsänderung des Servos
}

Grüße

Hallo,

schwierig den Überblick zubekommen. Irgendwie auch zu viele globale Variablen. Erste Maßnahme, alle millis Merker und Intervall für den Funktionaufruf lokal machen.

void Funktion ()  
{
  static unsigned long last_ms = 0;
  const unsigned int INTERVAL = 500;
  
  if (millis() - last_ms > INTERVAL) {
    last_ms = millis();´
    // hier sinnvolle Dinge tun
    // ...
  }
}

Funktion Deklarationen sind in der Arduino IDE nicht notwendig. Das nur nebenbei.

void Leiter();
void Beleuchtung();
void Martinshorn();

Hi,
überflüssige Funktiondeklarationen sind jetzt entfernt und die Sachen, die mit millis() zu tun haben sind nur noch als lokale Variablen vorhanden.

#include <SoftwareServo.h>

SoftwareServo leiterDrehen;
int Transistor = 0;
int PotiPin = 5;
int PotiVal = 0;

int Drehposition = 72 ;
int GrundPosDrehen = 72;
int StandardEndPosDrehen = 35;
int EndPosDrehen = StandardEndPosDrehen;

boolean forward = true ;   //Richtung in die Servos verstellt werden
boolean LeiterAusfahren = true;

int lautsprecher = 6;
int Signalzufall = 1;

int Licht2I = 0; //Licht2 Input vom Decoder
int SoundI = 0; //Sound Input

//nicht relevant für das Servoausfahren
boolean wechsel = false;
boolean signalwechsel = false;
boolean tonedirection = true;

int hz = 310;
///////////////////////PIN/gesamtZeit/AnzahlZustände/AUS/AN/AUS/AN...//gilt für LOW=LED ein
int Leitersicherung_timing[]   = { 1, 500,  5, 50, 150, 50, 150, 100};
int LeiterBlaulicht_timing[]   = { 2, 600,  5, 0, 150, 50, 150, 250};

int HA3_timing[]   = { 10, 500,  5, 50, 150, 50, 150, 100};
int HA4_timing[]   = { 9, 500,  5, 50, 150, 50, 150, 100};
int HA5_timing[]   = { 8, 500,  5, 50, 150, 50, 150, 100};

//eigene Animationen für die Heckabsicherung

int HAinnenZ = HIGH;
int HAmitteZ = HIGH;
int HAaussenZ = HIGH;
int HAduration = 1;
int HAcount = 3;
int HAzufall = random(3);

int Heckabsicherung1[] = {8, 9, 10, 250, 10, 250, 10, 150, 100, 150, 10};
int Heckabsicherung2[] = {8, 9, 10, 150, 100, 150, 50, 150, 100, 150, 50};

void setup() {
  pinMode(Transistor, OUTPUT);
  pinMode(Leitersicherung_timing[0], OUTPUT);
  pinMode(LeiterBlaulicht_timing[0], OUTPUT);

  for (int i = 0; i < 3; i++) {
    pinMode(Heckabsicherung1[i], OUTPUT);
  }

  HAduration = Heckabsicherung1[HAcount];
  pinMode(3, INPUT);
  pinMode(4, INPUT);

  digitalWrite(Transistor, HIGH);

  leiterDrehen.attach(7);
  leiterDrehen.write(Drehposition);

  //LEDs auf HIGH also aus
  digitalWrite(Heckabsicherung1[0], HIGH);
  digitalWrite(Heckabsicherung1[1], HIGH);
  digitalWrite(Heckabsicherung1[2], HIGH);

  digitalWrite(Leitersicherung_timing[0], HIGH);
  digitalWrite(LeiterBlaulicht_timing[0], HIGH);

}
void BlaulichtStatus(int* Blaulichtdata)
{
  // Anfangs von eingeschaltetem Blinkstatus ausgehen
  boolean blinkStatusOn = true;
  // Zeit im Blinkzyklus per Modulo-Arithmetik
  // aus millis() und der Gesamt-Zykluszeit des Turms errechnen
  long inCycleTime = millis() % Blaulichtdata[1];
  int onoffCount = Blaulichtdata[2]; // Anzahl der ein/aus Schaltungen
  while (onoffCount > 0 && inCycleTime - Blaulichtdata[3 + Blaulichtdata[2] - onoffCount] > 0)
  {
    // bereits abgelaufene Blinkzeit abziehen
    inCycleTime -= Blaulichtdata[3 + Blaulichtdata[2] - onoffCount];
    onoffCount--; // Anzahl der ein/aus Schaltungen vermindert
    blinkStatusOn = !blinkStatusOn; // Blinkstatus wechselt
  }
  // wenn alles durch, dann den errechneten Blinkstatus setzen
  digitalWrite(Blaulichtdata[0], blinkStatusOn);

}
void loop() {
  Licht2I = digitalRead(3);
  SoundI = digitalRead(4);

  if (millis() <= 45000) {// Innerhalb der ersten 45s soll die EndPos veränderbar sein

    PotiVal = analogRead(PotiPin);
    PotiVal = map(PotiVal, 0, 1023, 0, 180);//Werte werden auf 0 bis 180 Grad übertragen

    if (PotiVal >= 1 && PotiVal <= 90 && PotiVal <= GrundPosDrehen) {//Damit kein Schaden an der Leiter entsteht und das Programm ordentlich funktioniert
      // Ausgehend vom Richtwert StandardEndPos ist von außen erkennbar wie weit die Leiter ausfahren wird
      if (PotiVal == StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[2], LOW);
      } else {
        digitalWrite(Heckabsicherung1[2], HIGH);
      }
      if (PotiVal < StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[1], LOW);
      } else {
        digitalWrite(Heckabsicherung1[1], HIGH);
      }
      if (PotiVal > StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[0], LOW);
      } else {
        digitalWrite(Heckabsicherung1[0], HIGH);
      }
      if (StandardEndPosDrehen != PotiVal)
        EndPosDrehen = PotiVal;//neue EndPos

    }

  } else {
    Leiter();
    Beleuchtung();
    Martinshorn();
  }
  SoftwareServo::refresh();// Servo wird immer refresh
}

void Leiter() {
  static unsigned long ts = millis () ;   // time accounting.
  int DELAY = 20;

  if (millis () - ts >= DELAY) {
    ts = millis() ;   // setup timestamp for next time.

    if (Licht2I == LOW) {//LICHT2 schaltet am Decoder mit -
      if (LeiterAusfahren) {//Über diese Bedingung wird verändert, dass wenn Licht2I==LOW die Leiter nur einmal aus und einfährt
        if (forward)//Richtung wird hierrüber bestimmt// diese Drehrichtung funktioniert ohne Probleme
        {
          if (DELAY == 60)//schnelleres Ausfahren ist leichter für den Servo
            DELAY = 20;

          if (Drehposition != EndPosDrehen) {
            digitalWrite(Transistor, HIGH);//Transistor schaltet während der Bewegung den Strom für die Leiter an
            Drehposition -= 1;
          } else {
            forward = false ;
            DELAY = 35000;//Delay verlängert um die Leiter für eine gewisse Zeit ausgefahren zu lassen
            digitalWrite(Transistor, LOW);
          }
        } else {// Ab diesem Punkt scheint der Code nicht mehr richtig auf dem Attiny zu laufen
          if (DELAY == 35000)//Delay wieder kleiner nach der Pause
            DELAY = 60;
          if (Drehposition != GrundPosDrehen) {
            digitalWrite(Transistor, HIGH);
            Drehposition += 1;
          } else { // test for reverse
            //forward = true ;
            Drehposition = GrundPosDrehen;
            LeiterAusfahren = false;// damit nur einmal ausgefahren wird
            digitalWrite(Transistor, LOW);// kein unnötiger Stromverbrauch( LiPo wird genutzt)
          }
        }
      }
    } else {

      LeiterAusfahren = true;//Funktion des Leiterausfahrens wird zurückgesetzt für den nächsten Einsatz
      forward = true;

      DELAY = 60;
      if (Drehposition != GrundPosDrehen) {//als Kontrolle ob die Leiter eingefahren wurde
        digitalWrite(Transistor, HIGH);
        Drehposition += 1;
      } else { // test for reverse
        Drehposition = GrundPosDrehen;
      }

      digitalWrite(Transistor, LOW);// Strom für Servo aus

    }
  }
  leiterDrehen.write (Drehposition); //Positionsänderung des Servos
}

Hi, nach weiteren Versuchen habe ich herausgefunden, dass der Fehler mit der Variable DELAY zu tun haben muss, wenn diese nämlich nicht als static deklariert ist, wird die Leiter aus und wieder eingeifahren (nur halt ohne Pause daszwischen). Funktioniert es überhaupt diese Variable immer wieder zu ändern (wie ich es in meinem Code versuche) um die Geschwindigkeit des Ablaufes zu verändern?

wenn diese nämlich nicht als static deklariert ist, wird die Leiter aus und wieder eingeifahren

Wenn sie nicht static ist, wird sie bei jedem Aufruf von Leiter auf 20 gesetzt.

Wenn du sie aber ausgerechnet auf 35000 setzen willst, kriegst du ein Problem, bei einem int auf dem attiny84.

tips: - Probier mal 30000 - Probier mal static unsigned int DELAY;

tips: - Probier mal 30000 - Probier mal static unsigned int DELAY;

Beides ausprobiert, gelöst ist das Problem aber leider noch nicht. Es gibt aber eine neue Auffäligkeit, wenn die Leiter ein zweites Mal aus- und einfahren soll, bewegt diese sich von der ausgefahrenen Position (EndPosDrehen) einen kurzen Moment in Richtung der Grundposition (erreicht diese aber nicht) und wieder zurück auf die ausgefahrene Position (EndPosDrehen).

Hallo,

also DELAY solltest du beibehalten auf static unsigned int

Alles was von deinen Initialisierungen konstant bleibt, solltest du auch konstant machen. const davor schreiben Vielleicht meckert dann der Compiler wenn du im Sketch versehentlich versuchst eine Konstante zu ändern.

Ansonsten hilft wohl nur Code-Rückbau um den Überblick der if / else zubekommen Kleinere Funktionen die bei Ereignissen aufgerufen werden. Ablaufplan skizieren, welche Funktionen müssen ständig aufgerufen werden, welche bei Abhängkeiten.

Zur Vereinfachung habe ich den Code nochmal umgeschrieben und das zu passierende, wenn mit der Leiter etwas geschehen soll in drei Phasen unterteilt.

Alles was von deinen Initialisierungen konstant bleibt, solltest du auch konstant machen. const davor schreiben
Vielleicht meckert dann der Compiler wenn du im Sketch versehentlich versuchst eine Konstante zu ändern.

Ich habe versucht aus den DELAYs Konstanten zu machen und der Compiler meckert nicht, doch wenn jetzt die Leiter ein zweites Mal ausgefahren werden soll, wird das DELAY1 augenscheinlich geändert, da die Leiter nicht mehr pausiert und es geschiet, wenn die DELAYs als const deklariert wurden und wenn nicht.
Wie kann das passieren?

#include <SoftwareServo.h>

SoftwareServo leiterDrehen;
const int Transistor = 0;
const int PotiPin = 5;
int PotiVal = 0;

const int GrundPosDrehen = 72;
int Drehposition = GrundPosDrehen;
const int StandardEndPosDrehen = 35;
int EndPosDrehen = StandardEndPosDrehen;

//boolean forward = true ;   //Richtung
//boolean LeiterAusfahren = true;

const int lautsprecher = 6;
int Signalzufall = 1;

int Licht2I = 0; //Licht2 Input vom Decoder
int SoundI = 0; //Sound Input

//nicht relevant für das Servoausfahren
boolean wechsel = false;
boolean signalwechsel = false;
boolean tonedirection = true;

int hz = 310;
///////////////////////PIN/gesamtZeit/AnzahlZustände/AUS/AN/AUS/AN...//gilt für LOW=LED ein
int Leitersicherung_timing[]   = { 1, 500,  5, 50, 150, 50, 150, 100};
int LeiterBlaulicht_timing[]   = { 2, 600,  5, 0, 150, 50, 150, 250};

int HA3_timing[]   = { 10, 500,  5, 50, 150, 50, 150, 100};
int HA4_timing[]   = { 9, 500,  5, 50, 150, 50, 150, 100};
int HA5_timing[]   = { 8, 500,  5, 50, 150, 50, 150, 100};

//eigene Animationen für die Heckabsicherung

int HAinnenZ = HIGH;
int HAmitteZ = HIGH;
int HAaussenZ = HIGH;
int HAduration = 1;
int HAcount = 3;
int HAzufall = random(3);

int Heckabsicherung1[] = {8, 9, 10, 250, 10, 250, 10, 150, 100, 150, 10};
int Heckabsicherung2[] = {8, 9, 10, 150, 100, 150, 50, 150, 100, 150, 50};

void setup() {
  pinMode(Transistor, OUTPUT);
  pinMode(Leitersicherung_timing[0], OUTPUT);
  pinMode(LeiterBlaulicht_timing[0], OUTPUT);

  for (int i = 0; i < 3; i++) {
    pinMode(Heckabsicherung1[i], OUTPUT);
  }

  HAduration = Heckabsicherung1[HAcount];
  pinMode(3, INPUT);
  pinMode(4, INPUT);


  leiterDrehen.attach(7);
  leiterDrehen.write(Drehposition);

  //LEDs auf HIGH also aus
  digitalWrite(Heckabsicherung1[0], HIGH);
  digitalWrite(Heckabsicherung1[1], HIGH);
  digitalWrite(Heckabsicherung1[2], HIGH);

  digitalWrite(Leitersicherung_timing[0], HIGH);
  digitalWrite(LeiterBlaulicht_timing[0], HIGH);

}
void BlaulichtStatus(int* Blaulichtdata)
{
  // Anfangs von eingeschaltetem Blinkstatus ausgehen
  boolean blinkStatusOn = true;
  // Zeit im Blinkzyklus per Modulo-Arithmetik
  // aus millis() und der Gesamt-Zykluszeit des Turms errechnen
  long inCycleTime = millis() % Blaulichtdata[1];
  int onoffCount = Blaulichtdata[2]; // Anzahl der ein/aus Schaltungen
  while (onoffCount > 0 && inCycleTime - Blaulichtdata[3 + Blaulichtdata[2] - onoffCount] > 0)
  {
    // bereits abgelaufene Blinkzeit abziehen
    inCycleTime -= Blaulichtdata[3 + Blaulichtdata[2] - onoffCount];
    onoffCount--; // Anzahl der ein/aus Schaltungen vermindert
    blinkStatusOn = !blinkStatusOn; // Blinkstatus wechselt
  }
  // wenn alles durch, dann den errechneten Blinkstatus setzen
  digitalWrite(Blaulichtdata[0], blinkStatusOn);

}
void loop() {
  Licht2I = digitalRead(3);
  SoundI = digitalRead(4);

  if (millis() <= 45000) {// Innerhalb der ersten 45s soll die EndPos veränderbar sein

    PotiVal = analogRead(PotiPin);
    PotiVal = map(PotiVal, 0, 1023, 0, 180);//Werte werden auf 0 bis 180 Grad übertragen

    if (PotiVal >= 1 && PotiVal <= 90 && PotiVal <= GrundPosDrehen) {//Damit kein Schaden an der Leiter entsteht und das Programm ordentlich funktioniert
      // Ausgehend vom Richtwert StandardEndPos ist von außen erkennbar wie weit die Leiter ausfahren wird
      if (PotiVal == StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[2], LOW);
      } else {
        digitalWrite(Heckabsicherung1[2], HIGH);
      }
      if (PotiVal < StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[1], LOW);
      } else {

        digitalWrite(Heckabsicherung1[1], HIGH);
      }
      if (PotiVal > StandardEndPosDrehen) {
        digitalWrite(Heckabsicherung1[0], LOW);
      } else {
        digitalWrite(Heckabsicherung1[0], HIGH);
      }
      if (StandardEndPosDrehen != PotiVal)
        EndPosDrehen = PotiVal;//neue EndPos

    }

  } else {
    Leiter();
    Beleuchtung();
    Martinshorn();
  }
  SoftwareServo::refresh();// Servo wird immer refresh
}

void Leiter() {
  const long Leiterausgefahren = 40000;
  static int LeiterPhase = 0;
  static unsigned long ts0 = millis () ;
  static unsigned long ts1 = millis () ;
  static unsigned long ts2 = millis () ;
  unsigned int DELAY0 = 50;
  unsigned int DELAY1 = Leiterausgefahren;
  unsigned int DELAY2 = 100;

  if (Licht2I == LOW) { //LICHT2 schaltet am Decoder mit -
    digitalWrite(Transistor, HIGH);            //Transistor schaltet während der Bewegung den Strom für die Leiter an
    switch (LeiterPhase) {
      case 0:///////////Leiter ausfahren
        if (millis () - ts0 >= DELAY0) {
          ts0 = millis() ;   // setup timestamp for next time.

          if (Drehposition != EndPosDrehen) {
            Drehposition -= 1;
          } else {
            LeiterPhase = 1;
          }
        }
        break;
      case 1://////////Leiter pausieren
        if (millis () - ts1 >= DELAY1) {
          ts1 = millis() ;   // setup timestamp for next time
          LeiterPhase = 2;
        }
        break;
      case 2:///////////Leiter einfahren
        if (millis () - ts2 >= DELAY2) {
          ts2 = millis() ;   // setup timestamp for next time.

          if (Drehposition != GrundPosDrehen) {
            Drehposition += 1;
          }
        }
        break;
    }
  } else {
    LeiterPhase = 0;//Phase wird zurückgesetzt um bei nächster Bewegung wieder ausfahren zu können

    digitalWrite(Transistor, LOW);
  }
  leiterDrehen.write(Drehposition); //Positionsänderung des Servos
}

Hi

Erkläre mir doch Mal, wie der Ablauf eigentlich jetzt ist. Die ersten 45 Sekunden kannst Du die Endposition einstellen, also am Poti rumfummeln und die Leiter (??) dreht Sich entsprechend der Potieinstellung - Deine Endposition ist mit dem Ende der 45.ten Sekunde fest. (stimmt Das so?)

Was passiert dann? Wo drückst Du rum oder sendest was um was zu erhalten und bekommst dafür was? Ja, viele 'was' auf einem Haufen - hätte gerne zu Jedem eine Antwort. Noch ein was: Was passiert außerhalb der Leiter-Geschichte sonst noch Alles?

MfG

die Leiter (??) dreht Sich entsprechend der Potieinstellung

Die Leiter dreht sich nicht mit, wie weit die Leiter ausfahren wird, lässt sich ungefähr an den LEDs der Heckabsicherung ablesen. Sonst stimmt die Beschreibung.

Wo drückst Du rum oder sendest was um was zu erhalten und bekommst dafür was?

Die Bewegung der Leiter soll durch den digitalen Input Licht2I ausgelöst werden, der von einem anderen Decoder auf - geschaltet wird (abhängig von einem verarbeiteten Hallsensorsignal), wenn etwas passieren soll (Beide Komponenten sind elektrisch miteinander verbunden und der Input bleibt konstant, funktioniert an den anderen Stellen in Martinshorn() und Beleuchtung() an denen ich diesen nutze). Mein Attiny soll als Erweiterung des Funkionsumpfangs des (Dccar-)Decoders fungieren.

Was passiert außerhalb der Leiter-Geschichte sonst noch Alles?

Es gibt zwei weitere Funktionen Martinshorn() und Beleuchtung(), die keine Probleme machen, deshalb habe ich sie kaum erklärt, zu erwähnen ist, dass in Martinshorn() tone() genutzt wird.
Hier der Code dafür:

void Beleuchtung() {
  static unsigned long HApreviousM = millis();

  if (Licht2I == LOW) {

    if (HAzufall == 0) {
      BlaulichtStatus(HA3_timing);
      BlaulichtStatus(HA4_timing);
      BlaulichtStatus(HA5_timing);

    }
    BlaulichtStatus(Leitersicherung_timing);

    if (HAzufall == 1) {
      if (millis() - HApreviousM >= HAduration) {
        HApreviousM = millis();

        if (HAcount % 2 == 0) {
          if (HAcount == 3 || HAcount == 4)
            HAaussenZ = HIGH;
          if (HAcount == 5 || HAcount == 6)
            HAmitteZ = HIGH;
          if (HAcount > 6)
            HAinnenZ = HIGH;
        } else {
          if (HAcount == 3 || HAcount == 4)
            HAaussenZ = LOW;
          if (HAcount == 5 || HAcount == 6)
            HAmitteZ = LOW;
          if (HAcount > 6)
            HAinnenZ = LOW;
        }
        if (HAcount == 10) {
          HAcount = 3;
        } else {
          HAduration = Heckabsicherung1[HAcount];
          HAcount++;
        }
      }
    }
    if (HAzufall == 2) {
      if (millis() - HApreviousM >= HAduration) {
        HApreviousM = millis();

        if (HAcount % 2 == 0) {
          if (HAcount < 7) {
            HAaussenZ = HIGH;
            HAmitteZ = HIGH;
          }
          if (HAcount > 6)
            HAinnenZ = HIGH;
        } else {
          if (HAcount < 7) {
            HAaussenZ = LOW;
            HAmitteZ = LOW;
          }
          if (HAcount > 6)
            HAinnenZ = LOW;
        }
        if (HAcount == 10) {
          HAcount = 3;
        } else {
          HAduration = Heckabsicherung2[HAcount];
          HAcount++;
        }
      }
    }
  } else {
    digitalWrite(Leitersicherung_timing[0], HIGH);
    HAzufall = random(3);
    HAinnenZ = HIGH;
    HAmitteZ = HIGH;
    HAaussenZ = HIGH;
  }

  if (SoundI == LOW) {
    BlaulichtStatus(LeiterBlaulicht_timing);
  } else {
    digitalWrite(LeiterBlaulicht_timing[0], HIGH);
  }

  digitalWrite(Heckabsicherung1[0], HAinnenZ);
  digitalWrite(Heckabsicherung1[1], HAmitteZ);
  digitalWrite(Heckabsicherung1[2], HAaussenZ);
}

void Martinshorn() {
  //martinshorn mit wail unterbrechung
  const int wailstep = 8;
  int ton = 0;
  int Hornzufall = 0;
  static unsigned long previousMillis = 0;
  const long noteDuration = 620;
  static unsigned long wailpreviousMillis = 0;
  const long wailnoteDuration = 20;
  static unsigned long ZpreviousMillis = 0;
  const long ZnoteDuration = 12000;
  static unsigned long HpreviousMillis = 0;
  const long HnoteDuration = 1000;

  //stadtsignal tonhöhen: 410 und 547 Landsignal:362 und 483
  if (SoundI == LOW) {//Sound schaltet mit - denke ich

    if (millis() - HpreviousMillis >= HnoteDuration) {
      HpreviousMillis = millis();
      Hornzufall = random(12);
    }

    if (millis() - ZpreviousMillis >= ZnoteDuration) {
      ZpreviousMillis = millis();
      Signalzufall = random(4);
    }
    if (Hornzufall > 0) {
      if (Signalzufall > 0) {
        if (millis() - previousMillis >= noteDuration) {
          previousMillis = millis();


          if (wechsel) {
            ton = 463;
            wechsel = false;
          } else {
            ton = 362;
            wechsel = true;
          }

          tone(lautsprecher, ton);


        }

      } else {
        if (millis() - wailpreviousMillis >= wailnoteDuration) {
          wailpreviousMillis = millis();
          if (tonedirection) {
            hz += wailstep;
            if (hz >= 1500) {
              hz = 1500;
              tonedirection = LOW;
            }
          } else {
            hz -= wailstep;
            if (hz <= 310) {
              hz = 310;
              tonedirection = HIGH;
            }
          }
          tone(lautsprecher, hz);
        }
      }
    } else {
      tone(lautsprecher, 200);
    }
  } else {
    noTone(lautsprecher);
  }
}

GELÖST!!!: Der Fehler bestand darin, dass in einem case der gerade nicht aufgerufen wurde, die Variable für die vorherigen Millisekunden nicht auf millis() gesetzt wurde, sodass sobald der case wieder aufgerufen wurde die Aktionen in der Millis if direkt ausgeführt wurden, und da case 1 nur aus einmal warten besteht war der Fehler dort besonders auffälig.

Der funktionierende Code für die Leiter() Funktion:

void Leiter() {
  static int LeiterPhase = 0;
  static unsigned long ts0 = millis () ;
  static unsigned long ts1 = millis () ;
  static unsigned long ts2 = millis () ;
  const unsigned int DELAY0 = 50;
  const unsigned long DELAY1 = 45000;
  const unsigned int DELAY2 = 100;

  if (Licht2I == LOW) { //LICHT2 schaltet am Decoder mit -
    digitalWrite(Transistor, HIGH);            //Transistor schaltet während der Bewegung den Strom für die Leiter an
    switch (LeiterPhase) {
      case 0:///////////Leiter ausfahren
        ts1 = millis() ;
        ts2 = millis() ;
        if (millis () - ts0 >= DELAY0) {
          ts0 = millis() ;   // setup timestamp for next time.

          if (Drehposition != EndPosDrehen) {
            Drehposition -= 1;
          } else {
            LeiterPhase = 1;
          }
        }
        break;
      case 1://////////Leiter pausieren
        ts0 = millis() ;
        ts2 = millis() ;
        if (millis () - ts1 >= DELAY1) {
          ts1 = millis() ;   // setup timestamp for next time
          LeiterPhase = 2;
        } else {
          digitalWrite(Transistor, LOW);
        }
        break;
      case 2:///////////Leiter einfahren
        ts0 = millis() ;
        ts1 = millis() ;
        if (millis () - ts2 >= DELAY2) {
          ts2 = millis() ;   // setup timestamp for next time.

          if (Drehposition != GrundPosDrehen) {
            Drehposition += 1;
          }
        }
        break;
    }
  } else {
    ts0 = millis() ;
    ts1 = millis() ;
    ts2 = millis() ;
    LeiterPhase = 0;//Phase wird zurückgesetzt um bei nächster Bewegung wieder ausfahren zu können

    digitalWrite(Transistor, LOW);
  }
  leiterDrehen.write(Drehposition); //Positionsänderung des Servos
}

Danke für die Mithilfe an der Lösung diese Problems.

Wie sagte man mir vor kurzem. Selbst gefundene Fehler machen am Glücklichsten. :)