Go Down

Topic: Programming help needed for solar maximum power point tracker MPPT (Read 829 times) previous topic - next topic

antman85

Hey guys

I've built a buck converter board designed to charge batteries from a higher voltage solar panel see below thread
https://forum.arduino.cc/index.php?topic=374608.0

I've got some code running at the moment which works well at above 50 watts but once the power drops it finds a false maximum power point and gets stuck there until reset. The code works on dropping output current instead of output power.

This board has a huge amount of potential as a solar charger but needs a decent programmer to get it working properly. I'm very much a hardware guy and even Arduino is difficult for me to program.

I'd be willing to exchange a complete board for somebody's time and effort to write some code.

Here is the current code I'm using
Code: [Select]
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
//
// Boost Maximum Power Point Tracking
// Using Arduino Uno
// by: Rusdy Simano
// Last Update: 10 June 2014
//
// Full details in:
// http://epxhilon.blogspot.com.au/
//
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------




// ------------------------------------------------------------------------
// I/O pin settings
// ------------------------------------------------------------------------
const int pin_Vin = 0;          // pin of Vin connected to (A0)
const int pin_Iin = 3;          // pin of Iin connected to (A3)
const int pin_Vout = 2;         // pin of Vout connected to (A2)
const int pin_Iout = 1;         // pin of Iout connected to (A1)

const int switchPin = 11;  // pin of switching output connected to MOSFET





// ------------------------------------------------------------------------
// Constant variables
//
// RAW units are readings from Arduino Analogues
// Refer to the schematic for engineering unit conversion
//
// ------------------------------------------------------------------------
const int Vin_min = 230;  // Variable to store Vin_min, this is RAW unit (0 - 1023)
        // Currently, '430' corresponds to around 12VDC

const int Iin_max = 1000; // Variable to store Iin_max, this is RAW unit (0 - 1023)

const int Iout_max = 120; // Variable to store Iout_max, this is RAW unit (0 - 1023)
                                // With current PCB (Resistor drawn PCB), 800 (RAW) equals to 3 Amperes 

const int avgNum = 8;   // Number of iterations of the adc routine to average the adc readings





// ------------------------------------------------------------------------
// Variable declarations
//
// RAW units are readings from Arduino Analogues
// Refer to the schematic for engineering unit conversion
//
// ------------------------------------------------------------------------
int Vin = 0;    // Variable to store Input Voltage, this is RAW unit (0 - 1023)
int Iin = 0;    // Variable to store Input Current, this is RAW unit (0 - 1023)
int Vout = 0;   // Variable to store Output Voltage, this is RAW unit (0 - 1023)
int Iout = 0;   // Variable to store Output Current, this is RAW unit (0 - 1023)

int Vout_max = 258; // Variable to store maximum output voltage, this is RAW unit (0 - 1023)
      // With current schematic, '830' corresponds to 42V output voltage max.

int Vout_trickle = 254; // Variable to store trickle voltage charge, this is RAW unit (0 - 1023)
      // With current schematic, '826' corresponds to 41.8V output voltage max.

int currentPrev = 0;  // Variable to store Previous Sampled Current, this is RAW unit (0 - 1023)
int currentDiff = 0;  // Variable to store Current Difference, this is unitless


int dutyCycle = 0;  // Variable to store duty cycle of PWM output to MOSFET, 0 to 255
int state = 0;    // variable to store state machine
      // State '0' is start-up




// ------------------------------------------------------------------------
// This routine is automatically called at powerup/reset
// ------------------------------------------------------------------------

void setup()
{
//  Serial.begin(9600);

// running with high speed clock (set prescale to 16)
// so that analog sampling time is now approximately 17microsecond
// Source: Arduino Cookbook by MichaelMargolis 2nd chapter recipe 18-9

  bitClear(ADCSRA,ADPS0) ;
  bitClear(ADCSRA,ADPS1) ;
  bitSet(ADCSRA,ADPS2) ;

// Set switchPin to output mode
  pinMode(switchPin, OUTPUT);   


// Increase PWM frequency to 31kHz
// Source: http://playground.arduino.cc/Code/PwmFrequency

  TCCR2B = TCCR2B & 0b11111000 | 0x01;

}




