Servo mit gedrücktem Taster steuern

Hallo

Ich habe versucht, einen Sketch zu schreiben, mit dem ich einen Servo steuern kann. Jetzt soll aber nicht einfach ein Taster gedrückt werden und der Servo stellt sich auf den gewünschten Winkel, sondern der Servo soll sich so lange bewegen wie der Taster gedrückt bleibt. Also wenn der Taster gedrückt wird dreht sich der Servo raus gegen 90 Grad bis ich den Taster loslasse. Wenn ich den Taster nochmals drücke, dann dreht sich der Servo gegen 0 Grad zurück bis ich den Taster loslasse. Das heisst der Servo kann bei frühzeitigem loslassen auch bei z.B. 35 Grad stehen bleiben und bei erneutem Drücken geht er wieder gegen 0 Grad zurück.
Ich habe versucht mit einer Speichervariablen den gestellten Winkel zu speichern und diesen dann wieder für die nächste Abfrage zu verwenden. Der Winkel wird in 1 Grad Schritten erhöht um ihn stoppen zu können. Nun dreht sich der Servo gar nicht und auch die gespeicherten Tastendrücke “lastButtonState” bleiben auf HIGH, also 1 auch wenn ich den Taster drücke.

Hier den Sketch wie er bis jetzt ist:

#include <Servo.h>

int button = 2; //button an Pin 2 angeschlossen
int servoPin = 9; //Servo an Pin 9 angeschlossen
int lastButtonState = 0; //Speichert den vorherigen Zustand des Tasters
int servoState = 0; //Speichert Servoposition: 0 = Servobewegung rein, 1 = Servobewegung raus
int servoPos = 0; //Speichert aktuelle Servoposition
Servo servo; //Deklariert den Namen des ersten Servos

void setup() {
  pinMode(button, INPUT_PULLUP);
  servo.attach(servoPin); //servo an servoPin angeschlossen
  servo.write(0); //Gibt die Grundstellung des Servo beim Start an (Position 0 Grad)
}

void loop() {
   if ((digitalRead(button) == HIGH) && (lastButtonState == LOW)) { //Wenn button nicht gedrückt und lastButtonState gleich gedrückt, dann...
    servoState = 1 - servoState; //servoState gleich 1 minus servoState
    lastButtonState = HIGH; //lastButtonState gleich gedrückt
    delay(20); //Entprellen des Tasters
   }
   
    while ((digitalRead(button) == LOW) && (servoState == 0)) {   //Wenn button gleich gedrückt und servoState gleich 0, dann...
       if (servoPos < 90) { //Wenn servoPos kleiner 90 Grad ist, dann...
        servoPos ++; //servoPos plus 1
        servo.write(servoPos); //servo mit Winkel servoPos stellen
        lastButtonState = LOW; //lastButtonState gleich gedrückt
       }
       
    }

    while ((digitalRead(button) == LOW) && (servoState == 1)) {   //Wenn button gleich gedrückt und servoState gleich 1, dann...
       if (servoPos > 0) { //Wenn servoPos grösser 0 Grad ist, dann...
        servoPos --; //servoPos minus 1
        servo.write(servoPos); //servo mit Winkel servoPos stellen
        lastButtonState = LOW; //lastButtonState gleich gedrückt
       }
       
    }
   
}

Ich sehe den Wald vor lauter Bäumen nicht mehr. Kann mir da jemand weiterhelfen?

Grüsse

Stef

Wie hast Du den Taster denn angeschlossen?

Gruß Tommy

Der Taster ist an Pin 2 mit Ground angeschlossen, sollte also bei gedrücktem Zustand LOW ausgeben.

Taster prellen beim Loslassen und beim Drücken. Deine Entprell-Logik ist mir nicht ganz klar.

Ja, wenn ich den Taster drücke und gedrückt halte um den Servo zu bewegen, dann kann er ja nicht prellen!? Darum habe ich nur beim "loslassen", also den Wechsel auf HIGH mit einem delay von 20ms entprellt.

if ((digitalRead(button) == HIGH) && (lastButtonState == LOW)) { //Wenn button nicht gedrückt und lastButtonState gleich gedrückt, dann...
    servoState = 1 - servoState; //servoState gleich 1 minus servoState
    lastButtonState = HIGH; //lastButtonState gleich gedrückt
    delay(20); //Entprellen des Tasters
   }

Na ja, wenn du drückst, wird ein paarmal auch "loslassen" gesehen. Das erste Mal davon wechselt die Richtung und entprellt dann, genau wie beim echten Loslassen. Hast also 2 mal servoState getoggelt.

Klingt irgendwie logisch, aber ich seh den Lösungsansatz grad nicht. Oder anders gefragt, warum funktioniert bei meinem Sketch der Servo überhaupt nicht? Ob der servoState 0 oder 1 ist, sollte ja das eine oder das andere ausgeführt werden?

