Библиотека релейного регулятора для Arduino [31.01.2020]

ОБНОВЛЕНИЯ


  • v2.1 — исправлена getResultTimer

ТЕОРИЯ


Это библиотека не для модулей реле (им не нужны библиотеки), это библиотека для релейного регулятора, т.е. реализация релейного закона регулирования с гистерезисом и обратной связью по скорости изменения величины через коэффициент усиления. Что позволяет делать релейный регулятор:

  • Управлять какой-то величиной, включая и выключая орган управления (температура – обогреватель или холодильник, влажность – увлажнитель, и так далее)
  • Гистерезис – “окно” вокруг установленного значения, чтобы уменьшить количество включений/выключений реле (управляющего устройства)
  • Обратная связь (ОС) по изменению – в библиотеку встроено автоматическое вычисление производной измеряемой величины. Подобрав коэффициент усиления ОС можно добиться максимальной стабильности и точности удержания заданной величины: обратная связь по изменению позволяет отключать управляющее устройство до перехода через заданную величину снизу, и заранее включать при приближении к ней сверху

БИБЛИОТЕКА


Библиотека классического релейного регулятора для Arduino

  • Обратная связь по скорости изменения величины
  • Настройка гистерезиса, коэффициента усиления ОС, направления регулирования
  • Возвращает результат по встроенному таймеру или в ручном режиме

Поддерживаемые платформы: все Arduino (используются стандартные Wiring-функции)

УСТАНОВКА


  • Библиотеку можно найти и установить через менеджер библиотек по названию GyverRelay в:
    • Arduino IDE (Инструменты/Управлять библиотеками)
    • Arduino IDE v2 (вкладка «Library Manager»)
    • PlatformIO (PIO Home, вкладка «Libraries»)
  • Про ручную установку читай здесь

ДОКУМЕНТАЦИЯ


Инициализация

Можно создать объект с указанием направления регулирования GyverRelay regulator(REVERSE); Можно просто GyverRelay regulator;

Настройка

Основные параметры регулятора можно читать и изменять напрямую как члены класса:
  • input - входная величина, например температура
  • setpoint - установка (к чему регулятор будет стремиться привести входную величину)
  • output - выход (0 или 1) для управления реле (например через digitalWrite()). Менять его не нужно, этим занимается библиотека!
Настроечные параметры:
  • hysteresis - ширина окна (петли) гистерезиса. Гистерезис уменьшает количество переключений реле, но дестабилизирует систему.
  • k - коэффициент обратной связи по скорости (по первой производной), подбирается вручную (0.01 ~ 100). При нулевом значении ОС отключается. ОС по скорости изменения позволяет стабилизировать систему, см. картинку в начале статьи.
  • dT - время итерации для режима работы по встроенному таймеру.
  • setDirection(dir) - установить направление работы регулятора: NORMAL - включаем нагрузку при переходе через значение снизу (пример: охлаждение), REVERSE - включаем нагрузку при переходе через значение сверху (пример: нагрев).

Управление

Работа релейного регулятора завязана на времени между измерениями, особенно в режиме с ОС, поэтому период расчёта должен строго соблюдаться. Библиотека имеет три функции для расчёта состояния реле, все функции возвращают состояние 0 или 1, а также изменяют состояние output, которое можно использовать в коде для чтения:
  • compute(dt) - моментальный расчёт. Принимает dt в секундах для режима с ОС. Можно не передавать dt, тогда ОС не будет работать. Функция сделана для работы напрямую с расчётом, т.е. вы сами контролируете период вызова функции и передаёте его ей в миллисекундах (если нужна ОС). Демо-пример, вариант 3;
  • getResult() - моментальный расчёт. Встроенный таймер для режима с ОС. При вызове данной функции программа сама вычисляет время с предыдущего вызова с передаёт dt в расчёт. Таким образом нужно просто позаботиться о периодичности вызова этой функции, dt в расчёт она передаёт сама. Демо-пример, вариант 1;
  • getResultTimer() - расчёт по встроенному таймеру, самый простой в использовании вариант: делает расчёт и возвращает новое значение по своему собственному таймеру, а пока таймер не сработал - возвращает результат предыдущего расчёта. Т.е. эту функцию можно вызывать постоянно, новое значение она отдаст только когда придёт время. Демо-пример, вариант 2.
