Servo mit einem Taster zwischen Positionen hin und her schalten

Nabend alle beisammen.
Ich bin seid einiger Zeit stiller Mitleser und konnte aus euren Erfahrungen einiges lernen aber gerade stoße ich an meine Grenze.

Was ich probiere ist eigentlich recht simpel.
Ein Servo soll durch betätigen eines Taster von Position 0 ( Startposition ) auf Position 1 fahren.
Bei erneutem betätigen zurück auf 0. Ich habe eine Lösung aber die ist für mich nicht praktikabel. Der Taster muss eine gewisse Zeit gedrückt gehalten werden und beginnt dann den Servo zu steuern. Das Problem ist dass er dann solange der Taster betätigt wird ständig zwischen Pos. 1 und 0 wechselt.

#include <Servo.h>
int button = 2; 
int press = 0;
Servo servo;
boolean toggle = true;

void setup()
{
pinMode(button, INPUT); 
digitalWrite(2, HIGH); 
servo.attach(9);
servo.write(0); 
digitalWrite(2, HIGH); 
}

void loop()
{
press = digitalRead(button);
if (press == LOW)
{
if(toggle)
{
servo.write(180);
toggle = !toggle;
}
else
{
servo.write(0);
toggle = !toggle;
}
delay (500);
}
}

daraufhin war meine Idee heute den Servo wie eine LED zu behandeln und eine LED Pushbuttom Tutorial für den Servo um zu schreiben. aber auch hier fehlanzeige. der Servo beginnt dierekt damit wahrlos zu zittern weil die Befehle wohl zu schnell rein kommen. wenn ich den Taster betätige und gedrückt halte fährt er mal auf Pos. 0 oder 1. Sobald ich den Taster los lasse zittert der Servo wieder.

#include <Servo.h> // zugriff auf Servo Bibliothek

const int BUTTON = 2; // Pushbuttom Pin auf dem Board (2)
int val = 0; // speichert den Zustand des Tasters
int old_val = 0; // speichert den vorherigen wert von val
int state = 0; // 0 = Servo Position eins 1 = Servo Position zwei
Servo servo; // deklariert den Namen des ersten Servos

void setup() {
pinMode(BUTTON, INPUT); // Gibt an dass Buttom ein Input ist
servo.write(0); // gibt die Grundstellung des Servo beim start an
servo.attach(9); // gibt an auf welchem Pin der Servo mit dem steuerkabel anliegt
}
void loop() 
{
val = digitalRead(BUTTON); // liest den Input aus und cheked ob er gedrückt ist. 
if ((val == HIGH) && (old_val == LOW)){
state = 1 - state;
delay(10);
}

old_val = val; // aktueller val wird zu val alt
if (state == 1) {
servo.write(180); // Stelle servo auf 180 grad
} else {
servo.write(0); // stelle servo auf startposition
}
}

Ich habe mich im Web umgesehen aber finde keinerlei Lösung wobei ich denke doch auf dem richtigem Weg zu sein. Es ist ja viel learning by doing und ein Projekt konnte ich schon realisieren:

https://www.instagram.com/p/BPIhsgrgp8R/?taken-by=der_macl

aber der Servo ist mir noch ein böhmisches Dorf zu dem ich ein paar Lehrer bräuchte :slight_smile:

Edit:
Wenn jemand eine Lösung dazu hat würde ich mich tierisch darüber freuen wenn er/sie mir dabei erklären würde wo genau mein Fehler lag und warum Lösung XY funktioniert des Lerneffektes wegen.

Hallo!
Wie hast du deinen "Button" angeschlossen?
Könnte es sein, dass du den Button an Pin 2 und VCC (also 5 Volt) angeschlossen hast?
Falls es so ist, könnte es dann auch so sein, dass Eingang 2 "in der Luft hängt" wenn der Button nicht gedrückt ist? Das bringt "unerwartete Ergebnisse" :slight_smile:
Ein digitaler Eingang muss jederzeit einen definierten Zustand haben. Das bedeutet er muss immer beschaltet sein, wenigstens mit einem Pullup- oder Pulldownwiderstand (z.B. 10 Kiloohm-Widerstand vom Pin auf 5V bzw. auf Masse) oder den internen Pullup aktiviert haben.

