Kontroler ładowania MPPT na Arduino

Czas czytania: 8 min.

Podczas ładowania akumulatorów koniecznością jest zapewnienie odpowiedniej charakterystyki prądu, co pozwala zapobiec ich przeładowaniu. Dzięki temu zwiększana jest żywotność baterii w układzie panel solarny – akumulator. Po przekroczeniu krytycznego napięcia regulator odłącza źródło poboru energii, analogicznie jest przy pełnym naładowaniu akumulatora. Niniejszy artykuł przedstawia przykładowy prototyp solarnej ładowarki baterii opartej na Arduino, która działa na zasadzie śledzenia punktu mocy maksymalnej (MPPT).

Funkcje i cel stosowania kontrolera MPPT

Kontroler MPPT odpowiada za ładowanie baterii w różnych trybach, chroni baterię przed uszkodzeniem wskutek przeładowania, a także chroni panel słoneczny przed przetężeniem. Inne funkcje kontrolera MPPT to zabezpieczenie baterii przed przeciążeniem (blokada podnapięciowa) oraz śledzenie stopnia naładowania. Współczesne, nowoczesne baterie, np. ołowiowo-żelowe, wymagają ładowania 3-etapowego

Gdy bateria jest głęboko rozładowana, uruchamiane jest ładowanie w trybie bulk, tj. odpowiednio dużym prądem do pojemności baterii. W takim trybie, bateria jest ładowana prądem stałym w czasie do około 80% swojej całkowitej pojemności. Po osiągnięciu określonego progu napięcia, kontroler przełącza proces ładowania w tryb absorpcji. W tym trybie, bateria jest ładowana stałym napięciem, ale coraz niższym prądem. Kiedy faza absorpcji zostanie zakończona, kontroler ładowania przechodzi w tryb podtrzymania napięcia i ładuje akumulator prądem, którego wartość stanowi 1% pojemności baterii podzielonej przez godzinę, np. dla baterii o pojemności 2Ah byłby to prąd wynoszący 2mA. 

W naszym prototypie, zastosujemy akumulator o napięciu znamionowym 12V i pojemności 2Ah, który może być maksymalnie ładowany napięciem 14,4V i prądem 2A.

Budowa prototypowego kontrolera ładowania MPPT w oparciu o Arduino i jego zasada działania

 

Nasz kontroler ładowania MPPT musi być zdolny do odczytywania napięć i prądów wyjściowych i wejściowych, a także wykonywania niezbędnych obliczeń, umożliwiających niezbędną optymalizację procesu ładowania. W tym celu, jako czujnik prądu użyjemy dedykowanego modułu ACS712. Natomiast przetwornicę impulsową napięcia zasilającego będziemy sterować wykorzystując źródło sygnału PWM z Arduino oraz tranzystor MOSFET lub przekaźnik elektromagnetyczny, który będzie załączał i wyłączał obciążenie. Do odczytu parametrów ładowania, użyjemy wyświetlacza LCD w układzie 4×20 (cztery linijki po dwadzieścia znaków każda). Konieczna będzie także przetwornica obniżająca napięcie do 5V do zasilania płytki Arduino.

Kontroler ładowania MPPT - kod programu do pomiaru i stabilizacji prądu ładowania na stałym poziomie

Poniższy kod programu ma za zadanie sterować ograniczaniem prądu ładowania do 1A. Z tego względu, w przypadku podłączenia zbyt wysokiego napięcia ładowania, kontroler MPPT ma za zadanie ograniczyć prąd ładowania do programowo ustawionej wartości. Jest to realizowane poprzez odpowiednie zmniejszanie i zwiększanie współczynnika wypełnienia przebiegu PWM sterującego bramką tranzystora MOSFET, aby względnie ustabilizować prąd ładowania na wartość 1A.

Kod programu:

				
					//Program steruje stabilizacja pradu ladowania baterii przez kontroler ladowania MPPT
#include <Wire.h> //Inicjalizacja biblioteki Wire.h
#include <LiquidCrystal_I2C.h> //Inicjacja biblioteki do obslugi wyswietlacza LCD

LiquidCrystal_I2C lcd(0x27,20,4);  //Adresowanie wyswietlacza LCD do magistrali I2C

//Deklaracja stalych
#define LCD_refresh_rate 1000 //odswiezanie wyswietlacza LCD co 1s

//Deklaracja wejsc
#define solar_current_in A0 //pomiar pradu - wejscie analogowe A0
//Deklaracja wyjsc
#define PWM_out 10
#define load_enable 2

//Deklaracja zmiennych
int pwm_value = 0; //poczatkowy wspolczynnik wypelnienia sygnalu sterujacego MOSFETem
float solar_current = 0; //poczatkowy prad ladowania
float current_factor = 0.185; //Wartosc domyslna deklarowana przez producenta czujnika ACS712
unsigned int before_millis = 0;
unsigned int now_millis = 0;

void setup(){
  pinMode(solar_current_in,INPUT); //pin pomiaru pradu ladowania jako wejscie
  pinMode(PWM_out,OUTPUT); //pin sterujacy PWM ladowania jako wyjscie
  digitalWrite(PWM_out,LOW); //pin PWM ustawiony w stan niski - MOSFET nie przewodzi
  TCCR1B = TCCR1B & B11111000 | B00000001; //timer 1 ustawiony na czestotliwosc 31372.55Hz
  Serial.begin(9600); //wlaczenie transmisji szeregowej
  lcd.init(); //wlaczenie wyswietlacza LCD
  lcd.backlight(); //wlaczenie podswietlenia wyswietlacza LCD
  before_millis = millis; //rozdzielczosc czasu odswiezania wyswietlacza LCD
}

void loop(){
  solar_current = get_solar_current(10);
  now_millis = millis();
  if(now_millis - before_millis > LCD_refresh_rate)
    {
    before_millis = now_millis;
    //lcd.clear(); //wyczyszczenie zawartosci wyswietlacza LCD
    lcd.setCursor(0,0); //ustawienie kursora
    lcd.print(solar_current,2); //wyswietlanie pradu na wyjsciu panelu solarnego
    lcd.print("A"); //prad w Amperach
    }
//Stabilizacja stalego pradu ladowania
    if(solar_current > 1.0) //dla pradu ladowania wiekszego od 1.0A
    {
    pwm_value--;
    pwm_value = constrain(pwm_value,0,254); //zakres modulacji PWM od 0% do 99%
    } else {
    pwm_value++;
    pwm_value = constrain(pwm_value,0,254);
    }
    analogWrite(PWM_out,pwm_value); //wartosc wspolczynnika wypelnienia
//pomiar liczby probek
    float get_solar_current(int n_samples)
    {
        float Sensor_voltage; //napiecie z czujnika
        float current =0;
        for(int i=0; i < n_samples; i++)
        {
        Sensor_voltage = analogRead(solar_current_in) * (5.0 / 1023.0);
        current = current + (Sensor_voltage-2.5)/current_factor;
        } //odczyt napiecia z czujnika
    }
current = current/n_samples; //obliczenie liczby probek pradu
return(current);
}


				
			

Kontroler ładowania MPPT - kod programu do pomiaru i stabilizacji napięcia ładowania na stałym poziomie

Następna część kodu programu odpowiada za utrzymywanie napięcia o stałej wartości ładowania. W przypadku naszego projektu, będzie to wartość na poziomie 12V. Kod uwzględnia wszystkie trzy fazy procesu ładowania baterii.

Kod programu:

				
					//Program steruje stabilizacja napiecia ladowania baterii przez kontroler ladowania MPPT
#include <Wire.h> //Inicjalizacja biblioteki Wire.h
#include <LiquidCrystal_I2C.h> //Inicjacja biblioteki do obslugi wyswietlacza LCD
LiquidCrystal_I2C lcd(0x27,20,4);  //Adresowanie wyswietlacza LCD do magistrali I2C

//Deklaracja wejsc
#define battery_voltage_in A2
//Deklaracja wyjsc
#define PWM_out 10
#define load_enable 2

//Deklaracja zmiennych
float bat_voltage = 0; //poczatkowe napiecie ladowania baterii
int pwm_value = 0; //poczatkowy wspolczynnik wypelnienia sygnalu sterujacego MOSFETem
unsigned int before_millis = 0;
unsigned int now_millis = 0;
#define LCD_refresh_rate 1000 //odswiezanie wyswietlacza LCD co 1s

