View previous topic :: View next topic |
Author |
Message |
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
I have problem with the PI or PID code. |
Posted: Wed Dec 02, 2015 1:02 pm |
|
|
I have problem with the PI or PID code.
Facts:
250W DC engine controlled at the moment with a PWM controller without loop/feedback. Now I have installed an encoder. All is running without the loop! I can measure the RMP and control the engine with the PWM from 500-4500 RPM. So the hardware and software is prepared to the next step, the PI or PID code.
Problem:
Implement of the PI or PID code.
The RPM is from 500-4500. Let say the PWM steering value is between (int16 )200 to 475.
I have looked and read but can’t understand how to make the implementation?
There are a SetValue and a measured EncoderValue when they are equal all is nice.
Hints |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Wed Dec 02, 2015 3:54 pm |
|
|
OK I think i solved my confusing, it was understanding of the scaling values for the PID so it return a matching value for my PWM output. |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Thu Dec 03, 2015 11:21 am |
|
|
NOPE, i cant find the logic in the scaling.
My return signal is measured from the encoder end it return about 6000us and 53000us for the engine. That will say, fast rpm short signal return. It was the most simple way just to read the signal return time...
My PWM accept a value from 1 (150 is the motor lowest running duty) to 475 (99% duty).
Now I have to scale it but I can't, I'm confused. I don't know the relationship between the Duty and the RPM on the engine. The engine is _not_ linear to the PWM....
Maybe it's me there confusing it because I miss something in my brain, or think too much in the wrong direction?
I need some help on this. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Thu Dec 03, 2015 11:36 am |
|
|
One way is to run the PWM from 150 to 475 in say increments of 5 and record what the RPM of the motor is. Be sure to run for 5 to 10 seconds at each PWM level to get a solid RPM reading.
From those readings (about 66 of them) you should be able to analyze the algorithm of PWM vs RPM. These days you can just dump them into eXcel or MATLAB and have that program 'reverse engineer' the algorithm.
Jay |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Thu Dec 03, 2015 12:38 pm |
|
|
yes, but is it important on a PI (D) system? It is all these considerations and thoughts I have and therefore I stalled? |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Thu Dec 03, 2015 3:40 pm |
|
|
OK. You've been given several pointers.
What tests have you actually performed on your real hardware?
What were the results of those tests?
Or are you spending all your time just thinking about it?
Mike |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Dec 04, 2015 4:07 am |
|
|
You need also to understand the three parts of PID.
'P'. Proportional. Basically it sets the ratio between the requested 'output', and what is delivered to generate this. Getting this close to right helps reduce the need for the other terms. A simple 'trigger' controller on a drill or something, will only have a 'P' term. It'll slow down if loaded, but does mean that f you pull the trigger half way, the motor spins at close to half it's full speed rate.
'I'. Integral. This integrates _errors_ between what is requested, and what is actually being generated. If the motor runs slower than expected, it is this that applies the extra boost to bring the speed back. Allows the system to cope with extra power needed for extra load, and improves the ability to change speed as load changes, but at the risk that with sudden changes things can overshoot.
'D'. Differential (or derivative). This looks at the rates of change. If the output is _already moving in the requires direction_, this 'backs off' the adjustment being applied. It is this that tries to 'trap' the overshoot that sudden changes can produce. The faster the device is moving towards the desired target, the more this is applied.
Tuning a PID should be done in multiple stages. You generate a P term, by working out what rate is needed typically for the minimum load, for a given required power, and calculate the factor for this. Then you apply load, and generate an I term, that can apply the extra power needed to compensate for this. Then you try changing position quickly and see how much overshoot results, and calculate a D term for this. If the D is too high, everything will work well, but responses will be a little slow. Too small, and there will tend to be overshoot when the requested position is changed quickly. I term too small, and the motor will tend not to compensate as load increases. Too large, and it'll tend to 'hunt', overcorrecting each way. |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Sat Dec 05, 2015 11:23 am |
|
|
Thanks the help on this.
It is now running well, therefore I post my solution for other there maybe can use it, or this discussion on it.
The project is to implement a PID system on a DC motor. I use a “Hall sw” to detect the speed. It return 4 impulses/rpm. Not much but the system is running well. It is feed to ex_int_0. The measurement is done with a free running timer there are read in the interrupt on every L-H pulses.
The setpoint is made with a potentiometer connected to one AD converter and scaled for min/max pulses matching the return signal.
The control system use PWM in my case 16,7kzh with a duty cycle from >0 – 99.
In my main loop there are a time scheduler to control the read of the setpoint every 100ms, and check for stalling motor every 500ms.
The measurement task is called in the main loop, but is under control or in sync with the return impulses. On every new impulse it set a bit there mean, we have new samples and can now do the PID, and there after update the PWM. Updating of the PWM is done in sync with the already running PWN.
I post here some of the code for other. If my code or my logic is wrong, I hope someone will post correction.
Read feedback puls:
Code: |
#int_ext
void EXT0_isr(){
//int on encoder. timer1 count every 4us.
static int16 t1old=0;
int16 t1;
output_high(P_LED1);
t1=get_timer1();
PID.WorkPoint=t1-t1old;
t1old=t1;
PID.WorkPointIsNew=1;
PID.StallBit=1;
output_low(P_LED1);
}
|
Code for scaling the setpoint:
Code: |
void CalcSetSpeed(){
const int8 MaxAD=250;//must be float! Max value from AD
int16 Speed;
PID.ADBit=read_adc()&~0x01;
if (PID.ADBit>MaxAD){PID.ADBit=MaxAD;}
Speed=PID.MinRPMuS-(PID.ADBit*((float)(PID.MinRPMuS-PID.MaxRPMuS)/MaxAD));
if (PID.SetPoint!=Speed){
PID.SetIsNew=1;
PID.SetPoint=Speed;
}
}
|
PID code:
Code: |
signed int16 PIDDo(int16 SetPoint, int16 ActualPoint){
const int8 kp=8;
const int8 ki=100;
const int8 kd=25;
static signed int32 iState=0;
static signed int16 dState=0;
signed int16 error;
signed int16 pTerm,iTerm,dTerm;
error = (signed int16)ActualPoint-SetPoint;
pTerm = error / kp;
iState = error + iState;
if (iState > 50000) {iState = 50000;} else if (iState < -50000) {iState = -50000;}
iTerm = iState / ki;
dTerm = (ActualPoint - dState) / kd;
dState = ActualPoint;
return (pTerm + iTerm - dTerm);
}
|
PWM update:
Code: |
void UpdatePWM(signed int16 PWM){
output_high(P_LED3);
if (PWM>PID.DutyMax) PWM=PID.DutyMax; else
if (PWM<PID.DutyMin) PWM=PID.DutyMin;
clear_interrupt(INT_TIMER2);//clear and wait for a new start pwm puls some us..
while (!interrupt_active(INT_TIMER2)){;}//wait
set_pwm1_duty(PWM);
output_low(P_LED3);
}
|
Main regulation code:
Code: |
void DoReg(){
int16 setp,workp;
signed int16 PWM;
if (!Control.RegON) {return;}
if (!PID.WorkPointIsNew) {return;}//only when there are new input
PID.WorkPointIsNew=0;
output_high(P_LED2);
Disable_interrupts(Int_EXT);//encoder
setp=PID.SetPoint;
workp=PID.WorkPoint;
enable_interrupts(Int_EXT);
PWM=PIDDo(setp,workp);
UpdatePWM(PWM);
output_low(P_LED2);
}
|
Some of the main code:
Code: |
while (1){
DoReg();
if (!timer.ms100){
CalcSetSpeed();
timer.ms100=tReload.ms100;
}
if (!timer.ms500){
ChkStall();
timer.ms500=tReload.ms500;
}
|
Picture of the PID timing:
http://s000.tinyupload.com/?file_id=54358656248910856983
***
CCS forum link:
http://www.ccsinfo.com/forum/viewtopic.php?p=151009
http://www.ccsinfo.com/forum/viewtopic.php?t=53610&highlight=pid
http://www.ccsinfo.com/forum/viewtopic.php?t=47389&highlight=pid
PID theory:
http://www.embedded.com/electronics-blogs/spectra/4402378/The-Control-Loop
http://www.embedded.com/design/prototyping-and-development/4211211/PID-without-a-PhD
http://stackoverflow.com/questions/14614124/how-do-i-use-a-pid-controller
Microchip has some real good application notes:
AN964A: http://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en021807
AN718A: http://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en011730
AN937A: http://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en020434
Some nice person has already posted detail explanation on the PID system and link to theory on it. |
|
|
|