Optical Flow + MultiWii

mahowik

Посмотрел код на днях. Аксель наше все! 😃

  1. В основном все понятно, но есть очевидный скользкий момент в расчете горизонтальной скорости в CF. К примеру если накопилась ошибка интегрирования + качество поверхности для OF сенсора низкое (освещение, либо отсутствие деталей), то непонятно как и по чем будет корректироваться скорость. В итоге коптер понесет в не известном направлении…
// Apply ACC-OF complementary filter
         vel[axis] = ((vel[axis] + EstHAcc[axis]*accVelScale*dTime)*OF_ACC_FACTOR + vel_of[axis])/(1+OF_ACC_FACTOR);
  1. Проверил много раз. Походу нашел ошибочку. vel_of получился в метрах в секунду, а не см/сек.
// remove shift in position due to inclination: delta_angle * PI / 180 * 100
            // mm/sec(10m) * cm / us   ->    cm / sec
            vel_of[axis] = ((int32_t)(optflow_pos[axis] + (angle[axis] - prevAngle[axis]) * 17 )) * alt / dTime; 

/* displacment (in mm*10 on height 1m) */
данные с сенсора в мм*10 => нужно в см => (мм*10)/100
alt в см => нужно в метрах => alt/100
dTime в микросек. => нужно в сек. => dTime/1000000

в итоге числитель должен быть в 100 раз больше если результат в см/сек., т.е.

vel_of[axis] = ((int32_t)(optflow_pos[axis] + (angle[axis] - prevAngle[axis]) * 17 )) * alt * 100 / dTime ; 

Либо если перекинуть эту сотню в CF, то OF_ACC_FACTOR был 1000! Т.е. если я не ошибся, то алгоритм на видео считай летал на одном акселе 😃 и видимо он был очень хорошо откалиброван у тебя по всем осям… И зачем нам OF?! 😃

  1. И кстати почему мы верим больше акселю чем OF сенсору (OF_ACC_FACTOR = 10)? Даже если качество картинки/потока хорошее (optflow_squal), все равно большая погрешность с OF сенсора? Т.е. по идее можно подстраивать коэф. CF в соот-ии с optflow_squal если данные довольно точные…

  2. Почему высота более 2-х метров режется? Ведь это считай коэф. для расчета пробега по OF сенсору.

alt = constrain((uint16_t)EstAlt, 30, 200) * 100; 
mahowik

по второму пункту: увидел наконец свой косяк 😃
высота в мм*10, а привык что везде в ИМУ и в конечном ПИД она в см…

alt = constrain((uint16_t)EstAlt, 30, 200) * 100;
  1. Есть идея: Когда стики в нуле и коптер притормозил (т.е. когда скорость меньше заданного N), считать пройденную дистанцию/смещение по х,у и использовать его в ПИД регуле для возврата в точку удержания (х=0, у=0). Т.е. ввести доп. стабилизацию по смещению (когда коптер почти в покое), а не только по скорости…
    Тогда по идее фиксация в точке будет более точной. Тут уже основную роль сыграет OF сенсор (качество поверхности, освещение, контрастность текстуры поверхности и т.д.).
alexmos
mahowik:

К примеру если накопилась ошибка интегрирования + качество поверхности для OF сенсора низкое (освещение, либо отсутствие деталей), то непонятно как и по чем будет корректироваться скорость. В итоге коптер понесет в не известном направлении…

Если качество поверхности низкое, то скорость по сенсору зануляется и вычисленная по ускорению скорость уводится в ноль. Если нет движения, то аксель в любом случае 0 покажет, т.к. это примитивно разница с гирой, а гира под него подстроится (вспомни свою последнюю идею с altHold). Когда ошибка интегрирования перестанет возрастать, скорость быстро уводится в 0 комплементарным фильтром.

mahowik:

Проверил много раз. Походу нашел ошибочку. vel_of получился в метрах в секунду, а не см/сек

Я размерности кидаю туда-сюда, чтобы остаться в рамках int16_t по возможности, поэтому все запутано. Но я проверял по ГУИ, выводя проинтегрированную скорость с акселя и с сенсора - они совпадают примернр, так что ошибки в 10 раз быть не может 😃