void setup(){
  pinMode(battery_voltage_in,INPUT); //pin pomiaru napiecia ladowania baterii jako wejscie
  pinMode(PWM_out,OUTPUT); //pin PWM jako wyjscie
  digitalWrite(PWM_out,LOW); //pin PWM przerzucowny w stan niski
  TCCR1B = TCCR1B & B11111000 | B00000001; //timer 1 ustawiony na czestotliwosc 31372.55 Hz
  Serial.begin(9600); //wlaczenie transmisji szeregowej
  lcd.init(); //Wlaczenie wyswietlacza LCD
  lcd.backlight(); //Wlaczenie podswietlenia wyswietlacza LCD
  before_millis = millis;
}

void loop(){
  bat_voltage = get_battery_voltage(10); //napiecie baterii na podstawie wspolczynnika wypelnienia sygnalu PWM z pinu 10
  now_millis = millis();
  if(now_millis - before_millis > LCD_refresh_rate)
  {
    before_millis = now_millis;
    //lcd.clear(); //wyczyszczenie zawartosci wyswietlacza LCD
    lcd.setCursor(0,0); //zerowanie pozycji kursora
    lcd.print(bat_voltage,2); //napiecie baterii
    lcd.print("V"); //wyswietlanie wyniku w Woltach
  }

//Sterowanie stabilizacja napiecia ladowania
  if(bat_voltage > 12.0){ //Sprawdzenie warunku przekroczenia napiecia baterii
    pwm_value++;
    pwm_value = constrain(pwm_value,0,254);
  }
  else {
    pwm_value--;
    pwm_value = constrain(pwm_value,0,254);
  }
  analogWrite(PWM_out,pwm_value); //wysterowanie wyjscia PWM
}

//Pomiar i probkowanie wartosci napiecia baterii
float get_battery_voltage(int n_samples)
{
  float voltage = 0;
  for(int i=0; i < n_samples; i++)
  {
    voltage += (analogRead(battery_voltage_in) * (5.0 / 1023.0) * 7.85); //Pomiar napiecia
  }
  voltage = voltage/n_samples; //obliczenie liczby probek napiecia
  return(voltage);
}
				
			

Kontroler ładowania MPPT - kod programu do pomiaru i stabilizacji punktu mocy maksymalnej

Ostatnia część kodu programu dla kontrolera MPPT, jest odpowiedzialna za obliczanie i stabilizację punktu mocy maksymalnej, przy którym występują najbardziej optymalne warunki do ładowania baterii. Program wykonuje pomiary porównawcze prądów i napięć i przy spełnieniu określonych warunków dokonuje przełączenia pomiędzy trybami ładowania.

Kod programu:

				
					//Program steruje stabilizacja punktu mocy maksymalnej kontrolera ladowania MPPT i przelacza pomiedzy trybami ladowania
#include <Wire.h> //Inicjalizacja biblioteki Wire.h
#include <LiquidCrystal_I2C.h> //Inicjalizacja biblioteki do obslugi wyswietlacza LCD
LiquidCrystal_I2C lcd(0x27,20,4); //Adresowanie wyswietlacza LCD do magistrali I2C

//Inicjacja zmiennych
uint8_t Battery[8]  = {0x0E, 0x1B, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x1F};
uint8_t Panel[8]  = {0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x15, 0x1F, 0x00};
uint8_t Pwm[8]  = {0x1D, 0x15, 0x15, 0x15, 0x15,0x15, 0x15, 0x17};
uint8_t Flash[8]  = {0x01, 0x02, 0x04, 0x1F, 0x1F, 0x02, 0x04, 0x08};

