Servo Ansteuerung für Schallplatten-Waschmaschine

Hallo Forum,
ich bin mitten im Bau einer Waschmaschine für Schallplatten mit einer Punktabsaugung. Diese wird über den Tonarm eines alten Plattenspielers transportiert. Dazu möchte ich den Tonarm mittels eines Servos steuern, damit sich dieser zuerst auf die Schallplatte, dann langsam über die Schallplatte hinweg bewegt.

Ablauf:
– Zu Beginn auf die 0° Position kalibrieren
– Langsam (0.2sec/grad) auf 20° bewegen
– Pause von 5 sec
– Bewegen auf 45° in einer Geschwindigkeit von 5sec/grad, am besten in 0,5° Schritten
– Stop bei Erreichen der 45°
– Tonarm wird dann wieder manuell auf die 0° Position bewegt

Dazu ein Schaubild:

Mit folgendem Code (kopiert von turanis) habe ich bisher experimentiert:

#define SERVO_SIGNAL_PIN 9

void setup()
{
    pinMode(SERVO_SIGNAL_PIN, OUTPUT);

    for(int i=0; i<45; i+=1){
        setServoAngle(i);
        delay(2000);
    }
}

void loop()
{
}

void setServoAngle(byte angle)
{
    // calculate angle to delayTime
    int delayTime = map(angle, 0, 180, 1000, 2000);

    digitalWrite(SERVO_SIGNAL_PIN, HIGH);
    delayMicroseconds(delayTime);
    digitalWrite(SERVO_SIGNAL_PIN, LOW);
    delay(20); // short pause at the end of the regulating
}

Dieser bewegt immerhin den Tonarm von 0° auf 45°, allerdings kommt es manchmal dazu, das der Tonarm zu Beginn die vollen 180° des Servos dreht, was ich gerne ausschließen möchte (genauso wie andere ruckartige Bewegungen).
Wie ich nun den ersten Teil des Weges und die Pause einstelle oder plötzliche Bewegungen ausschließe, dazu bin ich noch nicht erfahren genug (keinerlei Programmierkenntnisse). Habe bisher einige Codes aus dem Web (Mit Servo Library und ohne) ausprobiert, bin bei oben geposteten Code gelandet.

Ist jemanden eine Lösung in Form eines Codes für einen ähnlichen Anwendnungsfall bekannt, kann mich in die richtige Richtung stoßen oder gar helfen, würde mich wirklich sehr freuen.

Die Hardware:
Arduino Uno
Servo: Analog, Blue Bird BMS-621MG (Angeschlossen an externer Stromversorgung 6V).

Vielen Dank!

Hallo

Hast du ein Servo oder einen Schrittmotor ?

Irgendwie sieht mir das recht wild zusammengemischt aus.

Schaue mal hier:

Ich wünsche einen geschmeidigen Tag und viel Spass beim Programmieren in C++.

Lesestoff Anleitung: RC-Servo mit Istpositionsmeldung - Anfangszucken unterdrücken

Mein Tipp ist die Bibliothek MobaTools sowohl für Servos wie für Zeiten.

Hinsichtlich Programmierung solltest Du Dich mit Schrittketten (=finite state machine, =endlicher Automat) beschäftigen. delay() solltest Du aus Deinem Werkzeugkasten verbannen.

Na, zum Debuggen und für Dekozwecke würde ich die delay() Funktion noch im Werkzeugkasten lassen. :grin:

wenn ich das richtig lese willst du einfach in 4 Stufen deinen Servo langsam verstellen

grad, sec
0     x     // Zu Beginn auf die 0° Position kalibrieren
20    4     // Langsam (0.2sec/grad) auf 20° bewegen
20    5     // Pause von 5 sec
45    5     // (45-20) / 5    // Bewegen auf 45° in einer Geschwindigkeit von 5sec/grad, am besten in 0,5° Schritten
            // Stop bei Erreichen der 45°
            // Tonarm wird dann wieder manuell auf die 0° Position bewegt

das sollte mit einem struct array eigentlich abarbeitbar sein.

edit:
oder einfach in einer finite state machine abarbeiten.
Ist vermutlich am Anfanger leichter zum Nachvollziehen:

/*
   move servos smoothly

   https://forum.arduino.cc/t/servo-ansteuerung-fur-schallplatten-waschmaschine/1109620/4

   based on:
   https://forum.arduino.cc/t/mehrere-servos-synchron-ansteuern/1030870/50

   Variant with a finite state machine / workflow

   by noiasca
   2023-04-01
*/

#include <Servo.h>

constexpr uint8_t startPin = 14;     // GPIO for a movement
constexpr uint8_t stopPin = 12;    // GPIO for another movement
constexpr uint8_t servoAPin = 26;   // GPIO for Servo A

constexpr uint8_t ledRPin = 21;
constexpr uint8_t ledYPin = 19;
constexpr uint8_t ledGPin = 18;

// make your own class for two servos
class SmoothServo {
  protected:
    uint16_t target {90};              // target angle
    uint16_t current {90};             // current angle
    uint8_t interval {1};              // delay time
    uint32_t previousMillis {0};       // last movement
    uint16_t targetTime {500};         // how long has the servo time for the movement
    uint32_t previousMillisStart{0};   // last start with set

  public:
    Servo servo;

