I am trying to make a signal closed loop for an interleaved boost converter. A few weeks ago, with the help of the community, I got the PWM signals sorted out.
Now I am trying to make the system closed loop. Output pins are 9 and 10, output voltage from the converter is on A0, and input voltage to the converter is on pin A1, frequency is 32kHz.
I have the PID closed loop (PID_v1.h) working with a simple boost converter on pin 6 but can’t work out how to get the outputs on pin 9 and 10. On my scope the duty cycles are not responding to anything and show 0%.
I have included the code I have tried, and a picture of the duty cycle required at 60%.
#include "TimerHelpers.h"
#include <PID_v1.h>
int pwmPin1 = 9;
int pwmPin2 = 10;
double analogPin0 = A0;
double analogPin1 = A1;
double Out = 0;
double Involtage = 0;
double Setpoint, Input, Output;
double Kp=0.4, Ki=0, Kd=0;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
pinMode(pwmPin1, OUTPUT);
pinMode(pwmPin2, OUTPUT);
TCCR1A = 0; // reset timer 1
TCCR1B = 0;
Timer1::setMode (8, Timer1::PRESCALE_1, Timer1::CLEAR_A_ON_COMPARE | Timer1::SET_B_ON_COMPARE);
ICR1 = 250; // 250 -> 32kHz w PRESCALE_1 Sets frequency with prescaler as f=F_CPU/PRESCALE/ICR/2
TCNT1 = 0; // reset counter
OCR1A = ICR1 / 4; // compare A register value
OCR1B = ICR1 - OCR1A; // compliment and invert
Serial.begin(115200);
analogWrite(pwmPin1, 120);
//initialize the variables we're linked to
Input = analogRead(analogPin0);
Setpoint = 200; // 175= 10v 220=12V
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0,220);
}
void loop() {
Out = analogRead(analogPin0);// read the output voltage pin
Involtage = analogRead(analogPin1);// read the input voltage pin
myPID.Compute();
analogWrite(pwmPin1, Output);
analogWrite(pwmPin2, Output);
OCR1A = ICR1 * 1UL * A0/1023; // duty cycle
OCR1B = ICR1 - OCR1A; // complement for inversion
Serial.print ("input volts ");
Serial.print ((Involtage * (5.0/1023)) * (12.3));// 12.3 for resistors
Serial.print(" ");
Serial.print (Involtage);
Serial.print(" output volts ");
Serial.print ((Out * (5.0/1023)) * (12.9));// 12.9 for resistors
Serial.print(" ");
Serial.println (Out);
}
[60% duty cycle.pdf|attachment](upload://nCyz8QwHeD6pwAwobonh7BxaEld.pdf) (26.7 KB)
I think your analogWrite and your timer manipulations are interfering with one another. Once you've got the WGM turned on at the pins in setup, all you need to do is set your OCR1A and OCR1B registers to get the duty cycle. Leave analogWrite out of it.
You are correct A0 is a constant and shouldn’t be there.
To be honest I tried to stitch together the code from 3 files to produce this file, so I am not entirely sure why I have added the line which refers to A0.
I think you want to vary the duty cycle, and those lines are key, but it is unclear if you want to vary it based on the PID's Output or an analogRead(A0).
Yes, the reading from A0 will automatically adjust the duty cycle based on the setpoint with a PID controller. The duty cycle will be on timer 1 which will control pins 9 and 10.
I tried the code in Post 14. The duty cycles to the two MOSFET’s don’t change at all as I change the input voltage, and I cannot set the output to a constant value with the Setpoint command.
I know the PID function works as I had a simple boost converter working with changing duty cycles to match a changing input voltage while keeping the output voltage constant.
I just ran the Wokwi to have a look. The duty cycles look they are responding but the output should remain constant, at a given setpoint, with a changing input. The output from the simulation changes with a changing input.
Maybe we're confusing Input and Output. A PID's Input is the Output of the Plant/Process/System, and the Output of the PID is the Input of the Plant/Process/System.
Wokwi doesn't have a part for whatever the Plant/Process/System is that the Arduino would hook up to, so per:
I was using a manually-controlled Potentiometer to simulate the signal from the external Plant/Process/System that is fed into A0. which gets processed through the PID's kP, Ki, Kd into OCR1A/ICR1 duty cycle outputs on the two pins.
I haven't a clue what, for example, a 10% duty cycle on the MOSFETs input fed into the Plant/Process/System would produce as the Plant/Process/System output that the arduino could read on A0.
The only way a PID Output is constant is if the error between the PID Input and PID Setpoint is constant.
Yes, you are correct, the PID input is the output from the DC-DC converter. The PID output directly controls the two duty cycles to the switches in the DC-DC converter.
I am sending varying voltage signals to the converter, which then, the PID should keep the output from the converter at a constant voltage as set by the setpoint command.
The PID output is not constant as it needs to change the duty cycles to keep the circuit output constant with a variable input voltage to the circuit.
I have a simple boost converter responding correctly to this PID code. The output voltage of the circuit is stable at 12.5v with an input of 2v to 12v. On the scope I can see the duty cycle change as I change the input voltage to hold the output voltage constant.
#include <PID_v1.h>
int pwmPin = 6;
int ledPin = 13;
int analogPin = 0;
int val = 0;
unsigned long previousMillis = 0; // will store last time
const long interval = 500; // interval at which to delay
double Setpoint, Input, Output;
double Kp=.2, Ki=.4, Kd=0;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
pinMode(pwmPin,OUTPUT);
pinMode(ledPin, OUTPUT); // onboard LED
TCCR0B = (TCCR0B & 0b11111000) | 0x01; // 62KHz @see http://playground.arduino.cc/Main/TimerPWMCheatsheet
analogWrite(pwmPin, 120);
Serial.begin(9600);
//initialize the variables we're linked to
Input = analogRead(analogPin);
Setpoint = 200; // 200 = 12v
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0,220);
}
void loop() {
Input = analogRead(analogPin); // read the input pin
myPID.Compute();
analogWrite(pwmPin, Output);
// Blink the status LED
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
digitalWrite(ledPin, !digitalRead(ledPin));
Serial.println(Input);
Serial.println(Output);
Serial.println("");
}
}