Ta strona używa ciasteczek (plików cookies), dzięki którym może działać lepiej. Dowiedz się więcejRozumiem i akceptuję

Jak zaimplementować regulator PID dla silnika z enkoderem?

Teoria 04.08.2015 GAndaLF

motor_encW artykule przedstawię proces projektowania regulatora PID do kontroli prędkości silnika DC wyposażonego w enkoder.

Najpierw zajmiemy się identyfikacją modelu silnika. Następnie dostroimy dla niego regulator PID, po czym sprawdzimy go w praktyce.

Wykorzystany sprzęt oraz oprogramowanie

W artykule wykorzystałem następujące elementy:

Kod na STM32 został napisany w środowisku Eclipse. Struktura programu jest podobna jak w moich wcześniejszych artykułach. Na mikrokontrolerze działa system FreeRTOS, a poszczególne zadania wykonywane są w wątkach. Do identyfikacji modelu transmitancyjnego silnika i zaprojektowania regulatora PID wykorzystałem środowisko MATLAB R2014a oraz pakiet Simulink wchodzący w jego skład.

Niezbędna teoria

Naszym obiektem sterowania jest silnik. Możemy nim sterować w pętli otwartej:

sch_open

Sterowanie w pętli otwartej

Gdzie u(t) to nasz sygnał wejściowy będący wartością sterowania podaną na silnik. Najczęściej jest to wypełnienie PWM. Natomiast y(t) to sygnał wyjściowy, którym jest prędkość obrotów silnika. Możemy ją odczytać za pomocą enkodera.

W tym wypadku w programie ustawiamy bezpośrednio wartość sterowania silnika. Dla tego samego sterowania prędkość może być różna w zależności od obciążenia. Program nie ma więc bezpośrednio kontroli nad prędkością silnika.

Przy sterowaniu w pętli otwartej podajemy pewną wartość na silnik wierząc, że spowoduje ona pojawienie się odpowiedniej wartości na wyjściu. Nie mamy jednak pewności, czy sterowanie odniosło pożądany skutek. Alternatywą jest sterowanie w pętli zamkniętej:

sch_closed

Sterowanie w pętli zamkniętej

Gdzie r(t) to sygnał zadany, czyli wartość prędkości, jaką chcieli byśmy uzyskać na wyjściu. Natomiast e(t) to uchyb sterowania czyli różnica między sygnałem zadanym, a sygnałem wyjściowym.

Tym razem w programie ustawiamy wartość prędkości, jaką chcieli byśmy zaobserwować na wyjściu. Regulator na podstawie sygnału uchybu dobierze odpowiednie sterowanie. W tym wypadku, jeśli zmieni się obciążenie silnika, zmieni się także sygnał sterujący.

Regulator PID jest implementowany za pomocą następującego wyrażenia:

Współczynniki kp, ki i kd, to parametry regulatora (człon proporcjonalny, całkujący i różniczkujący), e_sum to suma wszystkich wartości uchybu od początku sterowania, e_last to wartość uchybu z poprzedniej chwili czasu.

Do członu całkującego warto dodać ograniczenie na wartość e_sum niepozwalające sumie na urośnięcie powyżej zadanego progu.

Pomiar charakterystyki silnika

Do pomiaru charakterystyki silnika potrzebujemy programu składającego się z:

  • obsługi sterowania silnikiem
  • obsługi enkodera
  • akwizycji danych

Sterowanie silnikiem zostało zrealizowane na timerze TIM2 odpowiedzialnym za generowanie sygnału PWM i dwóch wyjściach sterujących. Timer TIM3 został ustawiony w Encoder Mode z inkrementacją na zboczu rosnącym i opadającym na obu kanałach.

Dane dotyczące aktualnego sterowania podanego na silnik i wartości odczytanej z enkoderów są wysyłane do komputera przez USART połączony z modułem Bluetooth. Dane binarne zostały zapisane do pliku za pomocą programu RS-232 Data Logger, a następnie przekonwertowane do formatu tekstowego jako dwie kolumny pomiarów. Wyniki przedstawia wykres.

plot_motor1

Odpowiedź skokowa silnika w pętli otwartej

Z pobranych danych możemy wyznaczyć odpowiedź skokową. W tym celu posłużymy się skryptem matlabowym:

Skrypt wczytuje dane z pliku i tworzy z nich strukturę iddata z czasem próbkowania 0.005. Ważne tutaj jest określenie ile pierwszych próbek znajduje się przed skokiem sygnału sterującego i odpowiednie skrócenie podawanych wektorów. U mnie nie branych pod uwagę jest 19 pierwszych próbek. Następnie funkcja tfest dopasowuje optymalny model do danych pomiarowych.

