Создание собственной системы стабилизации
6DOF fusion, пока не интересует, иначе нафига такой (F407) проц
Это точно! С таким процессором всякая шелупонь, требующая специфичного кода, не должна интересовать. Я вам даже немного завидую =) Можно писать понятный код без костылей и хитровыдуманных оптимизаций (быстрое извлечение корня, таблицы значений синуса и логарифмов). Не париться насчет int vs float. Можно организовать ИМУ алгоритм в лоб. За этим будущее - очевидный си-образнный код, мгновенное портирование и доработка\отладка\тестирование, когда видишь “x *= 10;” вместо “x = (4*x +x)*2;”
хочу барометр подцепить по SPI (на данный момент I2C)
А зачем вам SPI барометр? Я как-то думал, что лучше: использовать децимацию и включить сглаживание в барометре ИЛИ отключить сглаживание в барометре, с максимальной частотой скачивать сырье и в процессоре уже обрабатывать…
Насчёт дерготни компаса, см. видео, система кординат мировая, синий “самолётик” -текущее положение ИНС, красный “самолётик” - заданное положение(через р\у), синий вектор (в левом окне) - проекция магнита на плоскость нормальную G, белый вектор - аксель приведенный к мировой СК, в правом окне магнит в бортовой СК (крутиться вместе с ней). Смотрите сами…
Решился я на авантюру, IMU будет отдельно, пока только схема основной платы вырисовалась, следующая будет IMU:
Сергей, зачем трех этажную плату городить? Насколько я понял это нужно под утюг? Может лучше сделать разводку под промышленные нормы?
Несколько вопросов/предложений по твоей плате:
- Если хочешь использовать АЦП VDDA подключай через LC-фильтр, землю и VDDA (если нужно) выводи на разъем под аналоговые входы для каждого входа и рядом с полем аналоговой земли а плате. Выводы VREF вести отдельными проводниками до полей VDDA и AGND рядом с разъёмом. Как пример, у меня оптодатчики на одной плате работают замечательно, а на другой (полётной) такая дерготня, что даже тяжелыми фильтрами не успокоишь… В последней все вышеперечисленные правила нарушены. Можно сделать больше аналоговых входов?
- Стандартный УСБ загрузчик будет работать? Ему вроде как один из выводов PD нужен вроде USB+5V, ну и выводы или кнопки BOOT.
- Ус-во экспериментальное - нужен JTAG.
- Резисторы на линиях ШИМ тоже не помешают.
Вроде всё. В остальном всё очень красиво: много входов/выходов, юсартов , СД.
Сергей, зачем трех этажную плату городить?
А чем плоха модульность? потом если что доделать переделать надо меньше времени, вот хороший пример PX4 контроллера тоже модульный принцип. Тут главное сразу заложить при разводке плат некое подобие интерфейсных разъемов.
Может лучше сделать разводку под промышленные нормы?
Я бы с удовольствием, но пока нет золотого запаса тратится ещё и на платы…
сли хочешь использовать АЦП VDDA подключай через LC-фильтр, землю и VDDA (если нужно) выводи на разъем под аналоговые входы для каждого входа и рядом с полем аналоговой земли а плате. Выводы VREF вести отдельными проводниками до полей VDDA и AGND рядом с разъёмом.
планирую вообще отдельный питатель( при данной разводке позволяет), так же и на ИМУ будет два
Стандартный УСБ загрузчик будет работать? Ему вроде как один из выводов PD нужен вроде USB+5V, ну и выводы или кнопки BOOT.
PD4, на BOOT0 перемычка есть
Резисторы на линиях ШИМ тоже не помешают.
на входе есть, выходы только на моторы поместятся, а вот на “серво” могут и не влезть, постараюсь повесить…
а да, трёхэтажная - ИМУ и GPS можно менять без замены всего, думаю проц на долго останется и ИМУ ближе к ЦТ аппарата…
с АЦП ещё покумекаю, но лапы остальные далеко, пока 3-х думаю хватит, если нет, то подпаяюсь куда-нибудь …
а да, трёхэтажная - ИМУ и GPS можно менять без замены всего, думаю проц на долго останется и ИМУ ближе к ЦТ аппарата…
причина понятна.
Ещё один момент, почему на SPI выделил только один CS? Если стремишся к универсальности, то возможно будешь ставить датчики с несколькими ус-вами SPI.
В принципе да, можно ещё по две лапы задействовать на одном и на втором:)
Вобщем, дабы не плодить ненужных файлов, отпишусь на словах:
Сонар переехал на PE7 - эхо, PE8 - триггер, тем самым отжал ИМУ 4 резервных вывода(PE0,PE1,PC4, PC5), 2 из которых могут также быть и входами АЦП и входами прерываний PC4, PC5…
также добавил к выносному SPI два резервных вывода PB10, PB11, которые также могут быть второй шиной I2C…
Ну и добавил питатель на аналоговую часть, а также отделил дросселями аналоговую землю и аналоговые 5В от остального…
Вроде всё, а ещё, у F4 нет VREF- вмесо неё просто аналоговая земля, а то что у F1XX было VSSA у 4-го VDD ! чуть не напоролся 😃
Буду разводить, проц и большинство деталей будут со стороны пайки (внизу), чтобы с разъёмами проблем не было и ИМУ ниже ляжет…
Приветствую Вас, единомышленники.
прочитал вашу ветку на форуме и сделал вывод что можете мне помочь советом (или подсказкой).
Также как и вы хочу написать собственный софт для квадрокоптера.
Изучил в инете темы по алгоритмам и принципам стабилизации, решил для начала просто повторить рабочий мультивийный алгоритм, но тут столкнулся с проблемой.
Проблема в том что программирую в CVavr на Си, попытки разобраться с листингом проекта мультивии не увенчались успехом (уж очень он универсальный и “оброс” доп. функциями).
Понял только, что в нем допускаются некоторые упрощения в отличии от базовой теории.
Хочу всего лишь понять основной математический прием для гироскопа и акселерометра.
Постановка вопроса:
имеем последовательно считанные в основном цикле программы данные с гиры и акса (магнетометр о др. не интересует)
типа INT, назовем их условно Gx,Gy,Gz,Ax,Ay,Az.
Можете просто подставить их в формулу чтобы получить текущую переменную воздействия для скармливания ПИДу?
Или хотя бы объяснить мне бестолковому последовательность работы с этими величинами для получения результата стабилизации. Понятно что еще есть данные со стиков пульта, но допустим, чтоб не усложнять ответ примем их за ноль.
Надеюсь не утомил Вас длинным изложением, подскажите хоть что то, кто может…
ну если смотреть комплиментарный фильтр то
уголX = (0.8*(уголX+(угловая_скорость_с_гиры*dt)))+(0.2*(угол_X_с_акселя));
где уголX+угловая_скорость_с_гиры*dt интегрирование угловой скорости по времени - угол из показаний гироскопа, угол_X_с_акселя - угол, высчитанный из показаний акселя, ну это если по простому…
А вот тоже пытаюсь прикрутить AHRS 9DOF но что то туговато все идет. Датчики HMC5883L и MPU6050. Может кто то поделится исходниками или поможет консультацией?
на прошлой странице rcopen.com/forum/f134/topic224458/845, а также MultiWii, и ещё куча примеров…
Надеюсь не утомил Вас длинным изложением, подскажите хоть что то, кто может…
готовых рецептов никто не даст, точнее эти “рецепты” Вас не устроили (я про исходники МВ). А SergDoc чётко обрисовал основную формулу
, правда я её немного дополню:
уголX += 0.8*угловая_скорость_с_гиры*dt;
уголX -= 0.2*(уголX -угол_X_с_акселя);
Так как последний член есть поправка интеграла по абсолютному датчику (в том смысле что гиро датчик относительной величины).
И ещё момент, если Вам это нужно чтобы получить приемлемый результат и забросить, то пойдёт и АВР; если же есть желание двигаться дальше в части развития функционала и качества системы, то советую смотреть в сторону 32х разрядных процов.
Тааак, спасибо, поправьте если не так понял:
Угол_Х слева равенства это искомое значение (отклонение ЛА)
Угол_Х внутри скобок это предыдущее значение гиры за время цикла опроса dT?
dT в условных единицах ? (видимо мСек., или как оно вообще там реализовано)
0.8 и 0.2 - что это?
и с акселя данные уже как то обсчитанные или “голые”?
Александр, а можете сформулировать перспективность 32-х разрядов для данной задачи или если хотите тупиковось AVR?
Очень интересно понять, глобально эту проблему…
dt это дельта t - отрезок времени между измерениями вообще в системе СИ в секундах меряется…
0.8, 0.2 - коэффициенты фильтра (легко найти - комплиментарный или альфа-бета фильтр)
угол считается из проекций вектора ускорения свободного падения на оси акселерометра…
То есть все данные в формуле приводятся в системе Си: град/сек, градусы, и секунды соответственно.
dT как то придется считать аппаратно или программно между двумя обращениями к гироскопу…
понятно, буду пробовать…
С шумами датчиков МультиВии видимо не борятся ни как, чем точнее датчик тем лучше?
Не ну можно считать и в попугаях, только гироскопы выдают угловую скорость в град/сек, тогда и эти величины придётся переводить в град/попугай 😃
Понял, понял 😃, просто мучаю гиры Murata(аналоговые), поэтому и сомневался
С муратовскими гирами не всё так просто, у них 0.67мВ/град/сек и 0 у них 1.35В, 10-ти битного АЦП маловато, по сей причине надо для начала на Aref АВРки подать 1.65В (не забыв analogReference(EXTERNAL); сделать) - это максимум что могут выдать гиры, тоесть 1.65В будет равно 1024 для АЦП и тогда уже пытатся считывать с них какую-то информацию 😃
Я использую следующий алгоритм:
void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az) {
float recipNorm;
float halfvx, halfvy, halfvz;
float halfex, halfey, halfez;
float qa, qb, qc;
// Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation)
if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) {
// Normalise accelerometer measurement
recipNorm = invSqrt(ax * ax + ay * ay + az * az);
ax *= recipNorm;
ay *= recipNorm;
az *= recipNorm;
// Estimated direction of gravity and vector perpendicular to magnetic flux
halfvx = q1 * q3 - q0 * q2;
halfvy = q0 * q1 + q2 * q3;
halfvz = q0 * q0 - 0.5f + q3 * q3;
// Error is sum of cross product between estimated and measured direction of gravity
halfex = (ay * halfvz - az * halfvy);
halfey = (az * halfvx - ax * halfvz);
halfez = (ax * halfvy - ay * halfvx);
// Compute and apply integral feedback if enabled
if(twoKi > 0.0f) {
integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki
integralFBy += twoKi * halfey * (1.0f / sampleFreq);
integralFBz += twoKi * halfez * (1.0f / sampleFreq);
gx += integralFBx; // apply integral feedback
gy += integralFBy;
gz += integralFBz;
}
else {
integralFBx = 0.0f; // prevent integral windup
integralFBy = 0.0f;
integralFBz = 0.0f;
}
// Apply proportional feedback
gx += twoKp * halfex;
gy += twoKp * halfey;
gz += twoKp * halfez;
}
// Integrate rate of change of quaternion
gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors
gy *= (0.5f * (1.0f / sampleFreq));
gz *= (0.5f * (1.0f / sampleFreq));
qa = q0;
qb = q1;
qc = q2;
q0 += (-qb * gx - qc * gy - q3 * gz);
q1 += (qa * gx + qc * gz - q3 * gy);
q2 += (qa * gy - qb * gz + q3 * gx);
q3 += (qa * gz + qb * gy - qc * gx);
// Normalise quaternion
recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3);
q0 *= recipNorm;
q1 *= recipNorm;
q2 *= recipNorm;
q3 *= recipNorm;
q[0] = q0;
q[1] = q1;
q[2] = q2;
q[3] = q3;
}
Углы с кватерионов получаю так:
void getEuler(void) {
angles[0] = atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1) * 180/M_PI; // psi
angles[1] = -asin(2 * q[1] * q[3] + 2 * q[0] * q[2]) * 180/M_PI; // theta
angles[2] = atan2(2 * q[2] * q[3] - 2 * q[0] * q[1], 2 * q[0] * q[0] + 2 * q[3] * q[3] - 1) * 180/M_PI; // phi
}
Но значения углов скачут от фанаря. Что я не так делаю?