Телеметрия (часть 1)

serj
Dikoy:

Вот некоторые фотки. Коллекция ломаных винтов и срезаные после аварии с обратной строны штырьки на плате.

А “положительные” результаты можно выложить в виде фоток или в каком-нибудь еще виде?

А то у народа может сложиться впечатление что результаты " любительского автопилотостроения" в основном такие (неудачные) бывают 😃

smalltim

Сегодня “наполовину освоил” USB. Написал приложение, съел атмеговскую HID-dllку, сделал автоматическое определение наличия подключения к автопилотной плате по USB, реализовал мигание светодиодиком на платке по нажатию кнопки в приложении.
Пока всё оказалось просто, как мозг поросенка, но документация у Атмела - просто чудовищная. Времени из-за этого ушло очень много. Такое ощущение, что свой код перед публикацией они даже не перечитывают.
Теперь - изучить, как из своего приложения залить в атмегу взятую из файла прошивку, и дальше в бой 😃

smalltim

Разобрался, как из своей программы на PC заливать в свою плату свою прошивку через USB, без плясок с нажатием специальных кнопок на плате для старта бутлоадера. У FLIP в комплекте есть dllka, которую он сам и использует. Атмел предоставляет заголовочный файл, можно съесть эту dllку и не париться. Непонятно только, как fuse биты c помощью FLIP или dllки менять. Коллеги, что посоветуете?

Ну и, собственно, реализация USB на самой AT90USB1287. Это, коллеги, просто финиш. Вынос мозга. Этот встроенный USB умеет всё и еще немножко. Но мне-то всё - не надо! Можно, конечно, тупо вкрячить код из атмеловского примера и обо всём забыть, но чтобы самому по-хорошему разобраться, как эти эндпойнты, пайпы и прочая дрянь конфигурируется, надо много усилий. Третий день сижу, просветляюсь над доками. Есть какие-то искры, но полное просветление пока не пришло. Там три четверти кода просто не нужно - мне не надо все эти непотребства, мне надо простой HID интерфейс.

Зато скачал и поставил WinAVR, он как-то сам снюхался с AVR Studio, теперь могу писать в AVR Studio прямо на C, билдить проект одной кнопкой, и не париться с коммандлайн-интерфейсом, make файлами и прочими отрыжками богомерзкого линукса. Причем, всё это полнофункциональное и бесплатное, никаких кряков и прочей гадости.

Dikoy
smalltim:

Разобрался, как из своей программы на PC заливать в свою плату свою прошивку через USB, без плясок с нажатием специальных кнопок на плате для старта бутлоадера. У FLIP в комплекте есть dllka, которую он сам и использует. Атмел предоставляет заголовочный файл, можно съесть эту dllку и не париться. Непонятно только, как fuse биты c помощью FLIP или dllки менять. Коллеги, что посоветуете?

Ну и, собственно, реализация USB на самой AT90USB1287. Это, коллеги, просто финиш. Вынос мозга. Этот встроенный USB умеет всё и еще немножко. Но мне-то всё - не надо! Можно, конечно, тупо вкрячить код из атмеловского примера и обо всём забыть, но чтобы самому по-хорошему разобраться, как эти эндпойнты, пайпы и прочая дрянь конфигурируется, надо много усилий. Третий день сижу, просветляюсь над доками. Есть какие-то искры, но полное просветление пока не пришло. Там три четверти кода просто не нужно - мне не надо все эти непотребства, мне надо простой HID интерфейс.

Зато скачал и поставил WinAVR, он как-то сам снюхался с AVR Studio, теперь могу писать в AVR Studio прямо на C, билдить проект одной кнопкой, и не париться с коммандлайн-интерфейсом, make файлами и прочими отрыжками богомерзкого линукса. Причем, всё это полнофункциональное и бесплатное, никаких кряков и прочей гадости.

Насчёт фьюзов через флип - не знаю, не пробовал. Предполагаю, в хексфайл вносятся коды для флеша, еепрома и фьюзов. Т.к. адресные смещения памяти известны и расписаны в ДШ, бутлодер сам должен понимать, что сейчас он пишет.
По крайней мере мой программатор принимает именно такие, полные хексы.

Чтобы упростить код, мозно взять м646 или 1286. У них USB не поддерживает режим хост.
Код у атмела сравнительно компактный - 3 кб для м128 незаметно. Плюс там есть много директив условной компиляции - можно поотключать ненужные блоки. Насколько помню, втом примере так и сделано - просто не заданы хидеры для режима хост и т.п. Вот только они толком нигде не описаны 😦
А исходный код у всех примеров атмела одинаков - откройте хоть эмулятор мышки, хоть флешки. Те же файлы, тот же костяк, только хидеры другие.

