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 CCS Technical Support

PID issues - with Code
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PID issues - with Code
PostPosted: Tue Jan 16, 2024 4:35 pm     Reply with quote

Hi all, its been a while.

after 20 years of PICs its time for my first PID proyect...

I got 2 small 12v brushed DC motores with gear reductions and magnetic encoders on the back:
https://www.amazon.com/uxcell-Motor-Encoder-201RPM-Ratio/dp/B0792SBB5T
...driven by the classic L298 red PCB available under any rock.

Im using one motor as output (plant) and one as input by simply spining the encoder manually.

the goal is to be able to mirror the input to the output.
input encoder goes to 200 steps, the PID driven motor goes to 200 steps.
"simple", right.

there is no load on my output motor, just a plastic arrow for visual confirmation.

I did a lot of testing and got the best PWM response at a low frequency. lowest i was able to get was 133Hz which gave me a PWM range of 50 to 255 Duty.

anything below 50 the motor would not start, just vibrate.
while spinning it would go down to 25(duty).

PROBLEMS:
1) I would like to bring the PWM frequency lower. possibly 100 or 60Hz as it seems to continue to improve response. i tested using the 32MHz internal clock but was not able to get it working (the PWM) reliably... but in the moments it did work, i did get well below the previous 50 duty limit at 133hz.

2) I have crazy jitter/chatter on my motor when near the setpoint.
ive adjusted K gains as much as any sane person could... and get close to no improvement... probably worse.
any help going over the logic of my code would be awesome... maybe i have some bug i cant see from clawing my eyes out with this.

3) Having a faster loop time (calls to Compute()) seems to improve things. makes sense. BUT because im bringing the clock down to get lower PWM frequencies im stuck in this push pull scenario where fixing something breaks another...

current code below has me at a jittery medium... faster loop, not so low PWM which limits my duty 100-255.... kinda works.

help?

CODE:
Code:

#include <18F67K40.h>
#device PASS_STRINGS=IN_RAM
#device adc=10
#fuses MCLR
#fuses NOWDT
#fuses NOLVP
#fuses NOXINST
#fuses NODEBUG
#fuses NOPROTECT
#fuses HS
#fuses RSTOSC_EXT_PLL
#use delay(clock=32MHz)

#include <string.h>
#include <stdlib.h>

#include <Hardware - AZ.h>


#INT_EXT
void Encoder_1();
#INT_EXT1
void Encoder_2();

#INT_TIMER2
void Timer_2_ISR();

void Set_Motor_1(int,int);
void Compute_PID();

signed int32 Control_One_Position=0; //setpoint or...
signed int32 Motor_One_Position=0;
signed int32 Set_Point=0;            //Control_one_positon depending on what im doing...
signed int32 Last_Set_Point=0;

float Kp=10;        //the guessing game #1
float Ki=0;         //the guessing game #2
float Kd=1;         //the guessing game #3
float Interval=0.0082;          //Timer 2 is calling Compute() at about 8.2ms as per O-Scope

signed int32 Error=0;
signed int32 Error_Prev=0;
float Integral=0;
float Derivative=0;
float Output=0;
int16 M1_Duty=0;
int Current_Direction=0;

//==========================
void main()

    setup_oscillator(OSC_EXTOSC_PLL|OSC_CLK_DIV_BY_2|OSC_EXTOSC_ENABLED|OSC_EXTOSC_READY);
    setup_timer_2(T2_DIV_BY_128|T2_CLK_INTERNAL,255,2);
    delay_ms(1000); //Stabilize CLK
   
    setup_ccp1(CCP_PWM);   // Configure CCP1 as a PWM
    setup_pwm6(PWM_ENABLED|PWM_ACTIVE_HIGH|PWM_TIMER2); //Uses timer 2
   
    enable_interrupts(INT_TIMER2);     //Calls PID Compute at regular intervals
    enable_interrupts(INT_EXT);        //Motor Encoder
    enable_interrupts(INT_EXT1);       //Control Encoder
   
    ext_int_edge(0, INT_EXT_L2H);       //Encoder interrupts Edges
    ext_int_edge(0, INT_EXT1_L2H);      //Encoder2 interrupts Edges
   
    enable_interrupts(GLOBAL);
   
    fprintf(FTDI,"\fSTART\r\n"); //just to know things are running...
    delay_ms(1000); //to be able to read the start message.
 
   
    while(TRUE)
    {
        fprintf(FTDI,"%03Ld,%03Ld,%03Ld,%3.2f,%3.2f,%lu,Dir:%d\r\n",Set_Point,Motor_One_Position,Error,Integral,Derivative,M1_Duty,Current_Direction);
       
       
        /*
        //FOR PWM TESTING
        fprintf(FTDI,"Position:%Lu - PWM:%Lu\r\n",Motor_One_Position, M1_Duty);
        Set_Motor_1(1,M1_Duty);
        delay_ms(1000);
       
        if(Flag==1)
            M1_Duty+=5; 
        else
            M1_Duty-=5;
       
        if(M1_Duty==250)Flag=0;
        if(M1_Duty==25)Flag=1;
        */
        //fprintf(FTDI,"Position:%04Ld\r",Control_One_Position);
    }
   
}