// ------------------------------------------------------------------------
// This routine selects maximum output voltage during start-up
// specifically for Rusdy's shed setup
//
// If 24VDC battery is connected, this is a lead acid battery
// else, assume e-Bike battery, 36V Lithium NMC
//
// With current schematic:
// '356' corresponds to around 18.0 VDC output voltage
// '553' corresponds to around 28.0 VDC output voltage
// '557' corresponds to around 28.2 VDC output voltage
// '561' corresponds to around 28.4 VDC output voltage
// '830' corresponds to around 42.0 VDC output voltage
// 
// ------------------------------------------------------------------------

void determine_Vout_Max(void)
{
 
  if ((Vout >= 356) && (Vout <= 561)) // If Lead Acid 24VDC battery detected
  {
    Vout_max = 561;
    Vout_trickle = 557;
  }
}





// ------------------------------------------------------------------------
// This routine reads and averages the analog inputs for this system
//
// It is called with the ADC channel number (pin number) and returns the average ADC
// value as an integer.
//
// Credit: http://www.timnolan.com/uploads/Arduino%20Solar/ppt.pde
// ------------------------------------------------------------------------

int read_adc(int channel)
{
  int sum = 0;
  int temp;
  int i;
 
  for (i=0; i<avgNum; i++)
  {                             // loop through reading raw adc values avgNum number of times 
    temp = analogRead(channel); // read the input pin 
    sum += temp;                // store sum for averaging
    delayMicroseconds(10);      // pauses for 10 microseconds 
  }
  return(sum / avgNum);         // divide sum by AVG_NUM to get average and return it
}



// ------------------------------------------------------------------------
// Main routine
// ------------------------------------------------------------------------
void loop()
{
 
  Vout = read_adc(pin_Vout);   // Read Output Voltage 
  Vin = read_adc(pin_Vin);   // Read Input Voltage
  Iout = read_adc(pin_Iout);     // Read Output Current


  if ((Vin >= Vin_min) && (state == 0))   // Select maximum output voltage
        // Only required at start-up
  {
    determine_Vout_Max();
    state = 1;      // Change state
  }



  currentDiff = Iout - currentPrev;  // Calculate the current difference between now and previous sample


  if ((Vout >= Vout_max) || (Vin <= Vin_min))
  {
    dutyCycle = 0;    // If input and output voltages outside limit,
        // reset dutyCycle to 0 (of 255), i.e. OFF
  }
  else if (Vout >= Vout_trickle)
  {
    dutyCycle = dutyCycle - 8;  // If output voltage at trickle threshold
        // reduce dutyCycle
  }
  else if ((currentDiff < 0) || (Iout > Iout_max))
  {
    dutyCycle = dutyCycle - 4;  // If output current is decreasing, OR beyond maximum
        // reduce dutyCycle
  }
  else
  {
    dutyCycle = dutyCycle;  // else, do nothing
  }
 
  if (dutyCycle < 1)
  {
    dutyCycle = 0;   // making sure dutyCycle is not negative
  }
  else if (dutyCycle > 200)
  {
    dutyCycle = 200;    // making sure dutyCycle does not exceed 200 per 255
  }


  analogWrite(switchPin, dutyCycle);
  delay(100);
   
 
  Vout = read_adc(pin_Vout);   // Read Output Voltage 
  Vin = read_adc(pin_Vin);   // Read Input Voltage
  Iout = read_adc(pin_Iout);     // Read Output Current

 
  currentPrev = Iout;
  dutyCycle = dutyCycle + 1;

  if ((Vout >= Vout_max) || (Vin <= Vin_min))
  {
    dutyCycle = 0;    // If input and output voltages outside limit,
        // reset dutyCycle to 0 (of 255), i.e. OFF
  }
  else
  {
    dutyCycle = dutyCycle;  // else, do nothing
  }


  analogWrite(switchPin, dutyCycle);
  delay(10);
   
}

 

backwoodsjack

I'm interested.. If u still are there and still in need of help.. never-the-less i wonder if u got it figured out by now..

allanhurst

All you do is continuously vary the pwm up and down a bit (5%?) and find which way gives you the highest output current - follow that ..

regards

Allan

PaulMurrayCbr

If setting the duty cycle cant hurt anything, then you could just do a sweep every minute or so.

Alternatively, you could write code whose job it is to start trying to track the appropriate setting when it senses a  change.

How ab out: can you attempt to describe in english what value switchPin should be set to, given the values of Vout, Vin, and Iout?
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

Go Up