Edit:

Hab einen Fehler gefunden: Am Anfang wird der servoState = 1, demzufolge muss natürlich die while-Bedingung im servoState genau umgekehrt sein.

#include <Servo.h>

int button = 2; //button an Pin 2 angeschlossen
int servoPin = 9; //Servo an Pin 9 angeschlossen
int lastButtonState = 0; //Speichert den vorherigen Zustand des Tasters
int servoState = 0; //Speichert Servoposition: 0 = Servobewegung rein, 1 = Servobewegung raus
int servoPos = 0; //Speichert aktuelle Servoposition
Servo servo; //Deklariert den Namen des ersten Servos

void setup() {
  pinMode(button, INPUT_PULLUP);
  servo.attach(servoPin); //servo an servoPin angeschlossen
  servo.write(0); //Gibt die Grundstellung des Servo beim Start an (Position 0 Grad)
}

void loop() {
   if ((digitalRead(button) == HIGH) && (lastButtonState == LOW)) { //Wenn button nicht gedrückt und lastButtonState gleich gedrückt, dann...
    servoState = 1 - servoState; //servoState gleich 1 minus servoState
    lastButtonState = HIGH; //lastButtonState gleich gedrückt
    delay(20); //Entprellen des Tasters
   }
   
    while ((digitalRead(button) == LOW) && (servoState == 1)) {   //Wenn button gleich gedrückt und servoState gleich 1, dann...
       if (servoPos < 90) { //Wenn servoPos kleiner 90 Grad ist, dann...
        servoPos ++; //servoPos plus 1
        servo.write(servoPos); //servo mit Winkel servoPos stellen
        lastButtonState = LOW; //lastButtonState gleich gedrückt
       }
       
    }

    while ((digitalRead(button) == LOW) && (servoState == 0)) {   //Wenn button gleich gedrückt und servoState gleich 0, dann...
       if (servoPos > 0) { //Wenn servoPos grösser 0 Grad ist, dann...
        servoPos --; //servoPos minus 1
        servo.write(servoPos); //servo mit Winkel servoPos stellen
        lastButtonState = LOW; //lastButtonState gleich gedrückt
       }
       
    }
   
}

So dreht sich der Servo nun, aber nicht mit den gewünschten 1 Grad erhöhungsschritten, sondern auch wenn der Taster nur kurz gedrückt wird springt der Servo auf 90 Grad.

Edit2:

Habs gefunden!! Man denkt einfach nicht so schnell wie ein Arduino :smiley:
Hab ein delay von 10ms eingefügt nach dem Prinzip des “entprellens” und siehe da, es funktioniert wie es soll!

#include <Servo.h>

int button = 2; //button an Pin 2 angeschlossen
int servoPin = 9; //Servo an Pin 9 angeschlossen
int lastButtonState = 0; //Speichert den vorherigen Zustand des Tasters
int servoState = 0; //Speichert Servoposition: 0 = Servobewegung rein, 1 = Servobewegung raus
int servoPos = 0; //Speichert aktuelle Servoposition
Servo servo; //Deklariert den Namen des ersten Servos

void setup() {
  pinMode(button, INPUT_PULLUP);
  servo.attach(servoPin); //servo an servoPin angeschlossen
  servo.write(0); //Gibt die Grundstellung des Servo beim Start an (Position 0 Grad)
}

void loop() {
   if ((digitalRead(button) == HIGH) && (lastButtonState == LOW)) { //Wenn button nicht gedrückt und lastButtonState gleich gedrückt, dann...
    servoState = 1 - servoState; //servoState gleich 1 minus servoState
    lastButtonState = HIGH; //lastButtonState gleich gedrückt
    delay(20); //Entprellen des Tasters
   }
   
    while ((digitalRead(button) == LOW) && (servoState == 1)) {   //Wenn button gleich gedrückt und servoState gleich 1, dann...
       if (servoPos < 90) { //Wenn servoPos kleiner 90 Grad ist, dann...
        servoPos ++; //servoPos plus 1
        servo.write(servoPos); //servo mit Winkel servoPos stellen
        lastButtonState = LOW; //lastButtonState gleich gedrückt
        delay(10);
       }
       
    }

    while ((digitalRead(button) == LOW) && (servoState == 0)) {   //Wenn button gleich gedrückt und servoState gleich 0, dann...
       if (servoPos > 0) { //Wenn servoPos grösser 0 Grad ist, dann...
        servoPos --; //servoPos minus 1
        servo.write(servoPos); //servo mit Winkel servoPos stellen
        lastButtonState = LOW; //lastButtonState gleich gedrückt
        delay(10);
       }
       
    }
   
}

Ich danke allen, die mir ein wenig auf die Sprünge geholfen haben. Auch der Tipp mit dem Entprellen war sicherlich hilfreich!