Hallo Leuchtfeuer,
weil ich gerade Lust dazu hatte, und damit auch noch einen hässlichen Bug in den MobaTools gefunden habe, der mir beim unterdrücken von Warnings in die letzte Release reingerutscht ist, mal was zum knabbern für dich
:
Ich habe da noch 2 Taster zum Starten und Anhalten des Ablaufs reingemacht. Ich weis nicht, ob das so gut ist, wenn das z.B. 8 Stunden ohne jede Eingriffsmöglichkeit durchläuft.
#include <MobaTools.h>
// der folgende Block aktiviert Printausgaben für's debugging
#define debug // diese Zeile auskommentieren um die Debug-Ausgaben zu unterdrücken.
#warning "Debug-printing is active"
#define DB_PRINT( x, ... ) {char dbgBuf[80]; sprintf_P( dbgBuf, PSTR( x ), ##__VA_ARGS__ ) ; Serial.println( dbgBuf ); }
#else
#define DB_PRINT( x, ... ) ;
#endif
//------------------------------------------------
//Schrittkette mit 3 Servos und einem Relais
// Die Schrittkette kann mit je einem Taster gestoppt und wieder gestartet werden
const byte relaisPin = 5;
const byte servoPins[] = { 2, 3, 4 };
const byte SERVOZAHL = sizeof(servoPins);
const byte startPin = A0;//6;
const byte stopPin = A1;//7;
const byte stopLED = 6;
MoToServo servos[SERVOZAHL];
const byte servoInit[SERVOZAHL] = { 90, 0, 0 }; // Startwerte der Servos nach dem Einschalten
const byte servoSpeed[SERVOZAHL] = {20, 20, 20 }; // Bewegungsgeschwindigkeit der Servos
MoToTimer delTimer; // Timer für die Verzögerungszeiten in der Schrittkette
bool angehalten = true; // Schrittkette angehalten
bool servosRuhe = true; // Bewegungsende des Servo abwarten
byte aktSchritt = 0; // aktueller Schritt in der Schrittkette
// Aktionen der Schrittkette
enum action_t : byte { SRV1 = 0, SRV2 = 1, SRV3 = 2, RELAIS, IDLE };
// Schrittketten parameter
struct SkParam_t {
action_t action; // in diesem Schritt auszuführende Aktion
byte param; // =Winkel für Servo, EIN/AUS für Relais
word delayTime; // Verzögerungszeit bis zum nächsten Schritt in sek
};
const int delayFaktor = 10;//00; // Umrechnung auf ms ( kann für beschleunigten Test verkleinert werden )
// Die einzelnen Schritte der Schrittkette definieren
const SkParam_t schrittDaten[] = {
// Servo 1 geht:
{ SRV1, 0, 3 }, // * von 0 auf -90 grad + kurze Haltezeit (vielleicht 3 Sekunden)
{ SRV1, 180, 3 }, // * wechselt die Position auf +90 grad + Haltezeit (zurück über 0 grad)
{ SRV1, 0, 3 }, //* wechselt die Position auf -90 grad + Haltezeit (zurück über 0 grad)
{ SRV1, 180, 3 }, //* wechselt die Position auf +90 grad + Haltezeit (zurück über 0 grad)
{ SRV1, 90, 3 }, //* zurück auf 0 Grad
{ IDLE, 0, 900 }, //* dann 15 min Pause
//Servo 2 (Zyklus 1):
// * beginnt, wenn die 15 min Pause von der Taskliste "Servo 1" abgelaufen sind
{ SRV2, 180, 3 }, // * geht von den 0 grad auf 180 grad und hält diese Position
//Relais:
// * zieht an
{ RELAIS, 1, 1 }, // mit kurzer Verzögerung
//Servo 3:
// * beginnt, wenn Relais angezogen
{ SRV3, 135, 0 }, // * fährt von 0 auf 45 grad
{ SRV3, 0, 0 }, // * von 45 grad zurück auf null
{ SRV3, 135, 0 }, // * von 0 auf 45 grad
{ SRV3, 0, 0 }, // * von 45 zurück auf null grad
// * keine Pausen zwischen den Richtungsänderungen
//Servo 2 (Zyklus 2)
{ SRV2, 0, 0 }, // * geht zurück auf 0 grad und hält die Position
//Relais:
{ RELAIS, 0, 1 } // * wird wieder stromlos
// Ende Durchlauf
};
const byte SCHRITTZAHL = sizeof( schrittDaten ) / sizeof( SkParam_t );
void setup() {
#ifdef debug
Serial.begin(115200); // nur für debugging
#endif
// Ein- und Ausgangspins einrichten
pinMode( startPin, INPUT_PULLUP );
pinMode( stopPin, INPUT_PULLUP );
pinMode( relaisPin, OUTPUT );
pinMode( stopLED, OUTPUT );
// Servos einrichten und auf Startposition fahren
for ( byte i = 0; i < SERVOZAHL; i++ ) {
//servos[i].attach( servoPins[i], 1000, 2000 ); // Grenzwerte der Impulslänge für die Winkel 0 und 180
if (!servos[i].attach( servoPins[i] ) ) { // Grenzwerte der Impulslänge für die Winkel 0 und 180
DB_PRINT("Attach Servo %d fehlgeschlagen", i );
}
servos[i].setSpeed( servoSpeed[i] );
delay(100);
servos[i].write(servoInit[i]);
}
DB_PRINT ("Initiierung abgeschlossen");
}
void loop() {
// zuerst Stop/Starttaster abfragen und Stopzustand setzen
if ( !digitalRead( startPin ) ) angehalten = false;
if ( !digitalRead( stopPin ) ) {
if ( !angehalten ) DB_PRINT( " Schrittkette angehalten");
angehalten = true;
}
// Stopled schalten
digitalWrite( stopLED, angehalten );
// Schrittkette abarbeiten
if ( ! angehalten ) {
if ( ! delTimer.running() ) {
// Verzögerungszeit ist abgelaufen, Aktion ausführen
switch ( schrittDaten[aktSchritt].action ) {
case SRV1:
case SRV2:
case SRV3:
{ // Servo-Aktionen. Während sich ein Servo noch bewegt, bleibt die Schrittkette hier stehen
byte servoNr = schrittDaten[aktSchritt].action; // Servonr entspricht der 'action' Nummer
if ( servosRuhe ) {
DB_PRINT("Servo: %d , Position: %d ", servoNr, schrittDaten[aktSchritt].param );
servos[servoNr].write( schrittDaten[aktSchritt].param );
servosRuhe = false;
} else {
servosRuhe = ( servos[servoNr].moving() == 0 );
}
}
break;
case RELAIS:
digitalWrite( relaisPin, schrittDaten[aktSchritt].param );
DB_PRINT("Relais = %d " , schrittDaten[aktSchritt].param );
break;
case IDLE:
DB_PRINT("Idle");
;// nichts tun
} // Ende switch ( Aktionsauswahl )
// Verzögerungszeit bis zum nächsten Schritt setzen
if ( servosRuhe ) {
// solange sich ein Servo noch bewegt, wird die Schrittkette nicht weitergeschaltet
delTimer.setTime( (long)schrittDaten[aktSchritt].delayTime * delayFaktor );
DB_PRINT("Wartezeit: %d Sekunden", schrittDaten[aktSchritt].delayTime );
// Schrittzähler auf nächsten Schritt setzen
if ( ++aktSchritt >= SCHRITTZAHL ) aktSchritt = 0;
}
}
}
}
Wenn Du den Code auf Fehlerfreiheit getestet hast und verstehst, dann hast Du sicher eine ganze Menge gelernt 8)
Der gesamte Ablauf wird allein durch diese Tabelle gesteuert (Ausschnitt von oben):
Die einzelnen Schritte entstammen deinem ersten Post, wobei auf alle Winkel 90 draufaddiert wurden.
const SkParam_t schrittDaten[] = {
// Servo 1 geht:
{ SRV1, 0, 3 }, // * von 0 auf -90 grad + kurze Haltezeit (vielleicht 3 Sekunden)
{ SRV1, 180, 3 }, // * wechselt die Position auf +90 grad + Haltezeit (zurück über 0 grad)
{ SRV1, 0, 3 }, //* wechselt die Position auf -90 grad + Haltezeit (zurück über 0 grad)
{ SRV1, 180, 3 }, //* wechselt die Position auf +90 grad + Haltezeit (zurück über 0 grad)
{ SRV1, 90, 3 }, //* zurück auf 0 Grad
{ IDLE, 0, 900 }, //* dann 15 min Pause
//Servo 2 (Zyklus 1):
// * beginnt, wenn die 15 min Pause von der Taskliste "Servo 1" abgelaufen sind
{ SRV2, 180, 3 }, // * geht von den 0 grad auf 180 grad und hält diese Position
//Relais:
// * zieht an
{ RELAIS, 1, 1 }, // mit kurzer Verzögerung
//Servo 3:
// * beginnt, wenn Relais angezogen
{ SRV3, 135, 0 }, // * fährt von 0 auf 45 grad
{ SRV3, 0, 0 }, // * von 45 grad zurück auf null
{ SRV3, 135, 0 }, // * von 0 auf 45 grad
{ SRV3, 0, 0 }, // * von 45 zurück auf null grad
// * keine Pausen zwischen den Richtungsänderungen
//Servo 2 (Zyklus 2)
{ SRV2, 0, 0 }, // * geht zurück auf 0 grad und hält die Position
//Relais:
{ RELAIS, 0, 1 } // * wird wieder stromlos
// Ende Durchlauf
};
Edit: kleines Programmupdate - aber eigentlich sollst Du Fehler ja selbst finden 