Руководство · Начальный · 18 мин чтения
Как настроить ПИД-регулятор (PID): практическое руководство
Пошаговая настройка ПИД-регулятора: сначала пропорциональный коэффициент, затем производная и интегральная составляющая, без накопления интеграла.
ПИД-регулятор (PID) превращает ошибку между тем, где система находится, и тем, где вы хотите её видеть, в поправку. В нём есть три составляющие — пропорциональная, интегральная и производная, — а настройка означает выбор силы влияния каждой из них. Надёжный способ — добавлять по одной составляющей в фиксированном порядке и наблюдать отклик после каждого изменения. Можно повторять действия в симуляторе ПИД-регулятора.
Начните с пропорционального коэффициента
Установите интегральный и производный коэффициенты в ноль. Увеличивайте пропорциональный коэффициент (Kp), пока система не начнёт быстро реагировать на изменение уставки. Слишком мало — реакция вялая; слишком много — возникает перерегулирование и колебания. Остановитесь, когда отклик быстрый, но колеблется лишь слегка; это рабочая точка для добавления остальных составляющих.
Полезное правило: P даёт скорость. Он реагирует на текущую ошибку и больше ни на что.
Добавьте производную, чтобы укротить перерегулирование
Теперь увеличьте производный коэффициент (Kd). Производная реагирует на скорость изменения ошибки, поэтому при приближении системы к уставке она действует как тормоз. Именно это устраняет перерегулирование и колебания, оставляемые чистым пропорциональным регулированием.
Добавьте ровно столько производной, чтобы колебания затухали. Слишком много делает регулятор нервным, потому что производная усиливает любой шум измерения. Если сигнал зашумлён, фильтруйте его перед дифференцированием или полагайтесь на пропорциональную и интегральную составляющие.
Добавьте интеграл последней
Пропорциональная и производная составляющие вместе всё ещё могут оставлять небольшую постоянную ошибку — система останавливается чуть раньше уставки. Интегральная составляющая (Ki) исправляет её: она накапливает ошибку со временем и действует, пока установившаяся ошибка не исчезнет.
Добавляйте интегральный коэффициент медленно и только если повторяемая установившаяся ошибка сохраняется. Интегральная составляющая самая медленная и её легче всего переборщить, поэтому небольшого значения часто достаточно.
Следите за накоплением интеграла
Накопление интеграла — классический отказ ПИД-регулятора. Когда исполнительный механизм насыщается — двигатель уже работает на полной скорости, клапан полностью открыт, — система не может ответить, но интегральная составляющая продолжает накапливать ошибку. Когда ошибка наконец меняет знак, накопленное действие интегратора разряжается одновременно, и система сильно перерегулируется.
Предотвратите это ограничением интеграла (остановите добавление при насыщенном выходе) или обратным вычислением (уменьшайте интеграл на величину разницы между запрошенным и фактическим выходом). Простое ограничение:
float candidateIntegral = integral + error * dt;
float raw = kp * error + ki * candidateIntegral + kd * derivative;
float output = constrain(raw, outputMin, outputMax);
if (raw == output) integral = candidateIntegral; // only accumulate when not saturated
Поддерживайте честный хронометраж цикла
Все три составляющие зависят от постоянного шага времени. На микроконтроллере долгий delay() в цикле добавляет мёртвое время, из-за которого производная бесполезна при любом коэффициенте и искажает интеграл. Выполняйте цикл быстро и через постоянный интервал, передавая в вычисления реальное прошедшее время.
Быстрое приближение: начальная точка Циглера–Никольса
Увеличение P до появления колебаний — не просто проверка здравого смысла: оно даёт число, по которому можно вычислить всю настройку. Установите I и D в ноль, увеличивайте P, пока выход не начнёт устойчиво колебаться без роста и затухания, и запишите два значения:
Ku— пропорциональный коэффициент, при котором это происходит (предельный коэффициент)Tu— период колебаний в секундах
Затем:
| Регулятор | Kp |
Ki |
Kd |
|---|---|---|---|
| Только P | 0.5 Ku |
— | — |
| PI | 0.45 Ku |
0.54 Ku / Tu |
— |
| ПИД (классический) | 0.6 Ku |
1.2 Ku / Tu |
0.075 Ku Tu |
| ПИД без перерегулирования | 0.2 Ku |
0.4 Ku / Tu |
0.066 Ku Tu |
Это начальная точка, а не ответ. Классическая строка намеренно агрессивна и обычно даёт перерегулирование 20–40%, что допустимо для двигателя и неприемлемо для манипулятора рядом со столом. Последний вариант жертвует скоростью отклика ради достижения цели без перерегулирования.
Ценность метода в том, что он заменяет три неизвестных двумя измерениями. Двадцать минут на поиск Ku и Tu приближают вас к результату больше, чем целый день угадывания, после чего можно настраивать по ощущениям из разумной точки.
Берите производную из измерения, а не из ошибки
Это изменение в одну строку исправляет самую распространённую жалобу на D.
При скачке уставки ошибка также скачет. Производная скачка ненадолго становится огромной, поэтому регулятор выдаёт резкую поправку по причине, никак не связанной с физикой: ничего не переместилось, вы просто попросили о другом. На роботе это означает сильный рывок при каждом изменении цели.
// Derivative kick: the setpoint step goes straight into the output.
float derivative = (error - lastError) / dt;
// Derivative on measurement: the setpoint contributes nothing at all.
float derivative = -(measurement - lastMeasurement) / dt;
Знак меняется, потому что ошибка равна setpoint − measurement; дифференцирование измерения вместо этого означает отрицание. При постоянной уставке обе формы математически идентичны; при её изменении корректно ведёт себя только вторая.
Используйте производную из измерения, если нет конкретной причины поступить иначе. Случаев, когда рывок нужен, почти нет.
Фильтруйте производную, иначе D усилит шум
Дифференцирование усиливает высокочастотную составляющую, а шум датчика по определению высокочастотный. Сигнал с неравномерностью ±2 отсчётов, дискретизируемый с периодом 10 ms, даёт оценку производной с размахом ±200 отсчётов в секунду — которую D превращает в команды двигателя.
Обычно люди делают вывод, что D бесполезен, и устанавливают его в ноль. Настоящая проблема находится выше по цепочке:
// A first-order filter on the derivative term only.
// alpha = dt / (tau + dt); tau is the filter time constant in seconds.
const float tau = 0.05f; // 50 ms
const float alpha = dt / (tau + dt);
dFiltered += alpha * (dRaw - dFiltered);
Выбор tau — компромисс: слишком маленькое значение сохраняет шум, слишком большое заставляет D работать с уже устаревшей информацией, чего следует избегать. Начните с трёх–пяти периодов цикла и увеличивайте только до исчезновения дрожания выхода.
Полный регулятор
Всё вышесказанное в одном месте:
struct Pid {
float kp, ki, kd;
float outMin, outMax;
float tau; // derivative filter time constant
float integral = 0;
float lastMeasurement = 0;
float dFiltered = 0;
bool primed = false;
};
float pidUpdate(Pid &c, float setpoint, float measurement, float dt) {
if (dt <= 0) return 0;
const float error = setpoint - measurement;
// Derivative on measurement, low-pass filtered.
if (!c.primed) { c.lastMeasurement = measurement; c.primed = true; }
const float dRaw = -(measurement - c.lastMeasurement) / dt;
const float alpha = dt / (c.tau + dt);
c.dFiltered += alpha * (dRaw - c.dFiltered);
c.lastMeasurement = measurement;
// Provisional integral, committed only if the output does not saturate.
const float candidate = c.integral + error * dt;
const float raw = c.kp * error + c.ki * candidate + c.kd * c.dFiltered;
const float out = constrain(raw, c.outMin, c.outMax);
if (raw == out) c.integral = candidate; // conditional integration
return out;
}
Три вещи отличают регулятор, работающий на роботе, от регулятора из учебника: производная из измерения, фильтрованная производная и условное интегрирование, не позволяющее интегралу накопиться при насыщении исполнительного механизма.
Диагностика по форме отклика
По одной кривой отклика можно назвать почти любую ошибку настройки:
| Что видно | Что это значит | Что изменить |
|---|---|---|
| Медленно растёт и не достигает цели | Слишком мало P, нет I | Увеличьте P; добавьте I, если остаётся установившаяся ошибка |
| Установившееся значение остаётся ниже заданного | Нет интегральной составляющей | Медленно добавьте I |
| Перерегулирует один раз, затем устанавливается | Немного велико P, нет D | Добавьте D |
| Многократно перерегулирует с затуханием | Слишком велико P | Снизьте P или добавьте D |
| Бесконечно колеблется с постоянной амплитудой | P равен предельному коэффициенту | Вы нашли Ku — уменьшите его вдвое |
| Амплитуда колебаний растёт | P выше Ku |
Немедленно уменьшите |
| Быстрый, рваный, дрожащий выход | D действует на шум | Фильтруйте производную или сигнал датчика |
| Сильно дёргается при изменении уставки | Рывок производной | Берите производную из измерения |
| После большого перемещения сильно проезжает цель | Накопление интеграла | Условное интегрирование или ограничение |
| Вчера работало, сегодня вяло | Изменился объект — обычно аккумулятор | Коэффициенты описывают объект, а не код |
Последнюю строку стоит подчеркнуть, потому что это не ошибка. Коэффициенты описывают конкретный объект, в который входят заряд аккумулятора, масса шасси, поверхность и температура редуктора. Настройка, идеальная на свежих элементах, станет вялой на разряженных, потому что та же нагрузка теперь создаёт меньше момента. Профессиональные решения — контур скорости под ним (тогда регулятор задаёт скорость, а не рабочий цикл) или переключение коэффициентов (несколько настроек, выбираемых по режиму работы).
Хронометраж цикла в цифрах
И I, и D вычисляются по прошедшему времени, поэтому цикл, который выполняется с произвольными интервалами, вычисляет обе величины по ложным данным.
| Поведение цикла | Влияние на регулятор |
|---|---|
| Фиксированный интервал | Всё работает как задумано |
Переменный, но dt измеряется и передаётся |
Тоже правильно — это практичное решение |
Переменный, dt считается постоянным |
I накапливается неправильно; D усиливает шум |
Содержит delay() |
Мёртвое время — никакое значение D его не компенсирует |
Измеряйте dt через micros() и передавайте его в вычисления. Это ничего не стоит, переживает изменение длительности цикла по мере добавления функций и устраняет целый класс загадок настройки.
Если цикл можно ещё и сделать быстрым, сделайте это: регулятор с частотой дискретизации 20 Hz действует на данные, устаревшие на 50 ms, и никакой коэффициент не исправит устаревшую информацию. Удаление вызовов delay() обычно повышает частоту первого робота с 20 Hz до нескольких сотен, а слежение улучшается без изменения коэффициентов.
Попробуйте сами
Откройте симулятор ПИД-регулятора, установите I и D в ноль и пройдите этот порядок. Следите, как перерегулирование, время установления и установившаяся ошибка реагируют на каждую составляющую. Когда форма отклика станет понятной, та же интуиция перенесётся на реальный двигатель, нагреватель или контур руления в симуляторе робота, следующего по линии.
Исследуйте граф
Входит в эти сборки
Проекты и учебные пути, в которые входит это руководство.
Дополнительные материалы