void Compute_PID()
{
    output_high(PIN_H2);                        //set pins to see call frequency and execution time.
   
    //PROPORTINAL
    Error=Set_Point-Motor_One_Position;
    //INTEGRAL
    Integral+=(Error*Interval);
    if(Integral>255)Integral=255;               //Cap Integral at 255 to prevent windup
    else if(Integral<-255)Integral=-255;
    //DERIVATIVE
    Derivative=(Error-Error_Prev)/Interval;
    if(Derivative>255)Derivative=255;           //Cap Derivative at 255 --delete??
    else if(Derivative<-255)Derivative=-255;
   
    //COMPUTE OUTPUT
    Output=(Kp*Error)+(Ki*Integral)+(Kd*Derivative);
   
    M1_Duty=abs(Output);     
    if(M1_Duty>255)M1_Duty=255;             //ensure duty is within values that actually cause the motor to spin
    if(M1_Duty<50)M1_Duty=50;
     
    if(Error==0)                            //added this because otherwise it never stops jittering
    Set_Motor_1(0,M1_Duty);                 //dispair solution, dont judge.
   
    else if(Output<0)                       //control the motor This way
    Set_Motor_1(-1,M1_Duty);
    else                                    //control the motor That way
    Set_Motor_1(1,M1_Duty);
 
    Error_Prev=Error;
   
    output_low(PIN_H2);                     //set pins to see call frequency and execution time.
}

void Set_Motor_1(int Dir,int Duty)          //controls a L298 H-bridge board.
{
    set_pwm1_duty(Duty);                    //Change PWM Duty
   
    if(Dir!=Current_Direction)              //figured it was a good idea to bring both Ctrl lines low
    {                                       //before changing direction on the L298
        output_low(M1_FWD);                 //avoid any timing or whatever pin switching mishappenings.
        output_low(M1_RWD);
    }

        if(Dir==1)
        {
            output_high(M1_FWD);
            output_low(M1_RWD);
        }
        else if(Dir==-1)
        {
            output_low(M1_FWD);
            output_high(M1_RWD);
        }
        else
        {
            output_low(M1_FWD);
            output_low(M1_RWD);
            Duty=0;
        }

    Current_Direction=Dir;
}

//encoder reading stuff.
#INT_EXT
void Encoder_1()
{
    if(input(ENC_B)==TRUE)
        Motor_One_Position++;
    else Motor_One_Position--;
}
#INT_EXT1
void Encoder_2()
{
    if(input(CTRL_B)==TRUE)
        Set_Point+=10;          //since im spining this encoder by hand ive added a multiplier to make changes bigger.
        //Control_One_Position++;
    else //Control_One_Position--;
        Set_Point-=10;
}

#INT_TIMER2
void Timer_2_ISR()

    Compute_PID();
}


there is a re-entrancy warning on the timer 2 ISR.
I know, i need help with that too.


i would like to eventually move this to the 18F47Q43 or Q84 - i have both so if pic choice makes a diference, let me know!

thanks G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Tue Jan 16, 2024 5:51 pm     Reply with quote

https://www.google.ca/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiKpIKYjOODAxUdODQIHTxVAYMQFnoECAsQAQ&url=https%3A%2F%2Fwww.wescottdesign.com%2Farticles%2Fpid%2FpidWithoutAPhd.pdf&usg=AOvVaw1g9Ni5CH3lFdcukTFMRPBA&opi=89978449

If you haven't already, download the pdf "PID Without a PhD" by Tim Westcott. I used it to implement a thermal PID (homebrewing system) and the tips it contained made the project possible. I've also guided aeronautical engineers to use its plain approach to successfully tune an aircraft's PID systems (of which there are dozens).

Jitter around the setpoint can be a combination of integral and/or derivative issues.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Wed Jan 17, 2024 2:12 am     Reply with quote

Several things.

First the L298, is not a great driver. It introduces a lot of voltage drop
(typically about 2v). To drive a motor well, you need a good driver that
allows narrow PWM pulses at full power.
Second, your PID loop should not use floating point maths. The PID
calculation wants to be quick. Look at using scaled integer maths. This
has been discussed here before. This is your main problem. The sheer
time needed by the loop means the motor has started moving the wrong
way before the loop corrects. So oscillation.
Then voltage. Now it sounds odd here, this is a 12v motor, but the way
to drive a motor slower with PWM, is to use a much higher supply voltage!.
You have to setup the PWM and controller to limit the maximum current
at the maximum the motor is rated for, but with any inductive load, the
speed the current rises in the coil when power is applied, is limited by
the supply voltage. Apply a really narrow pulse, and it takes time for the
current to build. I have an industrial controller here using 24v servos. The
supply voltage is 150v DC!...
Chattering is a sign your servo parameter are not correctly tuned. Some
research online will find a lot of posts about how best to perform this
tuning, and even programs to help with this.
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Jan 17, 2024 6:57 am     Reply with quote

