Servo in xxx Grad Schritten über Umschalter steuern

Hallo, ich versuche jetzt bereits seit einer Woche ein Servo über einen Umschalter zu steuern.

Meine Ziel ist folgendes:

Ich möchte ein Servo mittels Umschalter EIN/AUS/EIN aus der Mitte heraus nach links und rechts bewegen können. Wenn ich den Umschalter betätige soll immer ein Schritt von 22.5 Grad nach links oder rechts erfolgen. In der Mittelstellung soll ein Ton erzeug werden.

Ein Servo habe ich am Nano bereits laufen. Servo steht am Anfang in der Mitte (90 Grad) und ich kann es dann nach links und rechts über den Umschalter bewegen. Leider ist das aber stufenlos und nicht in Grad Schritten.

Mit der Tonausgabe habe ich mich noch gar nicht beschäftigt da das andere ja auch noch nicht läuft.

Also wenn mal einer Lust und Zeit hat mir evtl. einen Tip zu geben wie ich das jetzt richtig hin bekomme dann herzlichen Dank dafür.

Hier mein aktueller Code:

#include <Servo.h>

const int buttonr = 2;
const int buttonl = 3;
Servo myservo;
int angle = 90;
int buttonrState = 0;
int buttonlState = 0;
int buzzPin = 8;
void setup() {
  
  myservo.attach(9);
  pinMode(buttonr, INPUT);
  pinMode(buttonl, INPUT);
}

void loop() {
  buttonrState = digitalRead(buttonr);
  buttonlState = digitalRead(buttonl);
  
  if (buttonrState == HIGH)
    if(angle > 0){
      angle = angle-1;
      delay(10);
    myservo.write(angle);
    }

  if (buttonlState == HIGH)
     if(angle < 180){
       angle = angle+1;
       delay(10); 
     myservo.write(angle);
}
  }

Lg, Florian

Abgesehen davon, das Du die dem Umschalter vermutlich entprellen musst, ist der Rest eigentlich einfach.
statt

if(angle > 0){
      angle = angle-1;
}

Was ja einen Schritt von 1° macht, einfach

if(angle > 22){
      angle = angle-22;
}

einen Schritt von 22° machen. Leider kannst Du so keine 22,5° abbilden, Du hast also bei 90° Winkel ca. 4° "Versatz". Mit etwas Programmlogik kann man das aber ausgleichen, wenn man einfach bei jedem 2. Schritt 23 statt 22 addiert, bzw. subtrahiert.
Achso in die Gegenrichtung ist es dann natürlich +22 (respektive 23)
Mario.

Hab ich jetzt mal probiert aber leider reagiert das Servo nicht mehr auf den Umschalter und macht am Anfang nur noch unkontrollierte Bewegungen nach links und rechts ohne Rücksicht auf die Grad Vorgaben.

Ich werd mir das mal mit dem entprellen durchlesen.
Danke aber für die Antwort.

@skyflo, hast Du entsprechende Pullups oder Pulldowns korrekt verwendet? Ein Umschalter mit Mittenstellung ist im übertragenen Sinne nichts anderes als zwei einzelne Taster, von denen jeweils nur einer gleichzeitig betätigt werden kann.

Zeige doch mal wie Du das alles angeschlossen hast.

Ich habe mal probiert wie in dem Tutorial Debounce einen 10 K ohm Resistor zwischen GND zu schalten. Hat aber irgendwie nix gebracht. Mein Umschalter hat ja drei Anschlüsse. Links hab ich den D-Pin2, rechts den D-Pin3 und in der Mitte GND. Schalten tut er jetzt in meinen eingestellten 23 Grad Schritten aber leider nicht wirklich zuverlässig. Das Servo bewegt sich auch immer zwischen den einzelnen Stellung ganz schnell hin und her. Mach mal nen Foto von meiner Verkabelung und evtl. auch ein Video damit man das besser sieht.

Hier mal der Code:

#include <Servo.h>

const int buttonr = 2;
const int buttonl = 3;
Servo myservo;
int angle = 90;
int buttonrState = 0;
int buttonlState = 0;
int buzzPin = 8;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  
  myservo.attach(9);
  pinMode(buttonr, INPUT);
  pinMode(buttonl, INPUT);
}

void loop() {
  buttonrState = digitalRead(buttonr);
  buttonlState = digitalRead(buttonl);
  
  if (buttonrState == HIGH)
  lastDebounceTime = millis();
   
  
  if ((millis() - lastDebounceTime) > debounceDelay) 
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    
    if(angle > 0){
      angle = angle-23;
       delay(20); 
    myservo.write(angle);
    }

  if (buttonlState == HIGH)
    lastDebounceTime = millis();
   
  
  if ((millis() - lastDebounceTime) > debounceDelay) 
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    
     if(angle < 180){
       angle = angle+23;
       delay(20); 
     myservo.write(angle);
}
  }