И вообще, то что меряет сенсор после нормализации, и то что меряет аксель, может сильно не совпадать (например из-за неотрегулированного коэффициента для учета FOV линзы). Мне кажется это все не страшно, т.к. есть комплементарный фильтр.

mahowik:

И кстати почему мы верим больше акселю чем OF сенсору (OF_ACC_FACTOR = 10)? Даже если качество картинки/потока хорошее (optflow_squal), все равно большая погрешность с OF сенсора? Т.е. по идее можно подстраивать коэф. CF в соот-ии с optflow_squal если данные довольно точные…

Согласен, тут тоже можно учесть качество поверхности. Я тестировал в плохом освещении, и тогда сенсор выдает пилу вместо ровнй линии. А с акселем *10 более-менее ровно получается. Ещё не забывай, что аксель интегрируется, и после этого шумит очень мало, так что он хорошо сглаживает шум OF-сенсора.
Но все равно, даже с последующим фильтром НЧ, коптер слегка подергивает.

mahowik:
  1. Почему высота более 2-х метров режется? Ведь это считай коэф. для расчета пробега по OF сенсору.

Чем больше высота, тем меньше доверия сенсору и надо ослаблять его влияние. Так как выход алгоритма прямо пропорционален высоте - можно в этом месте обрезать. (Мы же выдаем скорость, а не абсолютное перемещение). Т.е. скорость выше двух метров начнет снижаться - а вместе с ней и регулирование.

Я уже поменял эту часть немного - высоту увеличил до 3-х метров и умножил на качество поверхности вместо 100, чтобы сила регулирования зависела от качества.

Но тут остается проблема - акселерометр по прежнему считает скорость без учета обрезания высоты. Эту часть надо потестить. Можно оставить так или также делить на коэффициент. Пока так оставил, надо полетать побольше.

mahowik:
  1. Есть идея: Когда стики в нуле и коптер притормозил (т.е. когда скорость меньше заданного N), считать пройденную дистанцию/смещение по х,у и использовать его в ПИД регуле для возврата в точку удержания (х=0, у=0). Т.е. ввести доп. стабилизацию по смещению (когда коптер почти в покое), а не только по скорости…
    Тогда по идее фиксация в точке будет более точной. Тут уже основную роль сыграет OF сенсор (качество поверхности, освещение, контрастность текстуры поверхности и т.д.).

Примерно это и получается в PID-регуляторе. Именно иcходя из того, что у нас будет I-составляющая, я выбрал в качестве стабилизируемой величины скорость. В моих тестах четко видно - когда бросили стики в движении - коптер начинает тормозить (P-часть) и пролетает пару метров. В этот момент идет интегрирование I-части. После полной остановки, начинает рабоать I-часть и коптер возвращается туда, где бросили стики. Нужно просто правилно подобрать P и I.

При полной неподвижности, считать отдельно смещение нет смысла. Оно будет плыть из-за ошибок. В общем, в текщей версии I-часть как раз то и делает и вроде работает как надо - в конце концов гасит любые попытки куда-то уплыть.

Но если поверхность плохая, то уплывать будет в любом случае, при любых алгоритмах.

mahowik
alexmos:

Если качество поверхности низкое, то скорость по сенсору зануляется и вычисленная по ускорению скорость уводится в ноль. Если нет движения, то аксель в любом случае 0 покажет, т.к. это примитивно разница с гирой, а гира под него подстроится (вспомни свою последнюю идею с altHold). Когда ошибка интегрирования перестанет возрастать, скорость быстро уводится в 0 комплементарным фильтром.

Блин, точно! дампенинг скорости будет vel[axis]/OF_ACC_FACTOR в каждой итерации…
Прикольно! Используя этот эффект (дампенинг в компл. фильтре), без ОФ сенсора (т.е. на одном акселе), можно добиться практически полного торможения коптера при отпускании стиков. Идеально в точку не станет (и будет плыть болше чем без ОФ) ну и ветер держать не будет (т.к. I также будет душиться при дампенинге), но томожение близкое к нулю даст… Только фактор фильтра поднять надо будет для более мягкой корректировки в ноль…
A возможно для эффективного торможения достаточно будет лишь горизонтального ускорения в ПИД регуле… профит огромный, a математики зеро 😃

alexmos:

Но все равно, даже с последующим фильтром НЧ, коптер слегка подергивает.

