Предыдущие части демонстрируют впечатляющие возможности kOS для вывода на орбиту, довольно сложного маневрирования и трансферов. Разобранные примеры, в основном, демонстриро управление без обратной связи, т.е. программировалось
воздействие в надежде, что оно приведёт к желаемому результату. Однако во многих случаях лучше добавить обратную связь - грубо говоря, сделать так, чтобы система знала, какого
результата и корректировала введённое воздействие для более корректного его достижения.
Разберём подробнее, что имеется в виду под наличием и отсутствием обратной связи.
Пример системы, в которой управление организовано без обратной связи, - это духовка. Установка определённого уровня подачи газа (или сопротивления реостата на электрических) определяет температуру духовки, таймер - время работы. Работа устройства в режиме "180° на 10 минут" будет абсолютно одинаковой что при пустой духовке, что при поставленном туда стакане воды, что при поставленной замороженной курице.
Недостаток такого управления - необходимость точно знать характеристики системы, чтобы управляющее воздействие приводило к желаемому результату. В примере с духовкой обычно допустимая погрешность итогового результата обычно достаточно велика, чтобы нестабильность мощности и погрешность таймера не приводили к выходу за границы этой погрешности. Однако если вдруг в середине выполнения программы отключится газ/электричество, то при механическом таймере сигнал о выполнении, вероятно, не будет означать достижение желаемой цели.
При управлении с обратной связью управляющее воздействие представляет собой задание желаемого результата. В качестве примера можно привести современные электрические чайники. Целью является закипание налитой воды. Можно было сделать управление без обратной связи - например, установить таймер работы на фиксированное время, достаточное для закипания максимально возможного объёма налитой в чайник воды. Понятно, что это приведёт к лишнему расходу электричества, если кипятятся небольшие объёмы или начальная температура уже близка к 100°C. Поэтому там стоит датчик пара, по срабатыванию которого отключается питание. Благодаря этой обратной связи, реальное время работы зависит от начального состояния системы. Заодно корректно обрабатываются не вполне штатные ситуации - к примеру, если в налитую воду досыпали лёд.
Система без обратной связи обычно условно представляется следующей схемой:
Рисунок 1. Блок-схема системы управления без обратной связи. На систему подаётся управляющее воздействие
X(t), на что она реагирует изменением состояния
Y(t).
В систему с обратной связью подаётся не управляющее воздействие как таковое, а желаемый закон изменения состояния
G(t), и добавляется дополнительный элемент - регулятор (контроллер), который преобразует сигнал рассогласования (разницу реального и желаемого состояний)
E(t) = G(t) - Y(t) в собственно управляющее воздействие
X(t).
Рисунок 2. Блок-схема системы управления с обратной связью
Первое и очевидное преимущество управления с обратной связью, как должно к этому моменту уже стать понятно, - это возможность получить заданное состояние системы, не зная точно закон управляющего воздействия, которое приводит систему в это состояние. Пример с чайником: пользователь чайника не должен знать, на сколько нужно включить нагрев для кипячения двух стаканов воды. Другой пример: вшитый в нашу нервную систему контроллер положения тела позволяет вполне уверенно ходить, не зная точно массу, моменты инерции и силу сжатия мышц. Причём способность ходить не теряется при наборе/сбросе веса, навешивании на себя рюкзаков и других издевательств над организмом. Чтобы понять, насколько сложна ходьба при прямом управлении сгибанием конечностей, рекомендую
игру Toribash.
Менее очевидное, но не менее важное преимущество - это стабилизация системы. Если целевое состояние системы неустойчиво, но управляющее воздействие выполняется быстрее, чем развивается неустойчивость, то в некоторых случаях это состояние таки можно стабилизировать. К примеру, велосипед без наездника неустойчив и тся набок даже в движении. При наличии контроллера в виде человека он замечательно едет, никуда не заваясь. Но если посмотреть на траекторию переднего колеса (после проезда по луже она хорошо отпечатывается на асфальте), то видно, что она не ровная, а колеблется вокруг нужного положения.
На этом закончу элементы общей теории, перейду к конкретной реализации управления с обратной связью, вшитой в kOS (и, на самом деле, в сток тоже) - ПИД-регулятору.
ПИД означает Пропорционально-Интегрально-Дифференцирующий регулятор. В нём управляющее воздействие рассчитывается из сигнала рассогласования по формуле
где
KP, KI, KD - коэффициенты, подбираемые исходя из желаемых характеристик отклика.
Физически именно такую форму можно понимать следующим образом: пропорциональная часть учитывает текущее отклонение величины от желаемой, дифференциальная - делает поправку на изменение величины в будущем, интегральная - дополнительную поправку на основе учёта прошлого опыта.
Сток использует такую форму контроллера для стабилизации аппарата с помощью САС, в kOS есть встроенный ПИД для контроля ориентации (через lock steering to), а также есть общая структура, которая позволяет прицепить контроллер такого вида для произвольного управления.
Проанализируем некоторые интересные случаи применения регулятора.
Стандартные подходы для анализа - посмотреть отклик системы на входной сигнал
G(t) в виде "ступеньки" и в виде периодического сигнала.
1. Регулировка скорости изменением тяги
Предположим, стоит задача обеспечить спуск аппарата с постоянной скоростью. Регулируется непосредственно уровень тяги
T(t).
Ошибка регулирования
E(t) = Vext(t) - V(t), где
Vext(t) - желаемый закон изменения скорости.
Для начала, рассмотрим работу чисто пропорционального регулятора.
Тягу будем менять по закону:
Из второго закона Ньютона получаем дифференциальное уравнение первого порядка:
Решение для мгновенного изменения
Vext с
V0 до
V1 представляет собой экспоненциальное приближение к заданному значению со временем:
В случае синусоидального изменения желаемой скорости
Vext = V0cos(Ωt) отклик имеет следующий вид:
Видно, что с ростом частоты а) уменьшается амплитуда вынужденных колебаний и б) появляется нарастающее отставание по фазе отклика от желаемого сигнала, стремящееся к 90°. Это происходит потому, что на малых частотах в левой части диффура преобладает пропорциональное слагаемое, а при больших дифференциальное. В итоге имеем при малых частотах эффективное уравнение
V(t) = Vext(t), при больших
dV/dt = KP×Vext(t) = KP×V0cos(Ωt), и
V(t) ~ [KP×V0sin(Ωt)]/Ω.
Добавление дифференциального слагаемого приводит уравнение к следующему виду:
Качественно это не слишком сильно меняет картину. В случае скачкообразного изменения
Vext будет по-прежнему экспоненциальное приближение к нужной скорости, только характерное время увеличится в
(1 + KD) раз. При синусоидальном изменении
Vext амплитуда вынужденных колебаний будет не спадать к нулю при увеличении частоты, а выходить на константу
V0KD/(1 + KD), а сдвиг фазы будет падать к нулю. Такое изменение поведения на высоких частотах связано с тем, что теперь и справа, и слева преобладают слагаемые с производной, и уравнение стремится к
(1 + KD)×dV/dt = KD×dVext/dt.
Рисунок 1.1. Отклик скорости на мгновенное изменение целевой скорости с ПД-регулятором.И, казалось бы, всё тут хорошо и дополнительно интегрального слагаемого не требуется. Однако посмотрим, что будет, если с помощью ПД регулируется не разница между тягой и силой тяжести, а непосредственно тяга:
Примерно такое же выражение получится, если
T(t) = m[gтеор + KPE(t) + KDE'(t)] и
m[/i]gтеор отличается от
m[/i]g в силу неточного знания ускорения свободного падения, массы или тяги конкретного образца двигателя. Такие неопределённости, конечно же, в реальном проектировании неизбежны.
При заданной постоянной скорости
Vext = V0 найдём стационарное решение из условия
dV/dt = 0. Подставляем, получаем
KP×(Vext - V) - g = 0, или
V = Vext - g/KP. Дифференциальное слагаемое тут никак не исправит ситуацию, поскольку зануляется в стационарном решении. Для компенсации таких систематических отклонений и служит интегральное слагаемое.
Закон изменения скорости становится:
где
E(t) = Vext(t) - V(t). Чтобы его решить, обозначим
Z(t) = 0∫tE(τ)dτ, а V(t) обозначим как
Vext(t) - E(t). Получается следующее уравнение:
Это знакомое уравнение колебаний с трением, которое обычно записывается в виде
В данном случае
2γ = KP/(1 + KD), ω02 = KI/(1 + KD).
Случаю
Vext = const соответствует
f(t) = g/(1 + KD), а стационарному решению -
Z(t) = g/KI. Поскольку ошибка равна производной по времени от
Z(t), то в стационарном случае она равна нулю, т.е. скорость устанавливается в точности на требуемом уровне.
Рассмотрим переход при мгновенном изменении
Vext с
V0 до
V1. Необходимо решить уравнение с начальными условиями
Z(0) = g/KI, Z'(0) = E(0) = V1 - V0.
Решение будет иметь вид
Z(t) = g/KI + C1eλ1t + C2eλ2t, где
λ1 и
λ2 - корни уравнения
λ2 + 2γλ + ω02 = 0.В случае, когда
γ > ω0, уравнение имеет два отрицательных действительных корня. Итоговое решение с учётом начальных условий:
Дифференцированием получаем закон изменения ошибки
E(t) = dZ/dt и скорости
V(t) = V1 - dZ/dt = V1 - CZ(λ1eλ1t - λ2eλ2t)Характерной особенностью этой функции является "перелёт" через целевое значение и подход к нему с обратной стороны от той, с которой начиналось движение.
В случае
γ < ω0λ1 и
λ2 - комплексные числа, т.е. решение имеет вид суммы затухающих синусоиды и косинусоиды:
Z(t) = g/KI + (V1 - V0)e-γt[C1cos(ωt) + C2sin(ωt)],
ω2 = ω02 - γ2.Учитывая условие
Z(0) = g/KI, коэффициент перед косинусом равен нулю.
Закон изменения
V(t) снова получаем дифференцированием:
V(t) = V1 + (V1 - V0)e-γtsin(ωt - δ)/sin δ,
δ = arctg(ω/γ)При
γ = ω0 корни характеристического уравнения совпадают
λ1 =
λ2 =
γ, и решение имеет вид
Z(t) = g/KI + (V1 - V0)te-γtВ этом случае выход на стационарное значение происходит быстрее всего.
Рисунок 1.2. Отклик скорости на мгновенное изменение целевой скорости в зависимости от множителя при интеграле в ПИД-регуляторе.Отклик на периодическое изменение целевой скорости будет иметь резонансный характер, т.е. амплитуда вынужденных колебаний будет меняться с частотой немонотонно: максимальная амплитуда будет при частоте внешнего воздействия вблизи собственной частоты
ω0 (точнее, при
Ω2 = ω02 - 2γ2[/sup]).
Вывод из вышесказанного: основную работу в ПИД-регуляторе выполняют пропорциональный и дифференциальный члены. Интегральный член необходим для компенсации систематических отклонений, но при этом приводит к некоторой дестабилизации системы.
2. Регулировка высоты изменением тяги.
Теперь попробуем регулировкой тяги
T(t) обеспечить заданное изменение высоты со временем
Hext(t).
Ошибка регулирования
E(t) = Hext(t) - H(t).
При чисто пропорциональном регулировании
T(t) = m(g + KPE(t))получается, очевидно, уравнение гармонических колебаний вокруг нужной высоты, если
H[/i]ext(t) = const:
d2H(t)/dt2 = T(t)/m - g = KP(Hext - H)В отличие от предыдущего случая пропорциональная регулировка не обеспечивает стабилизации на нужном уровне.
ПД-регулирование приводит к уравнению гармонического осциллятора с затуханием, т.е. высота в итоге стабилизируется на нужном уровне.
Тем не менее, как и в предыдущем примере, стационарный уровень отличается от желаемого при прямом регулировании тяги, а не разницы тяги и веса.
Добавление интегрального слагаемого приводит к уравнению третьего порядка относительно интеграла от ошибки
Z(t) = 0∫tE(τ)dτ[/i]:При ступенчатом изменении
Hext с
H0 до
H1 решение выглядит как
Z(t) = g/KI + C1eλ1t+ C2eλ2t + C3e λ3tгде
λ1 ,
λ2 и
λ3 - корни уравнения
λ3 + KDλ2 + KPλ + KI = 0.Возможные случаи:
1) Все три корня действительные. Тогда, в силу положительности всех коэффициентов уравнения, все три корня должны быть отрицательными, т.е. будет экспоненциальная релаксация к новому равновесному положению.
2) Один действительный корень и два комплексно сопряжённых. В этом случае, поскольку свободный член характеристического уравнения положительный, действительный корень должен быть отрицательным. А вот у комплексно сопряжённых корней действительная часть может быть как отрицательной, так и положительной. В последнем случае, естественно, будут получаться колебания с расходящейся амплитудой.
Можно показать, что корни с положительной действительной частью в данном случае будут появляться при условии
[/i]KI >[/i] KP×KD[/i], т.е. увеличивать интегральное слагаемое опасно.
Вывод: при неправильном подборе коэффициентов ПИД-регулятора можно потерять устойчивость системы. Эффект обычно усиливается с ростом порядка дифференциального уравнения, описывающего систему.
3. Перевёрнутый маятник
Рассмотрим управление перевёрнутым математическим маятником, представляющим собой груз массой
m, закреплённый на тележке массы
M невесомым жёстким стержнем длины
l.
Рисунок 1.3. Схема перевёрнутого маятника.Уравнения движения для этой системы:
(M + m)d2x/dt2 - mlcosθ×d2θ/dt2 + mlsinθ×(dθ/dt)2 = Fl×d2θ/dt2 - gsinθ = d2x/dt2×cosθгде
x - смещение тележки,
θ - отклонение маятника от вертикали.
В случае малых отклонений от равновесного положения
θ=0 уравнения можно линеаризовать:
(M + m)d2x/dt2 - ml×d2θ/dt2 = Fl×d2θ/dt2 - gθ = d2x/dt2Подставив производную координаты из второго уравнения в первое, получим:
Ml×d2θ/dt2 - (M + m)g[/i]θ = FВ отсутствие внешней силы положение равновесия
θ=0 является неустойчивым, т.к. решением уравнения является функция вида
θ = C1e-λt + C2eλt, λ = [(1 + m/M)×g/l]1/2которая даёт неограниченное нарастание отклонения со временем.
Посмотрим, что будет, если ввести внешнюю силу, определяемую ПИД-регулятором:
F = -KPθ - KI×0∫tθ(τ)dτ - KDdθ/dt (знаки "минус" стоят, поскольку тележку, очевидно, нужно толкать в ту же сторону, в которую отклоняется маятник, тогда как в предыдущих примерах действие прикладывалось в противоположную сторону от отклонения).
При такой регулировке, если
K[/i]P[/sub] > (M+m)g[/i], то положение равновесия может быть устойчивым при не слишком большом коэффициенте
KI (см. предыдущий пример).
Вывод: в некоторых случаях ПИД-регуляторы позволяют стабилизировать неустойчивые системы.
В kOS используется дискретный вариант регулятора:
где
ti - моменты времени, в которые вычисляется ошибка управления.
Регулятор реализован через структуру PIDLOOP, имеющую следующие поля:
LASTSAMPLETIME // время последнего обновления
KP // коэффициент усиления пропорциональной компоненты
KI // коэффициент усиления интегральной компоненты
KD // коэффициент усиления дифференцирующей компоненты
INPUT // последнее входное значение
SETPOINT // текущее заданное значение, G(t)
ERROR // последнее значение ошибки E(t)
OUTPUT // последнее выходное значение Y(t)
MAXOUTPUT // максимальное выходное значение
MINOUTPUT // минмальное выходное значение
ERRORSUM // интегральная компонента до домножения на KI
PTERM // пропорциональная компонента KP*ERROR
ITERM // интегральная компонента KI*ERRORSUM
DTERM // дифференцирующая компонента KD*CHANGERATE
CHANGERATE // скорость изменения ошибки dE/dt
RESET // обнулить значение интеграла
UPDATE(time, input) // обновить выходное значение регулятора на основе момента времени и входного значения
Как можно заметить, кроме классического определения, добавлено ограничение выходных значений регулятора. Это может пригодиться, например, если регулятор используется для контроля ориентации самолёта, чтобы не превышать допустимые углы атаки. Также есть команда обнуления интеграла, поскольку интегральная ошибка имеет свойство со временем накапливаться и вызывать нежелательный дрейф.
Создание ПИД-регулятора возможно несколькими конструкторами:
set pid to pidloop(). // создаётся регулятор по умолчанию с KP=1, KD=KI=0
set pid to pidloop(KP).
set pid to pidloop(KP, KI, KD).
set pid to pidloop(KP, KI, KD, MINOUTPUT, MAXOUTPUT). // min и max в конструкторе должны обязательно встречаться парой
После создания в любой момент можно поменять коэффициенты усиления, максимальное и минимальное выходное значения, а также установить желаемое значение для регулируемой характеристики.
Рассмотрим работу с ПИД-регулятором на примере программирования ховеркрафта. Для демонстрации разницы настройки на одной и той же платформе сделаем ховеркрафт с ракетным двигателем (быстрый отклик на управление тягой) и с ВРД (медленный отклик).
Аппарат делаем в виде простейшего ховерборда:
Рисунок 3. Ховерборд - версия с воздушно-реактивными двигателями
Логика скрипта проста до неприличия. Задаётся PIDLOOP с выбранными коэффициентами усиления. Задаётся желаемая высота зависания. Затем в цикле выполняются функции LOCK THROTTLE TO PIDLOOP и PIDLOOP:UPDATE.
Для удобства пользователя в скрипт также добавлены функции изменения высоты зависания с шагом 1 метр, которые повешены на группы действия.
Тяга устанавливается как LOCK THROTTLE TO T_HOVER + PIDLOOP, где T_HOVER - уровень тяги, компенсирующий вес аппарата. Такая форма регулировки увеличивает устойчивость управления. Выходные значения регулятора ограничены значениями от -0,2×T_HOVER до 0,2×T_HOVER, чтобы аппарат слишком быстро не взмывал вверх и не впечатывался в землю.
clearscreen.
sas on.
function teleprint {
// выводит в терминал текущее состояние ПИД-регулятора
parameter pid.
print "Error: " + round(pid:error,2) at (0,5).
print "PTerm: " + round(pid:pterm,2) at (0,6).
print "ITerm: " + round(pid:iterm,2) at (0,7).
print "DTerm: " + round(pid:dterm,2) at (0,8).
print "Output: " + round(pid:output,2) at (0,9).
}
local dt to 0.1. // время между двумя обновлениями
// коэффициенты усиления
local Kp to 0.5.
local Ki to 0.1.
local Kd to 1.
local thrustpid to pidloop(Kp, Ki, Kd, -1, 1).
// задаём желаемую высоту зависания и ставим её как setpoint для регулятора
local wantedalt to 5.
set thrustpid:setpoint to wantedalt.
local da to 1.
// на группы 8 и 9 повесим уменьшение/увеличение высоты зависания
on AG9 {
set thrustpid:setpoint to thrustpid:setpoint + da.
local message2 to "Setpoint: " + round(thrustpid:setpoint,2) + " m".
hudtext(message2, 2, 2, 22, Yellow, false).
preserve.
}
on AG8 {
set thrustpid:setpoint to thrustpid:setpoint - da.
local message2 to "Setpoint: " + round(thrustpid:setpoint,2) + " m".
hudtext(message2, 2, 2, 22, Yellow, false).
preserve.
}
// на группу посадочных ног повесим вывод на экран текущих значений
on gear {
local message1 to "Increment: " + round(da,2) + " m".
local message2 to "Setpoint: " + round(thrustpid:setpoint,2) + " m".
hudtext(message1, 2, 2, 22, Yellow, false).
hudtext(message2, 2, 2, 22, Yellow, false).
preserve.
}
wait until stage:number = 0.
thrustpid:update(time:seconds, alt:radar).
until false {
local cosang to vdot(ship:facing:upvector,up:vector).
local thhover to ship:mass*Kerbin:mu / (Kerbin:radius+altitude)^2 / ship:maxthrust / cosang. // тяга, которая уравновешивает вес
set thrustpid:minoutput to -thhover*0.2.
set thrustpid:maxoutput to thhover*0.2.
lock throttle to thhover + thrustpid:update(time:seconds, alt:radar).
log "Time: " + round(missiontime,2) + " Altitude: " + round(alt:radar,2) to "hover.txt".
teleprint(thrustpid).
wait dt.
}
Этот скрипт работает с версией ховеркрафта на ракетных двигателях (например, если поставить 4 "Искры"). С воздушно-реактивными двигателями он будет вызывать сильные колебания высоты. Это происходит потому, что логика программы не учитывает большую инертность тяги ВРД. Грубо говоря, для устойчивости нужно подобрать коэффициенты таким образом, чтобы характерный период колебаний стал больше характерного времени разгона реактивных двигателей.
Для этого аппарата опытным путём установлены следующие коэффициенты, которые дают относительно неплохой результат с ВРД версией:
KP = 0.01
KI = 0.005
KD = 0.08..0.1
По сравнению с набором коэффициентов для ракетного двигателя, требуется гораздо большее отношение
KD/
KP - можно сказать, что с большим коэффициентом усиления для дифференциальной компоненты регулятор лучше "предсказывает" будущее состояние и поэтому хорошо справляется с более инертным двигателем.
Для разнообразия в скрипте также использована функция HUDTEXT, которая выводит сообщения не в kOS терминал, а непосредственно на экран игры (по типу игровых сообщений об изменении перемотки времени). Подробную документацию по этой функции предлагаю посмотреть
в официальном руководстве.
На этом завершаю настоящую часть гайда. Далее будем использовать регуляторы для функций взлёта и посадки.
Для ракетного ховерборда требуется включить бесконечное топливо и бесконечное электричество: топлива там на пару минут, а в "Искрах" нет генератора, в отличие от ВРД.
ships.zip