Ustawiony model zawiera jeden biegun i zero zer oraz czas próbkowania 0.005. Dalsza część skryptu rysuje na wykresie odpowiedź skokową wyznaczonego modelu i realnego układu.

simulink_open_loop1

Model otwartej pętli sterowania w Simulinku

Aby porównać otrzymany model z danymi rzeczywistymi, utworzyłem model pętli otwartej w Simulinku, a wynik naniosłem na jeden wykres z danymi pomiarowymi. Parametry transmitancji wziąłem ze zmiennej motor_tf ze skryptu. Wysokość sygnału skokowego ustawiłem na 50 zgodnie z sygnałem pobudzającym wykorzystanym w pomiarach.

plot_est_real

Porównanie danych pomiarowych i symulacji w Simulinku dla pętli otwartej

Analizując wykres widzimy, że identyfikacja modelu zakończyła się sukcesem. Oba wykresy są do siebie bardzo podobne.

Projekt regulatora PID

Do doboru nastaw regulatora PID posłużymy się automatycznym tunerem wchodzącym w skład Matlaba. W tym celu należy stworzyć w Simulinku model pętli zamkniętej układu:

simulink_closed_loop

Model w Simulinku dla pętli zamkniętej

Tym razem wysokość sygnału skokowego ustawiłem na 11. W poprzednim przypadku sygnał skokowy był wyrażony w procentach wypełnienia PWM. Teraz jest to prędkość wyrażona jako ilość ticków enkodera na jednostkę czasu równą okresowi próbkowania – 5ms. We wszystkich elementach modelu i opcjach symulacji próbkowanie ustawiłem na 0.005.

Po otwarciu właściwości bloku PID otworzy nam się następujące okno:

okno_pid

Okno bloku PID w Simulinku

Na czerwono zaznaczyłem wybór rodzaju regulatora (np. PI, PD, PID), pole czasu próbkowania, pola z parametrami P, I, D, wykorzystywany wzór regulatora PID oraz przycisk Tune.

W tym oknie możemy ręcznie modyfikować wartości parametrów i sprawdzać jaki mają wpływ na jakość sterowania. W zakładce PID Advanced należy ustawić Output saturation na wartości 100 i -100. Jest to ograniczenie sygnału sterującego związane z maksymalnymi wartościami PWM. Następnie klikamy przycisk Tune. Ukaże nam się następujące okno:

okno_tuner

PID tuner

Za pomocą suwaków możemy tutaj modyfikować szybkość odpowiedzi skokowej układu zamkniętego. Krótszy czas ustalania wiąże się z większym przeregulowaniem.

Po osiągnięciu zadowalającej charakterystyki klikamy Update block i parametry PID zostają zaktualizowane. Moje wartości to P = 5.94, I = 347.19 i D = -0.03. Warto zauważyć, że wartości I oraz D są znormalizowane względem czasu próbkowania. Widać to na wzorze w oknie bloku PID. Tak więc wartość I jest mnożona przez czas próbkowania, a wartość D dzielona.

Obliczone wartości wprowadziłem do programu na STM, który został rozszerzony o obliczanie sterowania za pomocą algorytmu PID. Porównanie wyników w pętli otwartej i w pętli zamkniętej z nastrojonym PID prezentuje wykres:

plot_pid_compare

Porównanie sterowania w pętli otwartej(niebieski) i w pętli zamkniętej z PID(czerwony)

Jak widać na wykresie, dzięki zastosowaniu PID udało się skrócić czas ustalania.

Podsumowanie

W artykule przedstawiłem sposób projektowania regulatora PID dla silnika z enkoderem. Wykorzystałem w nim gotowe funkcjonalności Matlaba takie jak funkcja tfest znajdująca model transmitancyjny dla danych pomiarowych, czy PID Tuner znajdujący automatycznie nastawy regulatora. Dzięki temu udało się uniknąć skomplikowanej teorii i wzorów.

W wyniku otrzymałem regulator PID, który znacząco przyspiesza czas ustalania prędkości w porównaniu ze sterowaniem w pętli otwartej. Dodatkową zaletą jest bezpośrednie sterowanie prędkością z poziomu funkcji sterującej, zamiast bardziej abstrakcyjnej wartości wypełnienia PWM.

Dzięki temu otrzymujemy gwarancję, że silnik będzie się kręcić z taką samą prędkością mimo np. rozładowującej się baterii, czy innej nawierzchni. Do artykułu załączam kod programu na STM z zaimplementowanym regulatorem PID.

Powiadomienia o nowych, darmowych artykułach!

Załączniki

motor_ident (zip, 324 KB) - Pobierz

kod źródłowy programu na STM32

matlab (zip, 13 KB) - Pobierz

skrypt Matlabowy i projekt Simulink

out001.txt (plain, 3 KB) - Pobierz

Przykładowy plik out001.txt

