RTV forum PL | NewsGroups PL

Optymalne strojenie PID dla silnika z enkoderem na Pi Pico zjawiska oscylacji?

PID - jeszcze raz

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Optymalne strojenie PID dla silnika z enkoderem na Pi Pico zjawiska oscylacji?

Goto page Previous  1, 2, 3

J.F
Guest

Sat Jan 31, 2026 5:50 pm   



On Sat, 31 Jan 2026 13:19:25 +0100, Mirek wrote:
Quote:
W dniu 24.01.2026 o 20:04, Waldek Hebisch pisze:
Bez członu "całkowego" prawie niemożliwe jest uzyskanie naprawdę
małego błedu.
Już się o tym przekonałem, i jakoś dało się ustabilizować z niezerowym
Ki, ale nie jestem do końca usatysfakcjonowany. Silnik wyraźnie rusza z
kopyta, zapiernicza i hamuje przed celem, zwykle nie trafia idealnie i
widać, że człon I po chwili dopiero wolniutko dociąga do celu.

Zwiększenie Ki przyspiesza to, ale prędzej czy później wprowadza układ w
oscylacje.

No tak to działa.
Nie udaje się trafić tak, żeby szybko dociągał i bez oscylacji?

Jeśli widzisz, że "wolniutko dociąga do celu", to chyba trzeba go
przyśpieszyć.

Quote:
Mały update i garść przemyśleń:
Próbowałem przepisać to i sprawdzić:
https://youtu.be/FJwgDaSsob8?t=664
Nie działa - enkoder gubi kroki, te przerwania chodzą jak chcą. Nie wiem
jak mogło mu to działać, może miał inną wersję i kupę szczęścia.

Obsluga enkodera w Pythonie?
A jakies maksymalnej częstotliwości kroków się spodziewasz?

Quote:
U mnie enkoder działa na PIO, ale jest (był) problem z utratą
rozdzielczości i długim czasem dostępu.
Przypadkiem znalazłem to:
https://forum.core-electronics.com.au/t/rotary-encoder-for-rp2040-board-in-arduino-pico-core/18120/3
Czyli okazuje się, że wystarczy dopisać parę nop-ów żeby kod ładował się
poprawnie tam gdzie powinien i mam dwukrotnie większą rozdzielczość.
Przy okazji okazało się że tutaj:

if(StateMachine.rx_fifo()>0:
pozycja_z_enkodera=StateMachine.get()

działa tak sto razy szybciej niź:

StateMachine.exec("in_(x, 32)")
pozycja_z_enkodera=StateMachine.get()
które miałem w poprzednim kodzie.

A co się dziwisz, że analiza tekstu "in_ (x, 32)" trwa?
Szczególnie, jak jeszcze w Pythonie oprogramowane? :-)

Quote:
Mogłem teraz radykalnie zwiększyć częstotliwość przeliczania PID-a...
czy coś to zmieniło? Nie specjalnie. Nadal jest problem przy małych
błędach - wtedy wyraźnie słychać kwantyzację enkodera. Są szarpnięcia
przy poszczególnych krokach i do tego jakby trochę losowe. Zastanawiam
się, czy to nie jest wina złej obsługi PWM tzn, co się dzieje jeśli się
zmienia wartość PWM w dowolnym momencie? - powinien skrócić go lub
wydłużyć jeśli jeszcze jest czas, jeśli nie, zacząć generować nowy czas
od nowego okresu. No chyba, że ten PWM ma być generowany symetrycznie,
to tylko od nowego okresu.

Zastanawiam się jeszcze, czy na tą kwantyzację przy małym błędzie nie
pomógł by jakiś filtr - może na samym członie D?

Jak pisałem - z D jest pewien kłopot.

Quote:
Jeszcze przy okazji:

jeśli sterowanie = P + I + D
to:
I = poprzednie_I + błąd*Ki
czy:
I = Ki*(poprzednie_I + błąd*Ki)
czy liczymy osobno:
Integral = Ki*(poprzednie_Integral + błąd*Ki)
i na końcu:
I = Ki * Integral