//Inicjacja stalych
#define bulk_voltage_max 14.5 //maks. napiecie w trybie bulk
#define bulk_voltage_min 13 //min. napiecie w trybie bulk
#define absorption_voltage 14.7 //napiecie w trybie absorpcji
#define float_voltage_max 13 //maks. napiecie w trybie podtrzymania
#define battery_min_voltage 10 //min. napiecie baterii
#define solar_min_voltage 19 //min. napiecie panelu solarnego
#define charging_current 2.0 //min. prad ladowania
#define absorption_max_current 2.0 //maks. prad absorpcji
#define absorption_min_current 0.1 //min. prad absorpcji
#define float_voltage_min 13.2 //min. napiecie w trybie podtrzymania
#define float_voltage 13.4 //ustalone napiecie w trybie podtrzymania
#define float_max_current 0.12 //maks. prad w trybie podtrzymania
#define LCD_refresh_rate 1000 //odswiezanie wyswietlacza LCD co 1s
byte BULK = 0; //przypisanie liczb do poszczegolnym trybom ladowania
byte ABSORPTION = 1;
byte FLOAT = 2;
byte mode = 0; //domyslnie ladowanie rozpoczynamy od trybu bulk

//konfiguracja wejsc analogowych do pomiarow
#define solar_voltage_in A1 //napiecie panelu solar - pin A1
#define solar_current_in A0 //prad na wyjsciu panelu solar - pin A0
#define battery_voltage_in A2 //napiecie baterii - pin A2

//konfiguracja wyjsc
#define PWM_out 10 //wyjscie sygnalu PWM - pin D10
#define load_enable 2 //zalaczanie ladowania - pin D2

//inicjacja zmiennych
float bat_voltage = 0; //napiecie baterii
int pwm_value = 0; //wspolczynnik wypelnienia
float solar_current = 0; //prad ladowania
float current_factor = 0.185; //stala pradowa dla czujnika ACS712 5A
float solar_voltage = 0; //napiecie panelu solarnego
float solar_power = 0; //moc panelu solarnego
String load_status = "OFF"; //status ladowania - wylaczone
int pwm_percentage = 0; //procentowa wartosc wsp. wypelnienia
unsigned int before_millis = 0;
unsigned int now_millis = 0;
String mode_str = "BULK";

void setup(){
  pinMode(solar_voltage_in,INPUT); //konfiguracja pinow jako wejscia
  pinMode(solar_current_in,INPUT);
  pinMode(battery_voltage_in,INPUT);
  pinMode(PWM_out,OUTPUT); //konfiguracja pin PWM jako wyjscie
  digitalWrite(PWM_out,LOW); //pin PWM ustawiony w stan niski - MOSFET nie przewodzi
  pinMode(load_enable,OUTPUT); //wyjscie zalaczajace ladowanie
  digitalWrite(load_enable,LOW); //wylaczenie ladowania (przekaznik)
  TCCR1B = TCCR1B & B11111000 | B00000001; //timer 1 ustawiony na czestotliwosc 31372.55Hz
  Serial.begin(9600); //wlaczenie transmisji szeregowej
  lcd.init(); //wlaczenie wyswietlacza LCD
  lcd.backlight(); //wlaczenie podswietlenia wyswietlacza LCD
  lcd.createChar(0, Battery);
  lcd.createChar(1, Panel);
  lcd.createChar(2, Pwm);
  lcd.createChar(3, Flash);
  before_millis = millis; //rozdzielczosc czasu odswiezania wyswietlacza LCD
}