serj:

А “положительные” результаты можно выложить в виде фоток или в каком-нибудь еще виде?
А то у народа может сложиться впечатление что результаты " любительского автопилотостроения" в основном такие (неудачные) бывают 😃

А что интересного в положительном результате? 😃 Взлетел, покружился, сел. А тут вон какая веселуха.
А результаты поначалу такие и будут. Как ни крути…

belkinnn

День добрый, мужики подскажите пожалуйста почему при расчете расстояния и азимута между двумя координатами один и тот же код на компе работает а в контроллере выдает всякую хрень причем через раз.

fdLambda = (StartLon - EndLon) * D2R;
fdPhi = (StartLat - EndLat) * D2R;
fPhimean = ((StartLat + EndLat) / 2.0) * D2R;
fTemp = 1 - e2 * (sin(fPhimean)*sin(fPhimean));
fRho = (a * (1 - e2)) / pow(fTemp, 1.5);
fNu = a / (sqrt(1 - e2 * (sin(fPhimean) * sin(fPhimean))));
fz = sqrt((sin(fdPhi / 2.0)*sin(fdPhi / 2.0)) + cos(EndLat * D2R) * cos(StartLat * D2R) * pow(sin(fdLambda / 2.0),2));
fz = 2 * asin(fz);

fAlpha = cos(EndLat * D2R) * sin(fdLambda) * 1 / sin(fz);
fAlpha = asin(fAlpha);

fR = (fRho * fNu) / ((fRho * pow(sin(fAlpha), 2)) + (fNu *pow(cos(fAlpha), 2)));
Distans = (fz * fR);

if ((StartLat < EndLat) && (StartLon < EndLon)) Bearing = abs(fAlpha * R2D);else
if ((StartLat < EndLat) && (StartLon > EndLon)) Bearing = 360 - abs(fAlpha * R2D);else
if ((StartLat > EndLat) && (StartLon > EndLon)) Bearing = 180 + abs(fAlpha * R2D);else
if ((StartLat > EndLat) && (StartLon < EndLon)) Bearing = 180 - abs(fAlpha * R2D);

smalltim
belkinnn:

День добрый, мужики подскажите пожалуйста почему при расчете расстояния и азимута между двумя координатами один и тот же код на компе работает а в контроллере выдает всякую хрень причем через раз.

А на конторллере, случаем, не 16-битные флоты? С такой математикой могут переполниться влегкую.
И вообще, такая сложная математика точно нужна? Если летать недалеко, то можно перейти к навигации на плоскости, и математики сразу меньше.
Подсчитайте, какая погрешность определения расстояния между точкой А и Б появится при переходе от стандартных моделей к высчислениям на плоскости, касающейся Земли в точке А. Если летать меньше, чем на 100 км, ошибка будет просто ничтожная, не помню уже сколько именно, но у меня получались какие-то чуть ли не сотые доли процента. И с уменьшением этого расстояния стремится к нулю быстрее, чем это расстояние. А погрешносто определения азимута будет еще меньше.

Кстати, это вот…
USB я наконец-то победил. Шлю пакеты и из приложения в плату, и обратно, перехожу в режим обновления прошивки и обновляю прошивку. Сказка.

Теперь вот думаю такую мысль: у нас на борту будет акселерометр и 3 гироскопа. Так почему бы не заставить плату работать просто как 3 гироскопа, когда
автопилот не задействован? Гироскопы “включать”, разумеется, не всегда, а по команде с пульта.

Всё это приводит к следующей мысли: состояние каналов элеронов, РН, РВ и т.д. надо всё-таки знать.
Соответственно, возникает вопрос: а как, имея атмегу128, это узнать?

Знать надо ширину импульсов РРМ в каждом из каналов, приходящих с приемника, и желательно с точностью до 1 мкс, чтоб было 1000 отсчетов на полный диапазон перемещения ручек передатчика (1мс…2мс).