Bo spotkałem wszystkie 3 sposoby w kodach z internetu.
Niby nie wiele zmienia, ale w przypadkach brzegowych może mieć znaczenie.

Dokładnie - wszystko dopuszczalne, tylko w drugiej wersji masz chyba
jakiś błąd, bo za dużo Ki.
Jeśli to Ki ma odpowiadać temu z teorii, to musi być w odpowiednim
miejscu wliczane, ale nie ma takiego obowiązku - wystarczy przeliczać
wartość zadaną przez użytkownika na używaną wewnętrznie do obliczeń
Gdzieś tam jest kwestia wygody ogranicznia wartosći całki - czy ma to
być na wartosciach błędu, czy wyjsciowych, może kwestia dokładnosci
obliczen numerycznych - szczególnie, jak sie chce to robić na liczbach
całkowitych, uwzględniania kroku czasu, jeśli zmienny, itp.

Quote:
No i sprawa ograniczania I, czyli anti windup, czy integral clamping.
Ograniczamy do dobranej doświadczalnie (obliczonej?) wartości, czy
ograniczamy do pełnej mocy z samego członu I, czyli u mnie:
-65535 < I < 65535

Czy to nie sa liczby zmiennoprzecinkowe u Ciebie ?

Quote:
czy ograniczamy, gdy cała wartość sterowania PID przekroczy 65535, ale
to by wymagało nieskończonej liczby iteracji, więc w praktyce można
ograniczyć (nie zmieniać) jeśli poprzednia wartość PID była 65535?
Wg mnie ten ostatni sposób ma najwięcej sensu.

A jaki masz zakres wartosci wyjsciowych?
PWM ... 0-64K, czy np 0-1023

Bo od tego może zależeć, jak to sensownie ograniczyć ... no i żeby się
jakaś wartość nie przekręciła na ostatnim sumowaniu.

J.

Mirek
Guest

Sat Jan 31, 2026 6:39 pm   



W dniu 31.01.2026 o 16:50, J.F pisze:

Quote:
Obsluga enkodera w Pythonie?
A jakies maksymalnej częstotliwości kroków się spodziewasz?

Ja się nie spodziewałem ale gość pokazuje, że mu działa.



Quote:
A co się dziwisz, że analiza tekstu "in_ (x, 32)" trwa?
Szczególnie, jak jeszcze w Pythonie oprogramowane? :-)


Nie, to nie to. Wydaje mi się, że samo StateMachine.get() czyta z bufora
o ile jest napełniony, jak jest pusty to czeka. Natomiast czemu
StateMachine.exec("in_(x, 32)") nie napełnia go natychmiast to nie wiem.
Sytuację trochę poprawiło umieszczenie tego w pętli kilka instrukcji
wcześniej, ale na tym zaoszczędziłem niewiele. Obecny kod zmienia to
radykalnie: bufor sam się napełnia jak jest zmiana, jak jest napełniony
to czytam, jak nie to znaczy że nie było zmiany.


Quote:
Dokładnie - wszystko dopuszczalne, tylko w drugiej wersji masz chyba
jakiś błąd, bo za dużo Ki.

Tak, myślałem o:
Integral = poprzednie_Integral + błąd*Ki
i na końcu:
I = Ki * Integral



Quote:
-65535 < I < 65535

Czy to nie sa liczby zmiennoprzecinkowe u Ciebie ?


Nie, bo z obliczonego wcześniej float robię int-a.

Quote:
A jaki masz zakres wartosci wyjsciowych?
PWM ... 0-64K, czy np 0-1023


PWM jest 16-bitowe czyli 64k

A przy okazji - gość od tych filmików ma tam błąd, bo kierunek silnika
uzależnia od znaku błędu, co zwykle zadziała ale nie zawsze.
Ja ustawiam w zależności od znaku wyniku całego PID.

Quote:
Bo od tego może zależeć, jak to sensownie ograniczyć ... no i żeby się
jakaś wartość nie przekręciła na ostatnim sumowaniu.


Przychodzi mi do głowy jeszcze jedna metoda, mianowicie jeśli sterowanie
osiągnie maksimum to zerować wartość I. No bo tutaj nic nie ma do roboty
- silnik kręci się z maksymalną prędkością i nie ważne jak to długo
trwa, póki samo P daje maksimum to nie ma co zbierać błędu. Może głupie,
ale sprawdzę jak to się zachowa.



