Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Präzisen Linearservo-Aktuator mit Positionsrückführung bauen – Schritt-für-Schritt

In diesem Tutorial lernen wir, wie man einen Linearservo-Aktuator baut. Im Gegensatz zu herkömmlichen Lineareaktoren, die bei angelegter Spannung einfach in eine Richtung fahren, bietet dieser Eigenbau präzise, wiederholbare Bewegungen mit exakter Steuerung.

Er heißt Servo-Aktuator, weil er ein Rückführsystem (Closed-Loop) besitzt, über das die Ausgabebewegung präzise geregelt wird.

Video ansehen oder schriftliche Anleitung unten lesen.

Überblick

Die Steuereingabe kann analog oder digital sein. Analog: beliebiges Potentiometer – Linear-, Drehpotentiometer, Joystick (wieder Drehpotentiometer) etc. Digital: RC-Sender. Für beide Modi nur 3 Drähte nötig: 2 für Stromversorgung des Eingabegeräts, 1 für das Signalsignal.

Cooles Feature: Benutzerdefinierter Start- und Endpunkt des Auslegerstabs sowie einstellbare Empfindlichkeit (Ansprechverhalten).

Mein Lieblingsfeature: Steuerung per PC/Laptop über seriellen Port. Im Arduino IDE Serial Monitor Millimeterwerte eingeben → Aktuator fährt dorthin.

Noch cooler: Wiederholbare Bewegungen speichern – an jeder gewünschten Position „save“ im Serial Monitor eingeben, dann mit „run“ die Sequenz in Endlosschleife abspielen lassen.

Jetzt alles Wissenswerte: Funktionsweise, Design, Nachbau.

Funktionsweise

Geschlossener Regelkreis basiert auf AS5600 magnetischem Drehwinkelsensor und implementierter PID-Regelung für den DC-Motor.

Ich nutze denselben Custom-Servo-Motor-Controller wie in meinem vorherigen Video – eigenes Mikrocontroller-Board, das jeden DC-Motor in einen Standalone-Servomotor verwandelt.

Dort wird detailliert erklärt, wie Servomotoren und Closed-Loop-Regelung funktionieren.

Kurz: Servomotor = Closed-Loop-System. Eingangssignal (Sollposition) wird mit Istposition (vom Positionssensor) verglichen. Differenz (Fehler) wird im Regler verarbeitet → Motor bewegt sich, bis Sollposition erreicht.

Dieser Linearservo hat dasselbe Prinzip, plus Umwandlung der Drehbewegung in Linearbewegung über Spindeltrieb (Lead Screw).

Linearservo-Aktuator Design

3D-Modell zeigt den Aufbau.

AS5600 sitzt hinten am Aktuator, erfasst Drehung der Spindel. Spindel: 8 mm Steigung → pro Umdrehung 8 mm Linearbewegung.

AS5600 ist 12-Bit-Encoder → 4096 Positionen pro Umdrehung. 8 mm / 4096 = 0,001953 mm Auflösung. Beeindruckend!

DC-Motor: 12V mit Getriebe, 480 U/min Ausgang. 480/60 = 8 U/s × 8 mm Steigung = 64 mm/s Lineargeschwindigkeit. Passt: Maximalhub 150 mm → ca. 2,5 s End-to-End (ca. 3 s mit Rampe). Daher 1:1 Übersetzung für Spindelantrieb.

Gesamtdesign basiert auf Custom-PCB (40×40 mm) und Spindel/Spindelmutter (22 mm Außendurchmesser). PCB-Maße = minimaler Zylinderblock-Durchmesser.

Spindelmutter und Stange verbunden mit 4 M3-Schrauben und Gewindeeinsätzen. Oben am Stab: Führungslager (gleitet im Zylinderblock, verhindert Verdrehung). Am Ausgangsdeckel: 4 kleine Lager für Führung der Stange aus dem Zylinder.

Gesamt kompakt für alle verbauten Komponenten.

Zusätzlich: Mikro-Endschalter im Zylinderblock für Homing/Startposition.

3D-Modell Download

3D-Modell im Browser mit Onshape erkunden (kostenloser Onshape-Account für Privatnutzer).

STL-Dateien für 3D-Druck sowie STEP-Datei auf Cults3D.

Maximalhub einfach erweiterbar: Zylinderblock und Stange verlängern. Ich wählte Maße passend für 220×220 mm Druckbett – größtes Teil (Stange) 215 mm.

