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.

XMega128A3 - PID, silnik DC, enkoder.

22 Sty 2017 02:21 1629 34
  • Poziom 13  
    Cześć wszystkim :)
    Zdaję sobie sprawę, że temat trochę już oklepany, ale zauważyłem, że każdy ma inny problem z tym PIDem :)
    Otóż muszę (do jutra wieczór) zaimplementować regulację prędkości obrotowej regulatorem PID dwóch silników DC (Dagu DG01D). Każdy z silników jest wyposażony w enkoder w postaci hallotronu. Na wale silnika osadzony jest magnes neodymowy ośmiopolowy, czyli mam 8 impulsów na obrót.
    Co zrobiłem do tej pory? Mam pomiar szerokości impulsu z enkodera. Oto kod:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Pozostaje sprawa implementacji PIDa. Jak prawie każdy, miałem teorię sterowania na wykładzie, jednakże wiadomo, że wykład jedno, a zrozumienie drugie. Pora więc temat zrozumieć. Znalazłem taki pseudokod obrazujący PID w wersji cyfrowej:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Muszę to teraz odnieść do swojego projektu.
    Silniki są na pokładzie robota, więc nie ma sensu żeby PID regulował jak nie jedzie. Chodzi mi o to, by PID załączał się w momencie komendy uruchamiającej silniki. Czy to jest dobre podejście?
    Kolejna sprawa - silniki są sterowane przy pomocy mostka TB6612FNG, więc mam możliwość podania PWM i myślałem właśnie, żeby procent wypełnienia PWM był wyjściem regulatora. Czy takie podejście jest słuszne?
    Wykonałem też pomiary i przy 100% PWM sygnał z enkodera ma wypełnienie 50% a szerokość impulsu waha się od 50 do 52ms. Dwa silniki i każdy kręci trochę inaczej, co jest normalne. Chciałbym je wyregulować by sygnał z enkodera miał szerokość 60ms, więc powinny się zrównać.

    Mam teraz kłopot jak połączyć to wszystko razem i wykonać PID. Czy output w tym pseudokodzie powyżej to powinna być wartość rejestru CCA/CCB odpowiadającego za współczynnika wypełnienia sygnału PWM?

    Proszę uprzejmie o wskazówki i pozdrawiam.

    Edit: tak sobie myślę o tym PIDzie i jest tak, że moim inputem jest sygnał z enkodera, czyli jego szerokość w mikrosekundach (milisekundach jak po odbiorze długości z kanału podzielę od razu przez tysiąc). Jednakże moim outputem powinien być jakiś procent wypełnienia sygnału PWM dla silnika.
    Napisane jest:
    Kod: c
    Zaloguj się, aby zobaczyć kod
    , czyli odejmuję aktualną szerokość impulsu z zadaną. Jak to jednak pożenić z outputem PIDa, który powinien być procentem PWM/ew. wartością rejestru?
  • Pomocny post
    Użytkownik usunął konto  
  • Poziom 13  
    80 - masz na myśli wyjściowy wsp. wypełnienia PWM?
  • Pomocny post
    Użytkownik usunął konto  
  • Poziom 13  
    Czyli formalnie zaczynam od regulatora typu P, tak? O ile wiem tam nie ma nic o czasie i walczę o zerowy uchyb.
    Ale dalej nie rozumiem niestety jak to przełożyć na PWM silnika.

    Dodano po 10 [minuty]:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Pomijając człony I oraz D mam takie coś. Jeżeli error dąży do zera to output też dąży do zera. A przecież z outputa mam wziąć informację dot. wypełnienia PWM dla silnika. Jak to powiązać? :)

    Dodano po 13 [minuty]:

    Czyli muszę output jakoś dodać/odjąć do wsp. wypełnienia PWM. Ale jak to zrobić żeby miało to ręce i nogi?

    Dodano po 20 [minuty]:

    Output mam z przedziału $$k_{p}[0, SETPOINT]$$ przy czym prawa granica przedziału oznacza PWM = 0%, ale nie znam procentu PWM dla lewej granicy przedziału, czyli dla zerowego uchybu (żądanej wartości).
    Nie widzę kurczę ciągle jak to przeliczyć.
  • Pomocny post
    Użytkownik usunął konto  
  • Poziom 13  
    Chodzi mi o prędkość silników. Fabrycznie są te same, ale się rozjeżdżają delikatnie, normalna sprawa.
    Mam sygnał z enkodera. Na 100% PWM jest szerokość impulsu ok. 50-52ms, wartości się różnią. Za pomocą enkodera i regulatora chcę tak wyregulować PWM obydwu, aby prędości silników odpowiadały szerokości impulsu z enkodera równej 60ms.

    Jakie to drogi?
  • Poziom 13  
    Znam tę notę. Nie widzę jednak tam nic o PWM.
    Jak rozumiem w Get_reference wpisuję wartość szerokości impulsu z enkodera jaką chcę osiągnąć. W Get_measurement zbieram pomiar. Dalej jednak nie wiem jak połączyć to wszystko z wyjściem regulatora i wypełnieniem PWM.
  • Użytkownik usunął konto  
  • Poziom 13  
    Oczywiście, że tak. Nie mam co do tego wątpliwości.
    I jak teraz output powiązać z PWMem? Nie czuję tego czym jest output, do czego on dąży i jak go powiązać z PWMem.
  • Użytkownik usunął konto  
  • Poziom 13  
    Cytat:
    Czyli error to jest różnica między czasem zadanym a zmierzonym. Jeżeli jest ujemno (czyli impulsy są wolniejsze zwiększasz PWM. Jezeli dodatnie to z mniejszasz.


    Oczywiście, to jest jasne.

    Chodzi mi o output regulatora PID, czyli to:
    Kod: c
    Zaloguj się, aby zobaczyć kod
    .
    Nie wiem co mam z tym zrobić.

    Patrząc na sam error i jego znak to PWM mogę zmniejszać/zwiększać zaraz po tej linijce:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Ale przecież po coś są kolejne linijki. I chciałbym zrozumieć jak je należycie wykorzystać.
  • Użytkownik usunął konto  
  • Poziom 13  
    No dobra, więc robimy regulator typu P.
    Kod: c
    Zaloguj się, aby zobaczyć kod

    Error wiadomo skąd jest. Jak należy dobrać Kp? Wartość output ma dążyć do jakiejś konkretnej wartości?
  • Użytkownik usunął konto  
  • Poziom 13  
    O co mi chodzi - mam np. error = 10 000, Kp = 1.04. Output = 10400. Jak uzależnić od tego pwm? Mam zrobić jakieś przeliczenie typu (przykładowo), że jak output jest w przedziale [10000, 20000] to pwm zwiększam/zmniejszam o 10%, jak w przedziale [0,100] to pwm nie zmieniam?
  • Użytkownik usunął konto  
  • Poziom 13  
    Dziękuję, o takie coś mi chodziło :) Napisałem wobec tego takie funkcje:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Jak to wygląda?
  • Użytkownik usunął konto  
  • Poziom 13  
    Piotrus_999 napisał:
    Jezeli zmieści się ona pomiędzy kolejnymi wywołaniami przerwania to ok.

    Czy chodzi Tobie tutaj o to, żeby czas wykonania tej funkcji w przerwaniu był mniejszy niż oczekiwanie na kolejne przerwanie?

    Dodano po 34 [minuty]:

    Zasadniczo coś się reguluje, bo silnik startuje. Ale do 60ms to jeszcze daleko. Na oscyloskopie widzę, że wynik waha mi się od 52 co 54ms. Coś nie tak z funkcjami?

    Dodano po 55 [minuty]:

    Nie działa to jak powinno. Nawet się nie zbliżam do zadanej wartości. Na co jeszcze mogę zwrócić uwagę?
  • Poziom 13  
    Działa. Oto, co zadziałało:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Długość impulsu z enkodera jest odwrotnie proporcjonalna do prędkości silnika, stąd dzielenie. Początkowa wartość actualValue to 65535, gdyż jak silnik stoi to długość impulsu dąży do nieskończoności (która to w naszym przykładzie wynosi tyle ile zmienna zmieści). Regulacja odpalana w przerwaniu.
    Jak silniki nie są za bardzo obciążone (czyli jak robot nie jeździ) to na oscyloskopie regulację widać, że regulacja działa, impuls oscyluje wokół zadanej wartości z jakąś odchyłką. Jak się go postawi na podłodze to zanim ruszy do przodu lekko skręci, jest odczuwalne pierwsze, duże przesterowanie regulatora.
    Czy dodanie członu całkującego zniweluje ten efekt?
  • Użytkownik usunął konto  
  • Poziom 13  
    Niestety zachowanie dalej podobne.
    Próbowałem jeszcze tak - zmienić regulację milisekundami na mikrosekundy. W tym celu musiałem pomnożyć desired_value oraz wzmocnienie kp przez tysiąc. Oprócz tego zmieniłem preskalery w systemie zdarzeń mierzącym mi szerokość impulsu. I co się stało? Właśnie chodzi o to, że nic. Koło lekko zakręci i staje. Próbowałem potem zmienić wszystkie zmienne na jeden typ, konkretnie long int, zmieniłem też typy użytych funkcji na long int, ale dalej to samo. Wzmocnienie jakie mam przy mikrosekundach wynosi kp = 40000000. Za duże liczby jak na avr'y?
  • Użytkownik usunął konto  
  • Poziom 13  
    No tak zgadza się, to zrozumiałem. Spróbuję może pokombinować z innymi wartościami różnicy.
    Masz może jakieś przemyślenia dotyczące poprzedniego postu? Czemu identyczna w treści funkcja, ale o zmienionym typie na long int wraz ze zmienionymi parametrami na long int zachowuje się inaczej?
  • Użytkownik usunął konto  
  • Poziom 13  
    Jest w takim razie jakiś sprytny sposób na operowanie dużymi liczbami w C dla AVR?
  • Użytkownik usunął konto