Skocz do zawartości

Regulator PID - wątpliwości


danioto

Pomocna odpowiedź

Hej,
od niedawna próbuję zmierzyć się z regulatorem PID, oczywiście w LineFollower'ze, jednak mam kilka wątpliwości co do wdrożenia technik, które szeroko oferują różnorakie strony, z różnorakimi specjalistami. Przejdźmy do rzeczy:

1) Mam pytanie odnośnie członu całkującego. Na przykład, podpatrując stronę pololu, chcę wprowadzić zmienną przechowującą sumę błędów (całkę). Jeżeli 'Error' to zmienna oznaczająca aktualny błąd, to według powyższej strony należy wprowadzić:

Integrate+=Error;

Ale jeżeli teraz założymy, że jedziemy na samym PI oraz napotkaliśmy jakiś ostry zakręt. W tym momencie całka szybko rośnie w jedną ze stron (załóżmy, że czujniki na prawo mają dodatnie wagi, a na lewo ujemne), robot coraz szybciej zaczyna skręcać chcąc powrócić na tor. Jak już powróci to szybko przejdzie na drugą stronę linii i od powyższej sumy zacznie dodawać ujemne wagi (odejmować). Zanim całka dojdzie do zera, albo lepiej, przekroczy je, to minie trochę czasu. W ten sposób, człon całkujący wprowadza ogromną bezwładność robota. Czy nie lepiej byłoby, na przykład przy zmianie znaku Error zerować całkę? Czy dobrze rozumuję?

2) Następne pytanie odnosi się do członu różniczkującego. Załóżmy znowu, że podglądamy stronę pololu. Wtedy według nich jest to:

Deriverate=Error - LastError;
LastError=Error;

Ale tutaj też mam wątpliwości. Załóżmy, że przepiszemy to równanie do naszego kodu. Wtedy jadąc na przykład na wprost cały czas jesteśmy na środkowych czujnikach. Jeżeli wchodzimy na przykład w lekki zakręt, to tylko przez jedną pętlę, LastError będzie różny od Error, a dalej będą sobie równe. Czyli człon różniczkujący praktycznie nie będzie występował. Czy to ja coś źle rozumuję, czy jest jakiś kawałek kodu, którego nie zauważyłem?

Byłbym wdzięczny za odpowiedzi, bo czuję się trochę, jak we mgle, a mój robot błądzi jeszcze bardziej 😋😉

Pzdr.

Link do komentarza
Share on other sites

Na początek powiem Ci, że jest bardzo wiele różnych struktur regulatorów PID, a do tego jeszcze najróżniejsze metody całkowania czy różniczkowania itp.

Czy nie lepiej byłoby, na przykład przy zmianie znaku Error zerować całkę? Czy dobrze rozumuję?

Rozumiesz dobrze ale Twoje rozwiązanie nie wydaje się być najlepsze. Sprawę całki powinien załatwić sam regulator przy dobrze dobranych parametrach Ki czy Ti w zależności od struktury, a ponadto można dodać do regulatora filtry typu anti-windup itp.

W ten sposób, człon całkujący wprowadza ogromną bezwładność robota.

Może wprowadzić, ale właśnie to zależy od nastaw regulatora.

Jeżeli wchodzimy na przykład w lekki zakręt, to tylko przez jedną pętlę

Aby nastała taka sytuacja to Twój robot musiał by być albo bardzo szybki, albo regulator za wolny więc tu moim zdaniem jest problem z odpowiednim dobraniem częstotliwości pracy regulatora do dynamiki robota.

Człon różniczkujący jak sama nazwa wskazuje "działa" na podstawie pochodnej uchybu więc tylko wtedy gdy uchyb się zmienia.

Czyli człon różniczkujący praktycznie nie będzie występował.

Więc człon różniczkujący będzie występował w zależności od dynamiki zmiany uchybu.

Link do komentarza
Share on other sites

Jeśli dobrze zrozumiałem, to całka ma zostać taka jaka jest, tylko trzeba ją odpowiednio wysterować. Rozumiem.