GyverRelay(boolean direction = REVERSE);
// NORMAL - включаем нагрузку при переходе через значение снизу (пример: охлаждение)
// REVERSE - включаем нагрузку при переходе через значение сверху (пример: нагрев)
	
// расчёт возвращает состояние для управляющего устройства (реле, транзистор) (1 вкл, 0 выкл)
boolean compute(float dt = 0);    // моментальный расчёт. Принимает dt в секундах для режима с ОС
boolean getResult();              // моментальный расчёт. Встроенный таймер для режима с ОС
boolean getResultTimer();         // расчёт по встроенному таймеру

void setDirection(boolean dir);	  // направление регулирования (NORMAL, REVERSE)
	
float input = 0;                  // сигнал с датчика (например температура, которую мы регулируем)
float setpoint = 0;               // заданная величина, которую должен поддерживать регулятор (температура)
boolean output = 0;               // выход регулятора (0 или 1)
	
float hysteresis = 0;             // ширина окна гистерезиса
float k = 0;                      // коэффициент усиления по скорости (по умолч. 0)	
int16_t dT = 1000;                // время итерации, мс (по умолч. секунда)

ПРИМЕРЫ


Остальные примеры смотри в папке examples библиотеки, также примеры можно открыть из Arduino IDE/Файл/Примеры

/*
   Пример работы релейного регулятора в автоматическом режиме по встроенному таймеру
   Давайте представим, что на 3 пине у нас спираль нагрева, подключенная через реле
   И есть какой то абстрактный датчик температуры, на который влияет спираль
*/
#include "GyverRelay.h"

// установка, гистерезис, направление регулирования
GyverRelay regulator(REVERSE);
// либо GyverRelay regulator(); без указания направления (будет REVERSE)

void setup() {
  pinMode(3, OUTPUT);         // пин реле
  regulator.setpoint = 40;    // установка (ставим на 40 градусов)
  regulator.hysteresis = 5;   // ширина гистерезиса
  regulator.k = 0.5;          // коэффициент обратной связи (подбирается по факту)
  //regulator.dT = 500;       // установить время итерации для getResultTimer
}

// вариант с delay
void loop() {
  int temp;                 // например читаем с датчика температуру
  regulator.input = temp;   // сообщаем регулятору текущую температуру

  // getResult возвращает значение для управляющего устройства
  digitalWrite(3, regulator.getResult());  // отправляем на реле (ОС работает по своему таймеру)
  delay(100);
}

/*
  // вариант со встроенным таймером
  void loop() {
  int temp;                 // например читаем с датчика температуру
  regulator.input = temp;   // сообщаем регулятору текущую температуру

  // getResult возвращает значение для управляющего устройства
  digitalWrite(3, regulator.getResultTimer());  // отправляем на реле
  
  // также можно получить значение с выхода регулятора
  // regulator
  }
*/

/*
// вариант со своим таймером
void loop() {
  static uint32_t myTimer = 0;
  if (millis() - myTimer > 2000) {    // свой таймер на миллис, 2 секунды
    myTimer = millis();
    int temp;                 // например читаем с датчика температуру
    regulator.input = temp;   // сообщаем регулятору текущую температуру

    // getResult возвращает значение для управляющего устройства
    digitalWrite(3, regulator.compute(2));  // отправляем на реле. Время передаём вручную, у нас 2 секунды
  }
}
*/
/*
  Симуляция работы реле. Обнули k и увидишь, как регулятор
  перестанет справляться с инерционной системой
*/

#include "GyverRelay.h"
GyverRelay regulator(REVERSE);

void setup() {
  Serial.begin(9600);
  regulator.setpoint = 40;
  regulator.hysteresis = 5;
  regulator.k = 0.5;
}

boolean state = 0;
float value = 0;

void loop() {
  process();
  regulator.input = value;
  state = regulator.getResult();

  Serial.print(value);
  Serial.print(' ');
  Serial.print(regulator.setpoint - 5 / 2);
  Serial.print(' ');
  Serial.print(regulator.setpoint + 5 / 2);
  Serial.print(' ');
  Serial.println(regulator.setpoint);
  delay(100);
}

void process() {
  static float coef = 0;
  coef += state ? 0.3 : -0.6;
  if (coef > 2.0) coef = 2.0;
  if (coef < -3.0) coef = -3;
  value += coef;
}

ВИДЕО


ПОДДЕРЖАТЬ


Вы можете поддержать меня за создание доступных проектов с открытым исходным кодом, полный список реквизитов есть вот здесь.

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

16 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх