Уголок коптер-программиста

mahowik
SergDoc:

чёт с математикой не слишком срослось? я конечно понимаю что нулей впереди до дури но всёже?

mahowik:

для косинуса картинка еще лучше… практически стабильные 3 знака после запятой…

т.е. с точностью до 3-х знаков и там и там ноль ))

  • надо учесть, что еще на входе погрешность, где угол в радианы переводится… т.е. (float)(i*Math.PI/180.0f)
SergDoc

а я как всегда со своей колокольни 😃 ±0 напрягает, можно невзначай и через 180 повернуть? 😃

mahowik
Gene:

Но вообще мне и сейчас кажется, что спокойнее все же посчитать константы самому

глянул… в свежей версии так и сделали…

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));
}
mahowik
mahowik:

обещаю!

Написал сегодня тестик. Подрюкался с загадками компиллятора 😃
Если sin/cos считать в цикле и результат функции не присваивать, либо присваивать, но не использовать вне тела цикла, то компиллер считает что “а нах. тогда функцию вообще вызывать” )) Пришлось в цикле контрольную сумму считать…

Результаты:

  1. _sin() быстрее библиотечного sin() на 84%

  2. _cos() быстрее библ. cos() всего на 23%

  3. sin_lut() быстрее библ. sin() на 96%

  4. 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));
}
Gene

Спасибо, Александр! Очень интересно. Но вот вопросик, ежели надо на входе угол в радианах (конечно и с плавающей точкой), не убьет ли конверсия все преимущество sin_lut по скорости? Я вот так навскидку не вижу, как можно без потерь адаптировать…

А насчет “медленного” _cos – это очевидно сказывается приведение к диапазону, float z = (x + 25165824.0f);
x = x - (z - 25165824.0f); потому что в остальном это тот же _sin со сдвигом.

7 days later
mahowik

Надоел мне совсем ардуиновский IDE для разработки, хотя по сути пользовал его только для компилинга, а писал в Notepad++
Вчера попробовал CodeBlocks-Arduino, может он и ничего, но не смог настроить проект…
Далее глянул MariaMole тоже не понравилась…
Потом решил поставить Visual Studio + Visual Micro pluggin.
Оказалось то что надо! Навигатор удобный как по файлам так и по функциям/перменным, code completion, подсветка синтаксиса с “приглушенным” контентом, если дефайн закрыт… Из минусов Visual Studio запросил гад 5 гб на С диске, также он триальный на 90 дней, НО разработчики Visual Micro пишут что через 90 дней будет доступен Atmel/Visual Studio

Собственно вопрос. Кто на чем пишет под arduino?

mataor
mahowik:

Собственно вопрос. Кто на чем пишет под arduino?

имхо… ардуино ИДЕ - убожество, да и многие другие, по сравнению с атмел студио.
при необходимости достаточно посидеть несколько часов над основными библиотеками ардуино и перетащить их на студию для удобства.

Sir_Alex
mahowik:

Кто на чем пишет под arduino?

UltraEdit )))

На днях прикрутили проект пирата к Eclipse… но по факту получилось только компиляция. Ошибки он не подсвечивает (точнее у него ошибка практически в каждой строке)

mahowik
mataor:

имхо… ардуино ИДЕ - убожество, да и многие другие, по сравнению с атмел студио.
при необходимости достаточно посидеть несколько часов над основными библиотеками ардуино и перетащить их на студию для удобства.

в том и дело Visual Studio + Visual Micro pluggin работает почти из коробки и ниче перетаскивать не надо… показал ей где ардуино фолдэр, открыл главный ino файл и готово!

SergDoc
Sir_Alex:

На днях прикрутили проект пирата к Eclipse…

а можно поподробней? я пытаюсь сейчас AutoQuad32 перетянуть - пока безуспешно (*.ino в *.срр интересно можно просто переименовать, а то гцц может и не понять что за фигня - далее знаю где подключается, так что изменить не проблема), с моими кривыми ручками это надолго - ибо переписываю makefile…

mataor
SergDoc:

*.ino в *.срр

попробуйте основной файл в .cpp а прочие в .h + придется разбиратся с переменными. По крайней мере в атмел студии я именно так и поступал.

SergDoc

у меня он единственный, сейчас компилятор наконец-то увидел (странно патчи прописывал как и раньше, а не пошло- пришлось ближе передвигать - …/…/ ), но ругается что правил для сборки нет, вот и думаю как безболезненно makefile переписать…

Sir_Alex
SergDoc:

а можно поподробней?

Ну суть в том, что у нас есть makefile, который собирает Пирата с использованием Cygwin + Arduino. Т.е. все работает из командной строки.
Теперь создаем “C” проект в Eclipse и подключаем наш makefile. Вот и все. Если сделать Build, то Eclipse подсвечивает ошибки в исходниках, но как только открываешь файлы, он начинает ругаться практически на все, т.к. не может сам проверить исходники. В общем, хоть что то и можно делать, но по сути не сильно отличается от обычного редактора 😦

Вероятно надо менять структуру исходников на нормальный C или C++ и после этого пользоваться любой средой, как Eclipse, так и Atmel…

SergDoc

у мультипилота pde рулит, но там не ардуино, а Cygwin+maple, библиотеки теже…

блин тема моя разрослась - фиг чего найдёшь - в папочке Librares - библиотеки ардупилота…
патчи выглядят так: …\…\…\eclipse;…\…\…\arm\bin;…\…\…\cygwin\bin;…\…\…\openocd\bin;…\…\…\ST-LINK_gdbserver

11 days later
biglev

Уважаемые! Хочу поделиться вопросом, а в перспективе - добиться (не без вашего совета) решения в следущем проекте: Измеритель вибрации (а конкретно амплитуды виброперемещения) по 3 осям с помощью акселерометра ADXL335, Ардуины и 1602 дисплея (для мобильности).
Вопрос: По какому принципу данные с акселерометра в Ардуине пересчитать в мм/с (или, к примеру, создать свою шкалу единиц (0…1000))? Какие формулы использовать?
На ровной поверхности, в состоянии покоя (1g) на выходе каждой оси примерно 330mV. И это напряжение меняется от углов наклона акселерометра.
Хочу мобильное устройство для контроля уровня вибрации двигателей коптера в поле. Телефон и планшет с g-сенсором не предлогать;) Думаю, кто-нибудь сможет найти данному устройству другое применение.

SergDoc

ну дык, если вся шкала АЦП 1024 - 5В если не поизвращатся с Aref проца (напряжение на нём - верхний предел для АЦП - не забыть выставить external) - отсюда и плясать… лучше всего посмотреть в даташит - какое максимальное напряжение на выходе акселя может быть, такое же и выставить Aref…

Sir_Alex

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

Probelzaelo
mahowik:

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

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