Den vorhandenen Winkel von Servos beim Einschalten lesen

Hallo und guten Tag!
Als Neuling im Thema Arduino habe ich mir wohl ein etwas zu schweres Projekt vorgenommen. Aber immerhin so etwa Dreiviertel funktioniert es schon!
Zum Verständnis hier die Idee, um die es geht:


Im Endausbau soll diese "Superkreuzung" mit einem Taster bedient werden. Dabei werden die 8 Weichen mittels Servo gestellt und eine LED für die entsprechende Stellung 1, 2 oder 3 eingeschaltet.
Das funktioniert auch soweit ganz gut. Es hat mich sehr gefreut, dass ich das hinbekommen habe!
Für mein Testprogramm habe ich erstmal nur 3 Servos ohne Last angeschlossen. Die externe Stromversorgung fehlt auch noch.
Also wenn ich den Arduino (kein Original, ein ELEGOO MEGA-R3) einschalte, soll die letzte Stellung der Servos gelesen werden und die entsprechende LED angehen.
Hier mein bisheriger Code:

//Programmcode ANFANG
//Licht AN/AUS mit Taster
//Idee von @hubertoberleithner4101
//Taster als an-aus-Schalter und Klicks zaehlen
//Kombiniert, um mit einem Taster 3 verschiedene Ereignisse (hier: Servos) zu steuern


#include <Servo.h>

Servo servo1;
Servo servo2;
Servo servo3;

byte LED_PIN1 = A0;  // Variablentypen immer so klein wie möglich wählen, damit der Arbeits-
byte LED_PIN2 = A1;
byte LED_PIN3 = A2;
byte BUTTON_PIN = 12;    // speicher nicht so voll wird.
bool buttonstatus = 0;   // Da buttonstatus und letzterStatus nur die Zustände 0 und 1 annehmen
bool letzterStatus = 0;  // können, sollte der Variablentyp bool genutzt werdern. Das spart
                         // Arbeitsspeicher und kann bei Berechnungen gut genutzt werden.
byte zaehlen;            //zaehlt die Klicks

void setup() {

  Serial.begin(9600);
  pinMode(LED_PIN1, OUTPUT);
  pinMode(LED_PIN2, OUTPUT);
  pinMode(LED_PIN3, OUTPUT);
  pinMode(BUTTON_PIN, INPUT);
  servo1.attach(2);
  servo2.attach(3);
  servo3.attach(4);

  
    if (servo1.read() <= 79) {       //Wenn Servo1 den vorgegebenen Winkel 10 hat, dann
      zaehlen = 0;                   //setze zaehlen auf 0 (entspricht Stellung 1) und
      digitalWrite(LED_PIN1, HIGH);  //schalte LED_PIN1 an und (warum ist das "verkehrt" herum?)
      digitalWrite(LED_PIN2, LOW);   //schalte LED_PIN2 aus und
      digitalWrite(LED_PIN3, LOW);   //schalte LED_PIN3 aus
    }
    if (servo1.read() >= 80 && servo1.read() <= 100) {  //Wenn Servo1 den vorgegebenen Winkel zwischen 80 und 100 (also 90) hat, dann
      zaehlen = 1;                                      //setze zaehlen auf 1 (entspricht Stellung 2) und
      digitalWrite(LED_PIN1, LOW);                      //schalte LED_PIN1 aus und
      digitalWrite(LED_PIN2, HIGH);                     //schalte LED_PIN2 an und
      digitalWrite(LED_PIN3, LOW);                      //schalte LED_PIN3 aus
    }
    if (servo1.read() >= 101) {      //Wenn Servo1 den vorgegebenen Winkel 170 hat, dann
      zaehlen = 2;                   //setze zaehlen auf 2 (entspricht Stellung 3) und
      digitalWrite(LED_PIN1, LOW);   //schalte LED_PIN1 aus und
      digitalWrite(LED_PIN2, LOW);   //schalte LED_PIN2 aus und
      digitalWrite(LED_PIN3, HIGH);  //schalte LED_PIN3 an
    }

}