Wenn ich deinen Sketch Nr. 2 nehme und den Button an Pin 2 und GND hänge und den Sketch ein wenig ändere, dann funktioniert es (zumindest bei mir):

#include <Servo.h> // zugriff auf Servo Bibliothek

const int BUTTON = 2; // Pushbutton Pin auf dem Board (2)
int val = 0; // speichert den Zustand des Tasters
int old_val = 0; // speichert den vorherigen wert von val
int state = 0; // 0 = Servo Position eins 1 = Servo Position zwei
Servo servo; // deklariert den Namen des ersten Servos

void setup() {
  pinMode(BUTTON, INPUT_PULLUP); // Gibt an dass Buttom ein Input ist - DAS IST GEÄNDERT
  servo.attach(9); // gibt an auf welchem Pin der Servo mit dem steuerkabel anliegt
  servo.write(0); // gibt die Grundstellung des Servo beim start an
}

void loop()
{  val = digitalRead(BUTTON); // liest den Input aus und cheked ob er gedrückt ist.
   if ((val == LOW) && (old_val == HIGH)) {   // HIER IST DIE ABFRAGE GEÄNDERT
     state = 1 - state;
     delay(20);
   }
  
  old_val = val; // aktueller val wird zu val alt
  
  if (state == 1) {
    servo.write(180); // Stelle servo auf 180 grad
  } 
  else {
    servo.write(0); // stelle servo auf startposition
  }
}

Vielen Dank!
Läuft jetzt tadellos.
Der Button war an pin2 und GND, das war es nicht. Dann war ich ja tatsächlich mit dem Sketch nah dran :slight_smile:

Aber zu meinem Verständnis.

Was bewirkt _PULLUP?

Macl:
Was bewirkt _PULLUP?

Damit wird der interne Pullup-Widerstand eingeschaltet.
Das ist ein Widerstand von ca. 20-30 Kiloohm der (intern) mit Vcc (5 Volt beim Arduino UNO und anderen) verbunden ist.
In Verbindung mit einem Button (Taster) der nach GND "schaltet" sorgt INPUT_PULLUP dafür, dass der Input Pin HIGH ist, wenn der Taster nicht gedrückt ist - also für einen definierten Pegel ("Pullup" heißt das, weil der Pin sozusagen auf 5 Volt "hinaufgezogen" wird).
Wenn der Taster dann gedrückt wird, wird der Pegel LOW (weil der Taster ja mit GND, also 0 Volt verbunden ist) und auch das ist ein definierter Pegel. So soll es sein :slight_smile:

Hier ist das mit den Eingängen noch mal genauer erklärt (Englisch):
http://www.thebox.myzen.co.uk/Tutorial/Inputs.html

Und: Ja, du warst mit dem Sketch nahe dran :slight_smile:
War nur eine Kleinigkeit, eine typische kleine "Stolperfalle" in die wahrscheinlich alle zu Beginn mal tappen. :slight_smile:

Macl:
... Was bewirkt _PULLUP?

Damit aktivierst Du den (Controller-internen) Pull-Up-Widerstand des Pins. D. h. es wird ein Widerstand zwischen Pin und Betriebsspannung gesetzt. So ist der Pin HIGH, wenn sonst nichts dort anliegt. Ohne diesen Widerstand hinge der Pin sonst „in der Luft“ und hätte keinen definierten Zustand.

Gruß

Gregor

Wieder was gelernt.
Gracias :slight_smile:

Hallo,

diese Anleitung hat mich super weitergebracht und es hat auf Anhieb funktioniert. Ich bin völliger Arduino Neuling, verstehe aber in Grundzügen was von Programierung. Wie schaffe ich es denn nun, einen zweitern Servo über einen zweiten Taster zu steuern?
Hier mal mein angepasstes Sketch, aber den Zweiten will er nicht steuern?!

