PID control

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi am implementing pid on atmega16 controller for which using avr221 as reference for my project. The proportional and derivative part work fine but I am not able to set the integrator as it needs to be bound as given in the program. I am taking data from a sensor and use the PID algorithm to set the PWM values for timer0. when i run   PID together the integrator eventually run off and i get 255 on pwm. Is there any method to set bound on integrator if so what will be the bound so that it fit in the PWM range.  the code is attached.

 

Thanks

/*This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
 *
 * \brief General PID implementation for AVR.
 *
 * Discrete PID controller implementation. Set up by giving P/I/D terms
 * to Init_PID(), and uses a struct PID_DATA to store internal values.
 *
 * - File:               pid.c
 * - Compiler:           IAR EWAAVR 4.11A
 * - Supported devices:  All AVR devices can be used.
 * - AppNote:            AVR221 - Discrete PID controller
 *
 * \author               Atmel Corporation: http://www.atmel.com \n
 *                       Support email: avr@atmel.com
 *
 * $Name$
 * $Revision: 456 $
 * $RCSfile$
 * $Date: 2006-02-16 12:46:13 +0100 (to, 16 feb 2006) $
 *****************************************************************************/

#include "pid.h"
#include "stdint.h"

/*! \brief Initialisation of PID controller parameters.
 *
 *  Initialise the variables used by the PID algorithm.
 *
 *  \param p_factor  Proportional term.
 *  \param i_factor  Integral term.
 *  \param d_factor  Derivate term.
 *  \param pid  Struct with PID status.
 */
void pid_Init(int16_t p_factor, int16_t i_factor, int16_t d_factor, struct PID_DATA *pid)
// Set up PID controller parameters
{
  // Start values for PID controller
  pid->sumError = 0;
  pid->lastProcessValue = 0;
  // Tuning constants for PID loop
  pid->P_Factor = p_factor;
  pid->I_Factor = i_factor;
  pid->D_Factor = d_factor;
  // Limits to avoid overflow
  pid->maxError = MAX_INT / (pid->P_Factor + 1);
  pid->maxSumError = MAX_I_TERM / (pid->I_Factor + 1);
}


/*! \brief PID control algorithm.
 *
 *  Calculates output from setpoint, process value and PID status.
 *
 *  \param setPoint  Desired value.
 *  \param processValue  Measured value.
 *  \param pid_st  PID status struct.
 */
int16_t pid_Controller(int16_t setPoint, int16_t processValue, struct PID_DATA *pid_st)
{
  int16_t error, p_term, d_term;
  int32_t i_term, ret, temp;

  error = setPoint - processValue;

  // Calculate Pterm and limit error overflow
  if (error > pid_st->maxError){
    p_term = MAX_INT;
  }
  else if (error < -pid_st->maxError){
    p_term = -MAX_INT;
  }
  else{
    p_term = pid_st->P_Factor * error;
  }

  // Calculate Iterm and limit integral runaway
  temp = pid_st->sumError + error;
  if(temp > pid_st->maxSumError){
    i_term = MAX_I_TERM;
    pid_st->sumError = pid_st->maxSumError;
  }
  else if(temp < -pid_st->maxSumError){
    i_term = -MAX_I_TERM;
    pid_st->sumError = -pid_st->maxSumError;
  }
  else{
    pid_st->sumError = temp;
    i_term = pid_st->I_Factor * pid_st->sumError;
  }

  // Calculate Dterm
  d_term = pid_st->D_Factor * (pid_st->lastProcessValue - processValue);

  pid_st->lastProcessValue = processValue;

  ret = (p_term + i_term + d_term) / SCALING_FACTOR;
  if(ret > MAX_INT){
    ret = MAX_INT;
  }
  else if(ret < -MAX_INT){
    ret = -MAX_INT;
  }

  return((int16_t)ret);
}

/*! \brief Resets the integrator.
 *
 *  Calling this function will reset the integrator in the PID regulator.
 */
void pid_Reset_Integrator(pidData_t *pid_st)
{
  pid_st->sumError = 0;
}

 

This topic has a solution.

Last Edited: Wed. Jul 25, 2018 - 05:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

nothing

Is there any method to set bound on integrator if so what will be the bound so that it fit in the PWM range

First just calculate the integrator & clip it to some limit.   Your else statement ( i_term = pid_st->I_Factor * pid_st->sumError;
) does not clip , though perhaps the calc  inherently gives a min/max value.  Just clip to be sure.

 

Do search for anti-windup:

https://www.embeddedrelated.com/showcode/346.php

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi thanks for the link, tried to clip off the sum but what happens is the process value gradually increases to the maximum limit and when the error starts decreasing the process value decreases only by a fraction, 

if my maximum process value is 255 i get around 180 process value when the error becomes 0 hence the process is always on even if the error becomes 0.  Should I decrease the limit of the integrator sum further more.

I want the process value to be 0 when the error becomes 0 but whenever i use the integrator the process value does not get 0

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Tuning your PID parameters takes care and understanding of the plant your attempting to control.  

You have not shown your PID params, or told us what your plant is, but with in the code shown is a way to limit the parameters, see MAX_I_TERM.

Your I values should be vary small and tuned slowly to achieve the best control.

 

Jim

Suggestion: google search for a pdf called PID without a PHD for tuning suggestions.

 

 

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Show the struct PID_DATA and pidData_t definitions.  Sometimes there are signed, unsigned, or overflow problems simply because the wrong data types are used.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

As long there is any measured error, the integrator will (should) keep integrating.

This means that when steady state is reached the P term will be zero.

As ki0bk #4 wrote, MAX_I_TERM is for anti-windup, and should be set to a value (lower then) the max PWM output.

 

I also find this line suspicious:

    i_term = pid_st->I_Factor * pid_st->sumError;

This does not look like an integrator, but like a P factor.

The integrater normally Integrates, meaning, add a value derived from the error.

So I would have expected "+=" instead of "=".

 

For tuning the loop parameters, use some proven algorithm such as Zichler-Nichols. Which means to first set the I and D parameters to zero and adjust the P factor. Then add I, then add D.

 

p_d wrote:
if my maximum process value is 255 i get around 180 process value when the error becomes 0 hence the process is always on even if the error becomes 0.

 

Once your regulator has reached steady state, the PWM output should be dependent on the value of the integrator, not from the P factor.

Printing a table (graph) of the P, I and D values will give you more insight in what is actually happening.

 

I also advise to (temporarily) disable the D part. For most processes it is not really needed, and disabling wil make the code shorter and easier to understand.

What is your integrator doing? My guess is it is not integrating.

To test the Integrator, you can set P to a low value, disable D, and then you should see a steady increase of the I part during the initial startup (step response) of the regulator.

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

 

   Suggestion: google search for a pdf called PID without a PHD for tuning suggestions.

thanks for the data it helped a lot in understanding the basics of PID and to tune them. the only problem i am facing is to set the anti windup values of the integrator as the pdf mentioned above states that the anti windup values should be less than the maximum pwm value also it changes according to the integrator constant. is there any rule for setting anti windup values to relate with pwm process and changing integral constant. 

 

So I would have expected "+=" instead of "=".

 

I have implemented this in my code but struggling to set the anti windup values.

 

 

 

My application for the PID is to control a packet filling machine according to weight. for which my input is from a load cell (Input variable) and some standard weight as my set point. according to these variables i set my control valve using pwm. 

 

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

p_d wrote:
My application for the PID is to control a packet filling machine according to weight.

 

Is PID really appropriate here?

I'm not a control engineer, but I thought PID was mostly about maintaining a system in a steady state ... ?

 

Do you remember previous suggestions on your filling applications: https://www.avrfreaks.net/commen...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

#7 So what do you use the I (in the PID) for, can you really take something out if it overshoot!?

 

Add:

 ok you need the I (but rather than a error func. I guess).

 

often it's just done at full speed, and then stop n kg/liter before full.

 

Last Edited: Mon. Jul 23, 2018 - 10:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

I'm not a control engineer, but I thought PID was mostly about maintaining a system in a steady state ... ?

Hi I am using PID to manage the flow control because on-off mechanism does not give repeat-ability with the process. so using PID algorithm to control the flow during start and stop process to reduce overshooting and undershooting errors. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

p_d wrote:

 

I'm not a control engineer, but I thought PID was mostly about maintaining a system in a steady state ... ?

Hi I am using PID to manage the flow control because on-off mechanism does not give repeat-ability with the process. so using PID algorithm to control the flow during start and stop process to reduce overshooting and undershooting errors. 

Seems like at most you want some form of P-control, no I or D.  Can you simplify further and do what gas station pumps do, which is to switch to a lower fixed flow rate as they near the "set point" and then turn the valve off upon reaching the set point?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm with kk6gm.

 

This application does not seem to be a good fit for a PID control loop.

Just start with full speed, and use a lower filling rate when nearly full before cutoff.

 

Also mechanical construction is important.

If any product is left in pipes that may or may not partially empty then you are never going to get accurate results.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com