Практика автоматического управления (легче теории)

Автор Владимир Бендик, Суббота, февраля 24, 2024, 06:59:13

« предыдущая тема - следующая тема »
Вниз

Владимир Бендик

Суббота, февраля 24, 2024, 06:59:13 Последнее редактирование: Суббота, февраля 24, 2024, 08:16:39 от Владимир Бендик
В честь намечающегося дня науки, я бы хотел поделиться учебным примером системы автоматического управления который вы можете повторить самостоятельно дома. Кроме того этот пример структурно похож на многие реальные примеры автоматизации тепловых процессов.
Объектом управления в нашем реальном случае будет являться температура корпуса датчика. Регулирование будет осуществляться сервоприводом, который способен пододвигать датчик ближе к источнику тепла (жалу паяльника в нашем случае) или отодвигать от него. Если сравнивать с реальными объектами, то наша система похожа на управление заслонкой пропускающей, например, горячий пар. Чем заслонка открыта сильнее, тем больше тепла подается на объект управления и аналогично в другую сторону. Роль контроллера у нас выполнять будет, конечно же, Ардуино нано. Схема подключения такова:

Теперь соберем все это не забыв источник тепла.

А теперь напишем код который будет всем этим управлять. В качестве самого регулятора возьмем наш любимый ПИ-регулятор.
#include "GyverPID.h"      // Подключение библиотеки ПИД регулятора
#include <microDS18B20.h>      // Подключение библиотеки измерителя температуры DS18B20
#include <ServoSmooth.h>       // Подключение библиотеки управления сервоприводами

MicroDS18B20<3> sensor1;       // Инициализация измерителя температуры и привязка его к пину D3
ServoSmooth servo;       // Инициализация сервопривода

float temp = 0;       // Создание переменной с температурой полученной от измерителя

GyverPID regulator(???, ???, ???);        // Инициализация ПИД регулятора, в скобках указываются коэффициенты составляющих, они будут добавлены позже

void setup() {
Serial.begin(9600);       // Запуск последовательной передачи данных
servo.attach(9);       // Привязка сервопривода к пину D9
servo.setSpeed(130);        //
servo.setAccel(0.1);       //  Прочие настройки сервопривода
regulator.setDirection(NORMAL);       // Настройка регулятора, NORMAL соответствует прямому направлению регулирования
regulator.setLimits(0, 180);      // Лимиты работы регулятора, соответствуют минимальному и максимальному углу поворота сервопривода
regulator.setpoint = 50;      // Уставка регулятора
}

void loop() {
servo.tick();      // Для работы сервопривода
sensor1.requestTemp();      // Запрос температуры с измерителя
if (sensor1.readTemp()) {       //  Если запрос удался
temp = sensor1.getTemp();      // То сохраняем результат в переменную temp
} else Serial.println("error");      // Иначе пишем сообщение о ошибке
regulator.input = temp;      // Передаем регулятору температуру
servo.setTargetDeg(regulator.getResultTimer());       // Задаем сервоприводу положение получаемое из регулятора
Serial.print(regulator.getResultTimer() / 10);       // Выводы сообщений в порт для отладки или сбора данных
Serial.print("\t");
Serial.print(temp);
Serial.print("\t");
Serial.println();
}

В инициализации регулятора присутствуют непонятные вопросительные знаки, это коэффициенты настройки регулятора, не написаны они потому что неизвестны. Что ж, найдем их через разгонную характеристику.
Разгонная характеристика это график показывающий изменение управляемой величины со временем при изменении задания. Говоря совсем уж не официально, разгонная характеристика это график похожий на тот, который мы можем получить для передаточной функции в МатЛабе через команду "step". Только самой передаточной функции у нас при этом нет, но в этом и вся соль, ведь мы получим ее через разгонную характеристику. В общем: зададим сперва сервоприводу крайнее левое положение и подождем пока температура сравняется с комнатной, затем зададим крайнее правое и снимем показания нагрева и соответствующее им время. В моем случае получились вот такие данные и такой график соответствующий им:
time =[0 5 10 15  17 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105]
temp = [32.75 35.19  39.88   45.13  48.00 50.38  53.19 54.81 56.25 59.19 60.50 61.50 62.50 64.69 66.81 68.06 68.56 69.12 70.44 70.94 70.31 70.31 70.31]-32.75
u = [180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 180 ]
figure(1)
plot(time,temp), grid


