DC-Motor-Steuerung meistern: Experten-Tipps & Tricks mit PID-Regler
Komponenten und Materialien
| Komponente | Anzahl | Hinweise |
|---|---|---|
| Arduino Due (oder beliebiges Arduino-Board) | 1 | Jedes Arduino-Board möglich |
| Makeblock Me TFT LCD | 1 | Optional – anderes Display oder gar keines möglich |
| Widerstand 4,75 kΩ | 4 | Können je nach Umsetzung variieren |
| Drehpotentiometer (generic) | 4 | 3 Stück optional (für PID-Koeffizienten) |
| PNP-Transistor (General Purpose) | 4 | Typ hängt von der Umsetzung ab |
| DC-Motor (generic) | 1 | |
| Schiebeschalter | 1 | Für Richtungswahl |
| Fotoelektrischer Drehzahlsensor HC-020K | 1 | |
| Breadboard (generic) | 1 | |
| Jumper-Kabel (generic) | 1 |
Apps und Online-Dienste
- Arduino IDE
Über dieses Projekt
Drehzahl- und Richtungssteuerung von DC-Motoren mittels PID-Regler und PWM-Ausgängen
Einführung
Fast alle verfügbaren Projekte steuern Motordrehzahl und -richtung direkt über PWM – selbst über eine Motortreiber-Schaltung. Diese Methode scheitert jedoch, wenn die Drehzahl exakt dem Sollwert entsprechen soll, wegen der „Zwillinge“ Reibung und Trägheit.
(Man sollte den Zwillingen nie die Schuld geben. Was auch immer man tun will – Trägheit lässt Dinge „nachdenken“, bevor sie handeln, Reibung begrenzt Beschleunigung und Geschwindigkeit. Und „Leistung“ ist „nichts“, wenn sie nicht voll kontrolliert ist.)
Wird die Motordrehzahl direkt über PWM angesteuert, weicht die tatsächliche Drehzahl erheblich vom Sollwert ab (Fehler). Die Lösung: PID-Regelung.
PID-Regler
Was ist PID-Regelung? Stellen Sie sich Autofahren vor: Zum Anfahren drücken Sie das Gaspedal stärker als bei konstanter Fahrt. Bei konstanter Geschwindigkeit korrigieren Sie nur Verluste; bei zu starker Beschleunigung lassen Sie leicht los. Das ist auch „effizientes Fahren“.
Der PID-Regler macht genau das: Er liest die Differenz „Fehlersignal (e)“ zwischen Soll- und Istwert. Er hat drei Anteile – Proportional, Integral, Differential – daher der Name. Der P-Anteil definiert die Steigung (Beschleunigung) des Reglers bzgl. des Fehlersignals. Der I-Anteil summiert Fehler über die Zeit, um den Endfehler zu minimieren. Der D-Anteil überwacht die Fehlerbeschleunigung und liefert eine „Korrektur“.
Auf meinem Arduino-Programm ist der PID-Regler als Funktion implementiert:
float controllerPID(float _E, float _Eprev, float _dT, float _Kp, float _Ki, float _Kd) {
float P, I, D;
/* Basismformel: U = _Kp * ( _E + 0.5*(1/_Ki)*(_E+_Eprev)*_dT + _Kd*(_E-_Eprev)/_dT ); */
P = _Kp * _E; // Proportionaler Anteil
I = _Kp * 0.5 * _Ki * (_E+_Eprev) * _dT; // Integraler Anteil
D = _Kp * _Kd * (_E-_Eprev) / _dT; // Differentialer Anteil
return (P+I+D);
}
Der finale Ausgabewert ergibt sich aus aktuellem Ausgangswert plus PID-Regler-Ausgang:
/* Fehlersignal, PID-Regler-Ausgang und finaler Ausgang (PWM) an Motor */
E = RPMset - RPM;
float cPID = controllerPID(E, Eprev, dT, Kp, Ki, Kd);
if (RPMset == 0) OutputRPM = 0;
else OutputRPM = OutputRPM + cPID;
if (OutputRPM < _minRPM) OutputRPM = _minRPM;
DC-Motor-Versorgungsschaltung
Einen DC-Motor direkt vom Arduino-Ausgang zu treiben, ist nie empfehlenswert – der Motor braucht deutlich mehr Strom als der Mikrocontroller liefern kann. Relais haben mechanische Teile und können langfristig ausfallen. Besser: Transistoren.
DC-Motoren werden durch Strom, nicht Spannung angetrieben. Ich entschied mich für vier BC307A PNP-Bipolartransistoren in Brückenschaltung zur Stromrichtungssteuerung (ein NPN-BC337-Satz wäre wegen höherer Kollektorströme besser, war aber nicht verfügbar).
Da Motorströme durch den Emitter-Kollektor-Pfad fließen, müssen die Transistoren annähernd gleiche DC-Stromverstärkung (hfe) haben. Zum Testen kann man folgende Schaltung nutzen und Transistoren mit ähnlicher Stromablesung am Amperemeter selektieren. Dabei sind zu beachten:
- Basis-Emitter-Einschaltspannung (VBEon) – Mindestspannung am Basisanschluss zum Einschalten.
- Typische DC-Stromverstärkung (hfe) bei Kollektorstrom nahe Motorstrom: hfe = IC / IB.
- Maximaler kontinuierlicher Kollektorstrom (ICmax) – Motorstrom darf diesen Betrag nicht überschreiten. BC307A reicht für meinen 70-mA-Motor (ICmax = 100 mA).
Basiswiderstand berechnen:
- Trigger-Spannung (VT) = Arduino-Ausgangsspannung (hier 3,3 V beim Due).
- Benötigter Basisstrom: IBreq = IM / hfe.
- Spannung am Widerstand: VR = VT – VBEon.
- Widerstandswert: R = VR / IBreq = (VT – VBEon) * hfe / IM.
In meinem Fall: IM = 70 mA, hfe ≈ 140, VBEon = 0,62 V, VT = 3,3 V → R ≈ 5.360 Ω (ich verwendete 4.900 Ω aus 2,2 kΩ + 2,7 kΩ für volle Drehzahlabdeckung und nur ~0,6 mA Basisstrom).
Richtungswechsel und wichtige Hinweise
Um die Drehrichtung umzukehren, muss der Stromfluss umgekehrt werden. Eine Brückenschaltung mit vier Transistoren macht dies: PWM-Ausgang #2 aktiviert T1A/T1B, PWM-Ausgang #3 aktiviert T2A/T2B – der Strom durch den Motor kehrt sich um.
Wichtig: Beim Start ziehen Motoren einen deutlich höheren Anlaufstrom (ca. 130 % des Nennstroms bei kleinen Motoren). Wird die Polarity während des Betriebs sofort umgekehrt, fließen extreme Ströme, da der Motor noch nicht stillsteht – Netzteil oder Motorwicklungen können beschädigt werden. Bei Transistortreibern ist das weniger kritisch, da diese den Strom begrenzen.
Ich habe im Programm eine Sicherheitsroutine eingebaut: Bei Richtungswechsel während des Laufs werden beide PWM-Ausgänge auf Null gesetzt und gewartet, bis der Motor vollständig stillsteht.
if (Direction != prevDirection) {
analogWrite(_chMotorCmdCCW, 0);
analogWrite(_chMotorCmdCW, 0);
do {
RPM = 60 * (float)readFrequency(_chSpeedRead, 4) / _DiscSlots;
} while (RPM > _minRPM);
}
Drehzahlmessung
Ich nutze den günstigen HC-020K-Drehzahlsensor. Er liefert Pegel an seiner Versorgungsspannung (Datenblatt: 5 V), aber der Arduino Due verträgt nur 3,3 V. Ich speise ihn direkt von 3,3 V – es funktioniert. Die folgende Funktion liest die Frequenz:
int readFrequency(int _DI_FrequencyCounter_Pin, float _ReadingSpeed) {
pinMode(_DI_FrequencyCounter_Pin, INPUT);
byte _DigitalRead, _DigitalRead_Previous = 0;
unsigned long _Time = 0, _Time_Init;
float _Frequency = 0;
if ((_ReadingSpeed <= 0) || (_ReadingSpeed > 10)) return (-1);
else {
_Time_Init = micros();
do {
_DigitalRead = digitalRead(_DI_FrequencyCounter_Pin);
if ((_DigitalRead_Previous == 1) && (_DigitalRead == 0)) _Frequency++;
_DigitalRead_Previous = _DigitalRead;
_Time = micros();
} while (_Time < (_Time_Init + (1000000 / _ReadingSpeed)));
}
return (_ReadingSpeed * _Frequency);
}
Der HC-020K hat 20 Schlitze. Die gelesene Frequenz geteilt durch 20 ergibt Umdrehungen pro Sekunde; mal 60 ergibt RPM:
RPM = 60 * (float)readFrequency(_chSpeedRead, 4) / _DiscSlots;
Grafische Darstellung
Zur Anzeige von Eingängen und Ergebnissen nutze ich ein Makeblock Me TFT LCD mit der Funktion CommandToTFT(), um den seriellen Anschluss zentral zu ändern. Funktionen Cartesian_Setup(), Cartesian_ClearPlotAreas() und Cartesian_Line() bereiten den Plotbereich vor, löschen ihn bei Erreichen des Zeitachsenendes und zeichnen Kurven. Details entnehmen Sie dem Makeblock-Handbuch.
Abschluss
Ich stelle den Code mit und ohne Grafikfunktionen bereit, damit Sie die reine Drehzahl-/Richtungssteuerung oder die Version mit Grafik prüfen können. Im Code finden sich weitere Erklärungen.
Normalerweise lässt sich ein unbe lasteter DC-Motor nicht unter 10–20 % Nenndrehzahl regeln. Mit PID-Regelung ist nach dem Anlauf sogar ca. 5 % möglich.
Edit (25.02.2018): Bei Verwendung von NPN- statt PNP-Transistoren beachten Sie die umgekehrte Stromrichtung: Bei PNP fließt Strom vom Emitter zum Kollektor (E+ C−), bei NPN vom Kollektor zum Emitter (C+ E−).
Code
Zwei Versionen stehen zur Verfügung:
- Code mit grafischen Funktionen (vollständig, für Makeblock Me TFT LCD)
- Code ohne grafische Funktionen (nur PID-Steuerung, universell einsetzbar)
Beide Versionen sind im Projektarchiv als .ino-Dateien enthalten.
Schaltpläne
Es handelt sich um einen Prototyp zur Erklärung der PID-geregelten DC-Motor-Drehzahlsteuerung und der Richtungswechsel-Betrachtungen.
Herstellungsprozess
- DC-Motor-Performance steigern mit Wolfram-Kupfer Legierungen
- Sensor-gesteuerte Audio-Effekte mit dem Satellite CCRMA Kit bauen
- Zwei Schrittmotoren mit Arduino Nano & Joystick steuern – Einfaches Tutorial
- 8×8 LED-Matrix mit Arduino Uno meistern: Schritt-für-Schritt-Anleitung
- Smartes Temperatur-Monitoring für Schulen – Arduino, Raspberry Pi, Sigfox & ThingSpeak
- Effiziente 8-Bit-I/O-Port-Bibliothek für Arduino – Digitale Steuerung erweitern
- Arduino 64-Tasten-Prototyp-Keyboard-Matrix – Eigenes Keyboard mit Schieberegistern bauen
- 2,8″ TFT-Shield für Arduino Nano – 320×240 SPI-Display mit Touch
- Isolierter Analogeingang für Arduino: Spannung/Strom galvanisch trennen
- Smartes Indoor-Navigations-Roboter-Kit für Arduino-Projekte