Vielen Dank schon mal im Voraus.
Sebastian

#include <Servo.h> // zugriff auf Servo Bibliothek

const int BUTTON = 2; // Pushbutton Pin auf dem Board (2)
int val = 0; // speichert den Zustand des Tasters
int old_val = 0; // speichert den vorherigen wert von val
int state = 0; // 0 = Servo Position eins 1 = Servo Position zwei
Servo servo; // deklariert den Namen des ersten Servos

const int BUTTON2 = 4; // Pushbutton Pin auf dem Board (2)
int val2 = 0; // speichert den Zustand des Tasters
int old_val2 = 0; // speichert den vorherigen wert von val
int state2 = 0; // 0 = Servo Position eins 1 = Servo Position zwei
Servo servo2; // deklariert den Namen des ersten Servos

void setup() {
  pinMode(BUTTON, INPUT_PULLUP); // Gibt an dass Buttom ein Input ist - DAS IST GEÄNDERT
  servo.attach(9); // gibt an auf welchem Pin der Servo mit dem steuerkabel anliegt
  servo.write(0); // gibt die Grundstellung des Servo beim start an
  pinMode(BUTTON2, INPUT_PULLUP); // Gibt an dass Buttom ein Input ist - DAS IST GEÄNDERT
  servo2.attach(10); // gibt an auf welchem Pin der Servo mit dem steuerkabel anliegt
  servo2.write(0); // gibt die Grundstellung des Servo beim start an
}

void loop()
{  val = digitalRead(BUTTON); // liest den Input aus und cheked ob er gedrückt ist.
   if ((val == LOW) && (old_val == HIGH)) {   // HIER IST DIE ABFRAGE GEÄNDERT
     state = 1 - state;
     delay(20);
   }
 
  old_val = val; // aktueller val wird zu val alt
 
  if (state == 1) {
    servo.write(140); // Stelle servo auf 180 grad
  }
  else {
    servo.write(90); // stelle servo auf startposition
  }
  
  val = digitalRead(BUTTON2); // liest den Input aus und cheked ob er gedrückt ist.
   if ((val2 == LOW) && (old_val2 == HIGH)) {   // HIER IST DIE ABFRAGE GEÄNDERT
     state2 = 1 - state2;
     delay(20);
   }
 
  old_val2 = val2; // aktueller val wird zu val alt
 
  if (state2 == 1) {
    servo2.write(180); // Stelle servo auf 180 grad
  }
  else {
    servo2.write(0); // stelle servo auf startposition
  }
}

Hi,

da wo der zweite Taster eingelesen werden soll sieht

val = digitalRead(BUTTON2);

anschliessend fragst Du auch richtig auf val2 ab ,

also Zeile ändern :slight_smile: dann sollte es klappen

val2 = digitalRead(BUTTON2);

Rentner:
Hi,

da wo der zweite Taster eingelesen werden soll sieht

val = digitalRead(BUTTON2);

anschliessend fragst Du auch richtig auf val2 ab ,

also Zeile ändern :slight_smile: dann sollte es klappen

val2 = digitalRead(BUTTON2);

Oh mann. Der Wald und die Bäume! Danke :slight_smile:

Hallo :slight_smile:

Für ein Modellbauprojekt bin ich auf der Suche nach einem Sketch der in etwa genau diesem hier entspricht.

Nun fährt das Servo leider immer mit der schnellstmöglichen Bewegung zum Zielpunkt.
Es wäre besser wenn die Stellgeschwindigkeit über einen Wert programmierbar wäre, ähnlich wie im Servo-Demo-Sketch "sweep"

Nun bin ich leider absoluter Neuling auf diesem Gebiet und habe leider keine Ahnung wie der Sketch aussehen sollte damit das Servo auf Tasterdruck dann langsamer läuft. Der Sketch wäre so schon brauchbar, nur leider zu schnell.

Vielleicht kann jemand helfen?

Vielen Dank, Poly