Ich habe mal probiert wie in dem Tutorial Debounce einen 10 K ohm Resistor zwischen GND zu schalten. Hat aber irgendwie nix gebracht. Mein Umschalter hat ja drei Anschlüsse. Links hab ich den D-Pin2, rechts den D-Pin3 und in der Mitte GND.

Wenn Du das so angeschlossen hast, das sind die beiden Schalter des Umschalters LOW-aktiv. Das bedeutet, das Du beim Schliessen einer der beiden Schalter diesen mit GND verbindest und damit das zugehörige Eingangs-Pins auf LOW schaltest.
Das ist nicht falsch, allerdings bringt Dir der 10k Widerstand gegen Masse dann nix, denn Du brauchst einen PULLUP und keinen PULLDOWN Widerstand. Soviel zur "schlechten" Nachricht. Die gute Nachricht ist, das der Arduino bereits einen internen PULLUP Widerstand hat.
Aktivieren kannst Du den, indem Du ein Pin mit pinMoude(pin, INPUT) als Eingang definierst und danach mittels digitalWrite(pin,HIGH) ein HIGH auf das Pin schreibst. Damit wird nicht das Pin gesetzt (denn das ist ja ein Eingang, kein Ausgang), sondern der interne PULLUP Widerstand aktiviert.

Achtung!! Damit verändert sich die Logik Deiner Eingänge. Durch den PULLUP Widerstand wird der Eingang nun dauerhaft auf HIGH gesetzt, ein if(digitalRead(pin) == HIGH) ist also immer wahr, wenn der Schater NICHT betätigt wurde. Ein digitalREAD(pin) wird dann ein LOW liefern, wenn Du den entsprechenden Schalter betätigst.

Das Ganze hat aber noch nix mit debouncing zu tun. Das musst Du immer noch selber machen. In Deinem Programm hast Du einen Fehler an folgender Stelle:

if (buttonrState == HIGH)
  lastDebounceTime = millis();
   
  
  if ((millis() - lastDebounceTime) > debounceDelay) 
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    
    if(angle > 0){
      angle = angle-23;
       delay(20); 
    myservo.write(angle);
    }

Es fehlen die Blöcke ( {}-Klammern) um die einzelnen IF-Abfragen.
Das "if (buttonrState == HIGH) lastDebounceTime = millis();" ist ein eigener, abgeschlossener Block. Der nachfolgende Code " if ((millis() - lastDebounceTime)..." wird IMMER ausgeführt, egal was bei "if (buttonrState == HIGH)" raus kommt.

Das passiert an beiden Stellen im Programm für buttonrState und buttonlState
Dein Debounce Code sorgt also eigentlich nur dafür, das der Servo automatisch und abwechselnd Schritte in die eine oder andere Richtung macht, unabhängig von der Stellung des Umschalters.

Ich habe jetzt nicht weiter geschaut, ob der Code überhaupt sinnvoll ist, auf den ersten Blick wirkt er aber so. Allerdings muss der zweite if-Block mindestens in den ersten Block, damit es sinnvoll wird. Weiterhin musst Du immer noch auf LOW statt auf HIGH prüfen:

//ACHTUNG!! die {-Klammer nach dem if ist wichtig!!
if (buttonrState == LOW) {
  lastDebounceTime = millis();
   
  
  if ((millis() - lastDebounceTime) > debounceDelay) 
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    
    if(angle > 0){
      angle = angle-23;
       delay(20); 
    myservo.write(angle);
    }
} //kompletten Block schliessen

Für den zweiten Schalter muss das natürlich analog gemacht werden.

Danke für die ganzen Tips. Der 1. Teil läuft jetzt mit diesem Code:

#include <Servo.h>

const int buttonr = 2;
const int buttonl = 3;
Servo myservo;
int angle = 90;
int buttonrState = 0;
int buttonlState = 0;

void setup() {
  
  myservo.attach(9);
  pinMode(buttonr, INPUT_PULLUP);
  pinMode(buttonl, INPUT_PULLUP);
  
}

void loop() {
  buttonrState = digitalRead(buttonr);
  buttonlState = digitalRead(buttonl);
  
  if (buttonrState == LOW)
      if(angle > 0){
      angle = angle-20;
      delay(1000);
      myservo.write(angle);

    }

  if (buttonlState == LOW) 
      if(angle < 180){
      angle = angle+20;
      delay(1000);
      myservo.write(angle);
}
  }

Will es jetzt nur noch ein wenig langsamer haben. Also die 20 Grad sollen nicht sofort gestellt werden sondern innerhalb 1 Sekunden oder so, damit das ein wenig ruhiger läuft. Muss ich noch mal weiter probieren und dann kommt noch der Ton dran...

LG, Florian