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

Jeden DC-Motor in einen individuellen 360°-Servo verwandeln – Schritt-für-Schritt

In diesem Tutorial lernen wir, wie man jeden DC-Motor in einen eigenständigen Custom-Servomotor mit vielen Features verwandelt. Im Gegensatz zu normalen Servos mit begrenzter Bewegung (180° oder 270°) hat dieser uneingeschränkten 360°-Bereich und lässt sich der Drehbereich beliebig einstellen.

Zudem kann der Mittelpunkt (Center Point) des Servos verschoben werden – Center und Range gleichzeitig anpassbar.

Video ansehen oder schriftliche Anleitung unten lesen.

Weitere Features: Einstellbare Empfindlichkeit (Ansprechgeschwindigkeit). Drei Eingabemodi: Analogspannung/Potentiometer, RC-Sender, Serial Port (Winkelwerte per Serial Monitor am PC/Laptop).

Gleichzeitige Steuerung möglich: Serial Monitor Werte eingeben + manuell per RC-Sender bewegen. Servo kennt seine Position jederzeit, im Serial Monitor sichtbar.

Top-Feature: Continuous Rotation Mode. Auch hier Positionserfassung und -steuerung mit unendlicher Drehzahl. Beliebige Position bei beliebig vielen Umdrehungen anfahrbar.

Alles dank 12-Bit-Encoder AS5600 (magnetischer Drehwinkelsensor) und PID-Regelung für DC-Motor.

Ich entwickelte eine Custom-Servo-Controller-Platine mit eigenem Mikrocontroller – alles drauf, um jeden DC-Motor (bis 3,5 A) in Standalone-Servo zu verwandeln. Board mittig auf Abtriebswelle (inkl. Magnet auf Welle), 12V Versorgung → fertig.

Ich führe dich durch den kompletten Bau: Servo-Prinzip, Closed-Loop, PID, Custom PCB & Getriebe Design, Code.

Servomotor Funktionsprinzip

Typischen RC-Servo zerlegen: Kleiner DC-Motor, Controllerplatine, Potentiometer, 3-Draht-Anschluss (2× Strom, 1× Signal), Getriebe für Drehzahlreduktion/Drehmomenterhöhung.

Potentiometer an Abtriebswelle = Positionssensor → gibt Istposition an Controller. Controller regelt Motor basierend auf Sollsignal (Eingang) und Istposition (Rückführung) → Closed-Loop.

Sollposition vs. Istposition → Fehler → Regler → Motor bewegt bis Fehler = 0.

Eigenen Servomotor bauen

Für größeren DC-Motor dasselbe Closed-Loop-Prinzip: Positionssensor an Abtriebswelle + Mikrocontroller für Motoransteuerung.

Einfacher Positionssensor: Potentiometer (wie im RC-Servo). Problem: Begrenzter Drehbereich (270°) → begrenzt Servobereich. Mehrgangpotentiometer bieten mehr Bereich/Auflösung, aber immer noch begrenzt.

Für unbegrenzten Drehbereich: Encoder. Elektromechanische Geräte, die Winkelposition bei unbegrenzter Drehung erfassen. Typen: inkrementell/absolut, optisch/magnetisch/kapazitiv – jeweils Vor-/Nachteile.

AS5600 Encoder – Magnetischer Drehwinkelsensor

Ich wählte magnetischen Encoder AS5600: sehr kompakt, einfach zu implementieren, hohe Präzision. Winziger Chip!

Integrierter Hall-Effekt-Sensor detektiert Änderungen der Magnetfeldrichtung. Magnet an Motorabtriebswelle, 0,5–3 mm Abstand zum Chip.

Bei Drehung erfasst Hall-Sensor Feldänderungen. 12-Bit A/D-Wandler → 4096 Positionen pro Umdrehung (360°). Auflösung: 0,0878° pro Schritt. Beeindruckend, günstig, leicht beschaffbar – ideale Wahl.