void loop() {

  buttonstatus = digitalRead(BUTTON_PIN);

  if (buttonstatus != letzterStatus) {  //Wenn Buttonstatus ungleich letzterStatus ist dann

    letzterStatus = !letzterStatus;  //setze letzterStatus auf nicht letzterStatus und

    zaehlen = zaehlen + buttonstatus;  //erhöhe zaehlen um buttonstatus (also 1 oder 0)
  }

  switch (zaehlen) {
    case 0:                          //Stellung 1
      servo1.write(10);              //drehe den Servo1 auf xx Grad und
                                     //hier soll eine Pause hin, damit die Servos nicht gleichzeitig arbeiten
      servo2.write(90);              //drehe den Servo2 auf xx Grad und
                                     //hier soll eine Pause hin, damit die Servos nicht gleichzeitig arbeiten
      servo3.write(170);             //drehe den Servo3 auf xx Grad und
      digitalWrite(LED_PIN1, HIGH);  //schalte LED_PIN1 an und
      digitalWrite(LED_PIN2, LOW);   //schalte LED_PIN2 aus und
      digitalWrite(LED_PIN3, LOW);   //schalte LED_PIN3 aus
      break;
    case 1:                          //Stellung 2
      servo1.write(90);              //drehe den Servo1 auf xx Grad und
      servo2.write(170);             //drehe den Servo2 auf xx Grad und
      servo3.write(10);              //drehe den Servo3 auf xx Grad und
      digitalWrite(LED_PIN1, LOW);   //schalte LED_PIN1 aus und
      digitalWrite(LED_PIN2, HIGH);  //schalte LED_PIN2 an und
      digitalWrite(LED_PIN3, LOW);   //schalte LED_PIN3 aus
      break;
    case 2:                          //Stellung 3
      servo1.write(170);             //drehe den Servo1 auf xx Grad und
      servo2.write(10);              //drehe den Servo2 auf xx Grad und
      servo3.write(90);              //drehe den Servo3 auf xx Grad und
      digitalWrite(LED_PIN1, LOW);   //schalte LED_PIN1 aus und
      digitalWrite(LED_PIN2, LOW);   //schalte LED_PIN2 aus und
      digitalWrite(LED_PIN3, HIGH);  //schalte LED_PIN3 an
      break;
    case 3:         //Wenn 3 erreicht ist,
      zaehlen = 0;  //wieder auf 0 setzen
  }


  Serial.print("zaehlen = ");
  Serial.print(zaehlen);
  Serial.print("; Buttonstatus = ");
  Serial.print(buttonstatus);
  Serial.print("; letzterStatus = ");
  Serial.print(letzterStatus);
  Serial.print(" Servo1: ");
  Serial.println(servo1.read());
  delay(10);  //Pause 10 ms
}

//Programmcode ENDE

In dieser Version landet "zaehler" beim einschalten oder Reset immer bei 1 und entsprechend bewegen sich die Servos zu den dort definierten Winkeln. Im seriellen Monitor wird auch der dazu gehörende Winkel 90 angezeigt.
Wenn ich die ganzen If-Schleifen im Setup entferne, dann ist zaehler = 0 und die Servos gehen in Stellung 1. Das erscheint mir auch richtig so.
Demnach ist meine Idee mit dem Servo lesen im Setup wohl nicht richtig.
Ich hatte die Schleifen auch schon im loop mit einer Hilfsvariablen für nur einmaligen Durchlauf ausprobiert, funktionierte aber auch nicht.
Wo liegt hier mein Denkfehler?
Danke schon mal vorab für Hilfe und Denkanstöße!
Gruß
Martin

RC Servos? keine Chance.

1 Like

Aus dem Headerfile:

    read()      - Gets the last written servo pulse width as an angle between 0 and 180.

Das heisst, Du bekommst nicht das zurück was Du willst, solange Du nicht schreibst.

read() ist "nur" eine API-Funktion um die letzte geschriebene Position zu ermitteln und liest nicht die Position des SERVO aus.
Dazu bräuchte es mindetstens einen Encoder oder Poti oder irgendwas, was die reale Position zurück gibt.
Alternativ kannst Du Deinen Weichen einen Kontakt auf einer Seite ansetzen und dann auslesen, ob der geschlossen oder geöffnet ist.

1 Like

Die gibt es nicht.
Und du solltest die Position deiner Servos speichern und bei Neustart wiederabrufen.

1 Like

edit: @my_xy_projekt war schneller.

weg damit

Das wird leider nicht funktionieren können.
Erstens haben - wie in #2 schon vermerkt - die normalen Servos keine Rückmeldung, es geht also schon wegen der Hardware nicht.
Zweitens steht es auch so in Servo.h:

Erst wenn Du seit dem letzten attach() einmal geschrieben hast und hoffnungsvollerweise das Servo die Position angefahren hat, bekommst Du mit read() diese letzte Position zurück.