3D-Druck

Mein Creality Ender-3 V3 SE druckte Stange horizontal entlang Y-Achse – top Qualität. Leichtes Schleifen nötig, aber diese Orientierung sorgt für glattere Oberfläche und festere Stange.

Wichtig: Horizontale Expansion im Slicer nutzen, um Filamentausdehnung zu kompensieren und dimensionsgenaue Teile zu erhalten.

Ich nutzte –0,1 mm – Testdrucke für optimale Werte auf eigenem Drucker machen.

Zylinderblock entlang Z-Achse gedruckt (wenig Support). Ender-3 V3 SE überzeugte auch hier. Angesichts Preis (< 200 $) einer der besten Budget-Drucker: Auto-Bed-Leveling, Direct Extruder, top Qualität, bis 250 mm/s.

Creality Store / Amazon. Mein Detailtest auf der Website.

Montage

Alle 3D-gedruckten Teile bereit – los geht’s.

Teileliste

Mechanik:

Elektronik:

Hinweis: Affiliate-Links.

Spindeltrieb montieren

Zuerst Spindel in Zylinderbasis einsetzen. Dazu 3D-gedruckte Mutter (gleiches Gewinde) auf Spindel schrauben – strammer Sitz gewollt (überträgt gesamte Schubkraft). Mutter hat Bohrung für Gewindeeinsatz + Madenschraube zur Fixierung auf Welle.

Spindel in Zylinderbasis gelagert: zwei Kugellager 22 mm Außendurchmesser. Hinten: Antriebszahnrad (ebenfalls Gewinde, zwei Gewindeeinsätze für Madenschrauben) – kritische Verbindung, darf nicht rutschen.

Unterbaugruppe: Erst Gewindeeinsätze in Zahnrad, Mutter, Zylinderblock einsetzen. Zahnrad und Mutter gegeneinander auf Spindel schrauben (nicht zu fest – Axialkräfte auf Lager). Dann per Madenschrauben an Spindel sichern.

Spindel noch nicht axial fixiert. Deckelplatte auf Zylinderblock → Lager bleiben in Position. Unterbaugruppe fertig: Spindel fest stehend, frei drehbar.

Stange vorbereiten: Hohl für Spindel. Gewindeeinsätze für Verbindung mit Spindelmutter einsetzen. Oben: Führungslager (13/6 mm) auf 3D-gedruckte 6-mm-Hülse, mit M3-Senkschraube 10 mm an Stange fixieren. Stange gleitet nun in Führungsnuten des Zylinders.

Zylinder auf Basisblock montieren. Zuvor Mikro-Endschalter einbauen: Kabel (NC) anlöten (~15 cm), durch Bohrung oben im Zylinder führen, mit zwei M2×8 Schrauben befestigen. Exakt dieser Endschalter nötig, damit Führungslager ihn zum richtigen Zeitpunkt auslöst. Andernfalls Bohrungen/Mechanik anpassen.

Zylinder an Basisblock: Gewindeeinsätze einsetzen, zwei M4×25 Schrauben (nur obere zwei vorerst, untere später mit Getriebe/PCB-Abdeckung).

Stange in Spindelmutter eindrehen. Führungslager in Führungsschienen. Durch Drehen am Hinterrad bewegt sich Stange zurück bis zum Endschalter.

Zylinderdeckel montieren: Vier kleine Lager (9 mm Außendurchmesser), Wellen 3D-gedruckt. Vorsicht beim Einpressen – Teil ist filigran, bricht leicht (passierte mir mehrmals). Lager unterstützen Stange für ruhigen Lauf. Deckel mit vier M4-Schrauben fixieren.

DC-Motor einbauen

DC-Motor einsetzen, mit sechs M3-Schrauben fixieren. Zahnrad auf Motorwelle, per zwei Gewindeeinsätze + Madenschrauben sichern.

Zahnräder passen → Getriebe- und PCB-Abdeckung hinten anbringen. Weitere Gewindeeinsätze in Zylinderbasis. DC-Motor-Kabel anlöten (~20 cm). Durch Bohrung in Basisblock führen (Motor- und Endschalterkabel). Durch zwei Halter an Abdeckung → Kabel fern vom Zahnrad.

