Добрый день, коллеги. Разбираюсь с джойстиком. Хочу посчитать угол (в градусах) отклонения ручки джойстика относительно оси Х. Т.к. в ардуине нет функций arcsin (arccos) решил решить задачу в лоб, и получать угол через таблицу синусов. Т.е. при отклонении джойстика, считать синус угла через величины отклонений по осям и искать это значение в таблице. Ниже код, который я наваял. Код (C++): #define X A1 #define Y A0 #define Z A2 int mSin[360]; int prevSin = 0; int coef = 10000; void setup() { //формирование массива синусов for(int i=0; i<=359; i++) { float rad = i * 3.14 / 180; mSin[i] = int(sin(rad) * coef); //умножение для подтягивания значений в диапазон int } Serial.begin(9600); /* //посмотреть на массив for(int i=0; i<=359; i++) { Serial.println((String) "a: " + i + " sin: " + mSin[i]); } */ } void loop() { // переменные для хранения значений // отклонения джойстика по осям X и Y int x, y; // считываем текущее значение джойстика x = readJoystick(X); y = readJoystick(Y); float c2 = sqrt(sq(x) + sq(y)); int mySin = int(y/c2 * coef); //умножение для подтягивания значений в диапазон int /* //проверка значения синуса if(prevSin != mySin) { Serial.println((String) "X= " + x + " Y= " + y + " Sin = " + mySin); prevSin = mySin; } */ //Предыдущая версия, которая тоже не работает. /* int i = -1; do i++; while(mSin[i] != mySin && i < 360); */ int i = 0; while(mSin[i] != mySin && i < 360) { i++; } if(prevSin != mySin) { Serial.println((String) "X= " + x + " Y= " + y + " Sin = " + mySin + " ug = " + i); prevSin = mySin; } } int readJoystick(int axis) { int val = analogRead(axis); val = map(val, 0, 1023, -100, 100); if(val <= 10 && val >= -10) return 0; else return val; } Собственно, проблема в том, что при поиске угла, переменная i принимает значение значительно больше 360 (1800, например). И я не понимаю, почему это происходит. В условии цикла стоит i<360, т.е. не может она быть больше. Подскажите, пожалуйста, что я не так делаю? Может я вообще не тот способ выбрал?
Переделайте условие. Ваше значение должно попадать в диапазон между предыдущим синусом и текущим или текущим и следующим.
Спасибо. Частично помогло. Я не учел, что могут быть большие расхождения при расчете значения синуса. Но все равно пришлось еще ограничивать значения x и y в определенных интервалах, и учитывать эти интервалы в расчетах.
А вот у меня тот самый матрёшка-джойстик В нули не возвращается. отклонение на сотню с лишним. Он никак не калибруется случайно?
Джойстик у меня всего один и не Амперка. Судя по видео и фоткам на Амперке сами исполнительные механизмы похожи, разница только в платах. У меня джойстик возвращается в ноль без проблем и уверенно. Какого-то большого люфта нуля я не заметил. Калибровка ему не нужна. Может быть имеет смысл посмотреть код? Может там какой множитель стоит эдак на 10 или 100. Вот Вам и отклонение от нуля. Мало ли. Ну и брак элемента тоже возможен. Может там возвратная пружина отвалилась или растянулась.
Очень похоже на то, что в компиляторе avr-gcc присутствует баг. Дело в том, что строки кода: Код (C++): int i = 0; while(mSin[i] != mySin && i < 360) { i++; } компилятор оптимизирует до: Код (C++): int i = 0; while(mSin[i] != mySin) { i++; } Т.е. он считает, что раз 'int i = 0;', то условие 'i < 360' всегда истина и выкидывает проверку этого условия, не учитывая того обстоятельства, что переменная 'i' меняется в теле цикла. Вот теперь интересно -- этот баг только в avr-gcc или во всей линейке GCC? И как теперь после этого код сочинять? PS: проблему решает Код (C++): volatile int i = 0; while(mSin[i] != mySin && i < 360) { i++; }
Интересный момент. А как Вы посмотрели, что он скомпилировал? Декомпилировали двоичный код? Собственно, декомпилировать можно до уровня ассемблера (не слишком сложно), а вот как до высокого уровня? Интересно, а без volatile обойтись получится? Например, объявить переменную в начале процедуры и потом присвоить ей 0?
Не фигурирует. Не очень понимаю как эта опция (определяющая размерность целых) влияет на то, что компилятор генерирует код, который не проверяет условие 'i < 360'?
Дело не в однобайтовости, а в том, что компилятор создаёт код, в котором отсутствует проверка условия. PS: вроде пытался ясно выразить мысль, которая заключается не в том, что условие не выполняется, а в том, что оно вообще не проверяется.