modifizierter Servo mit PWM angesteuert und Endlagenschalter

Hallo,
ich habe einen Servo modifiziert (Poti raus und in Nullstellung fixiert sowie Anschläge entfernt)
weil ich 360 grad Drehung brauch. Per Multischalter (RC Fernbedienung) steuer ich den Arduino an um den Servo rechts oder links ganz langsam zu drehen. Das funktioniert auch soweit. Jetzt möchte ich jedoch den links und rechts einen Endlagenschalter verwenden um das Servo zu Stoppen. Später ist auch noch ein Schalter für die Zentrierung geplant.
Der Endlagenschalter müsste also mit in die If Funktion, welche den Multischalter abfragt. Leider steh ich da bissl neben der Spur. Kann mir evtl. jemand helfen?
Hier der Code

#include <Servo.h>
Servo myservo;    // Erzeugt ein Objekt des Typs Servo
                  // maximal 8 Servoobjekte sind möglich
int pos = 110;    // Vmax des Servos im Uhrzeigersinn 100 ist neutral muss für jedes Servo individuell angepasst werden 
int pos1 = 90;    // Vmax des Servos gegen Uhrzeigersinn 100 ist neutral muss für jedes Servo individuell angepasst werden 
int pos_muS; 
int buttonPIN1 = 2;              // Anschluss Multiswitch Kanal 1
int buttonPIN2 = 3;              // Anschluss Multiswitch Kanal 2
int buttonPIN3 = 4;              // Anschluss Endschalter 1
int buttonPIN4 = 5;              // Anschluss Endschalter 2
int val = 0;                     // variable für lesen des Pin Status
const int buttonPin1 = 2;
const int buttonPin2 = 3;
const int buttonPin3 = 4;
const int buttonPin4 = 5;
int buttonState = 0;

void setup()
{
    myservo.attach(9);              // gibt den Pin an wo das Servo angeschlossen ist
                                    // es sind alle Pins mit PWM möglich:3,5,6,9,10,11
    pinMode(buttonPIN1, INPUT);     // legt Art des Einganges fest
    pinMode(buttonPIN2, INPUT);     // legt Art des Einganges fest
    pinMode(buttonPIN3, INPUT);     // legt Art des Einganges fest
    pinMode(buttonPIN4, INPUT);     // legt Art des Einganges fest
}
void loop() 
{
    val = digitalRead(buttonPin1);   // Multischalter Kanal 1 lesen
    if (val == LOW)                  // Wenn Eingang auf LOW
{
    pos_muS = map(pos, 0,216,1100,1900);     // Umrechnung des Winkels in Microsekunden
    myservo.writeMicroseconds(pos_muS);      // Variante B senden des PWM Signals an das Servo
    delay(10);                               // 15 Millisekunden warten
}
else 
{
    myservo.write(90);
}
    val = digitalRead(buttonPin2);   // Multischalter Kanal 2 lesen
    if (val == LOW)                  // Wenn Eingang auf LOW
{
    pos_muS = map(pos1, 0,216,1100,1900);    // Umrechnung des Winkels in Microsekunden
    myservo.writeMicroseconds(pos_muS);      // Variante B senden des PWM Signals an das Servo
    delay(10);                               // 15 Millisekunden warten
}
else 
{
    myservo.write(90);
}

}

Hallo und willkommen im Forum!

Vor der Endschalter-Frage fällt mir dies auf:

int buttonPIN1 = 2;              // Anschluss Multiswitch Kanal 1
int buttonPIN2 = 3;              // Anschluss Multiswitch Kanal 2
int buttonPIN3 = 4;              // Anschluss Endschalter 1
int buttonPIN4 = 5;              // Anschluss Endschalter 2
const int buttonPin1 = 2;
const int buttonPin2 = 3;
const int buttonPin3 = 4;
const int buttonPin4 = 5;

Da definierst Du zweimal dasselbe. Mein Vorschlag: nimm den Block mit const int und schreibe den Kommentar dort dahinter.

Das funktioniert auch soweit.

Wenn beide Multiswitch-Eingänge LOW sind, ist
pos_muS = 1507
pos_muS = 1433
in einem loop. Soll das so sein?