also...
be sure to use a power supply with LOTS of AMPS !
While the 298 driver is rated for 2 amps per unit, you need more than a simple 4 amp PSU
Depending on layout, wiring, connections,oad, etc. the motor might end up 'current starved'.
In the 'dinosaur days' I'd use a linear supply good for 5x the 'needed' current for the servomotors. Maybe 'overkill' but never ,ever had a servo not perform properly.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Wed Jan 17, 2024 7:52 am     Reply with quote

and remember that the trap diodes across the bridge elements are
essential, but that thee only work if the supply is capable of sinking
this current, without it's output voltage shooting up......
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Wed Jan 17, 2024 4:17 pm     Reply with quote

Im gonna run this again with a 24V psu:

https://www.mouser.com/ProductDetail/MEAN-WELL/SE-1000-24?qs=4Ewz1atfbqKd24YTAQMbSQ%3D%3D

The one on the link to be specific... should be enough to run a small 12v motor.
If that doesnt cut it i dont know what will...

Im reading the PID without PHD doc...

I know L298 is dated... availability and ease of use, available resources, etc made it a good choice for me. Plenty tutorials using it...
_________________
CCS PCM 5.078 & CCS PCH 5.093
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Wed Jan 17, 2024 6:04 pm     Reply with quote

higher/better power supply did not bring any changes... it settles a bit faster, and the motor gets a bit warm when oscilating.

im having the same behaviour, just faster jejejeje...
_________________
CCS PCM 5.078 & CCS PCH 5.093
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 5:50 am     Reply with quote

Which means the parameters of the PID are set wrong. You are
over-correcting for the initial error and then not damping enough.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 6:16 am     Reply with quote

Ive played for hours with the P/D gains... keeping Integral at 0.
Ajusting loop times too...when semi acceptable peformance is achieved i add some integral... more.hours... no improvement.

Is my math right?

This cant be this dificult...
I believe i need to lower my PWM frequency for finer adjustments.
With higher voltages my PWM DUTY range narrowed 30 to 100 duty vs 45ish to 255.
Up my loop time to as high as possible

i want to try and use the 32mhz internal clock to drive the PWM/timer2 and use the ext osc with pll at full blast to run the code.
I dont know if this is possible... datasheet reading time.
This should give me lower PWM and higher loop times.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 6:51 am     Reply with quote

PWM has to run from fosc/4... so im at the lowest feasable PWM freq. Which impacts my execution time clock so, slower loop times too.

I know its possible to go lower with other osc configurations but im trying to keep loop times fast.
_________________
CCS PCM 5.078 & CCS PCH 5.093
gaugeguy



Joined: 05 Apr 2011
Posts: 303

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 7:22 am     Reply with quote

PID aside, you need to test your hardware.
Using direct PWM drive, what is the smallest rotation you can reliably move the motor. Is it less than one encoder count?
As you have already found the motor requires more power to start turning than to keep turning.
Your PID cannot work better than your hardware is capable of.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 7:33 am     Reply with quote

That makes sense... i may be atributing super powers to PID.
However i see in youtube plenty people reaching precision with similar hardware.

How can i test this?
Should i set this to accept values within lets say 5% of target?...

So if im trying to get 100 encoder counts anything within 95 to 105 encoder counts is taken as a succesfull setpoint reach? Is that the suggestion/fix?
_________________
CCS PCM 5.078 & CCS PCH 5.093
gaugeguy



Joined: 05 Apr 2011
Posts: 303

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 7:53 am     Reply with quote

Regarding PID, what is your PID calculation loop time? Your sample time?
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Thu Jan 18, 2024 8:25 am     Reply with quote

i was calling my compute function within the TMR2 ISR which was executing at 8.2ms more or less.

othertimes in dispair i would call Compute_PID() from within the main loop and nothing else... and that would give me about 250us

the sample time i have not measured... its interrupt driven with the Encoder pulses EXT_INT.


I tried "slowing" the encoder by having the encoder mark 2 pulses as 1 step. this would make the motor travel twice as far obviously... but i figured it would give the PID more time to react to the measurements...

I could try again.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Sat Jan 20, 2024 7:46 am     Reply with quote

Ive added a conditional to the Error calculation.
Basically if im with 0 to 2 counts away from the setpoint just make error =0.
Good enough = 0 error jajajaj

So basically starting from 0 if i setpoint =100 my motor goes to 99 or 101... im getting about 1 count error...

I also upped my loop time to 4.1ms
And increased my min output to 80 instead of 50 duty.

No integral and a bit of derivative damping and its smooth as butter now.


Ill be testing repeatability and maybe some drift compensation if any (adding back that missed count)...
_________________
CCS PCM 5.078 & CCS PCH 5.093
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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