CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

sampling time in PID computing

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Carlos_Eguti
Guest







sampling time in PID computing
PostPosted: Wed Jul 30, 2008 12:40 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jul 30, 2008 12:46 pm     Reply with quote

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
PostPosted: Wed Jul 30, 2008 1:46 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jul 30, 2008 2:35 pm     Reply with quote

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
PostPosted: Thu Jul 31, 2008 10:15 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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