Hi
We have a problem with a homemade PI controller. We are not sure what the problem is, but by using the program we can never reach our setpoint.
And our duty cycle is swithing sometimes form 20 - 80 %.. but over 100 % as it was an overflow. but we can't see where this should be.
some that can help ?
The P and I parameteres are found according to so simulating in simulink they should be right according to our motor.
The external analog potential applied is 3 V and the range og the input is 0-2.8
/*
* Interrupt template http://popdevelop.com/2010/04/mastering-timer-interrupts-on-the-arduino/
*
* This program is sourpose to functions as a PI controller. witch takes the an analog reading
* controled by e 3us interrupt. each 30us it shoud take the avg of theres readings
* and do the PI calculations. The results is converted to 8 bit, for analog output (PWM).
* anti windup is implementet in the calculations.
*
* for every 30us a "flag" is raised from the interrupt to flip a port i the main (loop)
*
* Made by: Christian Winum and Mikkel Callesen
* SDU Sønderborg education: mechatronic
*/
unsigned int tcnt2;
int toggle = 0;
static boolean adcready = false;
static int adcvalue=0 , i , adcindex=0;
static unsigned int adc[10];
static unsigned char output8=0;
int inputPin= A1;
int outputPin= 5;
unsigned int output, input, setpoint, b=1, c=1;
unsigned int e_last, e, dedt, A;
float Kp, Ki,Ts;
void setup() {
pinMode(2, OUTPUT); // seting pinmode
TIMSK2 &= ~(1<<TOIE2); // First disable the timer overflow interrupt while we're configuring
TCCR2A &= ~((1<<WGM21) | (1<<WGM20)); // Configure timer2 in normal mode (pure counting, no PWM etc.)
TCCR2B &= ~(1<<WGM22);
ASSR &= ~(1<<AS2); // Select clock source: internal I/O clock
TIMSK2 &= ~(1<<OCIE2A); // Disable Compare Match A interrupt enable (only want overflow)
// Configure the prescaler to CPU clock divided by 256
TCCR2B |= (1<<CS22) | (1<<CS21); // Set bits
TCCR2B &= ~(1<<CS20); // Clear bit
tcnt2 = 69; // (CPU clock)/(precaler)/(tcnt2=256-69) = 3us interrupt
TCNT2 = tcnt2; // load and enable timer
TIMSK2 |= (1<<TOIE2);
analogReference(EXTERNAL);
Serial.begin(9600);
Kp=1.5832; // Load P values
Ki=5.4107; // Load P values
output=0;
e_last = 0, A=0, e=0, Ts=0.030;
}
ISR(TIMER2_OVF_vect) { // Interrupt Service Routine at timer2 overflow
TCNT2 = tcnt2; // Reload timer
adc[adcindex++]=analogRead(inputPin);
if(adcindex ==10){
adcvalue=0;
adcindex=0;
for(i=0;i<10;i++){
adcvalue=adcvalue+adc[i];
}
adcvalue=adcvalue/10; // avg of 10 meas
e=setpoint-adcvalue; // Error on motor dependent on stepoint
c=(output<=1024); // Windup parameters
b=(output>=0);
A=A+0.5*Ts*(e+e_last)*b*c; // Integration part with windup
e_last=e; // Set current error to last error
output = e*Kp+A*Ki; // PI output
output=output/4; // 10 bit int value to 8 bit int value
output8=(unsigned char)output; // 8 bit int value to 8 bit unsigned char value.
analogWrite(outputPin, output8);
adcready=true;
}
}
void loop() {
setpoint=500; // 10 bit value between 10 - 90 %
if(adcready==true){
digitalWrite(2, toggle == 0 ? HIGH : LOW); // test code for confermation of program runtime
toggle = ~toggle;
Serial.print("output 8 ");
Serial.println(output8, DEC);
adcready=false;
}
}