коптер может подергивать из-за провалов во времени цикла, когда на некоторые из итераций ложится много математики (был опыт такой). В ГУИ по цифрам ты этого можешь и не заметить, но если вывести на чарт в ГУИ то будет видно…

alexmos:

Чем больше высота, тем меньше доверия сенсору и надо ослаблять его влияние. Так как выход алгоритма прямо пропорционален высоте - можно в этом месте обрезать. (Мы же выдаем скорость, а не абсолютное перемещение). Т.е. скорость выше двух метров начнет снижаться - а вместе с ней и регулирование. Я уже поменял эту часть немного - высоту увеличил до 3-х метров и умножил на качество поверхности вместо 100, чтобы сила регулирования зависела от качества. Но тут остается проблема - акселерометр по прежнему считает скорость без учета обрезания высоты. Эту часть надо потестить. Можно оставить так или также делить на коэффициент. Пока так оставил, надо полетать побольше.

Если глубина резкости 30см=>бесконечность, то с увеличением высоты, проблему вижу только в малом количестве деталей поверхности, что отразится в уменьшении оптического потока (или кволити потока?)…
Т.е. более правильно мне кажется регулировать коэф. компл. фильтра, опираясь на кволити данных ОФ сенсора (и высоту, если кволити не отражает реалной картины). Тогда и (“акселерометр по прежнему считает скорость без учета обрезания высоты”) проблемы не будет + получим линейную зависимость влияния “чИстоты” данных ОФ сенсора на результат выхода компл. фильтра, а не просто “обрубание” после определенной высоты.

alexmos:

Примерно это и получается в PID-регуляторе. Именно иcходя из того, что у нас будет I-составляющая, я выбрал в качестве стабилизируемой величины скорость. В моих тестах четко видно - когда бросили стики в движении - коптер начинает тормозить (P-часть) и пролетает пару метров. В этот момент идет интегрирование I-части. После полной остановки, начинает рабоать I-часть и коптер возвращается туда, где бросили стики. Нужно просто правилно подобрать P и I.

Согласен. После интегрирования скорости в ПИД регуле (I-часть), получаем как бы усредненную скорость, что равносильно пройденному растоянию (в безразмерной величине), НО т.к. тут не учитывается время цикла (а оно не постоянно из за нарастающего изобилия математики 😃 ), то будет накапливаться дополнительная ошибка, что наверное не критично всеже, но будет отдалять от точки где кинули стики…

alexmos
mahowik:

то будет накапливаться дополнительная ошибка, что наверное не критично всеже, но будет отдалять от точки где кинули стики

Тут главное чтобы зависло, хоть где ниудь 😃 У нас только относителные данные (относительное перемещение) поэтому о точной позиционировании в какой-то точке можно и не мечтать.

alexmos

Попробовал включить зависимость от качества поверхности - чет совсем плохо стало, колбасит теперь в три раза сильнее. Думаю, потому что показатель качества очень сильно скачет, его надо сильно сглаживать. В общем пока все улучшения работают хуже, чем первая версия.

А ещё сегодня случился неприятный краш - коптер был в паре метрах от земли и в 5 метрах от меня, вдруг его начало закручивать по YAW и пошел резкий набор высоты. На 6-ти метрах сбросил газ в ноль, его крутануло, и об асфальт. Из потерь луч (ну это я из дерева за 5 минут вырезал), и пластиковый контейнер. А это хуже, т.к. его крышка была несущей для всей электроники. Буду придумывать новую защиту, контейнеры в топку. Он то спас мозги, но вот переделывать весь монтаж при каждом краше никакого желания.

Dimm168pin
alexmos:

Попробовал включить зависимость от качества поверхности - чет совсем плохо стало, колбасит теперь в три раза сильнее. Думаю, потому что показатель качества очень сильно скачет, его надо сильно сглаживать. В общем пока все улучшения работают хуже, чем первая версия.

А ещё сегодня случился неприятный краш - коптер был в паре метрах от земли и в 5 метрах от меня, вдруг его начало закручивать по YAW и пошел резкий набор высоты. На 6-ти метрах сбросил газ в ноль, его крутануло, и об асфальт. Из потерь луч (ну это я из дерева за 5 минут вырезал), и пластиковый контейнер. А это хуже, т.к. его крышка была несущей для всей электроники. Буду придумывать новую защиту, контейнеры в топку. Он то спас мозги, но вот переделывать весь монтаж при каждом краше никакого желания.

