|
|
View previous topic :: View next topic |
Author |
Message |
Carlos_Eguti Guest
|
sampling time in PID computing |
Posted: Wed Jul 30, 2008 12:40 pm |
|
|
Hi everybody !
I'm working with a PID algorithm to control a servomotor with PWM driver conected to a 1 channel encoder. Always the same question, but..
I decided to use this PID form:
Pk = Kp * (ek – ek1)
Ik = Ki * T * ek
Dk = (Kd/T) * (ek - 2*ek1 + ek2)
CVk = CVk1 + Pk + Ik + Dk
where ek = setpoint – encoder frequency
I will put the intire code but, first, I need one tecnical informatiom:
How can I find or determine the sampling time "T" to do the calculations?
Someone could give me some light, please?
Thanks
Carlos |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Wed Jul 30, 2008 12:46 pm |
|
|
That is the time between data samples. If 10 times a second you read the A/D, do the math, and produce an output, then your T is 1sec/10=100ms. You want to make this value stable with some sort of paced loop in your software. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Carlos_Eguti Guest
|
sampling time in PID computing |
Posted: Wed Jul 30, 2008 1:46 pm |
|
|
Hi Mr. SherpaDoug or/ and Everybody
My complete code is that: is not working very well. Lie, don't work nothing ...
// PCM Version 3.168
#include <16f877A.h>
#device ADC=10
#include <STDLIB.H>
#include <MATH.H>
#fuses HS, NOWDT, NOLVP, PUT, NOPROTECT, NOBROWNOUT
// Cristal with 20MHZ OK
#use delay(clock=20000000)
// GLOBAL VARIABLES
int16 frequency=0;
int16 frequency_k=0;
// -------------------------------------------------------------
// CCP1 interruption
// -------------------------------------------------------------
#int_ccp1
void ccp1_isr(void)
{
static int16 old_ccp = 0;
int16 current_ccp=0;
int16 isr_ccp_delta=0;
// read register 16-bit on CCP1
current_ccp = CCP_1;
isr_ccp_delta = current_ccp - old_ccp;
old_ccp = current_ccp;
// Frequency calculation for 16mhz
frequency = (int16)(625000 / isr_ccp_delta);
}
// -------------------------------------------------------------
// MAIN PROGRAM
// -------------------------------------------------------------
void main(void)
{
// Variable Declarations
// -------------------------------------------------------------
//Set Point
long SP=700;
//Encoder output
long PV=0;
//Control Variable
long CVk=0;
//Control Variable previous value
long CVk1=0;
//previous error 2
signed long ek2=0;
//previous error 1
signed long ek1=0;
//current error
signed long ek=0;
//setpoint direction mark
int fg=1;
//proportional term
float Pk = 0.0;
//integral term
float Ik = 0.0;
//derivative term
float Dk = 0.0;
//sampling time (test with 100ms)
float T=0.1;
// Init PIC
// -------------------------------------------------------------
// ADC Setup
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
// Setup of Timer1 and port CCP1
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8); // 20MHz count
setup_ccp1(CCP_CAPTURE_RE);
// Setup of CCP2 as PWM signal
setup_timer_2(T2_DIV_BY_4, 250, 1);
setup_ccp2(CCP_PWM);
// Enable Interrupsts
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
// Main LOOP
// ------------------------------------------------------------------------
while(1)
{
// --------------------------------------------------------
// Set the setpoint speed through push-button on E0 pull-up.
// SP increasing 5 by 5 until reach a maximum value, then return decreasing.
if (! input(PIN_E0))
{
delay_ms(100);
if (fg == 1)
SP = SP + 5;
else
SP = SP - 5;
if (SP >= 1024)
{
fg = 0;
SP = 1000;
}
}
// -------------------------------------------------------
// -------------------------------------------------------
// PID CYCLE
// change invalid frequency value with last value
if (frequency > 200)
frequency = frequency_k;
// Converter the frequency data from encoder -------------
PV = (10 * ( 212 - frequency )) / 6;
// error calculation --------------------------------------
ek = (signed long)(SP - PV);
// Proportional Gain calculation --------------------------
// Kp = 2 (proportional coeficient)
Pk = 2.0 * (float)(ek - ek1);
// integral Gain calculation ------------------------------
// Ki = 1.5 (integral coeficient)
Ik = 1.5 * T * (float)ek;
// derivative Gain calculation ----------------------------
// Kd = 2 (derivative coeficient)
Dk = (2.0 / T) * (float)(ek - 2 * ek1 + ek2);
// Control Variable (Output) ------------------------------
CVk = CVk1 + (long)(Pk + Ik + Dk);
// anti wind-up test --------------------------------------
// range between 700 and 1000 for duty cycle
if (CVk > 1000)
CVk = 1000;
if (CVk < 700)
CVk = 700;
// Variables up-date --------------------------------------
frequency_k = frequency;
CVk1 = CVk;
ek1 = ek;
ek2 = ek1;
// Set duty cycle on CCP2 ----------------------------------
set_pwm2_duty(CVk);
// Main LOOP end
// ------------------------------------------------------------------------
}
// Main program end
// ------------------------------------------------------------------------
}
Unfortunately, I'm working with an old compiler version, but here in this lab, we have, at this momment, only this version. I'm trying to buy a new version, but it is difficult.
I'm using a interrupt to read the frequency from an optical encoder, connect on the wheel of the servo, and electrical connected at CCP1 port. The servo running at low speeds and I have 70 pulses per wheel turn. This part of the code I caught from this Forum.
As you see, the problem is to find the sampling interval.
Any suggestions or comments?
Carlos |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Wed Jul 30, 2008 2:35 pm |
|
|
From this line
delay_ms(100);
I would guess you are going through your main loop somewhat less than every 100ms, as the rest of your code takes some time to run. I would set a pin to 1 when you are doing your computation like this:
Code: | output_low(pin x);
delay_ms(100);
output_high(pin x); |
The rate of pin x pulses gives your sampling rate. The length of the pulse tells how long your code takes. Eventually I would use a timer to generate a regular trigger a little slower than you code running time so that the sample rate is stable and does not vary with the data being processed.
Adjusting PID constants is a science & art of its own. Zillions of doctoral theses have been written on the subject. I would zero I & D and get P working first. then add a little I, then a little D. Then fiddle with it till it works well enough, or you run out of time. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
Carlos_Eguti Guest
|
sampling time in PID computing |
Posted: Thu Jul 31, 2008 10:15 am |
|
|
Good idea !!!
I'll try it.
But, another question. Is possible to transform an interrupt in fuction? I mean, is there a way to fix an interruption procedure calling?
anyway,
Thanks |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|