Was soll bei Erreichen eines Endschalters passieren?

Sowas wie
if (EndeLinks) ... //stop
else if (EndeRechts) ... //stop
else if (digitalRead...) myservo.write(90);
else ... //normale Bewegung

@agmue
Das mit der doppelten Auswahl hab ich geändert. Die Beiden Kanäle des Multischalters können nicht gleichzeitig LOW sein, weil es Kipptaster sind (2/0/1).
@drdietrich
Und an welche Stelle füge ich das ein.
Die Funktion brauch ich für ein drehendes Objekt, sodass ich mit den Multischaltern von rechts nach links Schwenken kann bis zu den maximalen Endausschlägen.

Die Funktion ist für folgendes Objekt siehe Video

murdok1980:
@agmue
Das mit der doppelten Auswahl hab ich geändert. Die Beiden Kanäle des Multischalters können nicht gleichzeitig LOW sein, weil es Kipptaster sind (2/0/1).

Dann bekomme ich:
Winkel = 90
pos_muS = 1433

oder

pos_muS = 1507
Winkel = 90

in einem loop! Ich muß nochmal fragen: Soll das so sein?

Ich glaub schon das drehen nach links und rechts funktioniert ja schließlich. Wenn am Code was falsch ist dann sag mir was und warum. Bin noch nicht ganz so firm im programmieren.
Es war ziemlich schwer die interne Servoelektronik zu der langsamen Drehung zu bewegen.
Bei einem Wert von 90 steht der Servo still und die anderen Werte (1433 und 1507) sind für die Drehrichtung links und rechts.

murdok1980:
Wenn am Code was falsch ist dann sag mir was und warum.

Es kann falsch sein oder ich verstehe es nicht, da liegt mein Problem.

 val = digitalRead(buttonPin1);   // Multischalter Kanal 1 lesen
  if (val == LOW)                  // Wenn Eingang auf LOW
  {}
  val = digitalRead(buttonPin2);   // Multischalter Kanal 2 lesen
  if (val == LOW)                  // Wenn Eingang auf LOW
  {}

Diese beiden if kommen direkt nacheinender und schließen sich nicht aus. Darüber stolpere ich.

