Перейти к контенту
← Назад

Зачем нужен регулятор

Тестовая статья

Любая роботизированная система пытается добиться заданного значения (позиции, скорости, угла, температуры и т.д.) несмотря на помехи: трение, нагрузка, задержки датчиков.
Регулятор — это алгоритм, который по ошибке e = setpoint − measured вычисляет управляющее воздействие на привод/мотор.

Три кирпичика: P, I, D

Комбинируя, получаем PI (часто для скорости/потока) и PID (универсальный для большинства задач слежения).

Как выбрать тип

Базовая настройка (стартовая евристика)

  1. Поставьте I = 0, D = 0, увеличивайте P, пока система не начнёт быстро, но без больших колебаний выходить к заданию.
  2. Добавьте I небольшими шагами, чтобы убрать остаточную ошибку. Если появляются «качели» — уменьшите I.
  3. Если наблюдается перерегулирование — добавьте D (или чуть уменьшите P).
  4. Введите ограничения: по выходу, по интегратору (anti-windup), по скорости изменения выхода (slew-rate).

Практично: вести логи ошибок/выхода, смотреть переходный процесс (перерегулирование, время установления), фиксировать удачные наборы коэффициентов.

Частые ошибки

Пример PID на Python (дискретный, с anti-windup)

class PID:
    def __init__(self, kp=1.0, ki=0.0, kd=0.0, dt=0.01,
                 out_min=None, out_max=None,
                 i_min=None, i_max=None,
                 d_limit=None):
        self.kp, self.ki, self.kd = kp, ki, kd
        self.dt = dt
        self.out_min, self.out_max = out_min, out_max
        self.i_min, self.i_max = i_min, i_max
        self.d_limit = d_limit
        self.integral = 0.0
        self.prev_error = 0.0
        self.initialized = False

    def reset(self):
        self.integral = 0.0
        self.prev_error = 0.0
        self.initialized = False

    def clamp(self, v, lo, hi):
        if lo is not None and v < lo: v = lo
        if hi is not None and v > hi: v = hi
        return v

    def __call__(self, setpoint, measured):
        e = setpoint - measured

        # P
        p = self.kp * e

        # I (anti-windup через ограничение интегратора)
        self.integral += e * self.dt
        self.integral = self.clamp(self.integral, self.i_min, self.i_max)
        i = self.ki * self.integral

        # D (по ошибке; при первом шаге D=0)
        if not self.initialized:
            d_raw = 0.0
            self.initialized = True
        else:
            d_raw = (e - self.prev_error) / self.dt
        if self.d_limit is not None:
            d_raw = self.clamp(d_raw, -self.d_limit, self.d_limit)
        d = self.kd * d_raw

        u = p + i + d
        u = self.clamp(u, self.out_min, self.out_max)

        self.prev_error = e
        return u

# Пример использования:
# pid = PID(kp=1.2, ki=0.6, kd=0.05, dt=0.01, out_min=-100, out_max=100, i_min=-10, i_max=10, d_limit=200)
# while True:
#     u = pid(setpoint, measured_value)
#     actuate(u)

Где ставить PID в роботе

Мини-чек-лист перед отдачей робота


Если нужно — добавлю сюда графики переходного процесса (как изображения) или разнесу текст на два уровня: «базовый» и «углублённый» с математикой. Также могу подготовить отдельную версию для страницы-раздела (list) и карточку для ленты с коротким excerpt.