Jeśli chodzi zaś o człon różniczkujący, to nie do końca rozumiem. Prawdziwe różniczkowanie ma sens tylko w przypadku funkcji ciągłej, a praca uC zawsze będzie 'próbkowana'. Skoro tak, to załóżmy, że mamy średniej szybkości uC (by nie popadać w skrajności) oraz, że dysponujemy w miarę dobrze wyregulowanym algorytmem. Wtedy mieliśmy uchyb na przykład przez 200 pętli równy 4. W 201 przejściu pętli uchyb zmienił się na 5, czyli teraz wspomniana wcześniej wartość 'Deriverate' jest równa 5-4=1, następnie przypisujemy LastError=Error, co sprawia, że w następnym 202. przejściu pętli Error-LastError=0, bo nie wierzę, że w czasie jednej dwóch pętli odczyt z czujników może się zmienić dwa razy (uC 72MHz)... Jak to jest z tym różniczkowaniem?

Link do komentarza
Share on other sites

Prawdziwe różniczkowanie ma sens tylko w przypadku funkcji ciągłej, a praca uC zawsze będzie 'próbkowana'.

Dlatego korzysta się z dyskretnych metod różniczkowania np. metoda różnic regresywnych.

Skoro tak, to załóżmy, że mamy średniej szybkości uC (by nie popadać w skrajności) oraz, że dysponujemy w miarę dobrze wyregulowanym algorytmem. Wtedy mieliśmy uchyb na przykład przez 200 pętli równy 4.W 201 przejściu pętli uchyb zmienił się na 5, czyli teraz wspomniana wcześniej wartość 'Deriverate' jest równa 5-4=1, następnie przypisujemy LastError=Error, co sprawia, że w następnym 202. przejściu pętli Error-LastError=0, bo nie wierzę, że w czasie jednej dwóch pętli odczyt z czujników może się zmienić dwa razy (uC 72MHz)... Jak to jest z tym różniczkowaniem?

Jest to mało prawdopodobne przy dobrze dobranym regulatorze, bo jak pisałem wcześniej czlon I dąży do eliminacji uchybu. Ale nawet jeżeli tak się zdarzy to w chwili zmiany uchybu zadziała człon różniczkujący jak napisałeś - i właśnie o to w tym chodzi.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Wybacz, ale totalnie nie rozumiem o co Ci chodzi...

Jest to mało prawdopodobne przy dobrze dobranym regulatorze, bo jak pisałem wcześniej czlon I dąży do eliminacji uchybu

Czyli jak dobrze dobiorę nastawy to jakimś magicznym sposobem zaraz po pętli, w której nastąpiła zmiana uchybu, nastąpi kolejna pętla ze zmianą? To byłoby bez sensu, bo tym bardziej nie pozwalałoby na stabilną jazdę...

Ale nawet jeżeli tak się zdarzy to w chwili zmiany uchybu zadziała człon różniczkujący jak napisałeś - i właśnie o to w tym chodzi.

Kolejna rzecz, która wydaje mi się lekko nielogiczna. Jeżeli mam rdzeń taktujący z prędkością 72MHz, to załóżmy, że moja pętla programowa (wczytywanie wartości z czujników, obliczanie nastaw itd.) trwa 100, albo nawet 1000 tyknięć zegara, to nadal trwa ona 72000 część sekundy, jeżeli właśnie robot zauważył, że nastąpiła zmiana uchybu, to wyliczy jakąś wartość poprawki na silniki. Następnie przejdzie do kolejnej pętli, w której już tej poprawki nie da (uchyb nie zmienił się od ostatniej pętli) i wyliczy wartość poprawki z członu D równą 0. Dołączając do tego bezwładność silników, nawet nie zauważymy, że człon D jest aktywowany...

Muszę coś źle rozumować. Ten człon musi jakoś inaczej wyglądać, bo postać:

Deriverate=Error-LastError;
LastError=Error;

absolutnie mnie nie przekonuje i według moich prób logicznego myślenia nie ma najzwyczajniej sensu.

Link do komentarza
Share on other sites

