This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/EK-TM4C123GXL: Velocity Control

Part Number: EK-TM4C123GXL

Tool/software: Code Composer Studio

Hi all,

I am trying to control velocity of DC motor using PID, but i am have trouble to stabilize it any desired velocity, and also the derivative terms stays zero all the time.

/*   DC Motor Velocity    */

#include "Config.h"

#define PERIOD_PWM 1250 // 2ms time period is equal to 1250 ticks

#define GET_MAG(X)  (X > 0 ? X : -X)

#ifndef DEGPS_RPM
#define DEGPS_RPM   0.16667
#endif

float encdrRdShldr, rotDirShldr, dpsShldr, rpmShldr, errVelShldr, intgErrShldr, dErrShldr, pidVelShldr, prevErrVelShldr;
float desVelShldr, kpVelShldr, kiVelShldr, kdVelShldr, pwm,D;
float scaledOutVelShldr;
float accErrVelShldr;
int a;
int main ( void )
{
   SysCtlClockSet ( SYSCTL_SYSDIV_2|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ ) ; //  400/2=200MHz (2 is default divider), 200/5=40MHz (System Clock become 40MHz),

   tmr0IntrptConfig(); // Call timer 0 interrupt Configuration
   encdrShldrConfig(); // Call Shoulder Motor encoder Configuration
   pwmShldrConfig();   // Call PWM Shoulder Configuration
   initlzVarConfig();
   kpVelShldr = 1.5; kiVelShldr = 1; kdVelShldr = 2;
   /*     Direction PINS   */
   SysCtlPeripheralEnable ( SYSCTL_PERIPH_GPIOB ) ;
   GPIOPinTypeGPIOOutput ( GPIO_PORTB_BASE, ( GPIO_PIN_0 | GPIO_PIN_1|GPIO_PIN_2 )  ) ;
mag = 99;
a = 0;
}

void Timer0IntHandler(void)
{
    encdrRdShldr = QEIVelocityGet(QEI0_BASE);
    rotDirShldr = QEIDirectionGet(QEI0_BASE);

    if(rotDirShldr == 1)        //CCW
    {
        dpsShldr = -1*(encdrRdShldr * 0.1124);
        rpmShldr = dpsShldr * DEGPS_RPM;
    }
    else if(rotDirShldr  == -1) //CW
    {
        dpsShldr = (encdrRdShldr * 0.1124);
        rpmShldr = dpsShldr * DEGPS_RPM;
    }

    if(desVelShldr > 60)
    {
        desVelShldr = 60;
    }   else if(desVelShldr < -60)
    {   desVelShldr = -60;
    }
    errVelShldr  = desVelShldr - rpmShldr;
    intgErrShldr = (accErrVelShldr) * 0.0001;
    dErrShldr    = (errVelShldr - prevErrVelShldr) * 10000;
    pwm = desVelShldr * 1.35; //  pwm according to desired velociety
    pidVelShldr  = (kpVelShldr * errVelShldr + kiVelShldr * intgErrShldr + kdVelShldr * dErrShldr)+pwm;
    D= kdVelShldr * dErrShldr;


    accErrVelShldr += errVelShldr;

    if(pidVelShldr >= 0)
    {
        if(pidVelShldr >= 254)  pidVelShldr = 254;
        if(pidVelShldr <= 1)    pidVelShldr = 1;
    }
    else if(pidVelShldr < 0)
    {
        if(pidVelShldr <= -254) pidVelShldr = -254;
        if(pidVelShldr >= -1)   pidVelShldr = -1;
    }

    if(pidVelShldr >= 0)
    {
        //Set direction bits to rotate motor CW
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_PIN_0);
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x00);
    }
    else
    {
        //Set direction bits to rotate motor CCW
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, 0x00);
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, GPIO_PIN_1);
    }

    scaledOutVelShldr = GET_MAG(pidVelShldr) * 5.0;
    if(scaledOutVelShldr > 1250)
        {scaledOutVelShldr = 1250;}
    PWMPulseWidthSet ( PWM1_BASE, PWM_OUT_7, scaledOutVelShldr);

    a++;
    if(a == 1){
        GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, GPIO_PIN_2);
    }if(a == 2){
    GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0x00);
    a = 0;}
    prevErrVelShldr = errVelShldr;
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);// Clear the timer interrupt

}

