-
Notifications
You must be signed in to change notification settings - Fork 0
DCMotor
Plik PIDController.cs zawiera implementację sterownika PID (Proporcjonalno-Różniczkowo-Integralnego), który jest kluczowym elementem w systemach sterowania automatycznego. Sterownik PID stosowany jest do regulacji procesów fizycznych, takich jak temperatura, ciśnienie, prędkość obrotowa, położenie czy napięcie, gdzie wymagana jest precyzyjna kontrola i minimalizacja błędu między wartością docelową (setpointem) a aktualną wartością (procesem).
Klasa PIDController stanowi komponent rejestrujący i przetwarzający błędy w czasie rzeczywistym, a jej zadaniem jest generowanie sygnału sterującego (output) na podstawie obecnego błędu oraz historii poprzednich błędów. W kontekście systemu, ten sterownik może być używany np. w sterownikach PLC, robotykach, systemach HVAC, lub w aplikacjach sterowania silnikami.
Z punktu widzenia architektury systemowej, klasa PIDController działa jako moduł niezależny, który może być używany przez inne komponenty, np. ThermostatController, MotorDriver, lub FlightController. Zależność od interfejsu IPIDController (zakładamy, że został zdefiniowany w innym pliku) pozwala na elastyczne testowanie, mockowanie oraz wdrażanie różnych implementacji sterowania PID bez zmiany kodu klienckiego.
Ponadto, klasa PIDController posiada cykl życia, który obejmuje:
- Inicjalizację z parametrami PID (
Kp,Ki,Kd,outputMin,outputMax) - Ustawienie wartości docelowej (
Setpoint) - Cykl
Update, który otrzymuje aktualną wartość procesu i oblicza nową wartość sterującą - Możliwość dynamicznej modyfikacji parametrów PID (
SetTunings)
W konstruktorze PIDController przekazywane są trzy parametry: Kp, Ki, Kd oraz opcjonalne outputMin i outputMax. Te parametry są przypisywane do prywatnych zmiennych członkowskich (_kp, _ki, _kd, _outputMin, _outputMax), które są wykorzystywane w obliczeniach PID.
Warto zauważyć, że nie ma żadnej walidacji danych wejściowych w konstruktorze – jeśli Kp, Ki, Kd są ujemne lub nieprawidłowe, kod może działać nieprawidłowo lub prowadzić do niestabilności sterowania. W systemach produkcyjnych warto dodać walidację lub logikę zabezpieczającą.
Metoda Setpoint ustawia wartość docelową (setpoint), która jest używana do obliczania błędu (error = setpoint - processValue). Wartość ta może być zmieniana dynamicznie w trakcie działania systemu – co pozwala na adaptację sterowania do zmieniających się warunków.
To najważniejsza metoda w klasie – odpowiada za obliczenie wartości sterującej. W szczególności:
double error = setpoint - input;Obliczenie błędu jest podstawą działania PID. Wartość ta reprezentuje odchylenie od wartości docelowej. W systemach, gdzie wartość procesu może się zmieniać bardzo szybko, może to prowadzić do problemów z przetwarzaniem, np. zjawiska „integral windup”.
double proportional = _kp * error;Człon proporcjonalny reaguje natychmiast na błąd. Im większy błąd, tym większa siła działania sterująca. Wartość Kp musi być dobrana do charakteru procesu – zbyt duża wartość może prowadzić do oscylacji, zbyt mała – do wolnego reagowania.
_integral += _ki * error;Człon całkujący akumuluje błąd w czasie i ma za zadanie eliminować błąd stały. Wartość _integral jest zwiększana o iloczyn ki * error. W systemach z dużym opóźnieniem lub dużym szumem, integral term może prowadzić do integral windup, czyli do przesadnego akumulowania błędu. W kodzie nie ma mechanizmu ograniczającego _integral, co może być problematyczne.
double derivative = _kd * (error - _lastError);Człon różniczkowy reaguje na szybkość zmiany błędu. Wartość ta pozwala „przepowiadać” przyszły błąd i zapobiegać przeregujcowi. Wartość _lastError jest zapisywana po każdym wywołaniu Update, co pozwala na obliczenie różnicy.
double output = proportional + _integral + derivative;Wynik PID to suma trzech członów. Następnie następuje ograniczenie wartości do zakresu [outputMin, outputMax]:
if (output > _outputMax) output = _outputMax;
if (output < _outputMin) output = _outputMin;_lastError = error;To pozwala na obliczenie członu różniczkowego w kolejnym cyklu.
Umożliwia dynamiczną zmianę parametrów PID (Kp, Ki, Kd). Może być używana w systemach, gdzie parametry PID są dostosowywane w czasie rzeczywistym – np. w systemach adaptacyjnych. Warto zauważyć, że metoda SetTunings nie resetuje _integral ani _lastError, co może prowadzić do niestabilności, jeśli parametry są zmieniane drastycznie.
Klasa PIDController implementuje interfejs IPIDController, który może wyglądać mniej więcej tak:
public interface IPIDController
{
double Update(double input);
void Setpoint(double value);
void SetTunings(double kp, double ki, double kd);
}Zaimplementowanie interfejsu pozwala na:
- Polimorfizm – różne implementacje sterowania mogą być używane w tym samym miejscu
- Testowalność – można łatwiej napisać testy jednostkowe, mockując interfejs
- Rozszerzalność – w przyszłości można dodać inne algorytmy sterowania, np. fuzzy logic, MPC
-
double input– wartość aktualnego procesu (np. temperatura z czujnika, prędkość obrotowa) -
double setpoint– wartość docelowa (np. 25°C, 1000 RPM) -
double kp, ki, kd– parametry PID -
double outputMin, outputMax– zakres wyjścia sterującego (np. 0–100% PWM)
-
double output– wartość sterująca (np. sygnał PWM, napięcie, prąd) - Zmienne
_integral,_lastError– używane wewnętrznie do obliczeń, nie są eksponowane
-
_kp,_ki,_kd– stałe PID, które kontrolują wpływ odpowiednich członów -
_outputMin,_outputMax– ograniczenia wyjścia, zapobiegają nadmiernemu sterowaniu -
_integral– akumulowany błąd, używany w członie całkującym -
_lastError– poprzedni błąd, używany do obliczenia członu różniczkowego
Klasa PIDController reprezentuje komponent sterowania, który działa w cyklu: odczyt → obliczenie → sterowanie. Jest to klasyczny wzorzec stosowany w systemach sterowania przemysłowego (SCADA, PLC, RTOS). Zastosowanie tego wzorca pozwala:
- Rozdzielić logikę obliczeniową od logiki sterowania fizycznego
- Wspierać testowanie (np. można symulować czujniki)
- Ułatwiać integrację z innymi komponentami sterującymi
Użycie interfejsu IPIDController pozwala na stosowanie wzorca Strategy – różne implementacje PID mogą być używane w zależności od kontekstu (np. PID klasyczny, PID z anti-windup, PID z filtrowaniem). W systemach z dużą ilością sterowania, wzorzec ten pozwala na łatwe przełączanie algorytmów bez zmiany kodu klienckiego.
-
Referencje i wartości: W C# nie ma wskaźników, ale obiekty są przekazywane przez referencję. W tym przypadku metoda
Updatenie ma parametrów przekazywanych przez referencję – wszystko jest przekazywane przez wartość, co jest bezpieczne, ale może być mniej wydajne w przypadku dużych struktur. -
Virtual Methods: Jeśli
Updatebyłby zdefiniowany jakovirtual, to można by tworzyć klasy dziedziczące zPIDController, np.AdvancedPIDController, który dodaje funkcje takie jak anti-windup, output filtering, lub integracja z logiką fuzzy. Obecnie nie ma takiej możliwości. -
Zmienne prywatne i chronione: Wszystkie zmienne są prywatne, co zapewnia enkapsulację i chroni przed nieprawidłowym dostępem z zewnątrz.
-
Integral Windup: Brak ograniczenia
_integralmoże prowadzić do przesadnego akumulowania błędu. Rozwiązaniem może być:if (_integral > _integralMax) _integral = _integralMax; if (_integral < _integralMin) _integral = _integralMin;
-
Zła inicjalizacja
_lastError: Wartość_lastErrorjest inicjalizowana jako0, co może prowadzić do dużego członu różniczkowego przy pierwszym wywołaniuUpdate. Rozwiązaniem może być:_lastError = double.NaN;
-
Brak synchronizacji: W systemach wielowątkowych (
Task,Thread,async) brak synchronizacji może prowadzić do błędnego wynikuUpdate. Warto zastosowaćlocklubInterlockedprzy dostępach do zmiennych_integral,_lastError. -
Brak walidacji danych wejściowych: Warto dodać walidację:
if (double.IsNaN(kp) || double.IsNaN(ki) || double.IsNaN(kd)) throw new ArgumentException("PID coefficients must be valid numbers");
W systemach sterowania przemysłowego, np. w HVAC, PID może być używany do regulacji temperatury:
-
input= temperatura z czujnika -
setpoint= temperatura docelowa -
output= ustawienie mocy wentylatora lub zaworu
W przypadku systemów robotycznych, np. sterowania silnikiem krokowym:
-
input= aktualna pozycja -
setpoint= docelowa pozycja -
output= sygnał sterujący silnikiem
- Nie używaj PID bez wiedzy o jego działania – PID to nie tylko wzór, ale system z wieloma parametrami do dostrajania.
- Zrozumienie integral windup – błąd może się akumulować i prowadzić do niestabilności.
-
Zrozumienie wpływu
Kd– człon różniczkowy może być bardzo wrażliwy na szum. - Testowanie PID – najlepiej testować PID w symulatorze, zanim wdroży się w rzeczywisty system.
-
Użyj
Interlockedlublockw systemach wielowątkowych. - Zadbaj o filtrowanie danych wejściowych – szum w czujnikach może prowadzić do niestabilności.
- Zadbaj o skalowanie danych – np. przekształcanie wartości z zakresu 0–1023 do 0–100.
- Zadbaj o dynamiczne dostrajanie PID – np. w systemach adaptacyjnych, warto używać algorytmów auto-tuning.
-
Zadbaj o dokumentację parametrów PID – w systemach produkcyjnych trzeba znać wartości
Kp,Ki,Kddla każdego procesu.
Jeśli chcesz, mogę również przygotować wersję dla testów jednostkowych, np. PIDControllerTests.cs, lub wersję z obsługą anti-windup, filtrowaniem, dostosowywania czasu próbkowania, itd.