--
Mirek

J.F
Guest

Sat Jan 31, 2026 8:40 pm   



On Sat, 31 Jan 2026 17:39:50 +0100, Mirek wrote:
Quote:
W dniu 31.01.2026 o 16:50, J.F pisze:
Obsluga enkodera w Pythonie?
A jakies maksymalnej częstotliwości kroków się spodziewasz?

Ja się nie spodziewałem ale gość pokazuje, że mu działa.

Tak prawdę mówiąc, to mało pokazuje.
Jak masz np enkoder 2000 impulsów na obrót i do 200 obr/s,
to spora częstotliwość wychodzi.

A jak np 180 imp/obr i maks 5 obr/s, to może i Python sobie poradzi.

Quote:
A co się dziwisz, że analiza tekstu "in_ (x, 32)" trwa?
Szczególnie, jak jeszcze w Pythonie oprogramowane? :-)

Nie, to nie to. Wydaje mi się, że samo StateMachine.get() czyta z bufora
o ile jest napełniony, jak jest pusty to czeka.

Prawdopodobne. A jak tak długo czeka i wstrzymuje pętlę regulatora,
to cuda mogą być.
ale masz to rx_fifo().

Quote:
Natomiast czemu
StateMachine.exec("in_(x, 32)") nie napełnia go natychmiast to nie wiem.

Ja się tam jednak podejrzliwie patrzę na ten parametr.
Jego dopiero trzeba zdekodować, co może być trudne lub łatwiejsze.

Ale ale - dokumentacja podaje, że można podać int zawierający gotowy
kod instrukcji PIO.

https://github.com/micropython/micropython/blob/master/docs/library/rp2.StateMachine.rst?plain=1#id3

Quote:
Sytuację trochę poprawiło umieszczenie tego w pętli kilka instrukcji
wcześniej, ale na tym zaoszczędziłem niewiele. Obecny kod zmienia to
radykalnie: bufor sam się napełnia jak jest zmiana, jak jest napełniony
to czytam, jak nie to znaczy że nie było zmiany.

Dokładnie - wszystko dopuszczalne, tylko w drugiej wersji masz chyba
jakiś błąd, bo za dużo Ki.

Tak, myślałem o:
Integral = poprzednie_Integral + błąd*Ki
i na końcu:
I = Ki * Integral

Nadal wydaje mi sie, że masz Ki podwójnie.

Werja 1
calka = calka+blad
I = Ki* calka

wersja 2
calka - calka+blad*Ki
I = calka

Pytanie, czy powinieneś tam uwzględniać krok czasu, czy nie trzeba, bo
stały.

Quote:
-65535 < I < 65535
Czy to nie sa liczby zmiennoprzecinkowe u Ciebie ?

Nie, bo z obliczonego wcześniej float robię int-a.

Ale wartość całki sumujesz na float?

Ale to własnie to wewnętrzną sumę całki chcesz ograniczyc,
bo bedzie się długo utrzymywał błąd, wartość(suma) całki urośnie np do
miliona, Ty ograniczysz wyjsciową wartość I ... ale ta wewnętrzna
wartość całki bedzie potem dłuuugo wracała do sensownej wartości.

Quote:
A jaki masz zakres wartosci wyjsciowych?
PWM ... 0-64K, czy np 0-1023

PWM jest 16-bitowe czyli 64k

A przy okazji - gość od tych filmików ma tam błąd, bo kierunek silnika
uzależnia od znaku błędu, co zwykle zadziała ale nie zawsze.
Ja ustawiam w zależności od znaku wyniku całego PID.

Ogólnie tak właśnie powinieś robić.

Pytanie, czy on tam aktywnie hamuje silnikiem, bo jak unika, to może
mu działa - albo sprawia takie wrażenie.
Bo nie pokazuje wykresu błędu :-)

No i przypadek dużego obciążenia zewnętrznego - powiedzmy,
że jakiś cięzar czy sprężyna chce kręcić silnikiem w prawo,
kontroler musi podawać prąd chcący kręcic w lewo,
i to w miarę niezależnie od błędu.