Komentarze

lukas.ch

21:43, 05.08.2015

#1

Mam jedno zastrzeżenie. Brak jednostek na osiach! Wydaje mi się, że to jest bardzo poważne niedopatrzenie.

Ogólnie artykuł bardzo spoko :)

Treker
Administrator

22:14, 05.08.2015

#2

lukas.ch, GAndalF wróci z urlopu, to się będzie tłumaczył ;-)

adam19_91

2:49, 08.08.2015

#3

Wreszcie jakiś ciekawy artykuł z teorii sterowania. Takie pytanie czemu w matlabie dobierasz nastawy dla regulatora dyskretnego a w programie stosujesz wzór dla ciągłego , w ogóle nie odejmujesz poprzedniej wartości sterowania ani nie uwzględniasz czasu próbkowania we wzorze?

http://images.slideplayer.pl/2/840379/slides/slide_4.jpg

Czy to trik polegający na tym, że wywołujesz przerwanie co okres próbkowania i wówczas można użyć regulatora ciągłego? Napisz z czego wynika wartość makra do antiwindup?

#define ERR_SUM_MAX 1000

I ostatnie najtrudniejsze patrząc na model matematyczny silnika DC można zauważyć, że sterowaniem jest napięcie zasilające wirnik i moment obciążenia. Natomiast ty w swoim artykule jako wyjście z regulatora PID czyli sterowanie używasz wartości PWM, która najoględniej mówiąc steruje prędkością kątową(liczbą obrotów w jednostce czasu). I tu moje pytanie czy nie należy wyjścia z regulatora jakoś przeliczyć na prędkość i dopiero podać na obiekt?

X1=Iw

X2=omega

U1=Uz

U2=Mobc

X2'=km/J*X1-B/J*X2+0*U1-1/J*U2;

i z tego całka, otrzymujemy wartość prędkości wymaganej do zrealizowania sterowania, którą przeliczasz na PWM.

Chodzi mi o to, czy wyjście regulatora może być czymkolwiek jest to wartość bez jednostki, za którą podstawiasz co ci pasuje?

r_bot

14:32, 09.08.2015

#4

Warto zamieścić jeszcze plik out001.txt.

Mam też problem z rozczytaniem wykresu "Odpowiedź skokowa silnika w pętli otwartej". Czy dobrze rozumiem, czerwona linia to wypełnienie PWM, a niebieska to liczba obrotów na minutę/sekundę?

Bobby

17:19, 09.08.2015

#5

adam19_91, nie jest przypadkiem tak, że to napięcie zasilania silnika jest wprost proporcjonalne do jego prędkości obrotowej? Przy odpowiednio dużej częstotliwości PWM można uprościć, że jest to tak naprawdę zmienne napięcie.

I co do regulatora dyskretnego/ciągłego - nie mogę poprzeć się stuprocentowo jakimś papierem, ale wydaje mi się, że jeśli wywołujesz regulator co jakiś stały okres czasu, robi się dyskretny. Czasu próbkowania nie trzeba uwzględniać, bo jest to stała, która została już wliczona we współczynniki:

Cytat:

Po osiągnięciu zadowalającej charakterystyki klikamy Update block i parametry PID zostają zaktualizowane. Moje wartości to P = 5.94, I = 347.19 i D = -0.03. Warto zauważyć, że wartości I oraz D są znormalizowane względem czasu próbkowania. Widać to na wzorze w oknie bloku PID. Tak więc wartość I jest mnożona przez czas próbkowania, a wartość D dzielona.

r_bot prawidłowo odczytujesz wykres ;) Odpowiedź jednak nie zbiega do wartości sterowania, bo są podane w różnych jednostkach - PWM to wypełnienie od 0-100, a niebieski to ilość ticków enkodera w jednostkowym czasie (okresie próbkowania).

GAndaLF
Autor wpisu

17:31, 10.08.2015

#6

lukas.ch, faktycznie zapomniałem o podpisaniu osi w wykresach. Na uczelni już by nie przyjęli :D

Oś pozioma na każdym wykresie to szas w sekundach. Na pierwszym wykresie czerwona linia to wypełnienie PWM w procentach, a niebieska to ilość ticków enkodera na okres próbkowania. Na drugim wykresie czerwona linia to wyjście układu w Simulinku, niebieska to wyjście rzeczywistego układu. W obu przypadkach jednostką jest liczba ticków enkodera na okres próbkowania. Na ostatnim wykresie oś pionowa to również ilość ticków enkodera na okres próbkowania.

adam19_91, w programie stosuję dyskretny PID tak samo jak w Matlabie. Odejmuję poprzednią wartość sterowania przy wyliczaniu err_d. Czasu próbkowania nie uwzględniam we wzorze dlatego, że jest już uwzględniony w matlabowym tunerze. Tak jak napisał Bobby.