в пенопласт? я на вертикальной сверлилке гопру запаковал, 30мм толщина, в ней на глубину 15мм выфрезеровал по контуру в размер, пробурил дырку для объектива и , с 100 метров упало об железяки, хоть бы что) рама в узлы (люминиь 12x10)

З.Ы полистирол всмысле, серый такой, не ломается на шарики, а просто сменается, сильно жестче обычного белого.
соберу вия наверно тоже под платки сделаю такой “черный ящик”

alexmos
Dimm168pin:

в пенопласт? я на вертикальной сверлилке гопру запаковал, 30мм толщина, в ней на глубину 15мм выфрезеровал по контуру в размер, пробурил дырку для объектива и , с 100 метров упало об железяки, хоть бы что) рама в узлы (люминиь 12x10)

З.Ы полистирол всмысле, серый такой, не ломается на шарики, а просто сменается, сильно жестче обычного белого.
соберу вия наверно тоже под платки сделаю такой “черный ящик”

Я долго вертел в руках выжившую крышку от контейнера и так не смог придумать как её притулить и закрепить на раму 😃 Полистирол это хорошо, но его надо где то найти, потом как-то обточить и высверлить нужное углуление. В общем не на один день занятие. Зато можно красивую мордашку выточить и раскрасить.

У меня есть пачка потолочной плитки, что если из нее склеить? Криво косо конечно получится но клеить проще чем фрезеровать.

Dimm168pin
alexmos:

Я долго вертел в руках выжившую крышку от контейнера и так не смог придумать как её притулить и закрепить на раму 😃 Полистирол это хорошо, но его надо где то найти, потом как-то обточить и высверлить нужное углуление. В общем не на один день занятие. Зато можно красивую мордашку выточить и раскрасить.

У меня есть пачка потолочной плитки, что если из нее склеить? Криво косо конечно получится но клеить проще чем фрезеровать.

вырезал под гопру минут за 10 две половинки) если нет вертикальной сверлилки, можно гравер или дрель как-то вертикально закрепить и все, эффект тот же) скрепил две половинки на гопре канц резинкой, из потолочки можно но она менее плотная, хотя при краше мозги точно должны выжить, а продается полистирол на всех строй рынках и магазинах, я далеко не в столице, но наличествует он на каждом углу практически.

alexmos

Спасибо, сегодня был проездом в строймаге, пощупал этот полистирол и купил лист (60мм толщиой) Он отлично режется канцелярским ножом, так что думаю без сверлений вырежу (в квартире особо не пофрезеруешь 😃 )

mahowik

Пришла посылка с ca.digikey.com
Быстрые ребятки однако! 3-4 дня и парочка ADNS-5050 уже ждут опытов 😃 Доставка правда вышла чутка дороже (8$) чем 3 сенсора, но в принципе учитывая скорость доставки очень даже рад 😃
Правда через пару дней еду в отпуск, так что мот и не успею покрутить…

alexmos

Хороший магазинчик, не знал про него 😃 А линзу какую поставишь?
Я так и не смог прдумал как прикрутить глазок от камеры. Не покупать же камеру ради линзы и держателя с резьбой 😃

Надеюсь завтра потестить прошивку, в которой поисправлял много чего (последние мои ревизии лучше не тестить, больно криво летает с optical flow)

mahowik

Ну это скорее мега монстр, крупнейший диллер по продаже радиодеталей, с кучей филиалов по всему миру www.digikey.com/us/en/International/global.html ток доставка в Рашу дорого наверное
встанет…
Не поверишь, я уже хожу вокруг камерки своей с соблазном выдрать из нее глаз 😄. Либо лазерную указку копеечную прикупить и ее разобрать. Далее посадить линзу на 3-4 винтика по периметру, чтобы фокус хоть как накрутить можно было…

Dimm168pin
mahowik:

Пришла посылка с ca.digikey.com
Быстрые ребятки однако! 3-4 дня и парочка ADNS-5050 уже ждут опытов 😃 Доставка правда вышла чутка дороже (8$) чем 3 сенсора, но в принципе учитывая скорость доставки очень даже рад 😃
Правда через пару дней еду в отпуск, так что мот и не успею покрутить…

