Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

DC-motorbeheersing onder de knie: Expert Tips & Trucs met PID-regeling

Onderdelen en Benodigdheden

Arduino Due (elk Arduino-board werkt) 1
Makeblock Me TFT LCD (optioneel, ander display of geen display mogelijk) 1
Weerstand 4,75 kΩ (waarden kunnen variëren) 4
Draaipotentiometer (3 zijn optioneel voor PID-coëfficiënten) 4
Algemene PNP-transistor (bijv. BC307A) 4
DC-motor 1
Schuifschakelaar (voor richtingskeuze) 1
Fotoelektrische snelheidssensor HC-020K 1
Breadboard en jumperdraden 1

Apps en Online Diensten

  • Arduino IDE

Over dit Project

Snelheids- en richtingsregeling van DC-motoren met PID-regelaar en PWM-uitgangen

Inleiding

Bijna alle projecten regelen motorsnelheid en -richting door direct PWM naar de motor te sturen (vaak via een stuurcircuit). Deze methode faalt echter als de snelheid precies moet overeenkomen met de gewenste waarde, door de "tweelingbroers" wrijving en tragheid. Zonder regeling zal de werkelijke snelheid altijd afwijken van de instelwaarde (fout). De oplossing: PID-regeling.

PID-regelaar

Een PID-regelaar werkt als het besturen van een auto: bij starten treedt men het gaspedaal dieper in dan tijdens constante snelheid. Men corrigeert snelheidsverlies en laat het gaspedaal los bij overmatige versnelling. De PID-regelaar doet precies hetzelfde:

  • Proportioneel (P): Bepaalt de helling (versnelling) van de uitgang ten opzichte van de fout.
  • Integrerend (I): Sommeert fouten in de tijd om de uiteindelijke fout te minimaliseren.
  • Differentierend (D): Reageert op de versnelling van de foutsignaal en voert een correctie uit.

Op mijn Arduino-programma is de PID-regelaar geïmplementeerd als functie:

float controllerPID(float _E, float _Eprev, float _dT, float _Kp, float _Ki, float _Kd) {
  float P, I, D;
  P = _Kp * _E; // Proportioneel
  I = _Kp * 0.5 * _Ki * (_E + _Eprev) * _dT; // Integrerend
  D = _Kp * _Kd * (_E - _Eprev) / _dT; // Differentierend
  return (P + I + D);
}

De uiteindelijke PWM-uitgang wordt bepaald door de PID-uitgang op te tellen bij de huidige uitgang:

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 Voedingsschakeling

Een DC-motor mag nooit direct vanuit een Arduino-aansluiting gevoed worden. Transistoren zijn nodig. Ik koos voor vier BC307A PNP-transistoren in een H-brugconfiguratie voor richtingsomschakeling. Let op: transistors moeten vergelijkbare DC-stroomversterking (hfe) hebben. De basisspanning (VBEon), hfe en maximale collectorstroom (ICmax) bepalen de basisweerstand.

Formule voor basisweerstand: R = (VT - VBEon) * hfe / IM

In mijn geval: IM = 70mA, hfe ≈ 140, VBEon = 0,62V, VT = 3,3V (Arduino Due) → R ≈ 5360Ω (ik gebruikte 4900Ω).

Richtingsomkeer en Belangrijke Opmerkingen

Om de richting om te keren, keert men de stroomrichting om via de H-brug. Echter, bij plotselinge polariteitsomkeer tijdens draaien treedt de motor een hoge opstartstroom op (tot 130% van nominaal), wat de voeding of spoelen kan beschadigen. Mijn software lost dit op: bij richtingswijziging worden beide PWM-uitgangen op nul gezet en wacht het programma tot de motor volledig stilstaat.

if (Direction != prevDirection) {
  analogWrite(_chMotorCmdCCW, 0);
  analogWrite(_chMotorCmdCW, 0);
  do {
    RPM = 60 * (float)readFrequency(_chSpeedRead, 4) / _DiscSlots;
  } while (RPM > _minRPM);
}

Snelheidsmeting

Ik gebruik de goedkope HC-020K snelheidssensor (20 gleuven). De sensor levert pulsen op 5V-niveau, maar mijn Arduino Due accepteert maximaal 3,3V. Ik voedde de sensor vanaf de 3,3V-uitgang van de Due – het werkt. De frequentie-inleesfunctie:

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);
}

RPM = 60 * frequentie / 20 (aantal gleuven).

Grafische Weergave (Optioneel)

