Hi all,
I'm trying to get my DC motor run like a cruise control system, by means of a PID controller. I managed to get it to work, but when I started tuning my PID parameters, I noticed it was having a neglible affect on the PWM signal.
This is what I had at that time in terms of my PID controller.
int updatePID(int targetRPM, int currentRPM) { int error; static int last_error; static int integrated_error; float pTerm, iTerm, dTerm; /* Calculate error and proportional value.*/ error = targetRPM - currentRPM; pTerm = i32Kp * error; /* Calculate error and intergral value.*/ integrated_error += error; iTerm = i32Ki * constrain(integrated_error, -1, 1); /* Calculate deriviative value and reset error.*/ dTerm = i32Kd * (error - last_error); last_error = error; /* Return the PID controlled duty cycle value. */ return constrain((i32K*(pTerm + dTerm)), -1, 1); }
Within this function, is the constrain function, which is shown below.
int constrain(int x, int a, int b) { if(x < a) { return a; } if(b < x) { return b; } else { return x; } }
The constrain function was to ensure the dutycycle never exceed 100%, but I quickly noticed this wasn't working as I intended, as the dutycycle is the value of clockticks, thus when configuring the PWM signal to work at a frequency of 24kHz when the system clock is running at 120MHz, the loaded value is 624. The code for this configuration is shown below.
void InitPWM(void) { /* Enable PWM clock.*/ PWMClockSet(PWM0_BASE,PWM_SYSCLK_DIV_8); /* Configure the GPIO pins.*/ GPIOPinConfigure(GPIO_PF0_M0PWM0); GPIOPinConfigure(GPIO_PF1_M0PWM1); GPIOPinConfigure(GPIO_PF2_M0PWM2); GPIOPinConfigure(GPIO_PF3_M0PWM3); /* Configure the GPIO pins as PWM pins.*/ GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); /* Calculate period and duty cycle.*/ ui32PWMClockFreq = (ui32SysClkFreq / 8); //(120000000 / 8 = 15000000 ui32PWMLoad = ((ui32PWMClockFreq / PWM_FREQUENCY) -1); //15000000 / 24000 = 624 //ui32PWMDutyCycle = ui32PWMLoad; /* Configure the PWMs to count-down, and sync with each other.*/ PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_SYNC);// | PWM_GEN_MODE_GEN_SYNC_GLOBAL | PWM_GEN_MODE_DB_SYNC_GLOBAL); PWMGenConfigure(PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_SYNC);// | PWM_GEN_MODE_GEN_SYNC_GLOBAL | PWM_GEN_MODE_DB_SYNC_GLOBAL); /* Set the periods.*/ PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, ui32PWMLoad); PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, ui32PWMLoad); /* Set the duty-cycle.*/ PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, ui32PWMLoad*0.1); PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, ui32PWMLoad*0.1); /* Enable the dead-time.*/ //PWMDeadBandEnable(PWM0_BASE, PWM_GEN_0, deadTime, deadTime); //15 pulses is roughly 1 us. //PWMDeadBandEnable(PWM0_BASE, PWM_GEN_1, deadTime, deadTime); /* Enable all of the PWM signal outputs.*/ PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT, true);//PF0 - PWM PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT, false);//PF1 - \PWM PWMOutputState(PWM0_BASE, PWM_OUT_2_BIT, true);//PF2 - PWM PWMOutputState(PWM0_BASE, PWM_OUT_3_BIT, false);//PF3 - \PWM /* Enable the sync.*/ PWMSyncTimeBase(PWM0_BASE, PWM_GEN_0_BIT | PWM_GEN_1_BIT); PWMSyncUpdate(PWM0_BASE, PWM_GEN_0_BIT | PWM_GEN_1_BIT); /* Enable the PWM gens.*/ PWMGenEnable(PWM0_BASE, PWM_GEN_0); PWMGenEnable(PWM0_BASE, PWM_GEN_1); }
e
I figured that my tuning was neglible, because I'm sending only a fraction of the dutycycle due to the constrain until -1 and 1 when it should in reality be 0 and 624. However, when I implement these methods, the dutycycle goes crazy as the value it loads to PWMPulseWidthSet() is in the thousands, causing the dutycyle to be a 100% at all times, rendering the whole controller useless.
I figured this was because I was dealing with the unsigned vs. signed values incorrectly, therefore I changed it once to allow for larger numbers and make them all signed, but this still provided crazy numbers.
What I dont understand is that my constrain function should prevent this from happening, and even though the dutycycle wants to be 10,000 because I set my Kp, Ki, Kd values really high, it should still only return the value between 0 and 624 due to the constrain function.
Anybody know what might be causing this irregularity in the numbers?