Создание собственной системы стабилизации
это оказывается COMport на компьютере глючит ! (во как)
Управление потоком отключите
с гирами беда какая-то - дёргаться даже в акро стал
Если раскачка плавная, то делай меньше П и побольше Д. Если же дерганья “нервные”, то делай меньше Д, происходит резкое перерегулирование по угловой скорости, при твоих винтах большой Д = высокие нагрузки на моторы (причем зарежимные, с низким КПД ВМГ),с вытекающими последствиями. Кроме того, если ты увеличил цикл обсчёта, то соответственно dt дифф. части тоже увеличилось (если ПО ПИДа это учитывает) и её вес возрос. Короче пробуй меньший Д.
а вот аксель в mpu-ке получше, это да…
Дык в нём весь корень зла для автоматики!
Короче пробуй меньший Д.
ну так я и поступил, но с циклом надо повозиться… а правильнее наверно сделать как в арду, привязать цикл к прерываниям от MPU, ибо батарейки не с проста греться стали…
но с циклом надо повозиться…
вот ещё подумалось: длинный цикл - высокие “ступеньки” в регулировании, тоже источник дерготни.
это да, да и фильтры надо пересматривать, думаю надо время задать примерно 1200 - 1300, с учётом того, что гироаксель читается быстрее, да частота проца высока…
думаю будет пару свободных вечеров, тебе верхнюю плату с твоим gps нарисовать? как разъём на антенну обзывается?
думаю будет пару свободных вечеров, тебе верхнюю плату с твоим gps нарисовать?
если нет “творческого порыва”, то не надо, пока она не к спеху. Надоть сначала основу облетать, жду комплектухи, а пока подбиваю теоретическую базу (книжек вумных набрал), учу математику…
как разъём на антенну обзывается?
не знаю, завтра уточню… а может кераму сразу на плату припаять?
для неё дырка на плате нужна, а значит сам модуль где-то снизу - не не выход, ну можно выкинуть MicroSD? либо “отодвинуть” питатели ближе к SPI на их место модуль, а на место модуля антенну, но думаю лучше выносную?
currentTime = micros();
if (mcfg.looptime == 0 || (int32_t)(currentTime - loopTime) >= 0) {
loopTime = currentTime + mcfg.looptime;
computeIMU();
// Measure loop rate just afer reading the sensors
currentTime = micros();
cycleTime = (int32_t)(currentTime - previousTime);
previousTime = currentTime;
короче просто изменение скорости петли опроса датчиков, как следствие нужно лишь вписаться чтобы маг с баро успевал прочитать если надо, а гироаксель успеет в любом случае, а так да происходит завышение D…
Александр mahowik меня тут озадачил, новым вийным ПИД-ом , полез я сравнивать и короче наткнулся вот на что:
// **** PITCH & ROLL & YAW PID ****
prop = max(abs(rcCommand[PITCH]), abs(rcCommand[ROLL])); // range [0;500]
for (axis = 0; axis < 3; axis++) {
if ((f.ANGLE_MODE || f.HORIZON_MODE) && axis < 2) { // MODE relying on ACC
// 50 degrees max inclination
errorAngle = constrain(2 * rcCommand[axis] + GPS_angle[axis], -500, +500) - angle[axis] + cfg.angleTrim[axis];
PTermACC = (int32_t)errorAngle * cfg.P8[PIDLEVEL] / 100; // 32 bits is needed for calculation: errorAngle*P8[PIDLEVEL] could exceed 32768 16 bits is ok for result
PTermACC = constrain(PTermACC, -cfg.D8[PIDLEVEL] * 5, +cfg.D8[PIDLEVEL] * 5);
errorAngleI[axis] = constrain(errorAngleI[axis] + errorAngle, -10000, +10000); // WindUp
ITermACC = ((int32_t)errorAngleI[axis] * cfg.I8[PIDLEVEL]) >> 12;
}
if (!f.ANGLE_MODE || f.HORIZON_MODE || axis == 2) { // MODE relying on GYRO or YAW axis
error = (int32_t)rcCommand[axis] * 10 * 8 / cfg.P8[axis];
error -= gyroData[axis];
PTermGYRO = rcCommand[axis];
errorGyroI[axis] = constrain(errorGyroI[axis] + error, -16000, +16000); // WindUp
if (abs(gyroData[axis]) > 640)
errorGyroI[axis] = 0;
ITermGYRO = (errorGyroI[axis] / 125 * cfg.I8[axis]) >> 6;
}
if (f.HORIZON_MODE && axis < 2) {
PTerm = ((int32_t)PTermACC * (500 - prop) + (int32_t)PTermGYRO * prop) / 500;
ITerm = ((int32_t)ITermACC * (500 - prop) + (int32_t)ITermGYRO * prop) / 500;
} else {
if (f.ANGLE_MODE && axis < 2) {
PTerm = PTermACC;
ITerm = ITermACC;
} else {
PTerm = PTermGYRO;
ITerm = ITermGYRO;
}
}
PTerm -= (int32_t)gyroData[axis] * dynP8[axis] / 10 / 8; // 32 bits is needed for calculation
delta = gyroData[axis] - lastGyro[axis]; // 16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800
lastGyro[axis] = gyroData[axis];
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
DTerm = ((int32_t)deltaSum * dynD8[axis]) >> 5; // 32 bits is needed for calculation
axisPID[axis] = PTerm + ITerm - DTerm;
}
и хде тут время цикла? - короче я как всегда запутался 😃
Таймкоп по ходу готовит 5-ю ревизию платы - обзавёлся SPI и кварц уже на 12мГц (интересно что за проц) и не понятно из каких побуждений использует РС13, РС14 для прерываний датчиков? на 4-й ревизии у него было PB12, PB13 и ничего путного из этого не вышло…
догнал оно же само в петле 😃
впихнул новый ПИД на выходных проверю…
Там в сообщении старый
новый сдёрнул отсюда code.google.com/p/afrodevices/source/…/mw.c?r=363
и хде тут время цикла? - короче я как всегда запутался
В старом нет, а в новом явно присутствует
delta = (delta * ((uint16_t)0xFFFF / (cycleTime >> 4))) >> 6;
Старый в петле самой…
а в этом могу задать время цикла магическое 2048…
подождём вечера/ночи, может mahowik чего умного подскажет 😃
смущает, в отличии от стандартного wii дифференциальная составляющая с плюсом, наверно надо P занизить изначально, короче пропы есть надо экспериментировать 😃
вот этот кусок:
static void pidRewrite(void)
{
int32_t errorAngle = 0;
int axis;
int32_t delta, deltaSum;
static int32_t delta1[3], delta2[3];
int32_t PTerm, ITerm, DTerm;
static int32_t lastError[3] = { 0, 0, 0 };
int32_t AngleRateTmp, RateError;
// ----------PID controller----------
for (axis = 0; axis < 3; axis++) {
// -----Get the desired angle rate depending on flight mode
if ((f.ANGLE_MODE || f.HORIZON_MODE) && axis < 2 ) { // MODE relying on ACC
// calculate error and limit the angle to 50 degrees max inclination
errorAngle = constrain((rcCommand[axis] << 1) + GPS_angle[axis], -500, +500) - angle[axis] + cfg.angleTrim[axis]; // 16 bits is ok here
}
if (axis == 2) { // YAW is always gyro-controlled (MAG correction is applied to rcCommand)
AngleRateTmp = (((int32_t)(cfg.yawRate + 27) * rcCommand[2]) >> 5);
} else {
if (!f.ANGLE_MODE) { //control is GYRO based (ACRO and HORIZON - direct sticks control is applied to rate PID
AngleRateTmp = ((int32_t) (cfg.rollPitchRate + 27) * rcCommand[axis]) >> 4;
if (f.HORIZON_MODE) {
// mix up angle error to desired AngleRateTmp to add a little auto-level feel
AngleRateTmp += (errorAngle * cfg.I8[PIDLEVEL]) >> 8;
}
} else { // it's the ANGLE mode - control is angle based, so control loop is needed
AngleRateTmp = (errorAngle * cfg.P8[PIDLEVEL]) >> 4;
}
}
// --------low-level gyro-based PID. ----------
// Used in stand-alone mode for ACRO, controlled by higher level regulators in other modes
// -----calculate scaled error.AngleRates
// multiplication of rcCommand corresponds to changing the sticks scaling here
RateError = AngleRateTmp - gyroData[axis];
// -----calculate P component
PTerm = (RateError * cfg.P8[axis]) >> 7;
// -----calculate I component
// there should be no division before accumulating the error to integrator, because the precision would be reduced.
// Precision is critical, as I prevents from long-time drift. Thus, 32 bits integrator is used.
// Time correction (to avoid different I scaling for different builds based on average cycle time)
// is normalized to cycle time = 2048.
errorGyroI[axis] = errorGyroI[axis] + ((RateError * cycleTime) >> 11) * cfg.I8[axis];
// limit maximum integrator value to prevent WindUp - accumulating extreme values when system is saturated.
// I coefficient (I8) moved before integration to make limiting independent from PID settings
errorGyroI[axis] = constrain(errorGyroI[axis], (int32_t)-GYRO_I_MAX << 13, (int32_t)+GYRO_I_MAX << 13);
ITerm = errorGyroI[axis] >> 13;
//-----calculate D-term
delta = RateError - lastError[axis]; // 16 bits is ok here, the dif between 2 consecutive gyro reads is limited to 800
lastError[axis] = RateError;
// Correct difference by cycle time. Cycle time is jittery (can be different 2 times), so calculated difference
// would be scaled by different dt each time. Division by dT fixes that.
delta = (delta * ((uint16_t)0xFFFF / (cycleTime >> 4))) >> 6;
// add moving average here to reduce noise
deltaSum = delta1[axis] + delta2[axis] + delta;
delta2[axis] = delta1[axis];
delta1[axis] = delta;
DTerm = (deltaSum * cfg.D8[axis]) >> 8;
// -----calculate total PID output
axisPID[axis] = PTerm + ITerm + DTerm;
}
А мне тут пришел наконец HMC5983. Буду эксперементировать с вынесением датчика на шелдвоном проводе
Буду эксперементировать с вынесением датчика
Что хотите выяснить? Что не нравилось когда компас на плате?
Да в принцепе устраивает более мене, плывет немного при перегазовках. Просто хочу узнать на своем опыте какая разница.
Вообщем чисто академический интерес.
Так как mahowik отдыхает в бане, приходится общаться через личку, он мне объяснил про новый ПИД, ну и дабы не устраивать глухой телефон, разглашу тайную переписку:
вроде догнал, он не отвязан от времени цикла, а масштабируется по времени цикла - я правильно понял?
если ты про новую имплементацию, то да
в классическом пид регуле два параметра из трех зависимы от dt
I * dt - умножение т.к. интегрирование/сложение
D / dt - деление т.к. дифферинцированиевот по простому о непонятном написано 😉 pidcontrol.narod.ru
Я в принципе понял в чём камень преткновения, и почему сделано так, а не иначе.
Я представлял себе так: есть возмущение - которое нужно погасить D составляющей - завышающей пропорцию, потом пропорцией (от этого возмущения) вернуть в исходное положение - естественно сгладив/подтянув I составляющей, но такой метод не подходит, ибо надо практически предсказать какое возмущение будет в момент “запуска” D составляющей. По этой причине используется более простое представление, где пропорцией возвращаем в нужное положение, D составляющая служит как “тормоз” от переруливания самой P ну а интегральная составляющая дотягивает до нужного положения “медленно но верно” без переруливания. По сей причине и формула выглядит так P+I-D, вот и смутило что в новом ПИДе:// -----calculate total PID output axisPID[axis] = PTerm + ITerm + DTerm;
как если бы было как в примере который я привёл выше…
посмотрел код… короче и там и там знак минус 😉
просто в одном случае расчет D части ведется по угловой скорости гиры,
delta = imu.gyroData[axis] - lastGyro[axis];
а в другом из ошибки по гире, а она в инверте
RateError = AngleRateTmp - imu.gyroData[axis]; .... delta = RateError - lastError[axis];
т.е. и там и там D работает на торможение 😉
ПИД работает 😃 и по моим ощущениям лучше старого, нашел источник вибраций - чуть аппарат не потерял - правый задний движек разболтался - думаю как быстрее починить и долетать батарейку…
нет не долетаю сегодня - он одну обмотку покоцал 😦 да блин… слов нет…
нашел в загашнике старый статор - надеюсь завтра починю, а нет - значит соберу обратно трёху…
а да подключил напряжометр (АЦП+DMA) работает…
Кто знает секрет: в каких единицах нужно подавать данные в FreeImu c акселя и магнетометра ??
С гирой все ясно - град./сек. переводим в радианы делим на “сампл.” и т.д…
А вот с акселем и магом мне непонятно…, по логике вещей вообще без разницы какой размерности (ведь считается отношение) но в готовом коде от ARDU присутствует “магический” коэфициент для акселя:
gains[0] = 0.00376390;
gains[1] = 0.00376009;
gains[2] = 0.00349265;
Сейчас активно кручу коэфициенты TwoKi и TwoKp, наблюдаю реакцию системы, пытаюсь понять воздействие/зависимости, а тут что то в тупик зашел…
получается картинка непривлекательная
Может я не прав…, а сместить центр тяжести в любое нужное место (например батареей) не проще?
Так как mahowik отдыхает в бане, приходится общаться через личку, он мне объяснил про новый ПИД, ну и дабы не устраивать глухой телефон, разглашу тайную переписку:
Вот замедленно что там с PD происходит
Синий столбец это Р зеленый D. Столбцы направлены в ту сторону в которую от них результирующая сила. При действии возмущающей силы D P тянут в одну и туже стороны. При снятии силы в противоположные. Т.е. сначала D сопротивляется возмущению, а потом препятствует перегулированию(это самая важная его задача) от Р.
т.е. Во всех системах D направлен одинаково иначе от него вред один.
Может я не прав…, а сместить центр тяжести в любое нужное место (например батареей) не проще?
ну пока так и летаю - батарея сзади 😃
на счёт ПИД, то что вчера казалось плавным и красивым, сегодня в ветер сыграло со мной злую шутку - жуткий расколбас (с увеличением, как будто перегулирование) как следствие - переворот и минус два пропа, остался один комплект 😦 сейчас смотрю в чём бяка…