Dobry regulator prędkości silników jest niezbędny do nawigacji w labiryncie. Robot powinien być w stanie zarówno robić małe skręty podczas jazdy w celu korekty ustawienia oraz skręty o 45, 90 i 180 stopni podczas eksploracji labiryntu i speed runu. Mój regulator powstał już jakiś czas temu, co opisywałem tu, tu i tu. Strojenie zajęło mi sporo czasu w końcu uzyskałem jakieś sensowne wyniki, jednak miałem wrażenie, że powinno to działać lepiej. Postanowiłem więc jeszcze raz przejrzeć implementację i znalazłem kilka grubych baboli.

Błąd w algorytmie PID

Jak możemy przeczytać w większości opracowań, algorytm PID składa się z jednego wzoru mającego postać:

u(t) = e(t) \cdot k_p + sum_e(t) \cdot k_i + \Delta e(t) \cdot k_d 

Mamy więc trzy człony:

  • Proporcjonalny kp zależny od uchybu sterowania e(t), czyli aktualnej różnicy między wartością zadaną a zmierzoną.
  • Całkujący ki zależny od sumy uchybów od początku sterowania.
  • Różniczkujący kd zależny od zmiany uchybu w stosunku do poprzedniej iteracji.

Przecież to tylko jedno równianie. Co tu może być nie tak?

Jak to jest w praktyce?

Otóż problem polega na tym, że te wszystkie opracowania pomijają zwykle jedną ważną rzecz. Jest to postać teoretyczna dla układu znormalizowanego, gdzie w stanie ustalonym sterowanie przy zerowym uchybie ma wartość u(t) = 0. Skoro uchyb jest zerowy, wszystkie trzy człony dadzą wartość 0. Jednak w praktyce zdecydowana większość rzeczywistych układów regulacji nie spełnia tego założenia. No bo jeżeli oczekujemy, że silnik będzie się kręcić z jakąś prędkością, musimy mu podać na wejście jakieś napięcie.

Dlatego algorytm trzeba zmienić tak, aby sterował zmianą sygnału sterującego, a nie jego wartością bezwzględną:

\Delta u(t)  = e(t) \cdot k_p + sum_e(t) \cdot k_i + \Delta e(t) \cdot k_d 

\Delta u(t) = u(t) - u(t-1)

u(t) = u(t-1) + e(t) \cdot k_p + sum_e(t) \cdot k_i + \Delta e(t) \cdot k_d 

Po tej zmianie PID dla prędkości liniowej robota dawał się bardzo łatwo nastroić. Nie musiałem analizować żadnych wykresów. Wystarczyło jedynie odczytywać na żywo pomiary z terminala i wprowadzać małe korekty. To ogromna poprawa wobec tego co było wcześniej.

Swoją drogą to ciekawe, że wcześniej mimo błędu jednak udawało się uzyskać jakieś efekty. Co prawda nastawy były zupełnie różne od obliczeń teoretycznych, a żeby je znaleźć musiałem spędzić długie godziny. Widziałem też inne projekty, gdzie wyliczone wartości teoretyczne zupełnie nie pokrywają się z praktyką, więc specjalnie mnie to nie dziwiło. Model jest uproszczony, są nieliniowości, zakłócenia, możliwe są błędy normalizacji względem czasu próbkowania. Powodów może być wiele. To smutne, że zupełnie nietrafione wartości teoretyczne były dla mnie czymś normalnym.

Błędne połączenie regulatorów

Drugi błąd popełniłem podczas projektowania układu regulacji. Przewidziałem w nim trzy regulatory PID:

  • Prędkość liniowa dla lewego silnika.
  • Prędkość liniowa dla prawego silnika.
  • Prędkość kątowa.

Wartość sterowania podawanego ostatecznie na silnik miała postać:

u_l(t)  = PID_l(t) - PID_\alpha(t) -offset

u_r(t)  = PID_r(t) + PID_\alpha(t) +offset

Gdzie u_l i u_r to wartości PWM podawane na lewy i prawy silnik, PID_l i PID_r to wyniki PID dla lewego i prawego silnika, a PID_\alpha to wynik PID dla prędkości kątowej. Offset jest dodawany, aby robot nie skręcał, gdy to samo sterowanie jest podane na oba silniki.

Taki układ z trzema regulatorami jest bez sensu. Regulatory dla lewego i prawego silnika biorą jako wartość zadaną tylko prędkość liniową i starają się zniwelować wpływ regulatora prędkości kątowej. Dlatego właśnie osiągnięcie zadanego kąta jest praktycznie niemożliwe.

Pomieszałem tutaj dwie koncepcje projektowania takiego układu regulacji. Jedną z nich jest zrobienie regulatorów dla lewego i prawego silnika, gdzie wartość zadana uwzględnia ruch postępowy i obrotowy. Drugą są regulatory dla prędkości liniowej i dla prędkości obrotowej bez podziału na lewy i prawy silnik. Właśnie ten drugi sposób mam zamiar docelowo wykorzystać.

Podsumowanie

Kiedy znalazłem te błędy, moją pierwszą myślą było: Jak to możliwe, że do tej pory cokolwiek działało? Co więcej taką błędną wersję PID zdarzyło mi się już kilka razy zaimplementować i zawsze układ sterowania był na tyle uprzejmy, że udawało się znaleźć sensowne nastawy. Tutaj z regulatorem prędkości liniowej też tak było. Dopiero regulator prędkości kątowej okazał się trudniejszy. Mam nauczkę, żeby nie tracić czujności, bo błędy mogą się czaić w najbardziej niespodziewanych miejscach. Przy okazji jest do dobry przykład, ile warta jest teoria bez praktyki. Wszędzie podawany jest uproszczony wzór, który w praktycznych zastosowaniach zwykle jest błędny.