adam19_91 napisał/a:

Napisz z czego wynika wartość makra do antiwindup?

#define ERR_SUM_MAX 1000

Wartość ta jest ustawiana na oko. Znając ki można sobie policzyć jaki wpływ na sterowanie będzie miał człon całkujący w najgorszym wypadku i wybrać zadowalającą wartość.

adam19_91 napisał/a:

I ostatnie najtrudniejsze patrząc na model matematyczny silnika DC można zauważyć, że sterowaniem jest napięcie zasilające wirnik i moment obciążenia. Natomiast ty w swoim artykule jako wyjście z regulatora PID czyli sterowanie używasz wartości PWM, która najoględniej mówiąc steruje prędkością kątową(liczbą obrotów w jednostce czasu). I tu moje pytanie czy nie należy wyjścia z regulatora jakoś przeliczyć na prędkość i dopiero podać na obiekt?

X1=Iw

X2=omega

U1=Uz

U2=Mobc

X2'=km/J*X1-B/J*X2+0*U1-1/J*U2;

i z tego całka, otrzymujemy wartość prędkości wymaganej do zrealizowania sterowania, którą przeliczasz na PWM.

Chodzi mi o to, czy wyjście regulatora może być czymkolwiek jest to wartość bez jednostki, za którą podstawiasz co ci pasuje?

Projektując regulator mogę sobie wybrać co ma być wejściem, a co wyjściem. Wybrałem na wejściu regulatora sygnał z enkodera, na wyjściu PWM, bo na takich wartościach bezpośrednio działa mikrokontroler i nic nie trzeba przeliczać. Tak samo obiekt u mnie przyjmuje na wejściu PWM, a na wyjściu zwraca prędkość jako odczyt z enkodera. Po prostu tak jest wygodniej - unikamy przekształceń i nie musimy znać wszystkich parametrów silnika.

adam19_91

22:53, 10.08.2015

#7

Wybacz mi dociekliwość ale nie potrafię zrozumieć jak regulator, który ma na wejściu uchyb prędkości na wyjściu generuje wypełnienie PWM? Skąd on ma wiedzieć na przykład jaką rozdzielczość ma PWM w twoim uC? Czy nie jest tak po prostu, że na wejściu regulatora jest uchyb prędkości to na wyjściu jest również wartość oznaczająca prędkość, o którą należy np. zwiększyć obroty? A dopiero tą wartość przeliczyć na PWM? A jak będzie w przypadku drona albo wahadła odwróconego gdzie wyjściem jest kąt, który wchodzi na regulator? Podaję kąt a on mi wylicza PWM czy kąt, o który należy zmienić położenie? To ważne pytanie jeśli chodzi o praktyczne podejście do tematu na zajęciach funkcjonują tylko pojęcia uchyb->regulator->sterowanie.

Pozdrawiam

GAndaLF
Autor wpisu

9:27, 17.08.2015

#8

Regulator może mieć na wejściu i wyjściu wartości w obojętnie jakich jednostkach. Jego zasada działania pozostaje taka sama. Dlatego nic nie stoi na przeszkodzie, żeby zwracał wypełnienie PWM. Należy tylko pamiętać, że regulator może zwracać wartości spoza zakresu -100-100%.

Wartości jakie regulator przyjmuje na wejściu i wyjściu określamy w fazie projektowania. Ja jako wejście obiektu (czyli wyjście regulatora) przyjąłem PWM i w takich jednostkach zebrałem odpowiedź skokową.

W przypadku drona, wahadła, albo jakiegokolwiek innego układu również możesz zaprojektować regulator tak, żeby wyjściem regulatora był PWM.

[ Dodano: 17-08-2015, 23:18 ]

W załączniku brakujący plik out001.txt

Treker
Administrator

10:55, 19.08.2015

#9

Dodałem wspomniany załącznik jeszcze dla pewności do samego artykułu :)

r_bot

11:18, 01.06.2017

#10

Cześć po dłuższej przerwie.

Przejrzałem dziś kod źródłowy regulatora PID, plik pid.c i jedna rzecz mnie zastananwia. Składowa struktury pid_params, err_last jest cały czas równa 0. Według mnie w funkcji pid_calculate powinnno się znajdować następujące przypisanie:

pid_params.err_last = pid_params.err;

Czy ktoś z forumowiczów mógłby to zweryfikować?

GAndaLF
Autor wpisu

23:41, 01.06.2017

#11

Masz rację, w kodzie brakuje aktualizacji zmiennej pid_params.err_last. Dzięki za wyłapanie.

Zobacz powyższe komentarze na forum

FORBOT Damian Szymański © 2006 - 2017 Zakaz kopiowania treści oraz grafik bez zgody autora. vPRsLH.