-
Notifications
You must be signed in to change notification settings - Fork 0
DroneData
Plik PIDController.cs zawiera implementację kontrolera typu PID (Proporcjonalno-Różniczkowo-Integrującego), który jest szeroko stosowany w systemach sterowania, szczególnie w zastosowaniach przemysłowych, robotyce oraz sterowaniach dynamicznym. W kontekście systemu, który zarządza procesem, np. regulacją temperatury, prędkości silnika lub położenia mechanizmu, kontroler PID pełni rolę regulatora, który dostosowuje sygnał sterujący w oparciu o błąd między wartością docelową (setpointem) a aktualną wartością (feedbackem).
Klasa PIDController została zaprojektowana z myślą o integracji z systemem sterowania w czasie rzeczywistym, gdzie dane wejściowe (np. z czujników) są przekazywane w sposób cykliczny, a wynik działania kontrolera (np. sygnał PWM) jest stosowany do sterowania elementem wykonawczym. Zatem, kontroler ten działa w kontekście cyklicznego wykonywania się procedury Update(), która reprezentuje jeden krok w czasie rzeczywistym systemu sterowania.
W kontekście architektury systemu, klasa PIDController może być częścią większego systemu sterowania, np. MotorController, TemperatureControlSystem, NavigationSystem, gdzie kontroler PID jest jednym z elementów w strukturze sterowania. Może być również używany jako komponent w systemie typu "component-based architecture", gdzie kontrolery PID są instancjami, które mogą być dynamicznie tworzone, konfigurowane i łączone z innymi komponentami sterującymi.
Klasa PIDController nie posiada jawnej logiki życia, ale jej cykl życia jest kontrolowany przez zewnętrzny system sterowania, który wywołuje metodę Update() w regularnych odstępach czasu. Zatem, jej cykl życia można opisać jako: inicjalizacja (ustawienie parametrów PID, ustawienie wartości początkowej), następnie cykliczne wywołanie Update() w pętli sterowania, a na końcu dezaktywacja (np. przez ustawienie wartości sterującego na zero lub wyzerowanie zmiennych wewnętrznych).
Klasa PIDController ma konstruktor, który przyjmuje trzy parametry: Kp, Ki, Kd (współczynniki PID). Te wartości są przechowywane w prywatnych zmiennych klasy (_kp, _ki, _kd). Dodatkowo, ustawiane są zmienne _previousError i _integral, które są potrzebne do obliczeń PID.
public PIDController(double kp, double ki, double kd)
{
_kp = kp;
_ki = ki;
_kd = kd;
_previousError = 0;
_integral = 0;
}W tym miejscu nie następuje żadna logika obliczeniowa, ale ustawione są wartości, które będą wykorzystywane w dalszej części obliczeń. Wartości te są typu double, co zapewnia dużą dokładność obliczeń, co jest istotne w systemach sterowania, gdzie błędy mogą mieć poważne konsekwencje.
Główną logiką działania kontrolera PID jest metoda Update(), która przyjmuje dwa argumenty: setpoint i processValue. Wartość setpoint to wartość docelowa, a processValue to aktualna wartość z procesu (np. temperatura, prędkość). Metoda ta zwraca wartość sterującą (output), która może być np. sygnał PWM do silnika.
public double Update(double setpoint, double processValue)
{
double error = setpoint - processValue;
_integral += error * _dt;
double derivative = (error - _previousError) / _dt;
double output = _kp * error + _ki * _integral + _kd * derivative;
_previousError = error;
return output;
}W pierwszej linii następuje obliczenie błędu jako różnicy między wartością docelową (setpoint) a aktualną wartością (processValue). Ten błąd jest kluczowym elementem w algorytmie PID, ponieważ decyduje o kierunku i intensywności działania regulatora.
W kolejnym kroku obliczana jest wartość całki błędu. Wartość _integral jest zwiększana o iloczyn błędu i czasu (_dt), co odpowiada zasadzie całkowania numerycznego (np. metoda trapezów). Wartość ta reprezentuje sumę błędu w czasie i jest używana do redukcji błędu statycznego.
Pochodna błędu jest obliczana jako różnica między aktualnym błędem a poprzednim błędem podzielona przez czas (_dt). Obliczenie to pozwala na reakcję kontrolera na szybkość zmiany błędu, co pozwala na zapobieganie nadmiernemu wahań i poprawia stabilność systemu.
W końcowym kroku obliczana jest wartość wyjściowa, która jest sumą trzech członów PID:
- Człon proporcjonalny:
Kp * error - Człon całkowity:
Ki * integral - Człon różniczkowy:
Kd * derivative
Wszystkie te składniki są mnożone przez odpowiednie współczynniki i sumowane, co daje ostateczną wartość sterującą. Wartość ta może być np. przekazywana do sterownika PWM lub innego elementu sterującego.
Po obliczeniu wartości wyjściowej, zmienna _previousError jest aktualizowana na wartość bieżącego błędu. Zmienna _integral jest aktualizowana w sposób cykliczny, co zapewnia, że błąd w czasie będzie sumowany i uwzględniony w przyszłych obliczeniach.
-
_previousError: Przechowuje poprzedni błąd, który jest potrzebny do obliczenia pochodnej. -
_integral: Przechowuje sumę błędów w czasie, co pozwala na eliminację błędu statycznego. -
_dt: Czas między kolejnymi wywołaniamiUpdate(). Wartość ta musi być konsekwentna i stała lub odpowiednio przeliczana w przypadku nieregularnych wywołań.
Klasa PIDController nie dziedziczy z żadnej klasy ani nie implementuje żadnego interfejsu. Jest to klasa samodzielna, co pozwala na jej prostą integrację z systemem sterowania. Jednak w bardziej rozbudowanym systemie, klasa może być częścią hierarchii interfejsów, np. IController, IRegulator, które mogłyby wymuszać implementację metody Update().
-
setpoint– wartość docelowa (np. temperatura 25°C) -
processValue– aktualna wartość procesu (np. temperatura z czujnika) -
_dt– czas między kolejnymi cyklami (np. 0.01 sekundy)
-
output– wartość sterująca (np. sygnał PWM 0–255) - Zmienne wewnętrzne
_integral,_previousError– modyfikowane w miejscu, nie zwracane bezpośrednio
-
_kp,_ki,_kd– współczynniki PID, które są ustawiane w konstruktorze i nie zmieniają się w trakcie działania. -
_previousError– przechowuje poprzedni błąd, potrzebny do obliczenia pochodnej. -
_integral– zmienna akumulująca błąd w czasie, wykorzystywana w członie całkowitym. -
_dt– czas cyklu, który musi być stały lub odpowiednio przeliczany w przypadku nieregularnych cykli.
Klasa PIDController nie stosuje jawnie żadnego wzorca projektowego, ale może być traktowana jako przykład wzorca Komponentu Sterującego (Control Component) w systemach sterowania. Wzorzec ten pozwala na modularne i niezależne sterowanie systemem, co zwiększa skalowalność i łatwość testowania.
W kontekście architektury systemu, kontroler PID może być częścią większej architektury sterowania typu Observer Pattern (jeśli kontroler reaguje na zmiany w systemie) lub może być częścią systemu sterowania typu Strategy Pattern, gdzie różne kontrolery PID mogą być używane w zależności od typu procesu (np. PID dla temperatury, PID z ograniczeniem dla prędkości).
Wartości _kp, _ki, _kd, error, integral, derivative, output są typu double. W języku C# typ double zapewnia precyzję do 15–16 cyfr dziesiętnych, co jest konieczne w systemach sterowania, gdzie nawet niewielkie różnice mogą mieć znaczący wpływ na działanie systemu.
Wartość _dt musi być stała i dokładnie określona. W przypadku nieregularnych cykli (np. z powodu przetwarzania w systemie), może to prowadzić do niestabilności lub błędów w obliczeniach pochodnej. W bardziej zaawansowanych implementacjach, _dt może być obliczany dynamicznie lub weryfikowany, aby zapewnić stabilność.
Zmienne _integral i _previousError są zmiennymi stanu kontrolera. W systemach wielowątkowych lub asynchronicznych, może to prowadzić do problemów z dostępem do zmiennych współdzielonych. W takich przypadkach konieczne jest stosowanie mechanizmów synchronizacji, np. lock, aby zapobiec błędom w obliczeniach.
W kodzie nie ma jawnych rzutowań, ale w bardziej rozbudowanych systemach może być konieczne rzutowanie typów, np. z float do double w przypadku przekazywania danych z czujników. Warto zwrócić uwagę na potencjalne utraty precyzji w takich przypadkach.
Klasa PIDController nie korzysta z dynamicznej alokacji pamięci, co oznacza, że nie ma ryzyka wycieku pamięci. Wszystkie zmienne są alokowane statycznie. Jednak w systemach wielowątkowych, zbyt częste wywoływania Update() mogą prowadzić do problemów z wydajnością, szczególnie jeśli obliczenia są złożone. W takich przypadkach warto rozważyć optymalizację obliczeń lub zastosowanie Span<T> lub Memory<T>.
-
Brak walidacji danych wejściowych: W przypadku przekazania
NaNlubInfinitydosetpointlubprocessValue, wynik działania może być nieprzewidywalny. -
Nieprawidłowe
_dt: Jeśli_dtwynosi zero lub jest ujemny, obliczenia pochodnej mogą być nieprawidłowe. -
Brak ograniczeń na
output: W systemach sterowania, wartość wyjściowa może być ograniczona (np. do zakresu 0–255 dla PWM). Brak ograniczeń może prowadzić do nadmiernego działania sterownika.
Klasa PIDController reprezentuje podstawową implementację kontrolera PID w systemie sterowania. Działa on w sposób cykliczny, przyjmując dane wejściowe i zwracając wartość sterującą. Jest to klasa prostych, ale bardzo istotnych obliczeń, które są kluczowe dla stabilności i dokładności systemu sterowania. Warto zwrócić uwagę na dokładność obliczeń, zarządzanie zmiennymi stanu oraz potencjalne zagrożenia związane z nieprawidłowymi danymi wejściowymi.