#include <Servo.h> // zugriff auf Servo Bibliothek

const int BUTTON = 2; // Pushbutton Pin auf dem Board (2)
int val = 0; // speichert den Zustand des Tasters
int old_val = 0; // speichert den vorherigen wert von val
int state = 0; // 0 = Servo Position eins 1 = Servo Position zwei
Servo servo; // deklariert den Namen des ersten Servos

void setup() {
  pinMode(BUTTON, INPUT_PULLUP); // Gibt an dass Buttom ein Input ist - DAS IST GEÄNDERT
  servo.attach(9); // gibt an auf welchem Pin der Servo mit dem steuerkabel anliegt
  servo.write(0); // gibt die Grundstellung des Servo beim start an
}

void loop()
{  val = digitalRead(BUTTON); // liest den Input aus und cheked ob er gedrückt ist.
   if ((val == LOW) && (old_val == HIGH)) {   // HIER IST DIE ABFRAGE GEÄNDERT
     state = 1 - state;
     delay(20);
   }
  
  old_val = val; // aktueller val wird zu val alt
  
  if (state == 1) {
    servo.write(180); // Stelle servo auf 180 grad
  } 
  else {
    servo.write(0); // stelle servo auf startposition
  }
}

Dann nimm doch das sweep als Vorlage und versuche zu verstehen, was da gemacht wird.

Tip: statt servo.write(ziel) wird servo.write(zwischenschritt) gemacht und der zwischenschritt nur ein bisschen verändert, und ein bisschen gewartet.

int ziel = 0; // 180 oder 0
int akt = 0; //  langsame Änderung
void loop()
{  val = digitalRead(BUTTON); // liest den Taster aus und checkt ob er gedrückt ist.
   if ((val == LOW) && (old_val == HIGH)) {   // Taster neu gedrückt
     ziel = 180 - ziel;  // springt bei jedem neuen Tasten zwischen 180 und 0 hin und her 
     delay(20); // entprellen
   }
   old_val = val; // um Wechsel in val zu erkennen

   if (akt != ziel) {   // Wenn ziel nicht erreicht ist
       if (akt < ziel) akt++; else akt--;   // akt nähert sich ziel schrittweise
       servo.write(akt);
       delay(10) ; // Geschwindigkeit: 1.8 sec für 180 °
   }
}

Variable state wird nicht mehr gebraucht

Es gibt mehrere Möglichkeiten.
Eine wäre - genau wie du schon geschrieben hast - es so ähnlich zu machen, wie im Beispiel "Sweep".

Es gibt auch eine Servo-Library, die "langsam fahren" kann. Sie wurde speziell für den Modellbau entwickelt - da hatte also schon mal jemand so ein Problem :slight_smile:
MobaTools

Hallo,

es gibt wie immer eine einfache Lösung und mehrere mit etwas mehr Aufwand die aber ein flexiebleres Ergebniss liefern.

Wenn der UNO sonst nichts mehr zu tun hat und Du eine Fahrbewegung nicht unterbrechen willst kannst Du mit einer for schleife arbeiten und die gesamte Bewegung damit in kleinere steps unterteilen. Nach jedem step machst Du eine Pause.

Vielen Dank für die schnelle Hilfe.

Ich habe den Sketch jetzt so zurecht geschrieben und es funktioniert:

const int BUTTON = 2; // Pushbutton Pin auf dem Board (2)
int val = 0; // speichert den Zustand des Tasters
int old_val = 0; // speichert den vorherigen wert von val


int ziel = 1; // 180 oder 0
int akt = 0; //  langsame Änderung

Servo servo; // deklariert den Namen des ersten Servos

void setup() {
  pinMode(BUTTON, INPUT_PULLUP); // Gibt an dass Buttom ein Input ist - DAS IST GEÄNDERT
  servo.attach(9); // gibt an auf welchem Pin der Servo mit dem steuerkabel anliegt
  servo.write(1); // gibt die Grundstellung des Servo beim start an
}

