Уголок коптер-программиста
расскажите пожалуйста здесь о результатах теста, у меня никах руки не доходят…
обещаю! 😉
p.s. меня все не покидает идея улучшения качества удержания позиции по гпс с применением акселя 😃, где аксель будет основноый и быстрый сенсор, а гпс лишь корректор…
на AVR-ке конечно же, т.е. на AIOP… и там как раз нужны быстрые sin/cos, чеб привести вектор акселя в глобальную систему координат, т.е. в которой живет гпс…
angle=90, _cos=-7.390978E-7, cos=-4.371139000186241E-8
Саш, чёт с математикой не слишком срослось? я конечно понимаю что нулей впереди до дури но всёже?
чёт с математикой не слишком срослось? я конечно понимаю что нулей впереди до дури но всёже?
для косинуса картинка еще лучше… практически стабильные 3 знака после запятой…
т.е. с точностью до 3-х знаков и там и там ноль ))
- надо учесть, что еще на входе погрешность, где угол в радианы переводится… т.е. (float)(i*Math.PI/180.0f)
а я как всегда со своей колокольни 😃 ±0 напрягает, можно невзначай и через 180 повернуть? 😃
Но вообще мне и сейчас кажется, что спокойнее все же посчитать константы самому
глянул… в свежей версии так и сделали…
int16_t _atan2(int32_t y, int32_t x){
float z = (float)y / x;
int16_t a;
if ( abs(y) < abs(x) ){
a = 573 * z / (1.0f + 0.28f * z * z);
if (x<0) {
if (y<0) a -= 1800;
else a += 1800;
}
} else {
a = 900 - 573 * z / (z * z + 0.28f);
if (y<0) a -= 1800;
}
return a;
}
вот еще в ardu нашел… самый быстрый sin/cos и сразу с углом на входе…
static const uint16_t pgm_sinLUT[91] PROGMEM = {0, 17, 35, 52, 70, 87, 105, 122, 139, 156, 174, 191, 208, 225, 242, 259, 276, 292, 309, 326, 342, 358, 375, 391, 407, 423, 438, 454, 469, 485, 500, 515, 530, 545, 559, 574, 588, 602, 616, 629, 643, 656, 669, 682, 695, 707, 719, 731, 743, 755, 766, 777, 788, 799, 809, 819, 829, 839, 848, 857, 866, 875, 883, 891, 899, 906, 914, 921, 927, 934, 940, 946, 951, 956, 961, 966, 970, 974, 978, 982, 985, 988, 990, 993, 995, 996, 998, 999, 999, 1000, 1000};
float
Trig_LUT::sin_lut(int16_t angle)
{
int8_t m,n;
int16_t _sin;
if (angle < 0){
m = -1;
angle = -angle;
}else{
m = 1;
}
// 0 - 360 only
angle %= 360;
// check quadrant
if (angle <= 90){
n = 1; // first quadrant
} else if ((angle > 90) && (angle <= 180)) {
angle = 180 - angle;
n = 1; // second quadrant
} else if ((angle > 180) && (angle <= 270)) {
angle = angle - 180;
n = -1; // third quadrant
} else {
angle = 360 - angle;
n = -1;
} // fourth quadrant
// get lookup value
_sin = pgm_read_word(&pgm_sinLUT[angle]);
// calculate sinus value
return (float)(_sin * m * n) / 1000;
}
float
Trig_LUT::cos_lut(int16_t angle)
{
return (sin_lut(90 - angle));
}
обещаю!
Написал сегодня тестик. Подрюкался с загадками компиллятора 😃
Если sin/cos считать в цикле и результат функции не присваивать, либо присваивать, но не использовать вне тела цикла, то компиллер считает что “а нах. тогда функцию вообще вызывать” )) Пришлось в цикле контрольную сумму считать…
Результаты:
-
_sin() быстрее библиотечного sin() на 84%
-
_cos() быстрее библ. cos() всего на 23%
-
sin_lut() быстрее библ. sin() на 96%
-
cos_lut() быстрее библ. cos() на 88%
Таким образом, если точность угла на входе с дискретностью в 1-цу устраивает (а также точность результата три знака после запятой), то табличный sin/cos имеет смысл…
Код теста:
void setup() {
Serial.begin(115200);
Serial.println("Start performance test:");
}
static float rad[181];
void loop() {
uint32_t totalTimeOrig = 0, totalTimeApprox = 0;
float summ = 0.0f;
// prepare input data in radians
for (int i = 0; i <= 180; i++) {
rad[i] = i*PI/180.0f;
}
uint32_t currentTime = micros();
for (int k = 0; k < 100; k++) {
for (int i = 0; i <= 180; i++) {
summ += sin(rad[i]);
summ += sin(-rad[i]);
}
}
totalTimeOrig = micros() - currentTime;
Serial.println(summ);
currentTime = micros();
for (int k = 0; k < 100; k++) {
/*for (int i = 0; i <= 180; i++) {
summ += sin_lut(i);
summ += sin_lut(-i);
}*/
for (int i = 0; i <= 180; i++) {
summ += _sin(rad[i]);
summ += _sin(-rad[i]);
}
}
totalTimeApprox = micros() - currentTime;
Serial.println(summ);
Serial.print("totalTimeOrig = ");
Serial.println(totalTimeOrig);
Serial.print("totalTimeApprox = ");
Serial.println(totalTimeApprox);
Serial.print("performance = ");
Serial.println((float)totalTimeOrig/totalTimeApprox);
Serial.println();
delay(2000);
}
float _sin (float x) {
x = x * 0.31831f;
float y = x - x * abs(x);
return y * (3.1f + 3.6f * abs(y));
}
float _cos (float x) {
x = x * 0.31831f + 0.5f;
float z = (x + 25165824.0f);
x = x - (z - 25165824.0f);
float y = x - x * abs(x);
return y * (3.1f + 3.6f * abs(y));
}
float _atan( float x )
{
uint32_t ux_s = 0x80000000 & (uint32_t &)x;
float bx_a = ::fabs( 0.596227f * x );
float num = bx_a + x * x;
float atan_1q = num / ( 1.f + bx_a + num );
uint32_t atan_2q = ux_s | (uint32_t &)atan_1q;
return (float &)atan_2q * 1.5708f;
}
float isqrt( float y )
{
float x2 = y * 0.5f;
long i = * ( long * ) &y; //evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); //what the fuck?
y = * ( float * ) &i;
y = y * ( 1.5f - ( x2 * y * y ) );
return y;
}
static const uint16_t pgm_sinLUT[91] PROGMEM = {
0, 17, 35, 52, 70, 87, 105, 122, 139, 156, 174, 191, 208, 225, 242, 259, 276, 292, 309, 326, 342, 358, 375, 391, 407, 423, 438, 454, 469, 485, 500, 515, 530, 545, 559, 574, 588, 602, 616, 629, 643, 656, 669, 682, 695, 707, 719, 731, 743, 755, 766, 777, 788, 799, 809, 819, 829, 839, 848, 857, 866, 875, 883, 891, 899, 906, 914, 921, 927, 934, 940, 946, 951, 956, 961, 966, 970, 974, 978, 982, 985, 988, 990, 993, 995, 996, 998, 999, 999, 1000, 1000};
float sin_lut(int16_t angle) {
int8_t m,n;
int16_t _sin;
if (angle < 0){
m = -1;
angle = -angle;
} else{
m = 1;
}
// 0 - 360 only
angle %= 360;
// check quadrant
if (angle <= 90) {
n = 1; // first quadrant
}
else if ((angle > 90) && (angle <= 180)) {
angle = 180 - angle;
n = 1; // second quadrant
}
else if ((angle > 180) && (angle <= 270)) {
angle = angle - 180;
n = -1; // third quadrant
}
else {
angle = 360 - angle;
n = -1;
} // fourth quadrant
// get lookup value
_sin = pgm_read_word(&pgm_sinLUT[angle]);
// calculate sinus value
return (float)(_sin * m * n) / 1000;
}
float cos_lut(int16_t angle) {
return (sin_lut(90 - angle));
}
Спасибо, Александр! Очень интересно. Но вот вопросик, ежели надо на входе угол в радианах (конечно и с плавающей точкой), не убьет ли конверсия все преимущество sin_lut по скорости? Я вот так навскидку не вижу, как можно без потерь адаптировать…
А насчет “медленного” _cos – это очевидно сказывается приведение к диапазону, float z = (x + 25165824.0f);
x = x - (z - 25165824.0f); потому что в остальном это тот же _sin со сдвигом.
Надоел мне совсем ардуиновский IDE для разработки, хотя по сути пользовал его только для компилинга, а писал в Notepad++
Вчера попробовал CodeBlocks-Arduino, может он и ничего, но не смог настроить проект…
Далее глянул MariaMole тоже не понравилась…
Потом решил поставить Visual Studio + Visual Micro pluggin.
Оказалось то что надо! Навигатор удобный как по файлам так и по функциям/перменным, code completion, подсветка синтаксиса с “приглушенным” контентом, если дефайн закрыт… Из минусов Visual Studio запросил гад 5 гб на С диске, также он триальный на 90 дней, НО разработчики Visual Micro пишут что через 90 дней будет доступен Atmel/Visual Studio…
Собственно вопрос. Кто на чем пишет под arduino?
Собственно вопрос. Кто на чем пишет под arduino?
имхо… ардуино ИДЕ - убожество, да и многие другие, по сравнению с атмел студио.
при необходимости достаточно посидеть несколько часов над основными библиотеками ардуино и перетащить их на студию для удобства.
Кто на чем пишет под arduino?
UltraEdit )))
На днях прикрутили проект пирата к Eclipse… но по факту получилось только компиляция. Ошибки он не подсвечивает (точнее у него ошибка практически в каждой строке)
имхо… ардуино ИДЕ - убожество, да и многие другие, по сравнению с атмел студио.
при необходимости достаточно посидеть несколько часов над основными библиотеками ардуино и перетащить их на студию для удобства.
в том и дело Visual Studio + Visual Micro pluggin работает почти из коробки и ниче перетаскивать не надо… показал ей где ардуино фолдэр, открыл главный ino файл и готово!
На днях прикрутили проект пирата к Eclipse…
а можно поподробней? я пытаюсь сейчас AutoQuad32 перетянуть - пока безуспешно (*.ino в *.срр интересно можно просто переименовать, а то гцц может и не понять что за фигня - далее знаю где подключается, так что изменить не проблема), с моими кривыми ручками это надолго - ибо переписываю makefile…
*.ino в *.срр
попробуйте основной файл в .cpp а прочие в .h + придется разбиратся с переменными. По крайней мере в атмел студии я именно так и поступал.
у меня он единственный, сейчас компилятор наконец-то увидел (странно патчи прописывал как и раньше, а не пошло- пришлось ближе передвигать - …/…/ ), но ругается что правил для сборки нет, вот и думаю как безболезненно makefile переписать…
а можно поподробней?
Ну суть в том, что у нас есть makefile, который собирает Пирата с использованием Cygwin + Arduino. Т.е. все работает из командной строки.
Теперь создаем “C” проект в Eclipse и подключаем наш makefile. Вот и все. Если сделать Build, то Eclipse подсвечивает ошибки в исходниках, но как только открываешь файлы, он начинает ругаться практически на все, т.к. не может сам проверить исходники. В общем, хоть что то и можно делать, но по сути не сильно отличается от обычного редактора 😦
Вероятно надо менять структуру исходников на нормальный C или C++ и после этого пользоваться любой средой, как Eclipse, так и Atmel…
Сказали, А, говорите и В 😃 в смысле, register map…
Увы, я свой выложить не могу, лицензионное соглашение сдуру на себя подписал.
Уважаемые! Хочу поделиться вопросом, а в перспективе - добиться (не без вашего совета) решения в следущем проекте: Измеритель вибрации (а конкретно амплитуды виброперемещения) по 3 осям с помощью акселерометра ADXL335, Ардуины и 1602 дисплея (для мобильности).
Вопрос: По какому принципу данные с акселерометра в Ардуине пересчитать в мм/с (или, к примеру, создать свою шкалу единиц (0…1000))? Какие формулы использовать?
На ровной поверхности, в состоянии покоя (1g) на выходе каждой оси примерно 330mV. И это напряжение меняется от углов наклона акселерометра.
Хочу мобильное устройство для контроля уровня вибрации двигателей коптера в поле. Телефон и планшет с g-сенсором не предлогать;) Думаю, кто-нибудь сможет найти данному устройству другое применение.
ну дык, если вся шкала АЦП 1024 - 5В если не поизвращатся с Aref проца (напряжение на нём - верхний предел для АЦП - не забыть выставить external) - отсюда и плясать… лучше всего посмотреть в даташит - какое максимальное напряжение на выходе акселя может быть, такое же и выставить Aref…
Все же предлагаю эту тему не захламлять вопросами-ответами. Эта тема была создана что бы тут складировать готовые решения.
в следущем проекте: Измеритель вибрации
по сути готовый виброметр, на базе мвия, с возможностью по желанию включать движки по отдельности из GUI:
code.google.com/p/multiwii/source/detail?r=1378
code.google.com/p/multiwii/source/detail?r=1381
Вроде решение готовое, чеб Алексей не ругался ))