Unter der Einschränkung, daß ich das Programm nicht wirklich verstehe, mein Endschaltervorschlag:

  if (digitalRead(buttonPin3) == LOW || digitalRead(buttonPin4) == LOW) {
    // Hier STOPP ausgeben
  } else {
    val = digitalRead(buttonPin1);   // Multischalter Kanal 1 lesen
    if (val == LOW)                  // Wenn Eingang auf LOW
...

Ich fange noch einmal von vorn an, vielleich gibts ja noch ne andere Lösung. Ich habe einen modifizierten Modellbau-Servo der unendlich dreht. Das ausgebaute Poti ist in Nullstellung fixiert somit gibts auch keine Rückmeldung der Servoarmposition. Des weiteren wurden die Endanschläge entfernt.
Diesen Servo will ich mit meiner Fernsteuerung nach links bzw. rechts drehen lassen.
Dafür ist an dem Sender ein Kipptaster, welcher 3 Stellungen hat. Hoch / Neutral / Runter.
Kippe ich den Schalter hoch so soll sich der Servo-Motor so lange nach links drehen wie ich den Schalter nach oben halte, spätestens am linken Endschalter jedoch abschalten.
Kippe ich den Schalter runter so soll sich der Servo-Motor so lange nach rechts drehen wie ich den Schalter nach oben halte, spätestens am rechten Endschalter jedoch abschalten. Quasi so das ich mit dem Hoch/Runter Taster hin und herdrehen kann.
An dem Empfänger befindet sich nun der Multischalter, welcher je einen Ausgang für Hoch/Runter auf LOW schaltet. Diese 2 Ausgänge hängen an den Ports D2 und D3 des Arduino. An D3 kommt der linke Endschalter und an D4 der rechte Endschalter. Auf D9 hängt der Signalanschluss (PWM) des Servos.
Weil die Servoelektronik keine Rückmeldung mehr gibt musste die PWM Ansteuerung manuell machen und mit den Werten experimentieren damit der Servo sehr langsam läuft.
Die Servo Lib liefert da keine brauchbaren Ergebnisse.
Wenn du ne bessere und sauberere Lösung hast bin ich natürlich nicht abgeneigt.

murdok1980:
Wenn du ne bessere und sauberere Lösung hast bin ich natürlich nicht abgeneigt.

Nö, erstmal muß es überhaupt funktionieren.

Da ich keinen Servo habe, nehme ich stattdessen den seriellen Monitor:

void loop()
{
  if (digitalRead(buttonPin1) == LOW && digitalRead(buttonPin3) == HIGH)  {
    Serial.println("Links drehen");
  }
  else if (digitalRead(buttonPin2) == LOW && digitalRead(buttonPin4) == HIGH)  {
    Serial.println("Rechts drehen");
  }
  else  {
    Serial.println("Stopp");
  }
  delay(500);  // Verzögerung für Debug-Ausgabe
}

Was hälst Du davon?

Weltklasse :slight_smile: der Code geht habe ihn so hier eingefügt.

#include <Servo.h>
Servo myservo;    // Erzeugt ein Objekt des Typs Servo
                  // maximal 8 Servoobjekte sind möglich
int pos = 110;    // Vmax des Servos im Uhrzeigersinn 100 ist neutral muss für jedes Servo individuell angepasst werden 
int pos1 = 90;    // Vmax des Servos gegen Uhrzeigersinn 100 ist neutral muss für jedes Servo individuell angepasst werden 
int pos_muS; 
int val = 0;                     // variable für lesen des Pin Status
const int buttonPin1 = 2;        // Anschluss Multiswitch Kanal 1
const int buttonPin2 = 3;        // Anschluss Multiswitch Kanal 2
const int buttonPin3 = 4;        // Anschluss Endschalter 1
const int buttonPin4 = 5;        // Anschluss Endschalter 2
int buttonState = 0;

void setup()
{
    myservo.attach(9);              // gibt den Pin an wo das Servo angeschlossen ist
                                    // es sind alle Pins mit PWM möglich:3,5,6,9,10,11
    pinMode(buttonPin1, INPUT);     // legt Art des Einganges fest
    pinMode(buttonPin2, INPUT);     // legt Art des Einganges fest
    pinMode(buttonPin3, INPUT);     // legt Art des Einganges fest
    pinMode(buttonPin4, INPUT);     // legt Art des Einganges fest
}
void loop()
{
  if (digitalRead(buttonPin1) == LOW && digitalRead(buttonPin3) == HIGH)  
  {
    pos_muS = map(pos, 0,216,1100,1900);     // Umrechnung des Winkels in Microsekunden
    myservo.writeMicroseconds(pos_muS);      // Variante B senden des PWM Signals an das Servo
    delay(10);                               // 15 Millisekunden warten
  }
 else if (digitalRead(buttonPin2) == LOW && digitalRead(buttonPin4) == HIGH)  
    
  {
    pos_muS = map(pos1, 0,216,1100,1900);    // Umrechnung des Winkels in Microsekunden
    myservo.writeMicroseconds(pos_muS);      // Variante B senden des PWM Signals an das Servo
    delay(10);  
  }
  else  {
    myservo.write(90);
  }
  
}

Wenn du mir jetzt noch erklärst was dein Code genau macht hätte ich auch was gelernt ich versteh z.B. nicht was die && bedeuten.
Jetzt brauch ich nur noch nen 3. Schalter für die Mittelstellung programmieren. Wenn ichs nicht hinbekomme frag ich noch einmal nach.

ich versteh z.B. nicht was die && bedeuten.

Ist normales C, auch wenn es hier als "Arduino" beschrieben ist
http://www.arduino.cc/en/Reference/Boolean

IMO gibt es auch fertige Servos, denen man die Geschwindigkeit vorgeben kann (statt Winkel) - keine Bastelei notwendig. Sonst kannst Du auch beliebige DC Motoren mit einem Motorshield (H-Brücke) ansteuern.

Programmtechnisch würde ich ein Unterprogramm schreiben, dem die Pinnummern und Servo-Objekt als Parameter übergeben werden. Evtl. als Methode einer von Servo abgeleiteten Klasse, dann kann man sich die Parameter-Übergabe auch sparen. Das erfordert dann etwas mehr C++ Kenntnisse, übt aber ungemein :wink:

Ich bräuchte nur noch den Schalter für die Mittelstellung einbinden. Das hatte ich schon versucht aber dann funktioniert der Richtungswechsel nicht mehr. Das mit der H-Brücke habe ich Testweise probiert, da war aber das Problem, dass ich die Geschwindigkeit nicht bis auf eine Umdrehung pro Minute runterregeln kann.

Probier bitte mal dies:

const int buttonPin1 = 2;              // Anschluss Multiswitch Kanal 1
const int buttonPin2 = 3;              // Anschluss Multiswitch Kanal 2
const int buttonPin3 = 4;              // Anschluss Endschalter 1
const int buttonPin4 = 5;              // Anschluss Endschalter 2
const int buttonPin5 = 6;              // Anschluss Schalter mitte
int val = 0;                     // variable für lesen des Pin Status
boolean altPin1;
boolean altPin2;
boolean altPin5;
boolean mitte = false;

void setup()
{
  Serial.begin(9600);
  pinMode(buttonPin1, INPUT_PULLUP);     // legt Art des Einganges fest
  pinMode(buttonPin2, INPUT_PULLUP);     // legt Art des Einganges fest
  pinMode(buttonPin3, INPUT_PULLUP);     // legt Art des Einganges fest
  pinMode(buttonPin4, INPUT_PULLUP);     // legt Art des Einganges fest
  pinMode(buttonPin5, INPUT_PULLUP);     // legt Art des Einganges fest
  altPin1 = digitalRead(buttonPin1);
  altPin2 = digitalRead(buttonPin2);
  altPin5 = digitalRead(buttonPin5);
}
void loop()
{
  if (digitalRead(buttonPin5) == LOW && altPin5 == HIGH)  {
    mitte = false;
  } else if ((digitalRead(buttonPin1) == LOW && altPin1 == HIGH) || (digitalRead(buttonPin2) == LOW && altPin2 == HIGH))  {
    mitte = true;
  }
  altPin1 = digitalRead(buttonPin1);
  altPin2 = digitalRead(buttonPin2);
  altPin5 = digitalRead(buttonPin5);
  if (digitalRead(buttonPin1) == LOW && digitalRead(buttonPin3) == HIGH && mitte)  {
    Serial.println("Links drehen");
  }
  else if (digitalRead(buttonPin2) == LOW && digitalRead(buttonPin4) == HIGH && mitte)  {
    Serial.println("Rechts drehen");
  }
  else  {
    Serial.println("Stopp");
  }
  delay(500);  // Verzögerung für Debug-Ausgabe
  }

Funktioniert das?

Probier ich demnächst aus und melde mich wieder.
Bei der bisherigen Schaltung habe ich Pullup Wiederstände von 5V auf die Digitalports der Schalter gezogen. Die ich die jetzt auf Grund von der Definition im Setup
"pinMode(buttonPin1, INPUT_PULLUP);" wohl weglassen oder?

Versuche nebenbei noch etwas über Interrupts zu lernen aber bis jetzt steig ich da noch nicht durch.
Grüße
Andre

Bevor das in Vergessenheit gerät:

Du wirst später noch Probleme mit der Drehzahl des Motors bekommen, sobald Last dranhängt.

Danke für den Tipp. Das wird kein Problem werden, weil keine Last dranhängt.

DrDiettrich:
IMO gibt es auch fertige Servos, denen man die Geschwindigkeit vorgeben kann (statt Winkel) - keine Bastelei notwendig.

Danke für den Hinweis, könnte eine Alternative zum Schrittmotor sein.

murdok1980:
Bei der bisherigen Schaltung habe ich Pullup Wiederstände von 5V auf die Digitalports der Schalter gezogen. Die ich die jetzt auf Grund von der Definition im Setup "pinMode(buttonPin1, INPUT_PULLUP);" wohl weglassen oder?

Weil ich faul bin, mache ich es mir zum Testen so einfach wie möglich, dazu gehört "INPUT_PULLUP". Wenn die internen Pullups mit den Digitalports zusammenpassen, ist das OK. Bei den Endschaltern (Öffner) würde ich eher externe Pulldowns verwenden, damit bei der Unterbrechung der Verbindung der Pegel auf LOW = false = Stopp geht.

Dein Programm enthält noch delay(10), was ja "Warten und sonst nix" bedeutet. Auch wenn es möglicherweise keine praktische Auswirkung hat, verträgt sich das grundsätzlich nicht mit Endschaltern, da die Gefahr des Überfahrens oder Überdrehens besteht. Bekommst Du es hin, das durch millis() zu ersetzen? Ich habe zu diesem Thema etwas Prosa geschrieben.

@agmue
Hab den Code jetzt bei mir eingefügt bissl angepasst und funktioniert gut.
Die als Schalteingänge benutzten Ports hab ich alle mit 1kOhm auf +5V gezogen.
Die Endschalter und der Mittelschalter ist jetzt ein Hall Sensor TLE 4905L.
Nun wollte ich noch nen 2. Servo mit anschließen, den der Multischalter parallel mit steuert und welcher seine eigenen Endschalter und Mittelschalter hat.
Den Code hab ich schon versucht anzupassen. Aber mit der weiteren Verschachtelung der Funktionen komme ich nicht klar. Oben im Code hab ich schon die eigene Geschwindigkeit für den zweiten Servo definiert. Aber nun komm ich nicht weiter.
Hier der Code bis jetzt

// Test modifizierter Servo Drehung links und rechts
// Mit Multischalter und Endlagen links und rechts
// Stopp bei erreichen der Mittelstellung
// mit einem Servo gehts schon

#include <Servo.h>
Servo myservo;     // Erzeugt ein Objekt des Typs Servo Nummer 1
Servo myservo1;    // Erzeugt ein Objekt des Typs Servo Nummer 2
                   // maximal 8 Servoobjekte sind möglich
int pos = 206;     // Vmax des Servos 1 im Uhrzeigersinn ca 200 ist neutral muss für jedes Servo individuell angepasst werden 
int pos1 = 198;    // Vmax des Servos 1 gegen Uhrzeigersinn ca 200 ist neutral muss für jedes Servo individuell angepasst werden 
int pos_muS; 
int pos2 = 206;    // Vmax des Servos 2 im Uhrzeigersinn ca 200 ist neutral muss für jedes Servo individuell angepasst werden 
int pos3 = 198;    // Vmax des Servos 2 gegen Uhrzeigersinn ca 200 ist neutral muss für jedes Servo individuell angepasst werden 
int pos_muS1; 
int val = 0;                     // variable für lesen des Pin Status
const int buttonPin1 = 2;        // Anschluss Multiswitch Kanal 1
const int buttonPin2 = 3;        // Anschluss Multiswitch Kanal 2
const int buttonPin3 = 4;        // Anschluss Endschalter 1  Servo 1
const int buttonPin4 = 5;        // Anschluss Endschalter 2  Servo 1
const int buttonPin5 = 6;        // Anschluss Schalter Mitte Servo 1
const int buttonPin6 = 7;        // Anschluss Endschalter 1  Servo 2
const int buttonPin7 = 8;        // Anschluss Endschalter 2  Servo 2
const int buttonPin8 = 9;        // Anschluss Schalter Mitte Servo 2

boolean altPin1;
boolean altPin2;
boolean altPin5;
boolean mitte = false;
boolean altPin8;
boolean mitte2 = false;


int buttonState = 0;

void setup()
{
    myservo.attach(10);              // gibt den Pin an wo das Servo 1 angeschlossen ist
    //myservo1.attach(11);             // gibt den Pin an wo das Servo 2 angeschlossen ist
                                     // es sind alle Pins mit PWM möglich:3,5,6,9,10,11
    Serial.begin(9600);
    pinMode(buttonPin1, INPUT_PULLUP);     // legt Art des Einganges fest
    pinMode(buttonPin2, INPUT_PULLUP);     // legt Art des Einganges fest
    pinMode(buttonPin3, INPUT_PULLUP);     // legt Art des Einganges fest
    pinMode(buttonPin4, INPUT_PULLUP);     // legt Art des Einganges fest
    pinMode(buttonPin5, INPUT_PULLUP);     // legt Art des Einganges fest
    altPin1 = digitalRead(buttonPin1);
    altPin2 = digitalRead(buttonPin2);
    altPin5 = digitalRead(buttonPin5);
    altPin8 = digitalRead(buttonPin8);
    pinMode(buttonPin6, INPUT_PULLUP);     // legt Art des Einganges fest
    pinMode(buttonPin7, INPUT_PULLUP);     // legt Art des Einganges fest
    pinMode(buttonPin8, INPUT_PULLUP);     // legt Art des Einganges fest
    
}
void loop()
{
  if (digitalRead(buttonPin5) == LOW && altPin5 == HIGH)  
  {
    mitte = false;
  }
  else if ((digitalRead(buttonPin1) == LOW && altPin1 == HIGH) || (digitalRead(buttonPin2) == LOW && altPin2 == HIGH))  
  {
    mitte = true;
  }
  
  altPin1 = digitalRead(buttonPin1);
  altPin2 = digitalRead(buttonPin2);
  altPin5 = digitalRead(buttonPin5);
 
  if (digitalRead(buttonPin1) == LOW && digitalRead(buttonPin3) == HIGH && mitte)  
  {
    Serial.println("Links drehen");
    pos_muS = map(pos, 0,432,1100,1900);     // Umrechnung des Winkels in Microsekunden
    myservo.writeMicroseconds(pos_muS);      // Variante B senden des PWM Signals an das Servo
    //delay(10);                               // 15 Millisekunden warten
  }
  else if (digitalRead(buttonPin2) == LOW && digitalRead(buttonPin4) == HIGH && mitte)  
  {
    Serial.println("Rechts drehen");
    pos_muS = map(pos1, 0,432,1100,1900);    // Umrechnung des Winkels in Microsekunden
    myservo.writeMicroseconds(pos_muS);      // Variante B senden des PWM Signals an das Servo
    //delay(10);  
  }
    else  
  {
    Serial.println("Stop");
    myservo.write(90);
    }
  
  }

Und dieser müsste quasi mit rein

void loop()
{
  if (digitalRead(buttonPin8) == LOW && altPin8 == HIGH)  
  {
    mitte2 = false;
  }
  else if ((digitalRead(buttonPin1) == LOW && altPin1 == HIGH) || (digitalRead(buttonPin2) == LOW && altPin2 == HIGH))  
  {
    mitte2 = true;
  }
  
  altPin1 = digitalRead(buttonPin1);
  altPin2 = digitalRead(buttonPin2);
  altPin8 = digitalRead(buttonPin8);
 
  if (digitalRead(buttonPin1) == LOW && digitalRead(buttonPin6) == HIGH && mitte2)  
  {
    Serial.println("Links drehen Servo 2");
    pos_muS1 = map(pos2, 0,432,1100,1900);     // Umrechnung des Winkels in Microsekunden
    myservo1.writeMicroseconds(pos_muS1);      // Variante B senden des PWM Signals an das Servo
    delay(10);                                 // 15 Millisekunden warten
  }
  else if (digitalRead(buttonPin2) == LOW && digitalRead(buttonPin7) == HIGH && mitte2)  
  {
    Serial.println("Rechts drehen Servo 2");
    pos_muS1 = map(pos3, 0,432,1100,1900);    // Umrechnung des Winkels in Microsekunden
    myservo1.writeMicroseconds(pos_muS1);      // Variante B senden des PWM Signals an das Servo
    delay(10);  
  }
    else  
  {
    Serial.println("Stop Servo 2");
    myservo1.write(90);
    }
  
  }
void loop()
{
  Code für Servo 1

  Code für Servo 2
}

Ich möchte nicht nerven, aber das geht nur ohne delay()!