Diese initialen Schreibvorgänge für einen definierten Anfangszustand könntest Du im setup() erledigen, wenn Du das Klappern und einen Moment lang "unmögliche" Weichenstellungen ertragen kannst.

Ja, MG90S
Wenn ich deine Antwort richtig verstehe, melden diese Servos ihre Stellung nicht zurück (laienhaft ausgedrückt)?

Okay, aber du hast verstanden, was ich meinte :wink:

[quote="HotSystems, post:4, topic:1370963"]
die Position deiner Servos speichern und bei Neustart wiederabrufen
[/quote]
Ah ja, ein neues Thema, von dem ich noch keine Ahnung habe. Aber ich werde es versuchen! Danke für den Tipp!

Verstanden schon....
Du steuerst doch deine Servos mittels digitalen "Werten" und diese speicherst du z.B. im EEprom. Bei Neustart werden diese wieder geladen und den Servos zugewiesen.

1 Like

Danke, das habe ich jetzt (hoffentlich) verstanden.
Aber mit zusätzlichen Encodern oder Potis oder Kontakten an den Weichen wird das zu umfangreich. Dann muss ich eben damit leben und dies als "Grundstellung" der Weichen ansehen.

Was für einen Controller verwendest Du?
Es gäbe evtl. noch die Variante die Werte zwischenzuspeichern und beim "Neustart" wieder auszulesen.

1 Like

Ich bin schon in meiner Fachliteratur am Blättern.
Da wird das an einem anschaulichen Beispiel erläutert.
Ich werde meine Fortschritte gerne hier zum gegebnen Zeitpunkt vorlegen.
Danke!

Eventuell hilft Dir meine etwas angestaubte Anleitung: RC-Servo mit Istpositionsmeldung - Anfangszucken unterdrücken. Dort findest Du auch einen Link zu Servos mit Rückmeldeleitung, wenn Du vorhandene Servos nicht selbst umbauen möchtes.

2 Likes

Zu den EEproms findest du hier drin alles notwendige.

Und hier noch etwas umfangreicher, gut für Einsteiger.

2 Likes

Die von Dir erwähnten Adafruit-Servos mit Rückmeldung sind momentan leider alle "out of stock".

@mk-bln Am großen Fluß gibt es aber eins: das hier. Habe ich aber noch nie in den Fingern gehabt.

1 Like

Jetzt weißt Du, was ich mit "angestaubt" meinte.

Mir geht es zunächst um das Verstämdnis, wie man zu einer Lösung kommt. Da helfen Links mit Bildern von LadyAda. Wenn man dann weiß, was man will, wird man ein Servo beim Händler des Vertrauens erwerben oder den Lötkolben selbst in die Hand nehmen. Für einen Modellbahner sollte das mutmaßlich keine unüberwindbare Hürde darstellen :slightly_smiling_face:

@mk-bln: Es gibt den Mega 2560 PRO MINI (nicht für ein Steckbrett geeignet!) zum Löten mit kleinen Abmessungen, so das relevant sein sollte.

1 Like

Hallo,

bei meiner Modelleisenbahn speichere ich die aktuelle Position aller Servos. Nach Reset o.ä. werden die Werte ausgelesen und alle Servos bei Programmstart in die alte Grundstellung gebracht. Sind alles ganz normale einfache Mini Servos von Conrad - Re3ly S-0008. Nimm unbedingt jetzt schon externe 5V für die Servos.

1 Like

Ich denke, das ist auch der richtige Weg. Auch bei meiner Moba werden die aktuellen Weichenstellungen im EEPROM gespeichert, und beim neu einschalten dann entsprechend gestellt.
@mk-bln: Du könntest dir auch meine MobaTools anschauen, Wenn Du das ganze mal mit echten Weichen aufbauen willst, sollten die Servos ja nicht mit 'full Speed' umlaufen. Und das langsame Umstellen geht mit der Lib ganz einfach.
Auch das Du bei den echten Weichen dann vermutlich für jede Weiche eine individuelle Servostellung für 'gerade' bzw. 'Abzweig' brauchst solltest Du berücksichtigen.
Was ist das denn für Gleismaterial?

Ich sehe Noppen - Lego oder ein anderer Klemmbaustein-Hersteller:
image

Das macht mir Spaß!

Ja. Und sie haben eine Homingsequenz (manchmal) und sie können nicht dort stehen wo du sie das letzte mal verlassen hast und sie zittern und ... --> vergiss es, such' eine andere Lösung ohne Feedback/speichern der Position.