Abdeckung an Basisblock: Unten zwei M4-Schrauben ~2–3 mm hineindrehen, Abdeckungshalter dazwischen, dann festziehen. Etwas fummelig, aber Abdeckung sollte klein und einteilig sein – PCB-Halter blockierten Schraubenzugang.

Custom Servo-Controller PCB einbauen

Controllerboard (aus vorherigem Video) einbauen. Hauptkomponente: AS5600, erfasst Winkelposition des Magneten an Abtriebswelle. Hier: Magnet an Ausgangsrad der Spindel. PCB einstecken → Magnet perfekt ausgerichtet mit AS5600.

PCB befestigen: M2-Muttern in Halterschlitze, vier M2-Schrauben anziehen.

Verdrahtung: Motoranschluss an Klemmblock (Polarität prüfen!). Vorher Motor testen (Spannung anlegen → Spindelmechanik prüfen). Endschalter: Masse an Elko-Massepad, NC an SCK-Pin (Digital 13 am ATmega328). Stromklemmblock seitlich an Abdeckung → 5,5-mm-Hohlstecker durch Bohrung. Kühlkörper auf DRV8871. Snap-Fit-Deckel hinten drauf – fertig.

Jetzt beliebiges Potentiometer oder RC-Empfänger an Eingangs-Pins → Linearakktor steuern.

Controller-Details (Schaltplan, PCB) im vorherigen Video – dort anschauen, wenn man Board selbst bauen will.

Schaltplan

Kurz: AS5600 erfasst Aktuatorposition → ATmega328 rechnet → DRV8871 treibt DC-Motor. DRV8871: bis 3,6 A Spitzenstrom. 12V Versorgung → AMS1117 auf 5V für Mikrocontroller/5V-Bauteile. 2-Kanal-DIP-Schalter: Eingabemodus wählen (analog, digital, Serial). Trimmer-Poti: Empfindlichkeit einstellen. Taster: Start/Endposition setzen.

PCB bei PCBWay bestellt: 4 Lagen (mittlere GND), Farbe Weiß, Oberflächenfinish Immersion Gold (kostenlos). Gerber in PCBWay Community.

Alternativ: Ohne Custom-Controller – AS5600 Breakout + Arduino + Motortreiber.

Code

Code des Linearservo-Aktuators:

/* Linear Servo Actuator - Arduino Code by Dejan, www.HowToMechatronics.com
Libraries: AS5600 encoder: https://github.com/RobTillaart/AS5600
PID controller: https://github.com/br3ttb/Arduino-PID-Library/blob/master/PID_v1.h */
#include "AS5600.h"
#include "Wire.h"
#include 
AS5600 as5600; // use default Wire
double Pk1 = 0.65; //speed it gets there
double Ik1 = 0;
double Dk1 = 0.1;
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, Pk1, Ik1, Dk1, DIRECT);
#define motor_IN1 5
#define motor_IN2 6
#define ch1 2
#define setButton 7
#define inputSwitch 3
#define modeSwitch 4
#define limitSwitch 13
int ch1Value;
long encoderValue, desiredValue, pwmValue;
String serialInput = ""; // string to hold input
int serialIntInput;
double totalDistance = 0;
long startPosition = 358;
long endPosition = 6750;
long rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
float angleValue = 0;
float rodPosition;
float positionsArray[100];
int positionsCounter = 0;
long quadrantNumber = 2;
long previousQuadrantNumber = 3;
long numberOfTurns = 0;
float totalAngle = 0;
char incomingByte = 0;
int intInput = 0;
void setup() {
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("AS5600_LIB_VERSION: ");
  Serial.println(AS5600_LIB_VERSION);
  Wire.begin();
  pinMode(motor_IN1, OUTPUT);
  pinMode(motor_IN2, OUTPUT);
  pinMode(setButton, INPUT_PULLUP);
  pinMode(inputSwitch, INPUT_PULLUP);
  pinMode(modeSwitch, INPUT_PULLUP);
  pinMode(limitSwitch, INPUT_PULLUP);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-255, 255);
  myPID.SetSampleTime(20);
  // --- HOMING ----
  while (digitalRead(limitSwitch) != 1) {
    digitalWrite(motor_IN1, LOW);
    analogWrite(motor_IN2, 70);
    encoderValue = as5600.readAngle();
  }
  while (digitalRead(limitSwitch) != 0) {
    analogWrite(motor_IN1, 50);
    digitalWrite(motor_IN2, LOW);
  }
  digitalWrite(motor_IN1, LOW);
  digitalWrite(motor_IN2, LOW);
  startPosition = as5600.readAngle() * 0.087890625;
  endPosition = 6000;
  Setpoint = startPosition;
  // --- HOMING End ---
}
void loop() {
  // Read encoder value - current position
  rodPosition = as5600.readAngle() / 0.001953125; // in millimeters
  // Serial communication mode
  if (digitalRead(modeSwitch) == 0) {
    while (Serial.available() > 0) {
      serialInput = Serial.readString();
      serialInput.trim();
      if (serialInput == "save") {
        positionsArray[positionsCounter] = totalDistance;
        delay(1000);
        positionsCounter++;
      }
      if (serialInput == "clear") {
        memset(positionsArray, 0, sizeof(positionsArray));
        positionsCounter = 0;
      }
      serialIntInput = serialInput.toInt();
      if (serialIntInput != 0) {
        if (serialIntInput < 0) serialIntInput = 0;
        if (serialIntInput > 150) serialIntInput = 150;
        Setpoint = serialIntInput * 45; // mm to degrees (1mm = 45°)
      }
    }
    // Run stored positions
    if (serialInput == "run") {
      while (serialInput != "stop") {
        for (int i = 0; i <= positionsCounter - 1; i++) {
          if (serialInput == "stop") break;
          while (positionsArray[i] > totalDistance + 25 || positionsArray[i] < totalDistance - 25 || pwmValue != 0) {
            Setpoint = positionsArray[i];
            readEncoder();
            runMotor();
          }
          delay(2000);
          while (Serial.available() > 0) {
            serialInput = Serial.readString();
            serialInput.trim();
          }
        }
      }
    }
  }
  // Potentiometer and RC Receiver control mode
  else if (digitalRead(modeSwitch) == 1) {
    if (digitalRead(inputSwitch) == 0) {
      // Analog input - Potentiometer
      desiredValue = analogRead(A0);
      if (desiredValue < 15) desiredValue = 15;
      if (desiredValue > 1008) desiredValue = 1008;
      Setpoint = map(desiredValue, 15, 1008, startPosition, endPosition);
    } else if (digitalRead(inputSwitch) == 1) {
      // Digital input - RC transmitter
      desiredValue = pulseIn(ch1, HIGH, 30000);
      if (desiredValue < 1000 || desiredValue > 2000) desiredValue = 1000;
      Setpoint = map(desiredValue, 1000, 2000, startPosition, endPosition);
    }
    // Confine setpoint limits
    if (Setpoint > endPosition) Setpoint = endPosition;
    if (Setpoint < startPosition) Setpoint = startPosition;
    // Adjusting sensitivity (commented out)
    // Pk1 = analogRead(A2) * 0.002;
    // myPID.SetTunings(Pk1, Ik1, Dk1);
    readEncoder();
    runMotor();
    // Set start and end positions by pressing "set" button
    if (digitalRead(setButton) == LOW) {
      delay(3000);
      if (digitalRead(setButton) == LOW) {
        endPosition = totalDistance;
        while (digitalRead(setButton) != HIGH);
      } else {
        startPosition = totalDistance;
      }
    }
  }
}
void readEncoder() {
  encoderValue = as5600.readAngle() * 0.087890625;
  if (encoderValue >= 0 && encoderValue <= 90) quadrantNumber = 1;
  else if (encoderValue >= 90 && encoderValue <= 180) quadrantNumber = 2;
  else if (encoderValue >= 180 && encoderValue <= 270) quadrantNumber = 3;
  else if (encoderValue >= 270 && encoderValue <= 360) quadrantNumber = 4;
  if (quadrantNumber != previousQuadrantNumber) {
    if (quadrantNumber == 1 && previousQuadrantNumber == 4) numberOfTurns++;
    if (quadrantNumber == 4 && previousQuadrantNumber == 1) numberOfTurns--;
    previousQuadrantNumber = quadrantNumber;
  }
  if (totalDistance >= 0) totalDistance = (numberOfTurns * 360) + encoderValue;
  else totalDistance = (numberOfTurns * 360) + encoderValue;
  Input = totalDistance;
}
void runMotor() {
  myPID.Compute();
  if (Output > 1) {
    pwmValue = Output;
    if (pwmValue < 50 && pwmValue > 15) pwmValue = pwmValue + 40;
    if (pwmValue <= 15) pwmValue = 0;
    analogWrite(motor_IN1, pwmValue);
    digitalWrite(motor_IN2, LOW);
  } else if (Output < 1) {
    pwmValue = abs(Output);
    if (pwmValue < 50 && pwmValue > 15) pwmValue = pwmValue + 40;
    if (pwmValue <= 15) pwmValue = 0;
    digitalWrite(motor_IN1, LOW);
    analogWrite(motor_IN2, pwmValue);
  } else if (Output > -1 && Output < 1) {
    pwmValue = 0;
    digitalWrite(motor_IN1, LOW);
    digitalWrite(motor_IN2, LOW);
  }
}

