Forum: Mikrocontroller und Digitale Elektronik PID-Regler


von sascha (Gast)


Lesenswert?

Hallo zusammen,

ich möchte zwei E-Motoren (12V) die beide über PWM angesteuert werden 
und beide tachoscheiben besitzen irgendwie in ihrer Drehzahl 
synchronisieren, egal ob digital oder analog.
Wer hat ideen wie dies möglichst genau zu bewerkstelligen ist ?
 P.S. Am liebsten via P.I.D.-regelung da sie schon an einem Prozessor 
hängen.
Dank' vorab für alle Antworten.
Gruss Sascha

von afzelia (Gast)


Lesenswert?

Hallo!

Anbei mal ein Software -PID Regler für einen SPS. Das ist zwar nicht 
kompatibel, aber du kannst zumindest erkenn wie sowas gemacht wird


cu Afzelia



(*&nbsp;PID&nbsp;controller&nbsp;/&nbsp;PID-Regler&nbsp;*)<BR>
FUNCTION_BLOCK&nbsp;PID<BR>
VAR_INPUT<BR>
  ACTUAL&nbsp;:REAL; 
(*&nbsp;actual&nbsp;value,&nbsp;process&nbsp;variable&nbsp;/&nbsp;Istwer 
t&nbsp;*)<BR>
  SET_POINT:REAL;    (*&nbsp;desired&nbsp;value,&nbsp;<FONT 
COLOR=#0000FF>Set</FONT>&nbsp;point&nbsp;/&nbsp;Sollwert&nbsp;*)<BR>
  KP:REAL;      (*&nbsp;proportionality&nbsp;<FONT 
COLOR=#0000FF>Const</FONT>.&nbsp;/&nbsp;Proportionalit&auml;tskoeff.&nbs 
p;&nbsp;*)<BR>
  TN:DWORD; 
(*&nbsp;reset&nbsp;time&nbsp;/&nbsp;Nachstellzeit&nbsp;<FONT 
COLOR=#0000FF>In</FONT>&nbsp;msec&nbsp;*)<BR>
  TV:DWORD; 
(*&nbsp;rate&nbsp;time,&nbsp;derivative&nbsp;time&nbsp;/&nbsp;Vorhaltzei 
t&nbsp;<FONT  COLOR=#0000FF>In</FONT>&nbsp;msec&nbsp;*)<BR>
  Y_OFFSET:REAL;    (*&nbsp;offset&nbsp;<FONT 
COLOR=#0000FF>For</FONT>&nbsp;manipulated&nbsp;variable&nbsp;/&nbsp;Stel 
lwert-Nullpunktsverschiebung&nbsp;*)<BR>
  Y_MIN:REAL;      (*&nbsp;minimum&nbsp;value&nbsp;<FONT 
COLOR=#0000FF>For</FONT>&nbsp;manipulated&nbsp;variable&nbsp;/&nbsp;mini 
maler&nbsp;Stellwert&nbsp;*)<BR>
  Y_MAX:REAL;      (*&nbsp;maximum&nbsp;value&nbsp;<FONT 
COLOR=#0000FF>For</FONT>&nbsp;manipulated&nbsp;variable&nbsp;/&nbsp;maxi 
maler&nbsp;Stellwert&nbsp;*)<BR>
  MANUAL:BOOL;    (*&nbsp;<FONT 
COLOR=#0000FF>True</FONT>:&nbsp;manual&nbsp;/&nbsp;<FONT 
COLOR=#0000FF>True</FONT>:&nbsp;manueller&nbsp;Betrieb&nbsp;*)<BR>
  RESET:BOOL;<BR>
END_VAR<BR>
VAR_OUTPUT<BR>
  Y:REAL;        (*&nbsp;manipulated&nbsp;variable,&nbsp;<FONT 
COLOR=#0000FF>Set</FONT>&nbsp;value&nbsp;/&nbsp;Stellgr&ouml;&szlig;e&nb 
sp;*)<BR>
  LIMITS_ACTIVE:BOOL:=<FONT COLOR=#0000FF>False</FONT>;<BR>
  OVERFLOW:BOOL:=<FONT COLOR=#0000FF>False</FONT>;<BR>
END_VAR<BR>
VAR<BR>
  CLOCK:TON;<BR>
  I:&nbsp;INTEGRAL;<BR>
  D:&nbsp;DERIVATIVE;<BR>
  TMDIFF:&nbsp;DWORD;<BR>
  <FONT COLOR=#0000FF>Error</FONT>:&nbsp;REAL;<BR>
  INIT:&nbsp;BOOL:=<FONT COLOR=#0000FF>True</FONT>;<BR>
END_VAR<BR>
<BR>
<BR>
<BR>
<BR>
<FONT COLOR=#0000FF>If</FONT>&nbsp;TN&gt;0&nbsp;<FONT 
COLOR=#0000FF>And</FONT>&nbsp;KP&lt;&gt;&nbsp;0&nbsp;<FONT 
COLOR=#0000FF>And</FONT>&nbsp;(<FONT 
COLOR=#0000FF>Not</FONT>&nbsp;OVERFLOW&nbsp;<FONT 
COLOR=#0000FF>Or</FONT>&nbsp;RESET&nbsp;<FONT 
COLOR=#0000FF>Or</FONT>&nbsp;MANUAL)&nbsp;<FONT 
COLOR=#0000FF>Then</FONT><BR>
  <FONT COLOR=#0000FF>Error</FONT>&nbsp;:=&nbsp;SET_POINT-ACTUAL; 
(*&nbsp;Regeldifferenz&nbsp;*)<BR>
<BR>
  <FONT COLOR=#0000FF>If</FONT>&nbsp;RESET&nbsp;<FONT 
COLOR=#0000FF>Or</FONT>&nbsp;MANUAL&nbsp;<FONT 
COLOR=#0000FF>Or</FONT>&nbsp;INIT&nbsp;<FONT COLOR=#0000FF>Then</FONT> 
(*&nbsp;Reset&nbsp;oder&nbsp;Handbetrieb&nbsp;*)<BR>
    I(RESET:=<FONT COLOR=#0000FF>True</FONT>);<BR>
    D(RESET:=<FONT COLOR=#0000FF>True</FONT>);<BR>
    OVERFLOW:=<FONT COLOR=#0000FF>False</FONT>;<BR>
    LIMITS_ACTIVE:=<FONT COLOR=#0000FF>False</FONT>;<BR>
    <FONT COLOR=#0000FF>If</FONT>&nbsp;RESET&nbsp;<FONT 
COLOR=#0000FF>Or</FONT>&nbsp;INIT&nbsp;<FONT 
COLOR=#0000FF>Then</FONT><BR>
      Y&nbsp;:=&nbsp;Y_OFFSET;<BR>
      INIT:=<FONT COLOR=#0000FF>False</FONT>;<BR>
    END_IF;<BR>
    TMDIFF:=0;<BR>
  <FONT COLOR=#0000FF>Else</FONT><BR>
    CLOCK; 
(*&nbsp;Timer&nbsp;abfragen&nbsp;*)<BR>
    TMDIFF:=TIME_TO_DWORD(CLOCK.ET); 
(*&nbsp;Zeitdifferenz&nbsp;seit&nbsp;letztem&nbsp;Aufruf&nbsp;*)<BR>
  END_IF;<BR>
<BR>
  <FONT COLOR=#0000FF>If</FONT>&nbsp;TMDIFF&gt;0&nbsp;<FONT 
COLOR=#0000FF>Then</FONT><BR>
    CLOCK(<FONT COLOR=#0000FF>In</FONT>:=<FONT 
COLOR=#0000FF>False</FONT>); 
(*&nbsp;Timer&nbsp;neu&nbsp;starten&nbsp;*)<BR>
    CLOCK(PT:=t#1h,&nbsp;<FONT COLOR=#0000FF>In</FONT>:=<FONT 
COLOR=#0000FF>True</FONT>);<BR>
<BR>
    D(<FONT COLOR=#0000FF>In</FONT>:=<FONT 
COLOR=#0000FF>Error</FONT>,&nbsp;TM:=TMDIFF,&nbsp;RESET:=<FONT 
COLOR=#0000FF>False</FONT>); 
(*&nbsp;Differential&nbsp;absch&auml;tzen&nbsp;*)<BR>
    I(<FONT COLOR=#0000FF>In</FONT>:=<FONT 
COLOR=#0000FF>Error</FONT>,&nbsp;TM:=TMDIFF,&nbsp;RESET:=<FONT 
COLOR=#0000FF>False</FONT>); 
(*&nbsp;Integral&nbsp;absch&auml;tzen&nbsp;*)<BR>
<BR>
    OVERFLOW&nbsp;:=&nbsp;I.OVERFLOW;<BR>
    <FONT COLOR=#0000FF>If</FONT>&nbsp;<FONT 
COLOR=#0000FF>Not</FONT>&nbsp;OVERFLOW&nbsp;<FONT 
COLOR=#0000FF>Then</FONT><BR>
      Y:=Y_OFFSET+KP*(<FONT 
COLOR=#0000FF>Error</FONT>+I.OUT/TN+D.OUT*TV);<BR>
      <FONT COLOR=#0000FF>If</FONT>&nbsp;Y&gt;1E30&nbsp;<FONT 
COLOR=#0000FF>Or</FONT>&nbsp;Y&lt;-1E30&nbsp;<FONT 
COLOR=#0000FF>Then</FONT> 
(*&nbsp;Overflow&nbsp;steht&nbsp;bevor,&nbsp;darf&nbsp;aber&nbsp;eigentl 
ich&nbsp;nicht&nbsp;passieren&nbsp;*)<BR>
        OVERFLOW:=<FONT COLOR=#0000FF>True</FONT>;<BR>
      END_IF;<BR>
<BR>
      LIMITS_ACTIVE:=<FONT COLOR=#0000FF>False</FONT>;<BR>
      <FONT COLOR=#0000FF>If</FONT>&nbsp;Y_MAX&gt;Y_MIN&nbsp;<FONT 
COLOR=#0000FF>And</FONT>&nbsp;Y&gt;Y_MAX&nbsp;&nbsp;<FONT 
COLOR=#0000FF>Then</FONT> 
(*&nbsp;Stellwert-Obergrenze&nbsp;&uuml;berschritten&nbsp;*)<BR>
        Y:=Y_MAX;<BR>
        LIMITS_ACTIVE:=<FONT COLOR=#0000FF>True</FONT>;<BR>
        I(<FONT COLOR=#0000FF>In</FONT>:=-<FONT 
COLOR=#0000FF>Error</FONT>,TM:=TMDIFF,RESET:=<FONT 
COLOR=#0000FF>False</FONT>); 
(*&nbsp;Integral&nbsp;korrigieren&nbsp;*)<BR>
      END_IF;<BR>
<BR>
      <FONT COLOR=#0000FF>If</FONT>&nbsp;Y_MAX&gt;Y_MIN&nbsp;<FONT 
COLOR=#0000FF>And</FONT>&nbsp;Y&lt;Y_MIN&nbsp;<FONT 
COLOR=#0000FF>Then</FONT> 
(*&nbsp;Stellwert-Untergrenze&nbsp;unterschritten&nbsp;*)<BR>
        Y:=Y_MIN;<BR>
        LIMITS_ACTIVE:=<FONT COLOR=#0000FF>True</FONT>;<BR>
        I(<FONT COLOR=#0000FF>In</FONT>:=-<FONT 
COLOR=#0000FF>Error</FONT>,TM:=TMDIFF,RESET:=<FONT 
COLOR=#0000FF>False</FONT>); 
(*&nbsp;Integral&nbsp;korrigieren&nbsp;*)<BR>
      END_IF;<BR>
    END_IF;<BR>
  <FONT COLOR=#0000FF>Else</FONT><BR>
    CLOCK(PT:=t#1h,IN:=<FONT COLOR=#0000FF>True</FONT>);<BR>
  END_IF;<BR>
<BR>
END_IF;<BR>

von afzelia (Gast)


Lesenswert?

Sorry - Ich dachte das Forum kann HTML.

Hier nochmal als reiner Text:

(* PID controller / PID-Regler *)
FUNCTION_BLOCK PID
VAR_INPUT
  ACTUAL :REAL;    (* actual value, process variable / Istwert *)
  SET_POINT:REAL;    (* desired value, set point / Sollwert *)
  KP:REAL;      (* proportionality const. / Proportionalitätskoeff.  *)
  TN:DWORD;      (* reset time / Nachstellzeit in msec *)
  TV:DWORD;      (* rate time, derivative time / Vorhaltzeit in msec *)
  Y_OFFSET:REAL;    (* offset for manipulated variable / 
Stellwert-Nullpunktsverschiebung *)
  Y_MIN:REAL;      (* minimum value for manipulated variable / minimaler 
Stellwert *)
  Y_MAX:REAL;      (* maximum value for manipulated variable / maximaler 
Stellwert *)
  MANUAL:BOOL;    (* TRUE: manual / TRUE: manueller Betrieb *)
  RESET:BOOL;
END_VAR
VAR_OUTPUT
  Y:REAL;        (* manipulated variable, set value / Stellgröße *)
  LIMITS_ACTIVE:BOOL:=FALSE;
  OVERFLOW:BOOL:=FALSE;
END_VAR
VAR
  CLOCK:TON;
  I: INTEGRAL;
  D: DERIVATIVE;
  TMDIFF: DWORD;
  ERROR: REAL;
  INIT: BOOL:=TRUE;
END_VAR

IF TN>0 AND KP<> 0 AND (NOT OVERFLOW OR RESET OR MANUAL) THEN
  ERROR := SET_POINT-ACTUAL;                ( Regeldifferenz )

  IF RESET OR MANUAL OR INIT THEN              (* Reset oder Handbetrieb 
*)
    I(RESET:=TRUE);
    D(RESET:=TRUE);
    OVERFLOW:=FALSE;
    LIMITS_ACTIVE:=FALSE;
    IF RESET OR INIT THEN
      Y := Y_OFFSET;
      INIT:=FALSE;
    END_IF;
    TMDIFF:=0;
  ELSE
    CLOCK;                        ( Timer abfragen )
    TMDIFF:=TIME_TO_DWORD(CLOCK.ET);          (* Zeitdifferenz seit 
letztem Aufruf *)
  END_IF;

  IF TMDIFF>0 THEN
    CLOCK(IN:=FALSE);                  ( Timer neu starten )
    CLOCK(PT:=t#1h, IN:=TRUE);

    D(IN:=ERROR, TM:=TMDIFF, RESET:=FALSE);        (* Differential 
abschätzen *)
    I(IN:=ERROR, TM:=TMDIFF, RESET:=FALSE);        (* Integral 
abschätzen *)

    OVERFLOW := I.OVERFLOW;
    IF NOT OVERFLOW THEN
      Y:=Y_OFFSET+KP*(ERROR+I.OUT/TN+D.OUT*TV);
      IF Y>1E30 OR Y<-1E30 THEN            (* Overflow steht bevor, darf 
aber eigentlich nicht passieren *)
        OVERFLOW:=TRUE;
      END_IF;

      LIMITS_ACTIVE:=FALSE;
      IF Y_MAX>Y_MIN AND Y>Y_MAX  THEN        (* Stellwert-Obergrenze 
überschritten *)
        Y:=Y_MAX;
        LIMITS_ACTIVE:=TRUE;
        I(IN:=-ERROR,TM:=TMDIFF,RESET:=FALSE);    (* Integral 
korrigieren *)
      END_IF;

      IF Y_MAX>Y_MIN AND Y<Y_MIN THEN          (* Stellwert-Untergrenze 
unterschritten *)
        Y:=Y_MIN;
        LIMITS_ACTIVE:=TRUE;
        I(IN:=-ERROR,TM:=TMDIFF,RESET:=FALSE);    (* Integral 
korrigieren *)
      END_IF;
    END_IF;
  ELSE
    CLOCK(PT:=t#1h,IN:=TRUE);
  END_IF;

END_IF;

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.