void loop(){
  solar_voltage = get_solar_voltage(15); //napiecie panelu solarnego
  bat_voltage =   get_battery_voltage(15); //napiecie baterii
  solar_current = get_solar_current(15); //prad panelu solarnego
  solar_power = bat_voltage * solar_current; //moc panelu solarnego
  pwm_percentage = map(pwm_value,0,255,0,100);
  
//wyswietlanie pomiarow na wyswietlaczu LCD
  now_millis = millis();
  if(now_millis - before_millis > LCD_refresh_rate)
  {
    before_millis = now_millis;
    lcd.clear();
    lcd.setCursor(0,0); //kursor ustawiony na kolumne 0 rzad 0
    lcd.write(1); //wpisanie "1" na LCD - pomiar dla panelu solar.
    lcd.print(" "); //spacja
    lcd.print(solar_voltage,2); //napiecie panelu solarnego
    lcd.print("V"); //napiecie w Woltach
    lcd.print("    "); //cztery spacje
    lcd.write(0); //wpisanie "0" na LCD - pomiar dla baterii
    lcd.print(" ");  //spacja
    lcd.print(bat_voltage,2); //napiecie baterii
    lcd.print("V"); //napiecie w Woltach
    lcd.setCursor(0,1); //kursor ustawiony na kolumne 0 rzad 1
    lcd.print("  "); //cztery spacje
    lcd.print(solar_current,2); //pomiar pradu dla panelu solar.
    lcd.print("A"); //prad w Amperach
    lcd.print("     LOAD "); //obciazenie
    lcd.print(load_status); //status obciazenia
    lcd.setCursor(0,2); //kursor ustawiony na kolumne 0 rzad 2
    lcd.print("  "); //Dwie spacje
    lcd.print(solar_power,2); //moc z panelu solarnego
    lcd.print("W"); //moc w Watach
    lcd.print("     PWM "); //wyswietlanie "PWM"
    lcd.print(pwm_percentage); //wartosc procent. wsp. wypelnienia
    lcd.print("%"); //wyswietlanie znaku procentow
    lcd.setCursor(0,3); //kursor ustawiony na kolumne 0 rzad 3
    lcd.print(mode_str);
  }
  if(bat_voltage < battery_min_voltage){
    digitalWrite(load_enable,LOW); //ponizej minimalnego napiecia obciazenie jest wylaczane
    load_status  = "OFF"; //status obciazenia - wylaczone
  }
  else{
    digitalWrite(load_enable,HIGH); //gdy bateria jest naladowana wlaczamy obciazenie
    load_status  = "ON"; //status obciazenia - wlaczone
  }

//Tryb podtrzymania napiecia baterii po zakonczeniu ladowania
//Dla napiecia baterii ponizej napiecia podtrzymania, wlaczyc ladowanie napieciem stalym w trybie BULK
  if(mode == FLOAT){
    if(bat_voltage < float_voltage_min){
      mode = BULK; //wlaczenie trybu bulk
      mode_str = "BULK";
    }
    else{
      if(solar_current > float_max_current){ //po przekroczeniu pradu panelu solarnego powyzej pradu podtrzymania, wlaczyc ladowanie pradem stalym w trybie BULK
        mode = BULK; //wlaczenie trybu bulk
        mode_str = "BULK";
      }//End if > 
      else{
        if(bat_voltage > float_voltage){
          pwm_value--;
          pwm_value = constrain(pwm_value,0,254); //dla napiecia baterii wiekszego od napiecia podtrzymania, zmniejszyc wsp. wypelnienia o 1
        }
        else {
          pwm_value++;
          pwm_value = constrain(pwm_value,0,254); //dla napiecia baterii mniejszego od napiecia podtrzymania, zwiekszyc wsp. wypelnienia o 1
        }
      }//End else > float_max_current //w innym przypadku zwiekszyc prad ladowania w stanie podtrzymania napiecia
      analogWrite(PWM_out,pwm_value);
    }
  }//END of mode == FLOAT //wylaczenie trybu podtrzymania napiecia

  //Zmiana trybu z bulk na absorpcje
  else{
    if(bat_voltage < bulk_voltage_min){
      mode = BULK;
      mode_str = "BULK"; //wlaczenie trybu ladowania bulk
    }
    else if(bat_voltage > bulk_voltage_max){
      mode_str = "ABSORPTION";
      mode = ABSORPTION; //wlaczenie trybu ladowania absorpcyjego
    }

//Wlaczenie trybu bulk
    if(mode == BULK){
      if(solar_current > charging_current){ //jesli prad panelu solar. wiekszy od pradu ladowania, zmniejszyc wsp wypelnienia o 1
        pwm_value--;
        pwm_value = constrain(pwm_value,0,254);
      }
      else { ////jesli prad panelu solar. mniejszy od pradu ladowania, zwiekszyc wsp wypelnienia o 1
        pwm_value++;
        pwm_value = constrain(pwm_value,0,254);
      }
      analogWrite(PWM_out,pwm_value);
    }//End of mode == BULK //wylaczenie trybu bulk

   //Tryb absorpcji
    if(mode == ABSORPTION){
      if(solar_current > absorption_max_current){
        pwm_value--;
        pwm_value = constrain(pwm_value,0,254); //jesli prad panelu solar. przekracza maksymalny prad absorpcji, zmniejszyc wsp. wypelnienia o 1
      }//End if > absorption_max_current ////jesli prad panelu solar. przekracza maksymalny prad absorpcji, zmniejszyc wsp. wypelnienia o 1
      else{
        if(bat_voltage > absorption_voltage){
          pwm_value--;
          pwm_value = constrain(pwm_value,0,254); //jesli napiecie baterii przekracza napiecie absorpcji, zmniejszyc wsp. wypelnienia o 1 w gore
        }
        else {
          pwm_value++;
          pwm_value = constrain(pwm_value,0,254); // //jesli napiecie baterii mniejsze od napiecia absorpcji, zwiekszyc wsp. wypelnienia o 1 w gore
        }
        if(solar_current < absorption_min_current){ //jesli prad panelu solarnego mniejszy od minimalnego pradu ladowania absorpcyjnego
          mode = FLOAT; //uruchomienie tryby podtrzymania napiecia
          mode_str = "FLOAT";
        }
      }//End else > absorption_max_current //jesli prad panelu solarnego wiekszy od maksymalnego pradu ladowania absorpcyjnego
      analogWrite(PWM_out,pwm_value);
    }// End of mode == absorption_max_current //wylaczenie trybu podtrzymania napiecia
  }//END of else mode == FLOAT 
  //Serial.println(bat_voltage); //napiecie baterii
}//End void loop