Code-Erklärung

Loop startet mit Einlesen Encoder (Istposition in mm):

rodPosition = as5600.readAngle() / 0.001953125; // 8mm/4096 = 0,001953125 mm pro Step

Serial-Modus (modeSwitch=0): Serial Monitor auslesen. „save“ → aktuelle Position im Array speichern. „clear“ → Array löschen.

if (serialInput == "save") { positionsArray[positionsCounter] = totalDistance; ... }
if (serialInput == "clear") { memset(positionsArray, 0, sizeof(positionsArray)); ... }

Zahleneingabe (0–150) → Setpoint. Umrechnung mm → Grad: ×45 (1 mm = 45° Drehung bei 8 mm Steigung). Andere Steigung → anderer Faktor.

serialIntInput = serialInput.toInt();
if (serialIntInput != 0) { ... Setpoint = serialIntInput * 45; }

„run“ → gespeicherte Positionen in Schleife abfahren (while/for loops).

if (serialInput == "run") { while (serialInput != "stop") { for ... { while (positionsArray[i] > totalDistance+25 || ...) { Setpoint = positionsArray[i]; readEncoder(); runMotor(); } delay(2000); ... } } }

Potentiometer/RC-Modus (modeSwitch=1): Analog → analogRead(A0) → Setpoint mappen. Digital → pulseIn() von RC-Empfänger → Setpoint mappen.

if (digitalRead(inputSwitch) == 0) { desiredValue = analogRead(A0); ... Setpoint = map(...); }
else { desiredValue = pulseIn(ch1, HIGH, 30000); ... Setpoint = map(...); }

Dann readEncoder() und runMotor() für PID-Regelung.

readEncoder(): RAW-Encoder in Winkel (0–360°), Quadranten-Erkennung für Drehzahlverfolgung (Vollumdrehungen zählen). totalDistance = Input für PID.

Trimmer-Poti (A2) justiert P-Anteil der PID (auskommentiert). runMotor(): PID-Output → PWM für Motor links/rechts/stop.

double Pk1 = 0.65; double Ik1 = 0; double Dk1 = 0.1;

Qualität der Regelung hängt direkt von diesen Werten ab.

Test

Genauigkeitstest: Rückkehr zur Position gut. Millimeterweise Bewegung: 1. Schritt 0,8 mm (statt 1 mm), nächste 4 nahe 1 mm. 4 mm Bewegung ~0,15 mm Abweichung. Rückschlag (Backlash) ~0,25 mm (Spindel/Mutter) + 3D-Druck-Zahnräder + Motorgetriebe. Unter Last größere Abweichung – durch PID-Tuning verbesserbar.

Das war’s für dieses Tutorial. Hoffe, es hat gefallen und du hast was gelernt.

Herstellungsprozess

  1. SolidWorks Feder-Animation: Adaptive Federn in Nockenwellen-Baugruppe
  2. Home Energy Saver: Smarte Stromspar-Steckdose mit Particle Photon & Blynk
  3. Effizienz freisetzen: 6 Hauptvorteile von Palettenregalsystemen
  4. Umfassender Leitfaden zu mechanischen Lagern: Funktion, Typen und Anwendungen
  5. Windkraftanlagen: Typen, Vor- und Nachteile im Überblick
  6. Fortgeschrittenes Tischtennisball-Tracking mit Raspberry Pi und OpenCV
  7. Stoßdämpfer schweißen? Vor- & Nachteile und Sicherheitstipps
  8. Lichtbogen-Schweißen: Verfahren, Typen und Anwendungen
  9. Der komplette Leitfaden zu Sicherungen: Schutz Ihrer Elektronik
  10. Arduino Energiemonitor & Datenlogger (Dr. Wattson, MCP39F521) – Schritt-für-Schritt