Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATTiny2313][Bascom]Stabilizacja obrotów silnika DC

22 Lut 2010 21:00 4857 11
  • Poziom 16  
    Witam.
    Mam do zrobienia stabilizację obrotów silnika DC (24V, 50W). Na razie zrobiłem regulację obrotów za pomocą PWM-a i pomiar prędkości obrotowej co 100ms. Tylko jak połączyć jedno z drugim aby procek utrzymywał w miarę stałe obroty?
    Próbowałem w taki sposób:
    Code:

    If obroty_zadane > obroty_mierzone Then
      Incr PWM
    Else
      Decr PWM
    End if   

    Niestety nie jest to dobry sposób bo silnik wolno reaguje na zmianę obciążenia a poza tym obroty dość mocno falują.
    Z internetu dowiedziałem się, że najlepiej to zrobić na regulatorze PID. Tylko jak takiego PID-a zrealizować w Bascomie? Czy ktoś mógł by mi to jasno wytłumaczyć?

    Pozdrawiam Jacek
  • Poziom 38  
    Program regulatora PID w Bascomie jest na stronie firmowej MCSElectronic.
    Czy jest dobry- nie wiem.
    to co zrobiłeś- to nie jest PID.
  • Poziom 16  
    Wiem, że to co zrobiłem to nie jest PID. Na stronie MCSElectronic znalazłem dwa programy takiego regulatora z czego jeden ma opisy w jakimś niezrozumiałym dla mnie języku (AN#150). Drugi program (AN#109) jest dla mnie bardziej zrozumiały. Tylko jak obliczoną wartość PID, która będzie liczbą ułamkowa, przełożyć na odpowiednią wartość PWM?
  • Poziom 21  
    u(t)=kp(e(t)+1/Ti•∫e(t)dt+Td•de(t)/dt)
    powyższy wzór określa sygnał wyjściowy z regulatora PID gdzie kp, Ti, Td są nastawami regulatora (są to stałe wartości trzeba je dobrać; z członu różniczkującego "D" raczej zrezygnuj na początku, wystarczy reg. PI);
    e(t)- uchyb regulacji=> wartość zadana - wartość rzeczywista.

    całkę należy aproksymować poprzez sumę:
    ∫e(t)dt=Σe(i)Tp; Tp - czas próbkowania
    w programie po prostu bedzie to zmienna która zawiera sumę uchybu (uchyb e(t) oczywiście liczba typu int)

    W praktyce należało by jeszcze wstawić ograniczenie na część całkującą, aby sumowanie nie "odleciało w kosmos" przy długo utrzymującym się dużym uchybie u(t)

    być może pomoże ci ta funkcja;

    Cytat:

    void Algorithm_PID( float *CurrentTemp)
    {
    static float fIntegral=0;
    static float fPrevious_error=0;
    float x=0;

    Regulator.ferror = Temp.fMean-(*CurrentTemp);
    fIntegral = fIntegral + Regulator.fP*Temp.uiTimeSample*Regulator.ferror/Regulator.fI;

    x = Regulator.fP*(Regulator.ferror + Regulator.fD*(Regulator.ferror-fPrevious_error)/Temp.uiTimeSample);
    Regulator.fOutput_PID = fIntegral + x;

    if(Regulator.fOutput_PID > 0.98*Regulator.uMax_AvergateVlotage)
    {
    fIntegral = 0.98*Regulator.uMax_AvergateVlotage-x;
    Regulator.fOutput_PID = 0.98*Regulator.uMax_AvergateVlotage;
    }
    else if(Regulator.fOutput_PID < 0.02*Regulator.uMax_AvergateVlotage)
    {
    fIntegral = 0.02*Regulator.uMax_AvergateVlotage-x;
    Regulator.fOutput_PID = 0.02*Regulator.uMax_AvergateVlotage;
    }

    Regulator.tx_offset= (uint16_t)(1000000*(acos ((Regulator.fOutput_PID*M_PI/Regulator.uMax_AvergateVlotage)-1))/(100*M_PI));//w us
    if(Regulator.tx_offset>5000)
    {
    Regulator.bFirst_Half=true;
    }
    else
    {
    Regulator.bFirst_Half=false;
    }
    Regulator.tx_offset=0xFFFF-Regulator.tx_offset; //wartosć która jest wpisywana do Timera1


    fPrevious_error = Regulator.ferror;
    }


    regulator wyliczał wartosc czasu offsetu który był wpisywany do timera i w ten sposób następowała regulacja temperatury - poprzez odpowiednie załączenie tyrystora, a więc trochę podobnie jak u Ciebie.
    ___________
    http://pcc.imir.agh.edu.pl/poz16/index.htm
  • Poziom 38  
    W bascomie też masz liczby zmiennoprzecinkowe- np. typ single.
    Jest też konwersja i dzielenie z resztą modulo.
    Tylko Attiny2313 może się w pewnym momencie okazać za mały.
    Ta część całkująca- to w zasadzie ograniczenie od góry PWM- oczywiście nie może być większe niż 100%.
    Znalazłem kiedyś taki link:
    http://elm-chan.org/works/smc/report_e.html
    Ale go nie sprawdzałem jeszcze.
  • Poziom 16  
    Pomału zaczynam łapać o co chodzi z tym regulatorem PI. Ale mam też kilka wątpliwości.
    Na początek załóżmy, że mam sam regulator P.

    1. Aby taki regulator w ogóle działał to uchyb nie może spaść do zera bo
    sygnał wyjściowy = uchyb * wzmocnienie, czy tak?

    2. Im wyższa prędkość zadana tym uchyb powinien być większy aby regulator mógł wystawić na wyjściu większy sygnał PWM?

    3. A co z sytuacją gdy prędkość zadana będzie mniejsza od prędkości zmierzonej? W takim przypadku uchyb wyjdzie ujemny. Jak ten ujemny uchyb pomnożony przez współczynnik wzmocnienia przełożyć na wartość PWM? Czy wartość PWM zmniejszyć np. do zera aż prędkość silnika spadnie poniżej prędkości zadanej?
  • Poziom 38  
    To co napisałeś w pierwszym poście to jest prawie regulator P.
    Prawie- bo nie wiadomo co zrobi jak obroty będą równe zadanym.
    A to co opisałeś- falowanie jest pewnie spowodowane stałą czasową odpowiedzi obiektu- silnika- na sygnał sterujący.
    To jest zwykle najtrudniejsze do obliczenia.
    Łatwiej zmierzyć w tym przypadku.
    Trzeba zrobić stanowisko pomiarowe.
    Dajesz np. PWM 70% i czekasz aż się obroty ustalą.
    Potem dajesz PWM np. 80% i mierzysz czas po jakim obroty się znowu ustalą.
    To pozwoli oszacować czas reakcji obiektu na sygnał sterujący.
    Silnik musi być obciążony tak jak w układzie docelowym.
    Zależność obroty= f(PWM) nie jest liniowa- zwłaszcza przy małym wypełnieniu.
    Tak że ta zależność będzie tyko lokalna.
    W praktyce ma być tak że po np. zwiększeniu wypełnienia czekasz jakiś czas na zwiększenie obrotów i dopiero po tym czasie dalej zwiększasz wypełnienie lub nie.
    Przy dużych zmianach obciążenia silnika zabawa staje się jeszcze lepsza.
  • Poziom 16  
    Nadal nie wiem co zrobić jak prędkość zadana jest mniejsza od prędkości zmierzonej. Uchyb jest ujemny czyli cały człon P też wyjdzie ujemny (człony I i D na razie pomijam). Jak to przełożyć na sygnał PWM? Zmniejszyć do zera aż prędkość silnika spadnie poniżej prędkości zadanej czy może zmniejszyć do jakiejś wartości minimalnej?

    W docelowym układzie silnik ma pracować z trzema prędkościami: 500, 1200 i 2000 obr/min. Pomiar prędkości obrotowej mierzę w czasie 100ms. Procek w czasie tych 100ms zlicza odpowiednio 50, 120 i 200 impulsów z enkodera. Pwm 10bit, czyli zakres 0...1023. Na tym etapie utknąłem i nie wiem jak dalej ruszyć.
  • Poziom 38  
    Jak prędkość zadana jest mniejsza od prędkości zmierzonej to PWM zwiększasz o x.
    Potem odczekujesz y ms
    Mierzysz cały czas.
    Jak jeszcze za mało to znowu zwiększasz o x
    Potem...
    Itd.
    Jak za dużo- to odwrotnie.
    x i y należy dobrać doświadczalnie albo obliczyć teoretycznie na podstawie czasu odpowiedzi układu silnik- obciążenie( czyli moment bezwładności silnika, moment bezwładności przekładni i układu obciążającego silnik- żadna pompa czy wentylator nie zmieni obrotów w nieskończenie krótkim czasie).
    Po wykonaniu obliczeń teoretycznych należy i tak sprawdzić w układzie- czyli dobrać x i y.
    Obliczenia teoretyczne są dobre do wyznaczenia rzędu wielkości.
    A to jaki smar jest w przekładni albo jak mocno ktoś naciągnął pasek klinowy- to są rzeczywiste warunki pracy.
    To co napisał ginar- to jest dużo trudniejsze.
    Obliczenie czasu odpowiedzi układu przy sterowaniu temperaturą- to jest wyzwanie.
  • Poziom 21  
    Powinieneś śledzić dwie wartości :
    1 - prędkość aktualną Va
    2 - zmianę prędkości od poprzedniego pomiaru dV

    dV = Va - Vp ( Vp - prędkość z poprzedniego pomiaru )

    Vp = Va

    jeśli Va < 200 to zwiększasz PWM o 2.
    Może nastąpić przypadek , że mimo zwiększenia PWM prędkość nadal spada ( obciążenie bardzo wzrosło ) wtedy zwiększasz PWM o 4

    jeśli prędkość wzrosła to zwiększasz PWM o 1.

    Jest z tym dużo "zabawy" , możesz zastosować inne przyrosty w zależności od odchyłki . Mniejszy przyrost dla odchyłki <=5% od Vzadanej , większy gdy odchyłka > 5%.
  • Poziom 16  
    Witam.
    Mając trochę wolnego czasu postanowiłem wrócić do zmagań z PIDem. W sieci znalazłem program PIDa w Bascomie na Atmegę8 (maluszek Attiny2313 okazał się niestety za mały). W programie wyłączyłem różniczkowanie - aby było łatwiej. Program działa dość dobrze tzn. obroty utrzymują się na żądanym poziomie ale troszkę oscylują wokół wartości zadanej. Szczerze mówiąc obracam się w tym temacie trochę po macoszemu. Nasunęło mi się kilka pytań:

    1. Wyjście regulatora to PWM 8bit. Czy lepsze byłoby zastosowanie PWM-a 10bit? Bo wydaje mi się, że PWM o większej liczbie "schodków" płynniej sterował by silnikiem.

    2. Pomiar obrotów dokonuję co 100ms. Przy maksymalnej prędkości silnika (3000 obr/min) procesor zlicza 300 impulsów w czasie 100ms. Skoro wyjście regulatora przyjmuje wartości 0...255 to czy wartości wejściowe (obroty zadane i zmierzone) mogą być dowolne czy powinny być odpowiednio wyskalowane aby mieściły się w przedziale 0...255?

    3. Impulsy z enkodera zlicza Timer0. Jednak nawet gdy silnik zasilany jest z osobnego źródła zasilania to wynik wciąż trochę "skacze". Zastanawiam się czy, podczas pracy regulatora, może to mieć wpływ na falowanie obrotów wokół wartości zadanej? Jeśli tak to jak to wyeliminować? Uśrednianie wyniku czy może inne rozwiązanie?
    Poniżej przedstawiam moje wypociny:
    Code:
    $regfile = "m8def.dat"
    
    $crystal = 8000000
    $hwstack = 32
    $swstack = 8
    $framesize = 24
    $baud = 19200


    Config Lcd = 16 * 2
    Config Lcdpin = Pin , Db4 = Portd.5 , Db5 = Portd.6 , Db6 = Portd.7 , Db7 = Portb.0 , E = Portb.7 , Rs = Portb.6

    Config Adc = Single , Prescaler = Auto , Reference = Avcc
    Start Adc

    Dim E As Integer
    Dim Esum As Integer
    Dim Eold As Integer
    Dim Kp As Integer , E_kp As Eram Integer
    Dim Ki As Integer , E_ki As Eram Integer
    Dim Kd As Integer , E_kd As Eram Integer
    Dim Ta As Integer
    Dim P As Integer
    Dim I As Integer
    Dim D As Integer
    Dim Cv As Integer
    Dim Gv As Single

    Dim Obroty As Integer
    Dim Obroty_zad As Single
    Dim Obroty_max As Integer , E_obroty_max As Eram Integer

    Dim Befehl As String * 9
    Dim Bcount As Integer
    Dim Ar(5) As String * 5
    Dim Tekst As String * 5 , Tekst2 As String * 5
    Dim Licz As Byte , Impulsy As Byte
    Dim Odczyt As Word , Pomoc As Integer

    Kp = E_kp
    Ki = E_ki
    Kd = E_kd
    Obroty_max = E_obroty_max
    Ta = 0.1

    E = 0
    Esum = 0
    Eold = 0

    Config Timer0 = Counter , Edge = Rising
    Enable Timer0
    On Timer0 Licz_imp

    Config Timer1 = Timer , Prescale = 256
    On Timer1 Pid
    Timer1 = 62419                               ' 65535 - (8000000/256/Ta)   Ta = 10
    Enable Timer1
    Enable Interrupts
    '62410
    Config Timer2 = Pwm , Compare Pwm = Clear Down , Pwm = On , Prescale = 1

    Cls
    Do
    Input "" , Befehl
    Bcount = Split(befehl , Ar(1) , "-")
       If Ar(1) = "kp" Then
          Kp = Val(ar(2))
          Print "Kp=" ; Kp
          E_kp = Kp
       End If
        If Ar(1) = "ki" Then
           Ki = Val(ar(2))
           Print "Ki=" ; Ki
           E_ki = Ki
       End If
        If Ar(1) = "kd" Then
           Kd = Val(ar(2) )
           Print "Kd=" ; Kd
           E_kd = Kd
       End If
        If Ar(1) = "max" Then
          Obroty_max = Val(ar(2))
          Print "Max=" ; Obroty_max
          E_obroty_max = Obroty_max
       End If
        If Ar(1) = "p" Then
            Print "Kp=" ; Kp ; "         " ; "P=" ; P
            Print "Ki=" ; Ki ; "         " ; "I=" ; I
            Print "Kd=" ; Kd ; "         " ; "D=" ; D
            Print "Esum=" ; Esum
            Print "PWM=" ; Ocr2
       End If
    Loop

    Licz_imp:
    Incr Impulsy
    Return


    Pid:                                         'przerwanie co 100ms
    Timer1 = 62410
    Pomoc = Impulsy                 'obliczanie obrotów rzeczywistych
    Impulsy = 0
    Pomoc = Pomoc * 256
    Pomoc = Pomoc + Timer0
    Timer0 = 0
    Obroty = Pomoc / 3
    Odczyt = Getadc(5)              'obliczanie obrotów zadanych
    Obroty_zad = 100 / 1024
    Obroty_zad = Obroty_zad * Odczyt

    E = Obroty_zad - Obroty                      'uchyb

    P = Kp * E                                   'człon proporcjonalny kp=3

    '******człon całkujący******
    Esum = Esum + E
    If Esum > 500 Then Esum = 500                'ograniczenie sumy uchybu
    If Esum < -500 Then Esum = -500              'aby nie rosło w nieskończoność
    I = Esum * Ki                                'ki=3

    'I = Ki * Ta
    'I = I * Esum

    If I > 600 Then I = 600                      'anti windup
    If I < -600 Then I = -600

    '******człon różniczkujący (nieaktywny)******
    'D = E - Eold
    'D = D / Ta
    'D = D * Kd

    Cv = P + I
    'Cv = Cv + D

    Gv = Obroty_max / 255                        '100/255
    Gv = Gv * Cv

    If Gv < 0 Then Gv = 0
    If Gv > 255 Then Gv = 255
    Ocr2 = Gv

    Eold = E

    Incr Licz
    If Licz = 5 Then
    Licz = 0
    Tekst = Fusing(obroty_zad , "#.##")
    'Tekst2 = Fusing(obroty , "#.##")
    Locate 1 , 1 : Lcd Obroty ; "  "
    Locate 1 , 10 : Lcd Gv ; "     "
    Locate 2 , 1 : Lcd Tekst ; "    "
    Locate 2 , 10 : Lcd E ; "    "
    End If
    Return


    Pozdrawiam Jacek
  • Poziom 21  
    Ta rozdzielczość nie ma tutaj aż takiego znaczenia, ale faktem jest że powiedzmy chcesz osiągnąć 2000 rpm , nominalnie silnik się kręci 6000 rpm to przy 8 bitach zwiększenie PWM o 1 powoduje wzrost obrotów o 23. Przy 10 bitach o 5,8 . Pytanie czy to musi być dokładnie 2000 rpm, może dodaj jakąś histerezę.