Вариантов реализации видится несколько:

  1. Подать 8 каналов с приемника на 8 ног порта Ё, повеситься на таймер и каждую микросекунду опрашивать его состояние. Вариант бестолковый, ибо на этот опрос уйдет больше половины ресурсов процессора - опрашивать порт Ё придется раз в 8 процессорных тиков, если проц работает на 8 МГц. Добавляем по паре тактов на вход-выход из процедуры обработки прерывания таймера, и получаем, что процессор ничто остальное сделать просто не успеет.

  2. Вешаем на порт Ё резисторные делители 1/2, 1/4, 1/8, и т.д, и суммируем то, что получается на выходе. Опрашиваем итоговое напряжение с помощью
    одного из каналов АЦП в режиме непрерывного преобразования и дальше математикой разбираемся, где что пришло. Вариант не сильно лучше предыдущего, если, вообще, лучше.

  3. Подаем 8 входов на порт Ё, и их же, через 8 диодов, на вход ICP. Взводим прерывание ICP на любое изменение состояния входа. Как только срабатывает прерывание ICP, подглядываем в порт Ё и узнаем, какой это из входов вздумал изменить состояние. Смотрим, какая предыстория была у этого входа, и делаем выводы.
    Вариант просто шикарный, процессорного времени требует доли процента, а точность опроса можно сделать хоть половину микросекунды.

Сами понимаете, вариант номер 3 прост и гениален.
С ним режим passthrough, когда автопилот не задействован, делается как два пальца. При каждом срабатывании ICP просто копируем порт Ё в порт Ы.

Добавлять-вычитать добавочки с гироскопов при работе платы автопилота в режиме трехосевого гироскопа - тоже просто. Сработало прерывание ICP - смотрим, какой канал изменился, смотрим, какая у него была ширина, изменяем в нужную сторону, взводим таймер на нужное время, и занимаемся своими делами. Срабатывает прерывание таймера - обновляем в прерывании порт Ы, сбрасываем прерывание и дальше занимаемся своими делами.

Но сработает этот вариант номер 3 только в том случае, если импульсы PPM в каналах разнесены по времени между собой, как написано в учебниках и статьях на RCDesign. Если же во всех каналах восходящие фронты импульсов приходят одновременно, или верхние “полки” импульсов накладываются, то грядет большой облом. Есть, конечно, варианты получше, чем 1 и 2, но не такие клёвые, как 3.

Соответственно, гуру, к вам вопрос: а можно ли быть уверенным, что импульсы PPM, приходящие с приемника в разных каналах, ВСЕГДА разнесены по времени?

smalltim

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

Dikoy
smalltim:

у Атмеги128 есть специально обученные ноги в количестве 8 штук, которые могут генерить прерывания при изменении состояния на входе.

Ну дык пол года лежит уже мой недоделок в инете, где это всё уже реализовано 😃 www.narod.ru/guestbook/?owner=13456664
Правда, там ошибка в математике вычисления периода, но это уже мелочи.

Ещё у атмеги есть прерывания PCINT. Оно одно, появляется при любом изменении на одной из ввереных лапок. В прерывании нужно понять, где и что произошло, это основное отличие от INTx. А лапок вверять можно много 😉

smalltim:

Теперь вот думаю такую мысль: у нас на борту будет акселерометр и 3 гироскопа. Так почему бы не заставить плату работать просто как 3 гироскопа, когда
автопилот не задействован? Гироскопы “включать”, разумеется, не всегда, а по команде с пульта.

Можно. Это избавляет от необходимости постоянной коррекции - состояние в момент включения и есть ноль.

belkinnn:

День добрый, мужики подскажите пожалуйста почему при расчете расстояния и азимута между двумя координатами один и тот же код на компе работает а в контроллере выдает всякую хрень причем через раз.

float 16-и битный, как считается тригонометрия ещё надо смотреть, возможно, ошибки в алгоритмах.
Эту математику МК будет просчитывать пол года 😃

belkinnn:

if ((StartLat < EndLat) && (StartLon < EndLon)) Bearing = abs(fAlpha * R2D);else
if ((StartLat < EndLat) && (StartLon > EndLon)) Bearing = 360 - abs(fAlpha * R2D);else
if ((StartLat > EndLat) && (StartLon > EndLon)) Bearing = 180 + abs(fAlpha * R2D);else
if ((StartLat > EndLat) && (StartLon < EndLon)) Bearing = 180 - abs(fAlpha * R2D);

Что за компилятор? Функция abs может быть некорректна. Просто пишешь (int)(fAlpha * R2D); или какой там тип Bearing.
И зачем там else?.. 😃