Quote:
Bo od tego może zależeć, jak to sensownie ograniczyć ... no i żeby się
jakaś wartość nie przekręciła na ostatnim sumowaniu.

Przychodzi mi do głowy jeszcze jedna metoda, mianowicie jeśli sterowanie
osiągnie maksimum to zerować wartość I. No bo tutaj nic nie ma do roboty
- silnik kręci się z maksymalną prędkością i nie ważne jak to długo
trwa, póki samo P daje maksimum to nie ma co zbierać błędu. Może głupie,
ale sprawdzę jak to się zachowa.

Też bym o takim czymś myślał, bo jak silnik się kręci szybko w jedną
stronę i nie nadąża, to nie ma co błędu całkować.

Ewentualnie ... to co Janusz pisał - nie skacz zadaną pozycją o dużą
wartość, tylko zadawaj mu stosowną trajektorię - stopniowy przyrost
pozycji, i jeszcze stopniowy wzrost i zmniejszenie prędkości.
Regulator będzie to naśladował, i błąd ma szanse być niewielki ....

J.

Mirek
Guest

Sat Jan 31, 2026 9:50 pm   



W dniu 31.01.2026 o 19:40, J.F pisze:

Quote:
Ja się tam jednak podejrzliwie patrzę na ten parametr.
Jego dopiero trzeba zdekodować, co może być trudne lub łatwiejsze.

Ale ale - dokumentacja podaje, że można podać int zawierający gotowy
kod instrukcji PIO.

Możliwe, że coś to przyspieszy, ale w tym momencie już bez znaczenia dla
mnie, bo nie używam tej metody.



Quote:
Integral = poprzednie_Integral + błąd*Ki
i na końcu:
I = Ki * Integral

Nadal wydaje mi sie, że masz Ki podwójnie.


A "I = Ki*(poprzednie_I + błąd*Ki)" - lepiej?

Przecież w poprzednie_I już jest Ki
a tak ma właśnie gościu na filmiku.



Quote:
Werja 1
calka = calka+blad
I = Ki* calka

wersja 2
calka - calka+blad*Ki
I = calka

No, czyli moja pierwsza wersja na dwa sposoby.


Quote:

Pytanie, czy powinieneś tam uwzględniać krok czasu, czy nie trzeba, bo
stały.


No krok jest stały, ale jeśli chcielibyśmy stosować reguły Z-N to chyba
trzeba.

Quote:

Ewentualnie ... to co Janusz pisał - nie skacz zadaną pozycją o dużą
wartość, tylko zadawaj mu stosowną trajektorię - stopniowy przyrost
pozycji, i jeszcze stopniowy wzrost i zmniejszenie prędkości.
Regulator będzie to naśladował, i błąd ma szanse być niewielki ....

Ja chcę zrobić regulator uniwersalny - chcę żeby mi to działało tak jak
na tym pierwszym filmiku, który podlinkowałem. Widziałem jeszcze lepszy
filmik, ale nie mogę go znaleźć, gdzie gość trzymał w ręce taki
niewielki silnik z takim jakby patyczkiem jakby wskazówką. Gość wytrącał
go palcem a ten wracał do pozycji jakby był na gumce i o coś uderzał.
Potem zrobił kilka obrotów palcem i to samo - patyczek po prostu
pojawiał się natychmiast na pozycji.

Paradoksalnie najgorzej mi się to zachowuje jak powoli zmieniam nastawę
- tzn, w pętli dodaję mu do pozycji stałą wartość - powinien jechać ze
stałą prędkością a "kołysze" tą prędkością jak tylko trochę zwiększę Ki.
Jest taki moment, że wydaje się, że już szybciej dociąga do celu i jest
stabilny przy gwałtownych zmianach nastawy a przy powolnych zmianach
jednak się kołysze.

--
Mirek

Goto page Previous  1, 2, 3

elektroda NewsGroups Forum Index - Elektronika Polska - Optymalne strojenie PID dla silnika z enkoderem na Pi Pico zjawiska oscylacji?

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map