and this is code for Config.c source file


#include "Config.h"

float mag;

void initlzVarConfig (void)
{
mag = 0.0;
}

void encdrShldrConfig (void)
{
SysCtlPeripheralEnable ( SYSCTL_PERIPH_GPIOD ) ;
//Unlock GPIOD7
HWREG (GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG (GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;
HWREG (GPIO_PORTD_BASE + GPIO_O_AFSEL) &= ~0x80;
HWREG (GPIO_PORTD_BASE + GPIO_O_DEN) |= 0x80;
HWREG (GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;

SysCtlPeripheralEnable ( SYSCTL_PERIPH_QEI0 ) ; // Enable QEI Peripherals
//Set Pins to be PHA0 and PHB0
GPIOPinConfigure(GPIO_PD6_PHA0); //GPIOPinConfigure ( 0x00031806 ) ; //0x00031806 =>GPIO_PD6_PHA0
GPIOPinConfigure(GPIO_PD7_PHB0); //GPIOPinConfigure ( 0x00031C06 ) ; // 0x00031C06 => GPIO_PD7_PHB0
GPIOPinTypeQEI(GPIO_PORTD_BASE, (GPIO_PIN_6 | GPIO_PIN_7)) ; //Set GPIO pins for QEI

// Configure quadrature encoder, use an arbitrary top limit of 2000 and enable QEI
QEIConfigure (QEI0_BASE, (QEI_CONFIG_CAPTURE_A | QEI_CONFIG_RESET_IDX | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP) ,640000) ;
QEIEnable(QEI0_BASE);

//Configure and enable velocity
QEIVelocityConfigure(QEI0_BASE, QEI_VELDIV_1, SysCtlClockGet()) ; // Divide by clock speed to get counts/sec
QEIVelocityEnable(QEI0_BASE);
}

void tmr0IntrptConfig (void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0) ;
TimerConfigure(TIMER0_BASE, TIMER_CFG_A_PERIODIC) ;
uint32_t InterruptPeriod = SysCtlClockGet() * 0.0001;
TimerLoadSet(TIMER0_BASE, TIMER_A, InterruptPeriod - 1) ;
IntEnable(INT_TIMER0A);
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
IntMasterEnable();
TimerEnable(TIMER0_BASE, TIMER_A) ;
}

void pwmShldrConfig (void)
{
// Enable the peripherals used by this program.
SysCtlPeripheralEnable ( SYSCTL_PERIPH_PWM1 ) ;
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_PWM1));
SysCtlPeripheralEnable ( SYSCTL_PERIPH_GPIOF ) ;
GPIOPinTypePWM ( GPIO_PORTF_BASE, GPIO_PIN_3 ) ; // Configure PF3 Pins as PWM
GPIOPinConfigure ( GPIO_PF3_M1PWM7 ) ;
SysCtlPWMClockSet ( SYSCTL_PWMDIV_64 ) ; // 40/64=0.625 MHz, 625KHz
PWMDeadBandDisable ( PWM1_BASE,PWM_GEN_3 ) ;
PWMGenConfigure ( PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC ) ; //Configure PWM Options
uint32_t PWMPeriod=1250; //PWM_GEN_2 Covers M1PWM4 and M1PWM5
PWMGenPeriodSet ( PWM1_BASE, PWM_GEN_3, PWMPeriod ) ; //PWM_GEN_3 Covers M1PWM6 and M1PWM7
PWMOutputState ( PWM1_BASE, PWM_OUT_7_BIT, true ) ; //Turn on the Output pins
PWMGenEnable ( PWM1_BASE, PWM_GEN_3 ) ; //Enable the PWM generator
}

  • *Sorry its
    uint32_t InterruptPeriod = SysCtlClockGet() * 0.001;
  • Hello Awais,

    While I understand the question at hand, it's not really clear to me where we can offer much advice. Are there some TM4C operations, TivaWare APIs, or other TM4C-specific concerns that you would like us to help address? Right now, this seems more to be an application implementation and a bit out of our range in terms of being able to support from the TI end.

    Also if you provide more details about what motor you are using and how you are trying to stabilize it and what issues you are running into, that would also give some of our community members better understanding and maybe one of them would be able to help you by sharing their own experiences.
  • thnx ralph, i agree its application of PID to control velocity of DC motor.
    and the problem i am having is that by using above code motor speed changes really quickly ,i mean if i give it some desired speed ,it rotates fast and then slows down( or stops sometime) and then again overshoots to fast speed ,i can't stabilize it at desired speed.
    so if anyone can point out if there is something wrong in code or is there anyother way to do the required task,it would be great.
  • Adding the "Differential Term" to any "PID" code always presents high challenge.

    Firm/I rank such "Motor Control" w/in the top third of our general Tech Design Business - and we (and others) normally/customarily will, "Introduce the Differential Term" only AFTER we've achieved, "Meeting/Exceeding Spec Performance" while employing "PI" terms & control manipulations - ONLY!

    The "D" term is especially forceful - and if those other terms (P & I) are not well applied & implemented - your chances for success are slight...

    This proves (yet another) illustration of the Power of  "KISS" - building towards final success by identifying and "measurably solving"  earlier occurring & easier challenges.

    Your writing is silent as regards:

    • the "Load" being applied to the motor
    • your Power Stage - its ability to meet the motor's requirements
    • your Programming, Applied Load, & Power Stage - all insuring that your Motor, "Remains w/in its rated spec" - throughout ALL Phases of its operation...

    One of  your early defines reveals:  "#define PERIOD_PWM 1250 // 2ms time period is equal to 1250 ticks" ...  This suggests an "F_PWM" of 625KHz - was this by intent?    If so - how did you arrive at this?

    None of your reasoning - nor your design choices - were revealed.     The absence of such data complicates & delays issue resolution.    I'd be (most) surprised if the "D" Term - "stands alone" - w/in the "Suspect Line-Up."

    KISS of course forces your attention upon each/every one of these areas - coming to "quick conclusions" (rarely - we find) yields the (proper) conclusions...

  • yes but derivative term in my case is always zero,(previous error is always equal to current error so there difference is zero).
    i am also not sure that algorithm here is correct for PID control of velocity .
  • Our posts crossed - do read the detailed posting.

    Again - I strongly recommend that you REMOVE any/all references to the Differential Control Term. There are MANY questions to be answered. Surely you can find multiple "PID" (ideally) just "PI" code examples...
  • ok i will remove the derivative term, and for the test operation i am not applying any load on motor ,its only rotor inertia and yes everything is within rated specs and my power stage can easily meet motors requirement.
    thnx for your reply help.
  • Note that running your motor (unloaded) is "outside" normal operating conditions - and while (you claim) "all specs are being met" - things change forcefully & quickly under "real-world/real-load" conditions - and your program code must be prepared to, "EXPAND to meet those, "More Difficult/Demanding, Real-World" conditions.

    I would add an, "independent Speed Monitor (tachometer), Current Monitor, and Temperature Sensors" at/around your Power Stage AND the Motor. Indeed your MCU can "perform those roles" - yet Safety & Proper KISS Procedure instructs that, "Independent Measurements" prove best - and are likely to, "Speed, Ease & Enhance" your project's success.
  • That (motor speed fluctuates in an unstable fashion) is a sign of too much gain. That can be solved by lowering the gain in the system....

    Time to dust off your control theory textbooks.

  • Danny F said:
    Time to dust off your control theory textbooks.

    Uhhhh ....  might that "dusting off" reveal,  "Property of NYC Public Library"  (greatly dimmed - but STILL legible)...

    As we all know - "Money too has a "velocity factor" - and a 30 (USD) book "SO overdue" - REALLY requires "Substantial Negative Feedback!"     (reducing - of course - overdue fees to Sub-ZERO!)