Weiter: Mikrocontroller + DC-Motortreiber. DRV8871 (bis 3,5 A) + ATmega328 (SMD-Version für kompakte PCB). Ziel: Kleinste Standalone-PCB mit allem Drum und Dran.

Custom Servomotor Schaltplan

Kompletter Schaltplan dieses Custom-Servos.

Bauteile:

Hinweis: Affiliate-Links.

ATmega328 mit Minimalbeschaltung (16 MHz Quarz, paar Kondensatoren, Widerstand). AMS1117 wandelt 12V → 5V für Mikrocontroller/5V-Bauteile.

AS5600 mit empfohlener Beschaltung (2 Kondensatoren, 2 Pull-ups für I²C). DRV8871: 1 Strombegrenzungswiderstand, 2 Entkopplungskondensatoren. Zwei Potis an Analogeingängen: eines für Drehbereich, eines für Empfindlichkeit. Taster für Center-Point-Einstellung. 2-Wege-DIP-Schalter für Betriebsmoduswahl. Pinheader für Servo-Eingang (Analogspannung oder Digital-PWM von RC-Empfänger) + 5V/GND. Pinheader für Programmierung (SPI + Serial).

Workflow: Eingang (Sollwinkel) an zwei Pins (Analog von Poti oder Digital-PWM von RC-Empfänger) → Mikrocontroller vergleicht mit Istwinkel (AS5600 via I²C) → Fehlerberechnung → PWM an DRV8871 → Motor fährt bis Soll erreicht. Gesamtschaltung 12V, AMS1117 liefert 5V.

PCB Design

PCB so klein wie möglich: 40×40 mm. AS5600 auf Unterseite exakt mittig – für einfache Montage/Ausrichtung auf Abtriebswelle. Restliche Bauteile auf Oberseite – keine Störung.

Bestellt bei PCBWay: Gerber hochladen, Eigenschaften wählen, günstig. 4 Lagen (mittlere GND) – etwas teurer. Nur Farbe Weiß geändert, Immersion Gold (kostenlos) akzeptiert. Gerber in PCBWay Community.

Nach paar Tagen: PCB top Qualität, alles wie designed, Immersion Gold Finish.

Bestückung: Erst kleine SMDs (LED, Kondensatoren, Widerstände). Erste Erfahrung mit so kleinen SMDs – echt schlecht gelaufen. ATmega328 löten: Pins winzig, eng beieinander – irgendwie geschafft. AS5600 auf Rückseite easy, THT-Teile (DIP-Schalter, Potis, Klemmen, Pinheader) easy. Endergebnis: ordentlich.

Passendes Getriebe für DC-Motor und Controllerboard designen.

Custom Servo 3D-Modell

Getriebe in Onshape designed. Design hängt vom DC-Motor ab. Controllerboard auf Rückseite des Getriebes, mittig zur Abtriebswelle ausgerichtet.

Verwendeter DC-Motor: 37 mm Durchmesser, eingebautes Getriebe, 50 U/min Ausgang. Gut für Servo, aber ich wollte niedrigere Drehzahl für mehr Drehmoment → 3-fache Reduktion im Getriebe. Kegelräder (Herringbone) – effizient, 3D-druckfreundlich.

Freie Gestaltungsmöglichkeit: Getriebe ganz nach Motor und gewünschter Ausgangsdrehzahl. Direktwellenantrieb möglich (1:1 Übersetzung für korrekte Positionsverfolgung) oder Riemenantrieb. Unendliche Möglichkeiten.

3D-Modell & STL Download

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

3D-Modell (STEP) sowie STL-Dateien für 3D-Druck hier:

STEP-Datei:

STL-Dateien:

Custom Servo montieren

3D-gedruckte Teile bereit. Dazu M3-Schrauben, Gewindeeinsätze, Lager.

DC-Motor auf Grundplatte: M3×8 Schrauben. Zwei Zahnräder: Kleines direkt auf Motorwelle, großes = Servoausgang. Ausgangswelle zweiteilig: Gewindeeinsätze beidseitig (eine Seite für Zahnrad, andere für Anbauteile). Kleines Zahnrad: Gewindeeinsätze für Madenschrauben zur Welle. Beide Zahnräder gleichzeitig einschieben (Herringbone – nacheinander geht nicht). Kleines Zahnrad per Madenschraube auf Motorwelle fixieren. 12V an Motor → Getriebe testen.

Getriebe fertigstellen: Seitenplatte, Kugellager für Abtriebswelle, Oberdeckel. M3-Gewindeeinsätze in Rückplatte, 20 mm M3-Schrauben für Gesamtbefestigung. Getriebe test → läuft super. Abtriebswelle dreht sich hinten → Magnet für AS5600 einsetzen.

Controllerboard mit M2-Schrauben/Muttern am Getriebe befestigen. AS5600 nun perfekt auf Magnet ausgerichtet – misst Feldänderungen korrekt.

Wichtig: Magnetisierungsrichtung des Permanentmagneten entscheidend. Axial oder diametral magnetisiert → Magnet senkrecht oder parallel zum AS5600 IC positionieren. Ich musste Magnetrichtung ändern, da falsche Magnetisierung für AS5600.

Zwei Drähte an DC-Motor löten, an Controllerklemme anschließen. Strom: Zwei Drähte an Stromklemme, andere Seite DC-Hohlstecker für 12V Netzteil. Fertig – Custom-Servo done.

Controller programmieren

Bootloader auf ATmega328p brennen – ohne versteht er den Code nicht.

Bootloader brennen

Arduino Board nötig (hier Nano). SPI-Verbindung: Passende SPI-Pins Arduino ↔ Controllerboard verbinden.

Arduino IDE: ArduinoISP Beispielsketch öffnen → auf Nano hochladen. Nano ist jetzt ISP-Programmer.

Tools → Programmer: „Arduino as ISP“ → „Bootloader brennen“. Nano-LEDs blinken stark → Erfolg.

Code hochladen

USB-to-UART-Interface-Modul für Code-Upload. Controllerboard hat dedizierte Pins dafür (wie Schaltplan).

Code öffnen, hochladen. Vorher Bibliotheken installieren: AS5600 (Library Manager), PID (Library Manager). Upload → Code auf ATmega328 via USB-UART.

Fertig! Potentiometer anschließen zum Test. Hinweis: Analogeingang geht an „S“-Pin (nicht „A“) – PCB-Layoutfehler: Pins vertauscht an ATmega328. DIP-Schalter auf Analogmodus, Strom an.

Servo folgt Potentiometer – DC-Motor erfolgreich zum Servo verwandelt.

Quellcode

Code des Custom-Servos:

/* Custom-built Servo Motor - 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;
double Pk1 = 2; double Ik1 = 0; double Dk1 = 0.025;
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 centerSet 7
#define inputSwitch 3
#define modeSwitch 4
int ch1Value;
int encoderValue, inputValue, pwmValue;
String inString = "";
int centerAngle = 2047; // 180 degrees
int angleDifference = 0;
int angleValue = 0;
int leftLimit = 30;
int rightLimit = 4067;
int rangeAdjustment = 0;
float sensitivityAdjustment = 0;
float angle = 0;
int quadrantNumber = 2;
int previousQuadrantNumber = 3;
int numberOfTurns = 0;
float totalAngle = 0;
int error = 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(centerSet, INPUT_PULLUP); pinMode(inputSwitch, INPUT_PULLUP); pinMode(4, INPUT_PULLUP);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(-255, 255); myPID.SetSampleTime(20);
}
void loop() {
  encoderValue = as5600.readAngle();
  // Continuous rotation mode
  if (digitalRead(modeSwitch) == 0) {
    while (Serial.available() > 0) {
      int inChar = Serial.read();
      if (isDigit(inChar)) inString += (char)inChar;
      if (inChar == '\n') { Setpoint = inString.toInt(); inString = ""; }
    }
    if (digitalRead(inputSwitch) == 0) {
      inputValue = analogRead(A0);
      if (inputValue < 400) Setpoint -= 0.3;
      if (inputValue < 300) Setpoint -= 0.3;
      if (inputValue < 200) Setpoint -= 0.3;
      if (inputValue > 600) Setpoint += 0.3;
      if (inputValue > 700) Setpoint += 0.3;
      if (inputValue > 800) Setpoint += 0.3;
    } else {
      inputValue = pulseIn(ch1, HIGH, 30000);
      if (inputValue < 1450) Setpoint--;
      if (inputValue < 1350) Setpoint--;
      if (inputValue < 1250) Setpoint--;
      if (inputValue < 1150) Setpoint--;
      if (inputValue > 1550) Setpoint++;
      if (inputValue > 1650) Setpoint++;
      if (inputValue > 1750) Setpoint++;
      if (inputValue > 1850) Setpoint++;
    }
    angle = encoderValue * 0.087890625;
    if (angle >= 0 && angle <= 90) quadrantNumber = 1;
    else if (angle >= 90 && angle <= 180) quadrantNumber = 2;
    else if (angle >= 180 && angle <= 270) quadrantNumber = 3;
    else if (angle >= 270 && angle <= 360) quadrantNumber = 4;
    if (quadrantNumber != previousQuadrantNumber) {
      if (quadrantNumber == 1 && previousQuadrantNumber == 4) numberOfTurns++;
      if (quadrantNumber == 4 && previousQuadrantNumber == 1) numberOfTurns--;
      previousQuadrantNumber = quadrantNumber;
    }
    if (totalAngle >= 0) totalAngle = (numberOfTurns * 360) + angle;
    else totalAngle = (numberOfTurns * 360) + angle;
    Input = totalAngle;
  }
  // Limited Rotation Mode
  else if (digitalRead(modeSwitch) == 1) {
    rangeAdjustment = analogRead(A1);
    leftLimit = 0 + 30 + rangeAdjustment;
    rightLimit = 4097 - 30 - rangeAdjustment;
    if (digitalRead(inputSwitch) == 0) {
      inputValue = analogRead(A0);
      if (inputValue < 15) inputValue = 15;
      if (inputValue > 1008) inputValue = 1008;
      Setpoint = map(inputValue, 15, 1008, -255, 255);
    } else {
      inputValue = pulseIn(ch1, HIGH, 30000);
      Setpoint = map(inputValue, 1000, 2000, -255, 255);
    }
    if (digitalRead(centerSet) == LOW) {
      centerAngle = encoderValue;
      angleDifference = 2047 - encoderValue;
      delay(1000);
    }
    if (centerAngle < 2047) {
      angleValue = encoderValue + angleDifference;
      if (encoderValue < 4097 && encoderValue > (4096 - angleDifference))
        angleValue = encoderValue - 4097 + angleDifference;
    }
    if (centerAngle > 2047) {
      angleValue = encoderValue + angleDifference;
      if (encoderValue >= 0 && encoderValue < abs(angleDifference))
        angleValue = encoderValue + 4097 + angleDifference;
    } else if (centerAngle == 2047) {
      angleValue = encoderValue;
    }
    Input = map(angleValue, leftLimit, rightLimit, -255, 255);
  }
  // Sensitivity adjust
  Pk1 = analogRead(A2) * 0.002;
  myPID.SetTunings(Pk1, Ik1, Dk1);
  myPID.Compute();
  if (Output > 1) {
    pwmValue = Output;
    if (pwmValue < 30 && pwmValue > 5) pwmValue += 30;
    if (pwmValue <= 5) pwmValue = 0;
    digitalWrite(motor_IN1, LOW); analogWrite(motor_IN2, pwmValue);
  } else if (Output < 1) {
    pwmValue = abs(Output);
    if (pwmValue < 30 && pwmValue > 5) pwmValue += 30;
    if (pwmValue <= 5) pwmValue = 0;
    analogWrite(motor_IN1, pwmValue); digitalWrite(motor_IN2, LOW);
  } else if (Output > -1 && Output < 1) {
    pwmValue = 0;
    digitalWrite(motor_IN1, LOW); digitalWrite(motor_IN2, LOW);
  }
}

Code-Überblick

Loop startet mit Encoder-Einlesen:

encoderValue = as5600.readAngle();

Continuous Rotation Mode (modeSwitch=0): Serial Monitor Werte als Setpoint.

while (Serial.available() > 0) { ... Setpoint = inString.toInt(); }

Poti-Modus: Analogwert lesen, Setpoint korrigieren je nach Ausschlag.

if (inputValue < 400) Setpoint -= 0.3; ... if (inputValue > 800) Setpoint += 0.3;

RC-Empfänger: pulseIn() lesen, Setpoint analog korrigieren.

RAW-Encoder in Winkel (×0,087890625), Quadranten-Erkennung für Drehzähler (Vollumdrehungen tracken). totalAngle = Input für PID.

if (quadrantNumber != previousQuadrantNumber) {
  if (quadrantNumber == 1 && previousQuadrantNumber == 4) numberOfTurns++;
  if (quadrantNumber == 4 && previousQuadrantNumber == 1) numberOfTurns--;
  previousQuadrantNumber = quadrantNumber;
}
totalAngle = (numberOfTurns * 360) + angle;
Input = totalAngle;

Limited Rotation Mode (modeSwitch=1): Erst Range-Poti (A1) lesen → left/right Limit setzen.

rangeAdjustment = analogRead(A1);
leftLimit = 30 + rangeAdjustment;
rightLimit = 4097 - 30 - rangeAdjustment;

Poti-Eingang (A0) → Setpoint mappen. RC-Eingang → pulseIn() → Setpoint mappen.

Setpoint = map(inputValue, 15, 1008, -255, 255); // Poti
Setpoint = map(inputValue, 1000, 2000, -255, 255); // RC

Center-Set: Taster gedrückt → aktuelle Encoder-Position als neuen Mittelpunkt speichern.

if (digitalRead(centerSet) == LOW) { centerAngle = encoderValue; angleDifference = 2047 - encoderValue; delay(1000); }

Encoderwerte um angleDifference offseten → angleValue. Dann auf left/right Limit mappen → Input für PID.

Input = map(angleValue, leftLimit, rightLimit, -255, 255);

Empfindlichkeit: Trimmer-Poti (A2) justiert P-Glied. PID rechnen → Output → Motor PWM ansteuern.

Pk1 = analogRead(A2) * 0.002; myPID.SetTunings(Pk1, Ik1, Dk1); myPID.Compute();

Output >1 → rechts, < -1 → links, dazwischen → stop. PWM-Minimum-Anhebung für Anfahrschwelle.

Code nicht optimal, Verbesserungspotenzial. Nachbau: Troubleshooting einkalkulieren (SMD-Löten, PCB-Fehler). Ich brauchte mehrere Anläufe (falsche Verbindungen, PCB-Neuauflage, etc.).

Dieser Artikelabschnitt ist noch im Aufbau, später wieder schauen…

Herstellungsprozess

  1. 65.280 Relais mit Arduino steuern: Erweiterbare IO- & Relais-Lösungen
  2. Jawbreaker: Geschichte, Zutaten und Handwerk eines klassischen Hartbonbons
  3. Automatische Zentralschmieranlagen: Funktionsweise, Typen & Nutzen
  4. Arduino-gesteuerte NeoPixel-Lichtschwerter mit Party-Modi (Kylo Ren & Rey)
  5. Gesteuerter Roboter per Gestensteuerung – Bauen Sie Ihren eigenen Motion-Sensing-Bot
  6. Handwerk und Geschichte der Gitarre: Von antiken Wurzeln zu modernen Meisterwerken
  7. Modellbahn DCC-Zentrale selbst bauen mit Arduino – Kostenlose App inklusive
  8. RFID-basierte Lagerort-Ortung für Raspberry Pi, Arduino & Komponenten
  9. Der moderne Haartrockner: Design, Sicherheit und zukünftige Innovationen
  10. Wesentliche Elemente des physischen Prototypings für die Produktentwicklung