Справочници, схемотехника, теория > Програмиране на микроконтролери, програматори, цифрови проекти
GPS-автопилот - алгоритъм
EDM electronics:
--- Цитат на: juliang в Април 26, 2022, 07:00:35 pm ---1. Контролера на Данфос има една функция, която ми показва за колко време се върти един Main цикъл.
Най-лесниото решение е в началото на Main-а да имаш един брояч, който да изхвърля логиката в 9 от 10 преминавания, или там колкото ти трябват за да се постигне желаната инертност.
2. Особено болезнен е цирка когато системата стартира и разликата между реалната и зададената стойност е много голяма.
--- Край на цитат ---
При STM32 има една библиотека HAL, която подобно на Ардуино предлага готови функции при апаратното програмиране и се ползва масово. Та там има една функция HAL_GetTick(), която представлява един брояч с точен период от 1 mS, независимо как ще настроиш честотата на контролера. Винаги тая функция дава 1 mS. Това е един 32-битов регистър-брояч, който се свързва на системния брояч-регистър на Систика, като се взима извод от пин с период 1 mS. В Ардуино същата функция е milis(). С тази функция се правят всички софтуерни таймери. Те са такива с не голяма точност. Ако трябват таймери с точност се правят вече апаратни. Пример:
unsigned long T;
if(HAL_GetTick() - T > 10) { //ако разликата между брояча и променливата е по-голяма от 10 mS
T = HAL_GetTick(); //приравняваме стойността на брояча
изпълняваме нужния код или вдигаме флаг
на всеки 10 mS
}
Така могат да се реализират безброй таймери само с една променлива и за всякакво време > 1mS. Таймера няма блокираща функция.
2. Няма ли тоя Данфос външно прекъсване? Да чакаш секунди за бутон ми се струва много голям компромис?
Гледах един клип как се настройва ПИД в реални условия най-лесно:
Закача се датчика на входа или променливата която ще се мери - при мен е разстояние между 2 точки. В плотера на компилатора /повечето съвременни имат/ се поставят три променливи: вход, изход и грешка. На графиката се изписват трите графики една върху друга и се вижда има ли колебания, за колко време се стабилизира процеса и най-важното съвпада ли сетпойнта с грешката, трябва да е равно на нула. Така без практически опити кой знае какви може да се настроят коефициентите.
juliang:
--- Цитат на: EDM electronics в Април 26, 2022, 07:39:54 pm ---Гледах един клип как се настройва ПИД в реални условия най-лесно:
Закача се датчика на входа или променливата която ще се мери - при мен е разстояние между 2 точки. В плотера на компилатора /повечето съвременни имат/ се поставят три променливи: вход, изход и грешка. На графиката се изписват трите графики една върху друга и се вижда има ли колебания, за колко време се стабилизира процеса и най-важното съвпада ли сетпойнта с грешката, трябва да е равно на нула. Така без практически опити кой знае какви може да се настроят коефициентите.
--- Край на цитат ---
И аз гледах клипове. Гледах и как се справят алгоритмите за адаптация на контролера на горелките (на Сименс, дет се занимават десетилетия с такива неща). Гледах как се справя с адаптацията алгоритъма на едни контролери KS 20 на West. В половината от случаите успява да се справи горе-долу, в другите случаи резултата е посредствен. Налага се да се дооправят коефициентите на ръка.
да оправиш коефициентите с чертане на графики... няма как да стане.
EDM electronics:
--- Цитат на: juliang в Април 26, 2022, 07:00:35 pm ---
1. Да, интегралното време е бройка преминавания през дадената библиотека, а не време като секунди. Същото е и с деривативното време - и то е брой цикли, а не секунди. Но когато знаеш за какво време програмата прави един loop, можеш да си сметнеш секундите... не че ти трябват точно секунди.
2. Защо не чета 99 стойности назад? Ами... ако пробваш алгоритъма ще разбереш. Понякога 90 от тия 99 записа сочат, че си бил под исканата стойност, а само последните 10 ти указват, че вече си я надхвърлил.
--- Край на цитат ---
Останаха неясноти - важни:
1. Според твоето обяснение integralTime и derivativeTime това не е някакво време, а броя на измерванията или броя на елементите на масива, т.е. делиш на техния брой? В други обяснения на ПИД от Интернет този делител е наистина време и това е времето на дискретизация, т.е. времето между две измервания на входа. От твоите теоретични обяснения обаче схващам, че това са броя измервания.
2. Ако ползваш само 10 измервания от масива, защо тогава правиш запис на 100? Да го разбирам ли, че останалите 90 ще ползваш, ако решиш да промениш параметрите на ПИДа при някакви други условия?
juliang:
1. Двата параметъра са на практика броячи - променят се с единица при всяко преминаване през Main метода. Да, ако трябва да сме съвсем точни - трябва да са секунди. Но от друга страна - защо точно секунди? Може да са стотни от минутата. А при бързи процеси може да са милисекунди. При бавни - може да са минути или часове дори... За какво ти е измерване в секунди, ако правиш робот който примерно играе тенис на маса? Тук със секунди ще се оправиш ли? :)
https://www.youtube.com/v/7Jw8m4pbTYI
2. Да. Kp, Ki и Kd са свободно избираеми от потребителя и се променят на място, като се следи поведението на цялата система и реакцията на изпълнителния механизъм.
Единия случай и го обясних - трбопровод, и една помпа трябва да реагира на отваряне на кран и да възстанови налягането. На практика реакцията трябва да е моментална - и на отваряне, и на затваряне на кран.
Втория случай е управление на горелката на отоплителен котел в голям хотел в Боровец. Като запалиш котела, топлата вода трябва да отиде на 100 метра настрани и на 10 етажа нагоре, и после да се върне обратно. Това отнема около 5 минути. Горелката се управлява по температура на връщащата се вода. Т.е. ти чак след 5 минути можеш да разбереш дали мощността ти е достатъча, дали трябва да добавиш още или вече си ощавил гостите :) Тогава горелката мърда с 1% мощност на 10-20 секунди, и Kd е огромна цифра - дори и най-малкия намек за повишаване на температурата, дори и да не е достигнало заданието трябва да е сигнал за алгоритъма управляващ горелката да забави хода на мощността й нагоре, или дори да почне да се връща към по-ниски мощности. Тоест Kd трябва да е достатъчно голям, за да може да се противопостави на пропорционалния Kp, който настоява мощността да се вдига, щото температураат е с 20 градуса по-ниска от заднието. 20 градуса по-ниска, ама на връщането... няма как да знаеш дали в хотела има отворен 1 радиатор, или са се прибрали 500 замръзнали скиора, които са отворили всички радиатори, пуснали са душове, вани и квот се сетиш :) А е изключитлно дискомфортно ако има отворен 1 душ и 1 радиатор, ти да пуснеш 1 мегават котел на 100% и да пратиш вода с температура 95 градуса към нещастния един гост на хотела :)
А, да... за интегралната част... тя в много от случаите е безполезна, ако не гониш някаква точност като тази на видеото. нейната единствена цел е да коригира натрупаните с времето грешки в измерването ил ив изпълнението на командите. Тоест ти искаш да вървиш точно на 43.276 градуса, но руля може да даде 43 или 44 градуса. Измервателното устройство отчита че има малка грешка, но Kp е достатъчно малък за да повлияе на руля. В тоя случай в Ki ще се натрупва постоянна грешка която в един момент ще доведе до отклоняване на руля въпреки че Kp не е показал нужда от това.
EDM electronics:
Направих от това, което съм разбрал функция ПИД с десет елемента от масив. Считам, че е достатъчно. Функцията връща резултата и ще се вика от таймер с време в зависимост от инертността на системата. В моя случай ще я викам на 5 сек. Така ще прави запис в масива за 50 сек - достатъчно дълго време за оценка на тенденцията.
int PID_regulator(float input, float setpoint, float kp, float ki, float kd, int minOut, int maxOut) {
static float errors[10]; //10 елемента за запис на входните числа
float integral = 0; //интегрална съставна
float derivative = 0; //дефиринциална съставна
static int Output = 0; //изход - връща значение
errors[0] = setpoint - input; //текущо значение и пропорционална съставна
for(int i = 9; i > 0; i--) errors[ i ] = errors[i - 1]; //преместваме стойността на errors[0] по масива
for(i = 0; i < 9; i++) integral += errors[ i ] * ki; //прочитаме записите в масива, събираме ги
integral /= 10; //делим на броя елементи от масива
derivative = (errors[0] - errors[9]) * Kd / 10; //деферинциална съставна
Output = errors[0] * kp + integral + derivative; //събираме трите съставни в изхода
if(Output < minOut) Output = minOut; //ограничаване по минимум
else if(Output > maxOut) Output = maxOut; //ограничаване по максимум
else Output; //четем изхода без ограничения
return Output; //връщаме значението от изхода
}
Навигация
[0] Списък на темите
Премини на пълна версия