Voor visualisatie gebruikte ik een Makeblock Me TFT LCD met eigen functies voor assen, plotten en wissen. Deze vallen buiten de kern van deze handleiding.

Conclusie

Normaal kan een DC-motor niet lager dan 10-20% van de nominale snelheid geregeld worden. Met PID-regeling is bij onbelaste motor ongeveer 5% haalbaar na opstart.

Toevoeging (25 feb 2018): Bij gebruik van NPN-transistoren in plaats van PNP: stroomrichting is omgekeerd (Collector→Emitter). Polarisatie: PNP = E(+) C(-), NPN = C(+) E(-).

Code

Code met Grafische Weergave

Volledige code met TFT-functies (zie origineel voor complete listing).

Code zonder Grafische Weergave (Kern: PID + Motorsturing)

/* I/O Toewijzingen */
int _chSpeedSet = A0, _chKp = A1, _chKi = A2, _chKd = A3;
int _chMotorCmdCCW = 3, _chMotorCmdCW = 2;
int _chSpeedRead = 24, _chDirection = 25;

/* Constanten */
#define _minRPM 0
#define _maxRPM 6000
#define _DiscSlots 20

/* Globale Variabelen */
boolean Direction, prevDirection;
float RPM=0, RPMset=0, OutputRPM=0, Kp=0, Ki=0, Kd=0;
float Kpmax=2, Kimax=1, Kdmax=1, E=0, Eprev=0, dT=1;

/* Functies: readFrequency(), controllerPID() – zie boven */

void setup() {
  analogReadResolution(12);
  pinMode(_chDirection, INPUT);
  pinMode(_chMotorCmdCCW, OUTPUT);
  pinMode(_chMotorCmdCW, OUTPUT);
  analogWrite(_chMotorCmdCCW, 0);
  analogWrite(_chMotorCmdCW, 0);
  Direction = digitalRead(_chDirection);
  prevDirection = Direction;
}

void loop() {
  int InitTime = micros();
  Kp = Kpmax * (float)analogRead(_chKp) / 4095;
  Ki = Kimax * (float)analogRead(_chKi) / 4095;
  Kd = Kdmax * (float)analogRead(_chKd) / 4095;
  Direction = digitalRead(_chDirection);
  RPM = 60 * (float)readFrequency(_chSpeedRead, 4) / _DiscSlots;
  RPMset = 5000 * (float)analogRead(_chSpeedSet) / 4095;

  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;
  if (OutputRPM > _maxRPM) OutputRPM = _maxRPM;

  if (Direction != prevDirection) {
    analogWrite(_chMotorCmdCCW, 0);
    analogWrite(_chMotorCmdCW, 0);
    do { RPM = 60 * (float)readFrequency(_chSpeedRead, 4) / _DiscSlots; }
    while (RPM > _minRPM);
  }

  if (Direction == HIGH) analogWrite(_chMotorCmdCCW, (int)(255 * OutputRPM / _maxRPM));
  else analogWrite(_chMotorCmdCW, (int)(255 * OutputRPM / _maxRPM));

  Eprev = E;
  prevDirection = Direction;
  dT = float(micros() - InitTime) / 1000000.0;
}

Schema's

Prototype-schema voor DC-motor snelheidsregeling met PID en richtingsomkeer. Zie afbeelding in originele project.

Productieproces

  1. Sensor-gestuurde Audio-effecten Bouwen met de Satellite CCRMA Kit
  2. Twee Stappenmotors Sturen met Arduino Nano & Joystick – Simpele Tutorial
  3. Een 8×8 LED-matrix beheersen met Arduino Uno: Stap-voor-stap handleiding
  4. Slim Temperatuurmonitoring Systeem voor Scholen: Nauwkeurig, Real-time en Beveiligd
  5. Efficiënte 8-bit IO-poort bibliotheek voor Arduino – Uitbreiding digitale controle
  6. Arduino 64-toets Prototoetsenbord Matrix – Bouw een Aangepast Toetsenbord met Shift Registers
  7. Hoogwaardige 2,8″ TFT Shield voor Arduino Nano – 320×240 SPI Display
  8. Geïsoleerde analoge ingangsschakeling voor Arduino bouwen
  9. Bouw een Kosteneffectieve Bliksemdetector met Arduino Uno
  10. Slim Indoor Navigatie Robot Kit voor Arduino Projecten
  11. DC-motor Prestaties Verbeteren met Tungsten-Koper Legeringen