    void begin(const byte pin) {
      servo.attach(pin);
      servo.write(target);   // bring the servo to a defined angle
    }

    void set(uint16_t target, uint16_t targetTime = 500) {
      this->target = target;
      this->targetTime = targetTime;
      previousMillisStart = millis();
    }

    void update(uint32_t currentMillis = millis()) {
      if (currentMillis - previousMillis > interval) { // slow down the servos
        previousMillis = currentMillis;
        if (target != current) {
          uint32_t passedTime = currentMillis - previousMillisStart;
          if (passedTime < targetTime) {
            uint32_t remainingTime = targetTime - passedTime;
            int diff = target - current;
            diff = abs(diff);
            interval = remainingTime / diff;
          }
          else {
            interval = 0;
            // could also be used to force the servo in the target position
          }
          if (target < current) {
            current = current - 1;
          }
          else if (target > current) {
            current = current + 1;
          }
          servo.write(current);
        }
      }
    }
};

SmoothServo smoothServo;  // create a servo object

void setup() {
  Serial.begin(115200);
  smoothServo.begin(servoAPin);          // start the servo object
  pinMode(startPin, INPUT_PULLUP);
  pinMode(stopPin, INPUT_PULLUP);
  pinMode(ledRPin, OUTPUT);   // für später mal
  pinMode(ledYPin, OUTPUT);
  pinMode(ledGPin, OUTPUT);

  // bring Servo in initial state
  smoothServo.set(0, 500);    // angle, milliseconds for movement
}

// read buttons, handle workflow  with a finite state machine
void fsm() {
  enum State {INIT, IDLE, STEP_A, PAUSE, STEP_B, END};
  static State state;
  static uint32_t previousMillis = 0;

  switch (state) {
    case State::INIT:
      if (millis() - previousMillis > 500) {
        Serial.println(F("go to IDLE"));
        state = IDLE;
      }
      break;
    case State::IDLE:
      if (digitalRead(startPin) == LOW) {
        previousMillis = millis();  // "reset" timer for next step
        Serial.println(F("STEP_A"));
        state = STEP_A;
        smoothServo.set(20, 4000);  // degrees, milliseconds
      }
      break;
    case State::STEP_A:
      if (millis() - previousMillis  > 4000) {
        previousMillis = millis(); // "reset" timer for next step
        Serial.println(F("PAUSE"));
        state = PAUSE;
      }
      break;
    case State::PAUSE:
      if (millis() - previousMillis  > 5000) {
        previousMillis = millis();  // "reset" timer for next step
        Serial.println(F("STEP_B"));
        state = STEP_B;
        smoothServo.set(45, 5000);
      }
      break;
    case State::STEP_B:
      if (millis() - previousMillis  > 5000) {
        Serial.println(F("END - wait for stop button (home)"));
        state = END;
      }
      break;
    case State::END:
      if (digitalRead(stopPin) == LOW) {
        previousMillis = millis();  // "reset" timer for next step
        Serial.println(F("go back to INIT"));
        state = INIT;
        smoothServo.set(0, 500);
      }
      break;
  }
}

void loop() {
  fsm();
  smoothServo.update();  // call the update method in loop
}

man macht sich also einfach eine Klasse für einen langsamen Servo dem man nicht nur die neuen Grad sondern auch die zur Verfügung stehende Zeit übergibt.
Die FSM arbeitet die Schritte ab.
Am Anfang / Nach dem Einschalten gibts halt das Problem dass der Servo zunächst mal in seine Startposition 0 kommen muss.

2 Likes

Aktuell mit einem Servo, wie oben unter Hardware beschrieben. Das Sweep Tutorial war das erste, was ich ausgetestet habe, aber mit meinen Anfängerkenntnissen konnte ich das noch nicht auf meinen Anwendungsfall adaptieren.

Danke für den Lesestoff-Link, super hilfreich! Zwei Fragen:
– Als mögliche Quelle für fertige Analogservos mit Feedback wird Adafruit genannt – gibt es auch welche mit Versand aus Deutschland?
– Wo finde ich die Bibliothek MobaTools?
Vielen Dank!

Ist Dein Google defekt?

Gruß Tommy

Genau erfasst. Struct array oder finite state machine sagen mir noch nichts, versuche den Aufbau nachzuvollziehen, arbeite mich gerne ein, damit ich das auch blicke.
Mega. Vielen vielen Dank für die Hilfe!!! Gerne PM mit Postadresse für eine Bierlieferung :smiley:

Ich habe noch nie eins gekauft, sondern den Lötkolben angeworfen, das lila Kabel ist das zusätzliche:

Ansonsten solltest Du die Suchmaschine Deiner Wahl beauftragen.

Nur mal beispielhaft Feetech FS5115M 180° Servo 56g 15.5kg 0,16sec Feedback

1 Like

Im Thema Realisierung einer Ampelsteuerung findest Du mit ampel[] das Feld einer Klasse1), ab switch (schritt) dann eine Schrittkette.

Im Vergleich mit #5 findest Du die Übereinstimmungen.


Anm:

  1. Struktur und Klasse unterscheiden sich nur durch public und private.

Here, you get full control of speed and motion (easing) ...

Hallo moleonmars

Läuft die Waschmaschine für Schallplatten?

Zeige mal Bilder, ich bin neugierig.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.