Я отнял от вектора temp 32.75 поскольку это начальная величина и, мне кажется, правильно будет ее сравнять с нулем(тут преподаватели могут меня поправить, если я не прав).
Теперь найдем передаточную функцию соответствующую этому графику, для этого воспользуемся расширением для МатЛаба System Identification, вызвать его можно написать в командной строке "ident". Работать с ним совсем не сложно, поэтому не буду тут расписывать инструкцию которую можно прочитать на Экспоненте. Импортируем туда наши данные: входной величиной будет вектор u (соответствует максимальному углу поворота сервопривода), выходной - температура. На основе этих данных МатЛаб предложит такую передаточную функцию:

Построим ее график на одном графике со снятыми данными.
tf1=tf([0.005417 0.002479],[1 0.4726 0.0107])
figure(2)
hold on
plot(time,temp+32.75,'red')
step(tf1*180+32.75), grid
hold off


Графики действительно совпадают часть времени, вполне вероятно, что если бы я продолжил нагревать датчик, то они совпадали бы и дальше, но я побоялся испортить его.
Теперь имея передаточную функцию системы найдем настройки регулятора самым простым способом и посмотрим на график работы системы с регулятором и обратной связью:
PI=pidtune(tf1,'PI')
figure(3)
step(feedback(PI*tf1,1)), grid


Настройки регулятора при этом следующие:

Допишем их в код контроллера: GyverPID regulator(7.24, 0.317, 0);
Третья цифра это коэффициент дифференциальной составляющей, т.к. регулятор у нас ПИ, то он равен нулю. Осталось лишь загрузить программу и посмотреть как она справится со своей задачей. Уточню, что уставка регулятора - 50 градусов.
https://youtube.com/shorts/WKANFbyNWZg?feature=share
Из видео видно, что я не умею снимать горизонтально и что регулятор отлично справился с задачей. Он выставил угол поворота в максимальное положение, дождался нагрева до 50 градусов и начал уменьшать угол. Таким образом предельное перерегулирование составило 53 градусов(что даже соответствует матлабовским 107% амплитуды перерегулирования с последнего графика!!!), уменьшив угол он остановился в положении при котором температура оставалась около 50 градусов.
В завершение хочу сказать, что основной целью написания этой статейки для меня было показать, что учиться решать практические задачи из сферы автоматического можно дома имея минимум оборудования, для этого не нужны ПЛК за 30 тысяч рублей и не нужно ждать лабораторную работу раз в 2 недели.

RVL

Добрый вечер, Владимир!
Неплохо бы закомментировать код, для ясности!

Владимир Бендик

Добрый вечер, Владимир!
Неплохо бы закомментировать код, для ясности!
Добавим!

RVL

Спасибо!

Serial.print(regulator.getResultTimer() / 10);       // Выводы сообщений в порт для отладки или сбора данных

Зачем здесь деление на 10?

ran

Всё здорово. Спасибо за доклад. Только никак не может температура быть объектом автоматизации. Как можно автоматизировать температуру? Ее можно только РЕГУЛИРОВАТЬ.

ran

#5
Суббота, февраля 24, 2024, 09:31:48 Последнее редактирование: Суббота, февраля 24, 2024, 09:34:21 от ran
"Регулирование будет осуществляться сервоприводом, который способен пододвигать датчик ближе к источнику тепла (жалу паяльника в нашем случае) или отодвигать от него"
Перечитал доклад и всё понял. Возражение снимается. Объектом управления действительно является температура:) Браво!

Владимир Бендик

Спасибо!

Serial.print(regulator.getResultTimer() / 10);       // Выводы сообщений в порт для отладки или сбора данных

Зачем здесь деление на 10?
Чтобы все поместилось на одном графике и не мешало друг другу :)

ran

Привет из девяностых,
А, может быть, из двадцатых:
От жала отодвинемся просто,
И будем свободно квакать.
Но жало не неподвижно,
Оно ползёт вперед датчика.
Порядок астатизма
Меньше на единицу. Удачи!

Вверх