Electrical – Input output functions inside a PID Interrupt handler

pid controller

According to my understanding, the best way to implement a PID handler is inside an Interrupt Service Routine which is usually a timer ISR with configurable frequency rate. Here we calculate the process output as a function of setpoint and process input, along with other calculations.

I have the following confusions about what needs to be included inside the ISR and main function.

1) Since the frequency of some PID loops is very high, it is a good idea to read the inputs, setpoint and other values from outside the ISR and calculate only the output inside ISR. In this case what will happen if some of my debug functions(usually a printf) delay the reading of an input or setpoint from the main function? What if the ISR calculated a perfect output value but the main program delays the output to the outside world because of the same debug functions? Here the program behaves in a slightly different manner(Sometimes noticeable differences) with and without the debug code.

2) Another option is to implement input and setpoint reading functions inside the ISR. In this case, both input and output may take a significant amount of time to read the values which will affect the ISR timing. For instance, setpoint can be a serial packet which can become a problem for the ISR execution time. Same happens when we output the calculated value to the outside world.

I am a little bit confused which approach to follow while designing a PID controller. What needs to be included inside the ISR(input, setpoint or output routines) and what needs to be included in the main function?

Implementation Details :- The experimentation setup consists of a 60RPM geared DC motor, an H bridge(VNH5019) and a magnetic rotary encoder(AS5048B). The H bridge has a PWM input for speed control and 2 other pins for direction control. AS5048B is an absolute encoder which gives a 14Bit output corresponding to 0 – 360-degree rotation of the motor shaft and the same act as a feedback signal for the plant. I am trying to implement a PID position control setup for this motor. Right now the PID Update function is written inside a timer ISR which runs at a frequency of 10KHz(may be an overkill for this particular application). The input comes from a rotary encoder which will be replaced by a serial packet in future. My plan is to read input and setpoint from a main function, access the values from PID Update ISR , calculate the output PWM value corresponding to the error just like the arduino PID library implementation as shown below

http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

The variables are shared with the PID Update ISR using pointers. So all the inputs read from within the main is available in the ISR and the output value calculated is available in the main function. The PWM value thus calculated is given to the input of the H bridge IC.

Note : Reading input, setpoint and output to H-bridge is not a part of any ISR right now. Only the calculation is done inside PID Update ISR.

Best Answer

1) If the debug functions change the behavior of the system, then you're debugging for Schrodinger bugs. You won't know if there is a bug or not because you are looking for it.
That is an issue that needs to be addressed.

You should use a fifo to output data asynchronous from the print call location. Have the print function output to the fifo, and use the TX complete interrupt to fetch a new byte to transmit. Make sure you do not overflow this fifo buffer, and that you're not interrupting the print functions with those in interrupts.
You need to treat it as log, with a low frequency of lines (like dmesg). Only on state changes, not for continuous plotting of measurement data.

2) If the setpoint arrives asynchronous, then you cannot wait for in in the PID thread. You have to cache it somewhere else.
If the measurements are also asynchronous, then you have another problem. It makes no sense to recalculate PID when:
- there is no new measurement.
- the previous output was not processed yet.
You might need to lower the frequency of PID calculation.

It looks like what you describe is a simple tasker system. You have an superloop (main `while(1)) with idle priority tasks, and a few ISR with high priority or regular tasks. For example, performing DSP on the ADC samples is such a regular high priority task. If you're late, the data is irrelevant and overwritten.
Things that are lower priority, for example, is communicating with a user or reading received setpoint message frames.

The priority of the various interrupts define the task priority, and if they can preempt. This is an extremely simple way of scheduling. But it has drawbacks. Tasks should not take longer then their interval, this included possible preempted tasks.
Make sure to setup the priorities correctly.

If you put the only watchdog reset in the superloop, you will know when any thread hung itself.
You should also watch for missed interrupts, for example, when you're still doing A, and the A IRQ is set again.

See also if an (RT)OS is of added value to your system.