void loop()
{  val = digitalRead(BUTTON); // liest den Taster aus und checkt ob er gedrückt ist.
   if ((val == LOW) && (old_val == HIGH)) {   // Taster neu gedrückt
     ziel = 170 - ziel;  // springt bei jedem neuen Tasten zwischen 180 und 0 hin und her 
     delay(20); // entprellen
   }
  
  old_val = val; // aktueller val wird zu val alt
  
   if (akt != ziel) {   // Wenn ziel nicht erreicht ist
       if (akt < ziel) akt++; else akt--;   // akt nähert sich ziel schrittweise
       servo.write(akt);
       delay(20) ; // Geschwindigkeit: 1.8 sec für 180 °

  } 
  
}

Auch der Stellweg lässt sich gut über ändern der Werte einstellen. Das ist genau das was ich brauche.
Jetzt muss ich nur schauen wie ich da noch weitere Servos integriert bekomme, aber das dürfte bestimmt kein Problem sein.

Auch der Stellweg lässt sich gut über ändern der Werte einstellen

Konstanten mitten im Code setzt man am besten, so wie z.B. die Pin-Nummer an den Anfang des Sketch mit einem Kommentar. Und verwendet dann diesen Namen.

const int BUTTON = 2;  // Pin für den Umschalt-Taster (Anderer Taster-Pin an GND)
const int MIN = 1;     // Servo Stellung am Anfang
const int MAX = 170;   // Servo Stellung am Ende 
const int SPEED = 20;  // ms / je Schritt, (MAX-MIN)*SPEED für den gesamten Weg

Und immer drauf achten, dass der Kommentar zum aktuellen Wert passt, denn falsche Kommentare sind schlechter als gar keine. :wink:

int ziel = MIN;
   
    ...
    ziel = MAX+MIN - ziel; // springt zwischen MAX und MIN hin und her


    ...

    delay(SPEED) ; // je höher der Wert, desto langsamer bewegt sich der Servo

Auch der Stellweg lässt sich gut über ändern der Werte einstellen. Das ist genau das was ich brauche.
Jetzt muss ich nur schauen wie ich da noch weitere Servos integriert bekomme, aber das dürfte bestimmt kein Problem sein.

Dann solltest Du sehen das Du das delay raus bekommst. bei einem Delay macht der Prozessor eine Pause und macht sonst nichts mehr. Damit kannst Du dann einen zweiten Servos nicht gleichzeitig laufen lassen.

Schau dir das Beispiel blink without delay an um das delay zu ersetzen. Kannst hier auch mal nach
"mehere Servos betreiben" suchen.

oder versuche es mal mit der hier schon angesprochenen anderen lib für Servos

Heinz

Hi,

als kleines Dankeschön habe ich hier ein kleines Video von der Sache für das ich diese Funktion brauche.

Ich kann zwar gut was bauen aber leider noch nix programmieren.

Mal schauen wie ich das hin bekomme.

Hi

WOW - Das will erst Mal 'nachgebastelt' werden!

Aber etwas Gutes hat Dein Video - ich bin nicht schuld - auch in Deiner Werkstatt sind die waagerechten Flächen belegt :wink:

Tolles Modell, sauber gearbeitet - gibt's irgendwo einen Rundgang durch Deine Werkstatt?
So zum lange Nase machen? (... und nein ... Gleiches ist bei mir noch lange nicht drin)

MfG

Vielen Dank.

postmaster-ino:
Aber etwas Gutes hat Dein Video - ich bin nicht schuld - auch in Deiner Werkstatt sind die waagerechten Flächen belegt :wink:

Ja, die Formel dafür ist recht einfach: leere waagerechte Fläche + zu viel Material = alles vollgestellt.

Sowas kann ich schon recht gut beherrschen, nur mit dem Programmieren habe ich noch Probleme. :wink:

Aber langsam wird es. Der Sinn liegt darin alle Türen im Körper hintereinander zu öffnen und so wieder zu schließen. Ich habe eine weitere Hilfe eines Bekannten erhalten und jetzt funktioniert alles.