ага , пытался однажды там купить bma180 ) доставка до украины 120$ ))

mahowik

Нехило… по Канаде вроде как если заказ более чем 200$, доставка бесплатно…

gena_g
Dimm168pin:

ага , пытался однажды там купить bma180 ) доставка до украины 120$ ))

Здесь появились такие датчики

Dimm168pin
gena_g:

Здесь появились такие датчики

да уж, 14 баксов это весело, он везде по 5 ), для разнообразия возьму наверно напопробовать lsm330 там же)
оффтоп ) там еще появились вот такие блу тач модули

😂

alexmos

Если ADNS-5050 по России доставлять - то в Элитане он есть недорого и доставка вменяеая… только долго доставляют

mahowik

забыл написать… ранее когда код смотрел, заметил что vel[axis] не обнуляется… не знаю это баг или фича ))
по идее когда стики в деадбенде и getEstHVel() интегратор начинает новый цикл возврата в точку, то надо занулить vel[axis], т.к. если небыло остановки коптера и к примеру начали новый маневр, то vel[axis] будет равен остаточной скорости от пред. цикла…

и отсюда второй не совсем ясный момент: т.к. getEstHVel() интегратор начинает новый цикл возврата когда стики в деадбенде, то скорость через ускорение (в начале цикла возврата) будет равна нулю, хотя она не ноль совсем… т.е. тут мы опираемся на скорость ОФ сенсора и через компл. фильр приходим к правильному значению?

alexmos:

А ещё сегодня случился неприятный краш - коптер был в паре метрах от земли и в 5 метрах от меня, вдруг его начало закручивать по YAW и пошел резкий набор высоты.

ты вроде как заимплементил корректировку на ветер (т.е. I-чаcть) через вращение векторов, мот там косяк какой…

alexmos
mahowik:

забыл написать… ранее когда код смотрел, заметил что vel[axis] не обнуляется… не знаю это баг или фича ))
по идее когда стики в деадбенде и getEstHVel() интегратор начинает новый цикл возврата в точку, то надо занулить vel[axis], т.к. если небыло остановки коптера и к примеру начали новый маневр, то vel[axis] будет равен остаточной скорости от пред. цикла…

и отсюда второй не совсем ясный момент: т.к. getEstHVel() интегратор начинает новый цикл возврата когда стики в деадбенде, то скорость через ускорение (в начале цикла возврата) будет равна нулю, хотя она не ноль совсем… т.е. тут мы опираемся на скорость ОФ сенсора и через компл. фильр приходим к правильному значению?

Я вообще удивлен что алгоритм заработал сразу - там ошибка на ошибке. Я сейчас много чего переделеал. И попробовал вообще без ускорения и интегратора - работает практически так же, т.е. на комнатных тестах разницы не видно. Поэтому отключил ускорение вообще, и заменил его на LPF.
Но тут ты прав - когда режим не задействован, вычисления не идут, и в LPF тоже висит накопленная перед выходом из режима скорость. Но это мне кажется не критично - примерно секунда нужна, чтобы скорость приняла текущие значения при включении режима. Я бы сделал сброс этой переменной, но это усложнит код - так как выход и вход в режим определяется в MultiWii.pde, а вычисления в IMU.pde.

По второму вопросу - если убрать ускорение, то эта проблема тоже решается. Вообще все эти переходные процессы при входе в режим длятся мало и это не столь критично при больших скоростях - там все равно разброс результатов корреции до десятка метров. А вот при подруливании на месте могут вылезать эти пороговые эффекты. Ну это будет видно на тестах. В комнате я на площади в 2 метра им подруливал в том режиме - контроль достаточно хороший.

alexmos

Оказывается, Flymentor использует примитивный оптический сенсор от мышки, с большой долей вероятности это ADNS-2610. rcopen.com/files/4c32fe669970730077ccdbec

Так что его можно подключить к моему алгоритму, нужно немного дописать чтение/запись и работу с регистрами. Если у кого есть такая железка и есть желание попробовать, напишите.

Судя по картинке - выводы такие:

Yellow - SCK
White - SDIO
Red - +5V
Black - Ground