Regulator PID z użyciem ESP32-CAM

Typ_projektu
microPython
Zdjecie główne
Krótki opis projektu

Kamera rejestruje obrazy w odcieniach szarości (GRAYSCALE) o rozdzielczości 120x160 pikseli, z odświeżaniem co 0,3 s. Algorytm oblicza średnią jasność w skali od 0 do 255 na podstawie 960 pikseli. Regulator PID steruje diodą, aby zwiększać jasność otoczenia i osiągnąć zadaną wartość, np. do doświetlania biurka.

Niezbędne elementy

1. ESP8266 NodeMCU V3 z układem CH340

2. ESP32-CAM

Opis projektu

Regulator PID

Regulator PID składa się z trzech składników:

  • P (proporcjonalny)
  • I (całkujący)
  • D (różniczkujący)

Na podstawie uchybu regulacji e(t), czyli różnicy między zadaną jasnością r(t) (0-255), a rzeczywistą jasnością otoczenia y(t), algorytm dynamicznie dostosowuje moc diody.

Schemat działania regulatora PID

Sygnał sterujący u(t) wyznaczany jest według wzoru:

Wzór określający regulator PID

Gdzie współczynniki kp, ki i kd regulują działanie członów proporcjonalnego, całkującego i różniczkującego.

 

Kroki wykonania:

Projekt został wykonany w MicroPythonie, jednak z racji na większą możliwość modyfikacji parametrów kamery zalecana jest również próba implementacji w C++ !!

Kod projektu zawarty jest w 4 plikach umieszczonych w zipie w załącznikach: jasnosc.py, latarka.py, kamera_P.py oraz kamera_PID.py

1. Wgranie obrazu na płytkę

Aby obsługiwać kamerę w MicroPythonie, należy wgrać odpowiednie oprogramowanie. Dostępne są dwie biblioteki:

Wgranie obrazu odbywa się poprzez program Thonny. Po pobraniu pliku BIN należy podłączyć płytkę, wybrać odpowiedni port i załadować firmware.

Wybór opcji Thonny 1Wybór opcji Thonny 2

2. Biblioteka "jasność"

Funkcja "jasność" analizuje obrazy i oblicza średnią wartość jasności. Biblioteka pozwala na uproszczenie kodu i może być wielokrotnie wykorzystywana bez konieczności ponownego definiowania funkcji.

Jej działanie opiera się odczycie wartości buforu dla co 20-stego piksela zdjęcia, zapisanego w formacie GRAYSCALE. Działa to optymalnie, ale potencjalną zmianę można dokonać w tej linicje kodu: "for i in range(0, len(buffer), 20):"

Aby wgrać bibliotekę na płytkę:

  1. W programie Thonny kliknij "Zapisz jako".
  2. Wybierz opcję zapisu na płytce ESP.

3. Program "latarka"

Sterowanie jasnością diody LED realizowane jest za pomocą sygnału PWM. Definicja latarka = PWM(Pin(4), 100) przypisuje wyjście, które jest odpowiedzialne za interesującą nas diodę oraz częstotliwość sygnału PWM.

Wyjście przypisywane jest za pośrednictwem oznaczeń GPIO:Rozkład pinów na płytce

 

Dla ESP32-CAM dioda znajduje się na GPIO4

 

W skali od "0 do 1024" deklarujemy jasność diody, za pomocą: latarka.duty(12)

Uwaga! Dioda świeci bardzo intensywnie! Zaleca się ograniczenie maksymalnej wartości do 150.

4. Regulator P i PID

W pierwszej kolejności zaleca się zaimplementować regulator P, a następnie regulator PID.

Zmienne:

  • SETPOINT - zadana wartość jasności
  • Kp - wzmocnienie składnika proporcjonalnego
  • Ki - wzmocnienie składnika całkującego (dla PID)
  • Kd - wzmocnienie składnika różniczkującego (dla PID)

