Телеметрия (часть 1)
… блин, всё никак не могу придумать, как половчее циферки из ASCII в 32-битные целые переводить, да чтоб код был покомпактнее, да чтоб не завязываться на фиксированное количество знакомест, а то разные GPS приемники разное количество точек после запятой выдают. Кстати, посчитал, 4 разрядов после запятой достаточно, 5-й, выдаваемый напромер u-bloxами отброшу. Одна десятитысячная доля минуты в широте дает 18 см по земле, куда еще точнее, когда сам GPS приемник точность плюс-минус 2-3 метра выдает ? 😃
У меня такая функция:
float mas_to_float(char *str, unsigned char len) {
float scale, result;
char *start;
result=0.0;
start = str;
str += len;
while (*str!=‘.’)
{
result=(result+(*str-‘0’))/10.0;
–str;
};
scale=1.0;
while (–str>=start)
{
result=result+scale*(*str-‘0’);
scale=scale*10.0;
};
if (*start==‘-’) result=-result;
return result;
}
Она короче Сишной atof и быстрее.
А быстро переводить не получится… Даже если десятичное умножение заменить сдвигами.
А подскажите, с этими очками данная телеметрия работать будет?
Насчёт пятого разряда, это вы зря 😉
Dikoy:
Смотрю на Ваши данные. Блин, если GPS приемник вздумает произвольно из 2D в 3D и обратно переключаться в полете, в зависимости от расположения спутников, то показания широны-долготы будут скакать, и судя по Вашим данным, сильно, на 500 метров туда-сюда. Надо будет запоминать базовые координаты в режиме 2D и в 3D, и в зависимости от текущего режима приемника, сравнивать текущие координаты с 2D или c 3D координатами.
Не поможет 😦 В 2D режиме сама точность хуже, сохранение ничего не даст.
Эти данные я снимал из окна. В полёте спутники теряются очень редко (если модуль и антенна правильные). Так что я бы забил и в 2D режиме просто не использовал данные, сохраняя предыдущий вектор.
Боюсь, математика, которая нужна для фильтрации таких событий, в мегу8 не влезет… Во первых, по времени, во вторых - по объёму. Мне пришлось писать свою математику и ставить фильтры, в итоге всё занимеает около 60 кБ… Но работает шустро зато.
Вуаля. Будут потери точности из-за целочисленной математики, табличного косинуса и сферической модели земли, но это какие-то доли процента, даже лень считать.
Табличный косинус - стандартное решение 😉 Все так делают, при определённой доле извращенства погрешность можно свести почти к нулю.
А насчёт целочисленной математики - вы же работаете от стартовой точки. Почему бы не взять её за ноль и не работать на добавках 😉 Даже умноженые на 10000 величины широт/долгот не выйдут за 16 бит, а регистры у АВР 16-битные 😉 Так получится сильно скорее.
Вот тут полезный материал: nauka.nsk.ru/e-books/Bond/naviga6/niva6_01.htm
Мда… Приехал…
Вижу…Никаких мыслей…
Надо беседовать с вертолетчиками…
А, сорри. Фактически вы так и делаете - просто отбрасываете целые. В принципе, так тоже можно. Только надо при старте зафиксировать координаты и раскурить на тему вероятности пересечения самолётом граничного разряда. Чтобы небыло ситуации, когда координата перевалит за 999 и станет 0 (условно) 😃
Я от этого отказался, т.к. датности более 100 км…
ПС. Я выкладывал тут результаты испытаний, там есть трек GPS, снятый с торпедо. Можно качнуть карту Тулы и посмотреть, как меняется ориентация и данные в разных режимах.
В самом конце - стоянка минут 10 во дворе супермаркета. Хорошо видно, как колбасит компас.
У меня такая функция:
float mas_to_float(char *str, unsigned char len) {
float scale, result;
char *start;
result=0.0;
start = str;
str += len;while (*str!=‘.’)
{
result=(result+(*str-‘0’))/10.0;
–str;
};scale=1.0;
while (–str>=start)
{
result=result+scale*(*str-‘0’);
scale=scale*10.0;
};if (*start==‘-’) result=-result;
return result;
}Она короче Сишной atof и быстрее.
А быстро переводить не получится… Даже если десятичное умножение заменить сдвигами.
А Вы видели, какой АСМ код из этого выдает компилятор?
На чистом АСМе, без операций с плавающей точкой (зачем вообще здесь она?) то же самое будет в разы компактнее и быстрее. В разы - это не в 2-3 раза, а, боюсь, в 20-30 раз.
>А, сорри. Фактически вы так и делаете - просто отбрасываете целые.
Нет. Обрезаю разницу из двух 4-байтных чисел до двух байт.
>В принципе, так тоже можно. Только надо при старте зафиксировать координаты и раскурить на тему вероятности пересечения самолётом граничного разряда.
Не надо. На удалениях до 47 км разница влазит в 2 байта.
>2D
То есть, 2D-режим - скорее, исключение, чем правило, и надо всегда пользоваться 3D режимом? Какова вероятность перескока из 3D в 2D в полете, при неудачном расположении спутников?
А Вы видели, какой АСМ код из этого выдает компилятор?
А эт зависит от компилятора 😃
На чистом АСМе, без операций с плавающей точкой (зачем вообще здесь она?) то же самое будет в разы компактнее и быстрее. В разы - это не в 2-3 раза, а, боюсь, в 20-30 раз.
Будет, согласен. Не в разы, но будет. Если делать по вашему методу, то работает другая функция:
long int mas_to_long_int(unsigned char *buf, unsigned char len) {
long int result=0;
unsigned char tempX;
while((*buf)++ != ‘.’) len–;
while(len–)
{
tempX = *buf++;
result = (result*10 + (tempX - 0x30));
}
return result;
}
Или её варианты под задачу. IAR собирает в 12 строчек, за счёт десятичной коррекции. Вот только эта функция - реюзибл 😉 Её вынул, вставил в любой текст и всё работает. А портирование асмовского кода? А если захотите сменить контроллер? 😉
Пока код маленький, пока над ним работаете только вы, всё хорошо. А вот когда он разростётся, да пройдёт пару лет?.. 😃
У меня queue система. Блочная. Есть Stream, на который я могу посадить любой программный модуль и под него выделится необходимый ресурс. Фактически, это псевдо-ОС система. Не так оптимальна, как чистый асм, но зато над ней работают десяток человек и никто не испытывает дискомфорта 😉 И модули работают в реалтайме.
>В принципе, так тоже можно. Только надо при старте зафиксировать координаты и раскурить на тему вероятности пересечения самолётом граничного разряда.
Не надо. На удалениях до 47 км разница влазит в 2 байта.
Не забывайте про дрейф координаты 😉
>2D
То есть, 2D-режим - скорее, исключение, чем правило, и надо всегда пользоваться 3D режимом? Какова вероятность перескока из 3D в 2D в полете, при неудачном расположении спутников?
Тут однозначно не скажешь. ОЧЕНЬ многое зависит от антенны и приёмника. Летал (в составе автопилота) я только с блоксами, с плоской антенной меньше 8 не видит. Со спиралью - 8-10. 2D режим появляется только на земле и на малых скоростях у земли, если под антенной маленький полигон. Если приёмник как у Вас, без полигона, над водой часты глюки (замечены у тримбла и лассена), блоха координаты не теряет, но они начинают ощутимо гулять.
В общем, надо выйти в чисто поле, поднимите приёмник на палке метра на четыре (или с крыши дома) и всё сразу станет понятно. Но в полёте, если часто не крутиться, а летать с кренами не более 15 градусов (стандартный разворот) переходов 2-3D ни у одного приёмника замечено небыло.
>дрейф координаты
Что это такое?
А это как раз когда приёмник приглючит. От помехи или переотражения - не суть. Иногда такое бывает, когда батарейка бекапная садится. И всё - скачёк на пару сотен КМ обеспечен. Вот скрин такого глюка.
Дополню.
У меня в софте стоит т.н. “исключающий фильтр”.
Есть пределы, которые самолёт никогда не превысит - скорость, ускорение и т.п. Обычно ускорения, вычисленные по изменению координаты во времени. Если предел превышен, точка признаётся нерелевантной.
Идея не нова, в инете достаточно много её реализаций в различных сферах.
Такой фильтр очень эффективно давит подобного рода глюки.
Будет работать с проводком к меге. Но проводков уже слишком много, да и помехи надо окончательно убить. Поэтому после вылизывания прошивки будет новая платка.
Тимофей, по-моему, сейчас как раз самое время вернуться к исходной шереровской схеме и отделить математику от отображаловки !
Тогда первую можно будет писать на нормальных сях (или на чем больше нравится) с нормальной плавучкой, не считая такты и байты, а во вторую сгружать готовые строки по SPI… - Собственно, я исходно именно так и планировал делать, но пока расчетов было мало - они хорошо ложились в один кристалл. Сейчас же проект его уже явно перерос.
PS: Кстати, “стрелка компаса” уже формируется в ОЗУхе, или это фонт ? Я так на взгляд прикинул: 24 положения, по 6 (скажем) знакомест, - это же больше половины всего знакогенератора… - Не слишком большая цена за красоту ? 😉
Впрочем, независимо от, идея в подарок: Значительно удобнее, когда оный “компас” привязан не к северу, а к курсу. Соответственно, у меня в центре стоит иконка самолета, а направления на “home” и на север бегают вокруг него кругами: всего 18 знаков (девять на “мячик”, девять на букву “N”) при тех же 24 пеленгах. И поле - всего 3х3…
Тимофей, по-моему, сейчас как раз самое время вернуться к исходной шереровской схеме и отделить математику от отображаловки !
Тогда первую можно будет писать на нормальных сях (или на чем больше нравится) с нормальной плавучкой, не считая такты и байты, а во вторую сгружать готовые строки по SPI… - Собственно, я исходно именно так и планировал делать, но пока расчетов было мало - они хорошо ложились в один кристалл. Сейчас же проект его уже явно перерос.PS: Кстати, “стрелка компаса” уже формируется в ОЗУхе, или это фонт ? Я так на взгляд прикинул: 24 положения, по 6 (скажем) знакомест, - это же больше половины всего знакогенератора… - Не слишком большая цена за красоту ? 😉
Впрочем, независимо от, идея в подарок: Значительно удобнее, когда оный “компас” привязан не к северу, а к курсу. Соответственно, у меня в центре стоит иконка самолета, а направления на “home” и на север бегают вокруг него кругами: всего 18 знаков (девять на “мячик”, девять на букву “N”) при тех же 24 пеленгах. И поле - всего 3х3…
Можете считать это блажью, но вот у меня пункт такой: хочу, чтобы всё было утоптано в один кристалл. Целый кристалл для одной только отображаловки - чудовищно расточительно.
И пока всё очень даже утаптывается. И на АСМе меня писать не напрягает, такты и байты приходилось считать только в коде непосредственно отбражения 😃
Для остального кода у меня времени и места - выше крыши. Я ж не занимаюсь рисованием весь кадр, только чуть-чуть вверху кадра и немного внизу кадра.
А “нормальная плавучка” в приложении к Атмеге - понятие, в нашем случае не имеющее практического смысла.
Стрелки там 24 положения по 9 знакомест, исходно 1728 байт, но используется 256-байтная таблица переадресации символов, типа компрессии. В общем, в итоге используется половина знакогенератора, 1 кБ.
> в центре стоит иконка самолета, а направления на “home” и на север бегают вокруг него кругами
Не, это много тригонометриии. В моем же варианте ее просто нет. То есть, вообще нет. Целочисленная арифметика только.
Тимофей, по-моему, сейчас как раз самое время вернуться к исходной шереровской схеме и отделить математику от отображаловки !
… Сейчас же проект его уже явно перерос.
+1
Для остального кода у меня времени и места - выше крыши. …Целочисленная арифметика только.
Ну и возьмите мегу 64(644) и утапливайте в неё всё 😉 По габаритам выйдет не сильно больше м8, а по возможностям сильно больше.
Насчёт плавучки - у мег аппартный умножитель, иар очень неплохо умеет его пользовать. Сейчас сделал проект на тини2313, прибор для корректировки цифровых спидометров. Он включается между датчиком скорости и спидометром, измеряет период входных импульсов и выдаёт выходные с коррекцией, введённой извне (или определённой автоматически). То есть спидометр показывает правильно независимо от шин, главной пары и прочего тюнинха.
Ну так вот, там одна плавучка, и всё это работает на килогерцах! По трём прерываниям и в реалтайме. На тиньке! И ничего - иар упихал всё это в 1992 байта 😃
На разработку ушло два дня. А сколько ушло бы на асме? 😉
Вы просто загоняете себя в угол… Уже сейчас огранициваете качественный параметр - отображение курса - из-за наличия тригонометрии. А могли бы загнать таблицу Брадиса в память и очень быстро считать всё, что надо (для ЖПС тоже полезно).
Можете считать это блажью, но вот у меня пункт такой: хочу, чтобы всё было утоптано в один кристалл. Целый кристалл для одной только отображаловки - чудовищно расточительно.
Ну, как говорилось в одной пословице, “Хозяин-барин: хочет - пляшет, хочет - удавится.” 😉
Просто я, например, неторопливо обдумываю уже следующие шаги: привод для “наведения” на модель направленной антенны приемника (чтобы не вертеть ее руками), а следом - и зачатки “автопилота”, при потере аплинк-сигнала возвращающего аппарат “на базу”…
И в один корпус это не лезет уже не столько даже по быстродействию и объемам памяти, сколько архитектурно-идеологически.
Вообще, запихивание измериловки в один кристалл с отображаловом у меня было шагом чисто тестовым и осознанно промежуточным, так что я, признаться, нынче искренне удивлен, как много Вам удалось туда затолкать разной арифметики… Однако, несмотря на все достижения, путь этот - явно тупиковый: как с точки зрения расширябельности, так и по удобству дальнейшего сопровождения проекта. И если уж Вы решились разводить “нормальную” плату - то, imho, самое время пожертвовать на ней лишний квадратный сантиметр под второй кристалл.
(Впрочем, я никого не уговариваю 😃, а просто высказываю “мысли вслух”.)
Я вовсе не отказываюсь от второго кристалла, просто планы у меня на него несколько другие, и не совсем еще на 100% определенные.
На второй плате - логгинг данных в память, расчет управления для беспилотного полета, интерфейс с PC для слива-залива данных и конфигурирования системы, и.т.д.
Решение предполагается двухплатным: одна, нынешняя плата (ну разве что переразведенная, чтоб проводки к ногам не паять и чтоб помехи убить) будет законченным решением, и вторая в паре с первой - законченное решение. Хочешь - паяй одну, хочешь больше - паяй две. На первой плате - “измериловка” и “отображаловка”, на второй - “большая математика” и интерфейс с PC.
привод для “наведения” на модель направленной антенны приемника (чтобы не вертеть ее руками), а
Делали мы такое 😃 GPS в самолёте засекает координаты базы, потом антена наводится на передаваемую с борта координату самолёта. Прикольно работало!
Особенно эффектно, когда самолёт возвращается с “задания” и стыкуется с наземкой по радио. Сложеная до этого антена разворачивается и шустренько ловит самик 😁
Кстати, я свернул в вывод буковок на экран в цикл, это экономит ну просто дохрена места (по объему - около 25% всего кода !!). Почему Шеререр (или Artie? 😃) не сделал этого сразу - непонятно.
Букивки у меня 8х6. Нужно код с 32-мя вызовами макроса shiftout заменить на следующее. По объему это вот следующее как раз равно одному макросу shiftout:
LDI R17, 31
LPM R16,Z
OUT VIDPORT,R16
NOP
NOP
LSL R16
OUT VIDPORT,R16
NOP
NOP
LSL R16
OUT VIDPORT,R16
NOP
NOP
_output_char:
LSL R16
OUT VIDPORT,R16
NOP
NOP
LSL R16
OUT VIDPORT,R16
LD ZL,Y+
LSL R16
OUT VIDPORT,R16
LPM R16,Z
OUT VIDPORT,R16
NOP
NOP
LSL R16
OUT VIDPORT,R16
NOP
LSL R16
DEC R17
OUT VIDPORT,R16
BRNE _output_char
NOP
LSL R16
OUT VIDPORT,R16
NOP
NOP
LSL R16
OUT VIDPORT,R16
LD ZL,Y+
LSL R16
OUT VIDPORT,R16
Кстати, я свернул в вывод буковок на экран в цикл, это экономит ну просто дохрена места (по объему - около 25% всего кода !!).
Действительно, красиво. 😃 - Вот что значит свежий взгляд !
… Причем, у меня и времени на пиксел на один цикл больше… (Вы так и не перешли на 20МГц тактовой ?)
Почему Шеререр (или Artie? 😃) не сделал этого сразу - непонятно.
“Элементарно, Уотсен !” - Потому, что тупые 😊. Оба.
На самом деле, объема под код здесь было - хоть опой ешь (у меня до сих пор всего около 70% занято), а разорвать цикл посередине - просто не догадались. (Хочется думать, что если/когда бы приперло - тоже сообразили бы, но это самооправдание…)
>Вы так и не перешли на 20МГц тактовой ?
Ну , официально Atmega8-16 до 16 МГц, выше - разгон. Некошерно 😉
>объема под код здесь было - хоть опой ешь
У меня парсинг NMEA и перевод из ASCII float в целые неожиданно много места занял (пишу с претензией на универсальность, чтоб любое количество знаков после запятой понимал, об ошибках парсинга рапортовал и т.д.), поэтому пришлось еще раз критически посмотреть на код. Под горячую руку попал вывод букивок 😉
Ну , официально Atmega8-16 до 16 МГц, выше - разгон. Некошерно 😉
А я сразу поставил 88ую; - в частности и из-за тактовой.
У меня парсинг NMEA и перевод из ASCII float в целые неожиданно много места занял (пишу с претензией на универсальность, чтоб любое количество знаков после запятой понимал, об ошибках парсинга рапортовал и т.д.), поэтому пришлось еще раз критически посмотреть на код. Под горячую руку попал вывод букивок 😉
С “горячей рукой” все понятно, а координаты я в свое время делил “пополам”: градусы с минутами превращал в целые минуты, вычитал из них “базовые” координаты, умножал на тыщу и прибавлял к ним, как целые, доли минут.
В результате получались координаты без потери точности, умещавшиеся не то что в long - в двухбайтовый int…
Навигацию вокруг всего земного шара на такой математике, конечно, осуществлять нельзя было, но в пределах пары десятков километров - “на ура”. Правда, для пересчета дальности был нужен целочисленный квадратный корень, который как-то очень плохо “таблетизировался”…
Нынче же я на все эти “изыски” наплевал, и считаю в [почти честной] плавучке, благо double sin (double) требует что-то всего около 500-700uS (или как-то похоже). Со всеми отсюда вытекающими.