Nie bardzo rozumiem Twój problem z członem I. Jednak uważam stosowanie członu całkującego w LF'ach za przerost formy nad treścią. Jak wcześniej zostało zauważone główną cechą członu I jest wprowadzenie do układu astatyzmu (zerowy uchyb ustalony). Dzieje się to kosztem dużych przeregulowań (nawet utratą stabilności) lub długim czasem regulacji. Miałoby to zastosowanie przy długich prostych. Jednak trasy po których scigają się roboty są kręte. Nie ma sensu na tak krótkie odcinki prostych starać się o zerowy uchyb kosztem szybkości regulacji.

Natomiast jeżeli chodzi o człon D to może rozjaśni Ci coś mój wywód:

Zakładając, że sygnał z czujników odczytujesz binarnie(0 lub 1) można przyjąć uproszczenie, że cały system jest ciągły, a pomiary dyskretne - znacznie większe interwały czasu są pomiędzy zmianą czujnika, który jest na linii a wykonaniem pętli. Wtedy pochodną jest tak jak mówisz różna od zera tylko w momencie skoku (zmiany czujnika).

Jednak jeżeli weźmiesz pod uwagę odczyt z wartość ADC, bądź bardzo gęsto ułożone czujniki wtedy przebieg pomiaru(uchybu) staje się bardziej gładki - odstępy między kolejnymi zmianami wartości uchybu maleją. Zazwyczaj nie zdarzy się tak, że kolejne pomiary będą takie same. Idąc tym tokiem myślenia można zauważyć, że funkcja uchybu staje się coraz bardziej zbliżona do ciągłej, a jej pochodna jest miarą jej stromość. Im bardziej stroma ta funkcja (większa zmiana) tym mocniejsza odpowiedź członu D.

Ogólnie Twoje rozumowanie było poprawne, bo bardzo wolny system pomiarowy w szybkich i dynamicznych obiektach znacznie utrudnia (uniemożliwia) poprawne wykorzystanie regulatora PID. Dlatego wydawało Ci się to nie logiczne.

Mam nadzieję, że trochę rozjaśniło Ci to sprawę.

Link do komentarza
Share on other sites

Twoje rozumowanie kling wydaje mi się logiczne, jednak nie do końca zgodne z prawdą.

Zazwyczaj nie zdarzy się tak, że kolejne pomiary będą takie same.

Zliczyłem stosunek pętli, w których uchyb zmienił się, do pętli w których pozostał taki sam i wyszło mi ledwie 3 % (100 tyś. do 3 tyś.), dlatego wydaje mi się, że nie można przyjąć, że uchyb zmienia się dynamicznie i prawie ciągle... Wydaje mi się, że jedynym logicznym sposobem na to, by takiemu zjawisku zapobiec jest wprowadzenie kilku zmian w strukturze członu D. Człon D ma za zadanie 'przewidzenie' szybkości zmian uchybu, dlatego najlepiej jest mierzyć ilość pętli, w których uchyb jest taki sam, wtedy jednoznacznie dostaniemy szybkość jego zmiany. Algorytmicznie można byłoby wprowadzić zmienną 'IloscStara' oraz 'IloscNowa'. 'IloscStara' byłaby to ilość pętli poprzedniej wartości uchybu, ona właśnie wchodziłaby w skład obliczenia wartości poprawki, zaś 'IloscNowa' zliczałaby ilość pętli aktualnego uchybu, po to, by po jego zmianie przypisać ją do zmiennej 'IloscStara'. Czy to ma rację bytu?

Link do komentarza
Share on other sites

Rozumiem, ze wyliczasz sterowanie w petli glownej programu? Moim zdaniem nie ma to sensu, poniewaz miedzy kolejnymi pomiarami uchyb jest staly. o ile dla czlonu kp nie ma to najmniejszego znaczenia to takie podejscie psuje idee czlonu I i D. mianowicie, tak jak mowisz po jednej petli czlon D ma wartosc zero, a czlon I sumuje uchyby, na ktore faktycznie nie ma wplywu. Dlatego, tez sugerowalbym przeliczanie sterowania w jednokrotnie, zaraz po wykonaniu kazdego pomiaru i trzymanie wartosci sterowania (predkosci silnikow) az do kolejnego pomiaru.

