# How frequently should a PID controller update?

I am developing a quadcopter platform on which will be extended over the next year. The project can be found on Github. Currently, we are using an Arduino Uno R3 as the flight management module.

At present, I am tuning the PID loops. The PID function is implemented as:

int16_t pid_roll(int16_t roll)
{
static int16_t roll_old = 0;
int16_t result =
(KP_ROLL * roll) +
(KI_ROLL * (roll_old + roll)) +
(KD_ROLL * (roll - roll_old))
;
roll_old += roll;
result = constrain(result, PID_MIN_ROLL, PID_MAX_ROLL);
return -result;
}


I am having trouble interpreting the system response on varying the constants. I believe the problem is related to the questions below.

• How frequently should a PID controller update the motor values? Currently, my update time is about 100-110 milliseconds.
• What should be the maximum change that a PID update should make on the motor thrusts? Currently, my maximum limit is about +-15% of the thrust range.
• At what thrust range or values, should the tuning be performed? Minimum, lift off, or mid-range or is it irrelevant?
• 10Hz seems quite slow! I would recommend something in the range 100Hz - 1000Hz. Crank it up to the highest possible speed. May 30 '14 at 15:42
• I dont see how I will be able to bring the time below 20-40 milliseconds. May 30 '14 at 16:36
• Faster microcontroller? Alternatively, ask the question "How can I optimise this PID code?". I have had a 5kHz PID control loop running on a PIC18, which was also handling CAN bus traffic, and EEPROM writing at the same time. I'm sure there's something we can do to get your loop time down to less than 10ms. May 30 '14 at 17:00
• May 31 '14 at 5:27
• @Rocketmagnet After seeing your comment, I went through the source code and checked the execution time of each of the main functions. After some experimentation, the time came down to 45 milliseconds. Also, out of the 45 milliseconds, 37 ms is being consumed by the pilot input function probably because of the pulseIn command. Other than that, 7 ms is being taken by the IMU. So, thanks! 100 Hz might just be achievable. May 31 '14 at 7:51

1) I would try find out how fast your ESCs can update and use that as the PID update rate. Your current rate is definitely too slow (need at least 50Hz for marginal performance).

2) Putting a threshold on the maximum change should only be used to handle emergency/unexpected situations. You should NOT expect it to be part of the normal operation, and if you are see spikes during normal operation it means you need to fix something somewhere else or lower gains.

3) Tune the PIDs wherever you need best performance, which depends on your application. One strategy is to use different sets of gain values for different situations (e.g. separate takeoff gains) but each set of gains needs to be tuned separately so it adds more work.

I have programmed a quad myself and learned to stay away from the PulseIn function. What it basically does is waiting and constantly reading the pin. I believe Arduino UNO has 2 interrupt input pins, try using those.With some receivers it is possible to use OR ports if pulses are sent one after the other, and combine pulses into a CPPM signal. Interrupt handlers don't take too much time, all you need to do is to start and read a timer. Using this technique I got a rate of well over 200Hz

It is related with response time of electronic speed controller units and bldc motors. In discrete time only Ki and Kd have time variable. In a stable system If you change the sample rate you have to change Ki and Kd to companse it. So you can do it conversly. You can change just Ki and Kd constants instead of changing sample rate. both make same effect.

• Adjusting k values would only work if the system is controllable with the current time step size, right? You cannot control the system (a flying object) if the time step is 2 seconds, for example. Jun 28 '15 at 13:03
• different step sizes needs different constants. If you use dynamic sampling rates you can compansate with dynamic constants.
– acs
Jun 28 '15 at 14:53
• Do you mean gain constants can be dynamic? isn't it counter-intuitive? constants are by definition constants, and do not change. Or, do you mean under different conditions (like hover and forward flight), that delta_t could be changed to keep the gains the same? Could you tell what is the advantage of keeping gains constant and trying to come up with dynamic delta_time? I guess it is the same effort for tuning, and software could get even more complicated. Jun 28 '15 at 15:30
• PID is just piece of code. you can change everything dynamicaly in that code. If your system changes sample time you have to update with proper constants. that means you can response to sample time changes.
– acs
Jun 28 '15 at 17:08
• that's correct, you can change for example the Kd constant as well, a simple way to accomplish the same result is to multiply it with the current delta-time. Jun 28 '15 at 17:12

Your code assumes that the CPU is running at a constant clock. However, in real life it will change, and sometimes even drastically! So it is required to insert a Delta Time (dt) factor to your KI and KD terms in the computations.

i.e.

(KI_ROLL * (roll_old + roll) *dt) +
(KD_ROLL * (roll - roll_old) *dt)


(dt = time_now - time_previous)

By the way, your Integral term is a wrong one! As it stands, it's probably destabilizing the whole system. An integral controller should use a Integral_Roll_error variable, which is the addition of errors in time. For example:

Integral_Roll_error = Integral_Roll_error + roll - roll_old;


Running fast is important, but running a stable rate is required, especially if you want to be able to analyse your system, or do tests, compare different control logics, to add a Navigation algorithm, or payload control algorithm later on, etc.

Coming back to the question:

"I am having trouble interpreting the system response on varying the constants."


It would be beneficial to elaborate a little bit more on what sort of funny or difficulties you ran into. Adding some response charts from your tests would probably let the community help many in practical ways.

The second question asks about the rate limit of the motor control output command. This depends a lot on what sort of a performance you are expecting. The code is only computing the roll_command. How it is turned to motor commands is a relevant topic. In general, as long as the motor accelerations do not cause harm, you could make them as fast as you could.

The performance requirement of the controller (how fast it should stably bring the system to the desired state, how far it should/could overshoot, what sort of a damping it should have), derives the required motor_rate_limit. For example, lift off could be one of the performance requirements. From a standing position to leving the ground, if it takes 30 seconds, is it acceptable? or if the vehicle is tilted by 60 degrees in 2 seconds, (the lift will drop to half if not compensated), you need more Lift all of a sudden. So angular agility of the vehicle is indirectly affecting the lift_agility of the vehicle, and in turn the motor_control_rates.

3) At what thrust range or values, should the tuning be performed? Minimum, lift off, or mid-range or is it irrelevant?


It is relevant. At the limits of thrust, you are not able to accelerate the motors that are already at their maximum. (unless you never allow to go beyond a specific total_Thrust, which is a workaround, by giving up some performance.) So the gains of the controller must be tuned at the maximum, as well as some other points of the operational envelope (forward flight, hover). Reminder: Max thrust and similarly min thrust tests would not be easy to achieve with normal flights.

• The derivative term is also incorrect. I will update the answer. The derivative should be multiplying the derivative of the error, not the difference to error. Should also check the proportional term. Jun 28 '15 at 12:59
• I just found the time to check a bit further. As long as "roll" is not defined, my understanding of the algorithm is incomplete. Maybe "roll" is already the state error. My comments about correctness assumes that "roll" is the state variable. Jun 28 '15 at 16:24