//Pomiar napiecia panelu solarnego poprzez probkowanie napiecia
float get_solar_voltage(int n_samples)
{
  float voltage = 0;
  for(int i=0; i < n_samples; i++)
  {
    voltage += (analogRead(solar_voltage_in) * (5.0 / 1023.0) * 8.0); //obliczanie napiecia panelu solarnego dla przetwornika ADC
  }
  voltage = voltage/n_samples;
  if(voltage < 0){voltage = 0;}
  return(voltage);
}

//Pomiar napiecia baterii poprzez probkowanie napiecia
float get_battery_voltage(int n_samples)
{
  float voltage = 0;
  for(int i=0; i < n_samples; i++)
  {
    voltage += (analogRead(battery_voltage_in) * (5.0 / 1023.0) * 7.85); //obliczanie napiecia dla przetwornika ADC
  }
  voltage = voltage/n_samples;
  if(voltage < 0){voltage = 0;}
  return(voltage);
}

//Pomiar pradu z panelu poprzez probkowanie napiecia
float get_solar_current(int n_samples)
{
  float Sensor_voltage;
  float current =0;
  for(int i=0; i < n_samples; i++)
  {
    Sensor_voltage = analogRead(solar_current_in) * (5.0 / 1023.0); //obliczanie spadku napiecia dla przetwornika ADC
    current = current + (Sensor_voltage-2.5)/current_factor; //obliczanie pradu na podstawie spadku napiecia
  }
  current = current/n_samples;
  if(current < 0){current = 0;}
  return(current);
}
				
			

Arduino jako kontroler MPPT - podsumowanie

Przedstawiona koncepcja kontrolera ładowania MPPT obrazuje prosty prototyp, który choć spełnia swoją rolę dostatecznie, to w dalszym ciągu ma pewne ograniczenia wynikające m.in. z niskiej sprawności paneli fotowoltaicznych. Niemniej jednak, w miarę ulepszania technologii paneli solarnych, wzrośnie ich sprawność i w połączeniu z wykorzystaniem algorytmu MPPT, fotowoltaika stanie się jeszcze bardziej korzystna ekonomicznie. Z czasem taka technologia sprawdzi się jeszcze lepiej w zasilaniu odbiorników o wzmożonym poborze energii elektrycznej.

Jak oceniasz ten wpis blogowy?

Kliknij gwiazdkę, aby go ocenić!

Średnia ocena: 4.3 / 5. Liczba głosów: 11

Jak dotąd brak głosów! Bądź pierwszą osobą, która oceni ten wpis.

Podziel się:

Picture of Maciej Figiel

Maciej Figiel

Wszechstronny, chętnie podejmuje się wyzwań, bo uważa, że jest to najszybsza droga ku rozwojowi. Ceni sobie kontakt z naturą i aktywny wypoczynek. Pasjonat motoryzacji i nowych technologii.

Zobacz więcej:

Jedna odpowiedź

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Ze względów bezpieczeństwa wymagane jest korzystanie z usługi Google reCAPTCHA, która podlega Polityce prywatności i Warunkom użytkowania.