dikoy44.narod.ru/piros.html - более прямая ссылка.
Насчёт разноса по времени, Кузнецов, в своё время, со свойственной ему экспрессией довольно внятно объяснил историческую суть вопроса: на борту стоял тупой счётчик, который выделял канальные импульсы из потока данных радиоканала. А там не могут быть выделены импульсы одновременно, только последовательно.
То есть, если приёмник работает в “том” стндарте, что канальные импульсы возникают последовательно. Но сейчас половина аппаратуры на AVR делается, так что не факт… PCM точно может одновременно молотить, PPM, наверное, таки до сих пор последовательно. Одновременно передать состояния всех каналов в аналоговой системе радиопередачи невозможно.
Точнее возможно, но никто таким извратом заниматься не будет в цифровую эру.
Отсюда вывод: если радиоканал аналоговый, а у ППМ оно обычно так, то импульсы 100% последовательны. Если цифровой - скорее всего одновременны.
Был бы у меня приёмник, мог бы посмотреть осциллом. У меня он 4 канальный запоминающий 😃

Володимир
Dikoy:

Отсюда вывод: если радиоканал аналоговый, а у ППМ оно обычно так, то импульсы 100% последовательны. Если цифровой - скорее всего одновременны.

У цифровых передача информации все равно идет последовательно, а чтобы не расходовать много времени на один пакет, применяют разные ухищрения.

nokpblwkuH

2smalltim
система становиться все более и более навороченее, пора вводить интерактивные настройки, меню: какой-то канал отвечает за режим работы: меню или управление. в режиме меню, дальше меги ничего из сигналов не отдаем а ручки используем для навигации по меню.
второй вариант - постоянно отдаем 2 канала на меню. Двух каналов (т.е. двух кнопок) для меню достаточно.

belkinnn

Компилятор CodeW. abs работает коректно.А вот математа не лезет во float а double я так понял чтов МК ничем не отличается от float. А какая у вас математика, просто я пробывал просто по через теорему Пифагора ничего толкогово не получилось.Буду благодарен если поделитесь кодом или хотябы формулами.А растояния я не планирую больше 10 км от место старта.

Dikoy
belkinnn:

Компилятор CodeW.

Кодевижн чтоли? Он с плавающей точкой вообще через зад работает…
Переведи вычисления на дабл, должно помочь.

smalltim
Dikoy:

>Гироскопы “включать”, разумеется, не всегда, а по команде с пульта.

Можно. Это избавляет от необходимости постоянной коррекции - состояние в момент включения и есть ноль.

А подробнее можно? Что и где в момент включения есть ноль?

belkinnn
Dikoy:

Кодевижн чтоли? Он с плавающей точкой вообще через зад работает…
Переведи вычисления на дабл, должно помочь.

Пробывал таже песня при маленьких расстояниях происходит переполнение.При больших работает как часы.

Psw
Володимир:

У цифровых передача информации все равно идет последовательно

Да вот в том-то и дело, что Серж как-то жаловался на НЕ последовательную Футабу ПЦМ номер не вспомню.
Так что самое правильное но быть может не самое дешёвое - взять состояние принятых каналов по UART из хакнутого или самодельного приёмника типа Вад64, и туда же в приёмник отдать состояние выходных каналов по тому-же UART.
Но это так - мечты/мечты.
А использовать не дешёвые бортовые гиры для стабилизации модельки (особенно такой как верт) по 3м осям в нормальном полёте очень даже не помешает и полёт по камере могет значительно облегчить. Хотя математически и тут всё не так уж и просто, особенно если делать ПИ(Д) алгоритмы - я что-то плохо себе представляю, как будет лететь самаль, которому задали крен 30 градусов и кабрирование 1 градус, он же будет иметь угловую скорость вокруг вертикальной оси к примеру, при этом хвост станет пытаться эту скорость убрать и сохранять первоначальный азимут полёта. Что будет дальше - не представляю, но наверняка придётся сводить команды самалю к высоко уровневым согласованным манёврам. Потому как взаимо проникновение каналов гир будет ещё и через полётные свойства модели идти.

pvp
Dikoy:

Насчёт фьюзов через флип…

Вот ссылочка на соответсвующий документ: www.atmel.com/dyn/resources/…/doc7769.pdf.
На странице 12, п. 7 FAQs, читаем 3-ий вопрос-ответ:

  1. Can I modify the fuse bits using Flip?
    • No, Flip cannot modify the fuse bits. To modify the fuse bit you can use either the JTAG ICE
    MKII, the AVRISP MKII, or parallel programming.
smalltim

>3. Can I modify the fuse bits using Flip?
>• No, Flip cannot modify the fuse bits. To modify the fuse bit you can use either the JTAG ICE
>MKII, the AVRISP MKII, or parallel programming.

Да, я это уже успел увидеть. Ну, пока дефолтное состояние фьюзов меня устраивает.

belkinnn:

Компилятор CodeW. abs работает коректно.А вот математа не лезет во float а double я так понял чтов МК ничем не отличается от float. А какая у вас математика, просто я пробывал просто по через теорему Пифагора ничего толкогово не получилось.Буду благодарен если поделитесь кодом или хотябы формулами.А растояния я не планирую больше 10 км от место старта.

Устраиваем систему координат на плоскости в точке старта так: ось Х - с запада на восток, ось Y - с юга на север.

Расстояния от базы до самика по этим осям будет равно:

DX ~ Rземли*(разница долгот между стартом и самиком выраженная в радианах)*cos(широта точки старта)
DY ~ Rземли*(разница широт между стартом и самиком выраженная в радианах)

При этом используется известный факт, что для маленьких углов a
sin(a) ~ tg(a) ~ a

Дальше считайте азимуты как Вам угодно 😃

Artie
Psw:

Так что самое правильное но быть может не самое дешёвое - взять состояние принятых каналов по UART из хакнутого или самодельного приёмника типа Вад64, и туда же в приёмник отдать состояние выходных каналов по тому-же UART.
Но это так - мечты/мечты.

Я давно предлагаю Тимофею свои доработки мультиплексовских приемников (именно для этого), но он пока не хочет… 😛

leliksan

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

smalltim

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

+1
Тоже думал об этом, но не так живо представлял себе поведение модели. Ну и отлично, мне же меньше работы будет 😃

lodeworx
smalltim:

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

Ну вот типа: например. Из моего декодера PPM. Использует ICP. Если по каналам, я использовал “подключатель” на hct125d- лишний драйвер тоже не помешает, для выравнивания фронтов. Что касается самих импульсов, я думаю, что если с контроллера выводятся напрямую к машинкам(в приемнике)- то одновременно стартуют…(все включил, по счетчику отключил)
[codebox]
//////////////////////////////////////////////////////////////
#define PULSEZ 32
#define RC_SEQ_PRESENT 0
#define RC_SEQ_ACKQ 1
#define TURN_LED_ON PORTB|=_BV(LED_0)
#define TURN_LED_OFF PORTB&=~_BV(LED_0)
volatile uint16_t MeasuredIcpz[PULSEZ*2], RcvdData[8], cntz;
uint8_t ChnlCnt, SYS_LOGIC_BITS, pulse_Piece;
//////////////////////////////////////////////////////////////
void InitCapture (void) {
cli();
TCCR1B=0;
TCNT1=0;
TCCR1B |=_BV(CS11) |_BV(ICES1);// Период измерения равен 8*65536/XTAL
TIMSK |=_BV(TICIE1) |_BV(TOIE1);
sei();
}
ISR (TIMER1_CAPT_vect){
TCCR1B&=~_BV(CS11);//стоп таймер
TCNT1=0; //счетчик в ноль
if (bit_is_clear(TCCR1B,ICES1)) TCCR1B|=_BV(ICES1);// переключаем полярность срабатывания
else TCCR1B&=~_BV(ICES1);
TCCR1B|=_BV(CS11);// таймер старт
if (ICR1<5555) {// мин. значение длительности на которое следует реагировать (для JR при кварце 12mhz в моем случае)
//TURN_LED_OFF;
SYS_LOGIC_BITS|=_BV(RC_SEQ_PRESENT); // последовательность присутствует!
MeasuredIcpz[pulse_Piece]=ICR1;// сохраняем все данные???
if (MeasuredIcpz[pulse_Piece]>777) {// канальный синхро ~550 не нужен
///////////////////////////////////////////////////////
RcvdData[ChnlCnt]=(RcvdData[ChnlCnt]+MeasuredIcpz[pulse_Piece])>>1;// усредняем???
///////////////////////////////////////////////////////
if (ChnlCnt++>=7) ChnlCnt=7;// сохраняем 8 каналов
}
if (pulse_Piece++==(PULSEZ*2)-1) pulse_Piece=0;
} else {
cntz=pulse_Piece;
ChnlCnt=0;
pulse_Piece=0;
SYS_LOGIC_BITS|=_BV(RC_SEQ_ACKQ);// если больше 5555 - посылка принята!
}
}
ISR (TIMER1_OVF_vect){// при переполнении таймера сбрасываем бит наличия и счетчики
cntz=pulse_Piece;
pulse_Piece=0;
SYS_LOGIC_BITS&=~_BV(RC_SEQ_PRESENT);
SYS_LOGIC_BITS&=~_BV(RC_SEQ_ACKQ);
//TURN_LED_ON;
}
[/codebox]
Типа, вот. просто и понятно. Работает шикарно. Input Capture Noise Canceler -не пробовал, за ненадобностью
MeasuredIcpz и cntz можно выкинуть