Regulator PID dostosowuje jasność diody w czasie rzeczywistym, jednak ESP32-CAM w MicroPythonie automatycznie dostosowuje jasność obrazu, czego nie da się wyłączyć, używając tego języka programowania, co może wpływać na wyniki. Zaleca się:

  • Testowanie w kontrolowanym, przyciemnionym otoczeniu
  • Użycie filtra na obiektyw (np. kawałek kolorowej taśmy)

Domyślnie wyznaczone w programie współczynniki wzmocnień i SETPOINT są wynikiem moich testów. Ta konfiguracja była skuteczna u mnie zarówno po przysłonieniu obiektywu taśmą, jak i używaniem kamery pod kartonowym pudełkiem (w ten sposób stwarzając przyciemnione, kontrolowane środowisko)

5. Dobór nastaw regulatora

Wartości zmiennych można obserwować w ploterze Thonny.

Regulator P:

  1. Ustaw początkowe wzmocnienie Kp.
  2. Jeśli wykres nie stabilizuje się, zmniejsz wartość Kp.

Regulator PID:

  1. Dobierz wartość Kp (jak w regulatorze P).
  2. Stopniowo dostosuj Ki i Kd.
  3. Jeśli odpowiedź systemu jest zbyt powolna - zwiększ Ki.
  4. Jeśli system jest niestabilny - zmniejsz Kd.

Przykładowe wykresy:

  • Niestabilna regulacja - oscylacje wokół zadanej wartości

Wykres 1

  • Stabilna regulacja - wartość jasności stabilizuje się po czasieWykres2
kod programu
##############################
Plik: kamera_PID
####################

import camera
import network
import time
import gc
import jasnosc

from machine import Pin, PWM

latarka = PWM(Pin(4), 100)
latarka.duty(0)

SETPOINT = 40

#taśma
Kp = 1.2
Ki = 6
Kd = 0.001

#pudelko war. poczatkowe nr 1
#Kp = 0.2
#Ki = 1
#Kd = 0.002

#pudelko war. poczatkowe nr 2
#Kp = 0.05
#Ki = 0.5
#Kd = 0.001

previous_error = 0
integral = 0
dt = 0.32

# Funkcja regulatora PID
def pid_controller(setpoint, measured_value):
    global previous_error, integral
    
    # Obliczanie błędu
    error = setpoint - measured_value
    
    # Składowa proporcjonalna
    P = Kp * error
    
    # Składowa całkowa
    integral += error * dt
    I = Ki * integral
    
    # Składowa różniczkowa
    derivative = (error - previous_error) / dt
    D = Kd * derivative
    
    # Sygnał sterujący
    control_signal = P + I + D
    
    # Aktualizacja błędu poprzedniego
    previous_error = error
    
    return control_signal


try:
    camera.init(0, format=camera.GRAYSCALE, framesize=camera.FRAME_QQVGA, xclk_freq=camera.XCLK_10MHz, fb_location=camera.PSRAM)
    print('camera initialazed')
    
    while True:
        buffer = camera.capture()
        
        average_brightness = jasnosc.calculate_average_brightness(buffer)
        print(average_brightness)
        
        buffer = None  # Usuń dane bufora
        gc.collect()   # Wymuś zbieranie pamięci
        
        control_signal = pid_controller(SETPOINT, average_brightness)

        #print("control_signal:", control_signal)
        control_signal = round(control_signal)
        if control_signal < 0:
            control_signal = 0
        elif control_signal > 1023:
            control_signal = 1023
        #print("control_signal:", control_signal)
        
        latarka.duty(control_signal)
        time.sleep(0.2)
            
except Exception as e:
    print('An issue occurred')
    
finally:
    camera.deinit()
    print('Camera deinitialized')

Tagi
PID Regulator ESP32-CAM analiza_obrazu DIY
Odnośniki zewnętrzne
https://github.com/lemariva/micropython-camera-driver/tree/master
https://github.com/shariltumin/esp32-cam-micropython-2022