Link do komentarza
Share on other sites

Rozumiem, że funkcja od czujników wyzwala pomiary, czeka na ich zakończenie i zapisuje je do pewnej zmiennej? Jeżeli tak jest to spełnia to moją koncepcję, ale nieco dziwi mnie Twój wynik - tylko co 30 pomiar jest inny...

Link do komentarza
Share on other sites

Nie wiem, czy Cię dobrze zrozumiałem. Moja główna mniej więcej wygląda tak:
while (1)
{
   Wczytaj_Czujniki();
   Oblicz_Nastawy();
}

Nie rozumiem co sugerujesz uczynić?

To co przedstawiłeś nie ma prawa działać. niestety ale brakuje Ci podstaw.

Każdy regulator musi działać z określoną stałą częstotliwością tak samo jak każda dyskretna metoda całkowania czy różniczkowania.

Ponadto jeżeli mikrokontroler jest taktowany częstotliwością 72MHz to pokazany przez Ciebie regulator będzie pracował w MHz. Tak duża częstotliwość powoduje powstanie zbyt małego stosunku sygnału do szumu przez co regulator PID zamienia się w dwustanowy.

Link do komentarza
Share on other sites

Funkcja na nic nie czeka. Dokonuje odczytu stanu czujników i wychodzi. Nie rozumiem również, dlaczego ten wynik miałby dziwić.

Również nie rozumiem, dlaczego nie ma to podstaw do działania. Szczególnie ciekawym jest fakt, że przy trochę zmienionej idei członu D, regulator, pełny PID zaczął dzisiaj naprawdę nieźle działać, mimo, że nie ma podstaw do działania. Aby pokazać stałość interwału regulatora mam dokonać kolejnych podobnych do wcześniejszego 'eksperymentów'?

P.S.

Nie każdy regulator potrzebuje stałego interwału, ale to nie jest sedno tematu.

Link do komentarza
Share on other sites

Przetworniki A/C działają z dużo mniejszą częstotliwością niż jest taktowany zegar uC. Dlatego pętla główna programu zdąży obrócić kilka razy zanim pojawią się nowe wyniki pomiarów.

Link do komentarza
Share on other sites

Nie używam wbudowanego przetwornika ADC, właśnie po to, by nie tracić czasu. Używam komparatorów o czasie próbkowania 300 ns. Dlatego główna pętla programu dlatego obraca kilka razy, bo faktycznie w ciągu tych 300 ns sygnał z czujników się nie zmienił.

Link do komentarza
Share on other sites

Pierwsza podstawowa rzecz na którą powinno się zwracać uwagę przy wszystkich artykułach dotyczących PID w line followerach jest fakt, że to nie jest to jego główne zadanie! Żeby nadawać się do LF trzeba ten algorytm specjalnie zaadaptować.

Sygnał sprzężenia zwrotnego (z czujników linii) w LFie ma bardzo małą rozdzielczość. Nawet jeżeli zastosujesz 20 czujników to i tak nie oznacza to 20 bitowej rozdzielczości. Możesz dzięki temu uzyskać jedynie kilka kombinacji w zależności od szerokości rozstawienia. Ta mała rozdzielczość jest sporym utrudnieniem, szczególnie jeśli chcesz pracować przy tak wysokiej częstotliwości. Poza tym nie znasz modelu sterowanego obiektu i nie masz za bardzo możliwości jego wyznaczenia. Przez to twoje szanse na dobranie odpowiednich nastaw poszczególnych członów maleją. Do tego dochodzą jeszcze utrudnienia programistyczne związane na przykład z dyskretyzacją i możliwością przepełnienia poszczególnych zmiennych.

To tyle jeżeli chodzi o ogólne uwagi dotyczące problemów z PIDami w LF. Z rzeczy praktycznych, widzę, że w kodzie z pierwszego posta nie uwzględniasz wag poszczególnych członów. W twoim wypadku oba będą mieć wartość 1 co na pewno nie będzie dobrym rozwiązaniem. W dyskretnym sterowniku PID wagi poszczególnych członów powinny być znormalizowane względem częstotliwości próbkowania.

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.