Нужна помощь в понимании скетча

nail2007
Offline
Зарегистрирован: 08.12.2017

Здравствуйте!

У меня есть задача - измерить колебания руки с помощью акселерометра.

у меня аксель mpu6050. нашел для него и библиотеку и код для просмотра работы.

так же нашел по сути готовый теоретический алгоритм "как измерить частоту". Но я не пойму как мне сделать пару вещей в коде.

Это код с одного из сайтов на просторах интернета:

#include <I2Cdev.h>
 
#include <MPU6050.h>
 
#define T_OUT 20
 
MPU6050 accel;
 
unsigned long int t_next;
 
void setup() {
    Serial.begin(9600);
    accel.initialize();
    Serial.println(accel.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}
 
void loop() {
    long int t = millis();
    if( t_next < t ){
        int16_t ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw;
 
        t_next = t + T_OUT;
        accel.getMotion6(&ax_raw, &ay_raw, &az_raw, &gx_raw, &gy_raw, &gz_raw);
 
        Serial.println(ax_raw); // вывод в порт проекции ускорения на ось Y
    }
}
 
Это то, что я нашел по своей теме
 
не пойму вот что: как мне написать кодом а1 и а2? 
В голове не укладывается как два последовательных ускорения получить в коде.
Скорее всего ответ достаточно простой, но я ,к сожалению, не частый пользователь ардуино.
А эту фиговину мне нужно сделать для одного отчета. (я студент-медик)
 
Заранее благодарю за конструктивную критику и ответы) 
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Мне кажется, приведенный текст тоже писал студент-медик.

nik182
Offline
Зарегистрирован: 04.05.2015

Да нет, медику писать ещё кто то помогал, вот только не разберусь кто - физик или матаматик.

Ну и стандартная рекомендация ТС прочитать в песочнице правила форума и вставить скетч правильно. 

По программе. В терминал что либо выводится? 

В статье описано что а1 и а2 это два последовавательно полученных ускорения, а получаете и выводите только одно. Присвойте этому значению имя а1. Добавте строчек со вторым вызовом функии получения ускорения с необходимой задержкой. Это будет а2. Дальше  в статье описано как считать. 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016
 int16_t a1x_raw, a1y_raw, a1z_raw, g1x_raw, g1y_raw, g1z_raw;
 int16_t a2x_raw, a2y_raw, a2z_raw, g2x_raw, g2y_raw, g2z_raw;

и далее два раза последовательно читаем в эти переменные

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

nik182, еще раз посмотрите на (1.2). Какие физики с математиками!

nik182
Offline
Зарегистрирован: 04.05.2015

Ну с точки зрения что внутри  модуля все члены положительные и изначальная формула подверглась принудительной модификации для ухода от плагиата путем внесения дельты под модуль с нарушением некоторых правил математики все ж склоняюсь к физику. 

nail2007
Offline
Зарегистрирован: 08.12.2017

Здравствуйте!

Прошу прощения за нарушение правил форума! Исправлюсь

Про терминал немного непонятно, т.к. не в курсе что это)

Ок, понял на счет вызова а1 и а2, а вот задержку через что расписать?

nail2007
Offline
Зарегистрирован: 08.12.2017
#include <I2Cdev.h>

#include <MPU6050.h>

#define T_OUT 20

int a1; //переменная для а1
int a2; //переменная для а2
int da; //переменная для дельты
int k; //переменная для подсчета а1-а2-да
int n; //количество колебаний
int v; //переменная частоты



MPU6050 accel;

unsigned long int t_next;

void setup() {
    Serial.begin(9600);
    a1 = 0;
    accel.initialize();
    Serial.println(accel.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
    long int t = millis();
    if( t_next < t ){
        int16_t a1x_raw, a1y_raw, a1z_raw, g1x_raw, g1y_raw, g1z_raw; //вызываем в первый раз значения ускорений
        int16_t a2x_raw, a2y_raw, a2z_raw, g2x_raw, g2y_raw, g2z_raw; //вызываем во второй раз их

        t_next = t + T_OUT; //не могу понять для чего эта строка и следующие две 
        accel.getMotion6(&a1x_raw, &a1y_raw, &a1z_raw, &g1x_raw, &g1y_raw, &g1z_raw); 
        accel.getMotion6(&a2x_raw, &a2y_raw, &a2z_raw, &g2x_raw, &g2y_raw, &g2z_raw);

       a1=a1x_raw; //иду по алгоритму статьи
       a2=a2x_raw;

       da=a1-a2;
       abs(da);
       k=a1-a2-da;
       abs(k);

       if (k!=0) {
        n=2*k;
       }

       v=n/1000;
 
        Serial.println(v); 
    }
}

 

nail2007
Offline
Зарегистрирован: 08.12.2017

Здравствуйте!

Вроде понял, выше прислал написанный код. 

Скорее всего там ошибки (уверен, что они есть). 

В чем я теперь неправ в данном случае?

nail2007
Offline
Зарегистрирован: 08.12.2017

ua6em, я тут вот собрал что-то похожее на код, на какие строки обратить мне внимание? естественно код не работает)))

#include <I2Cdev.h>
#include <MPU6050.h>

#define T_OUT 20

int a1; //переменная для а1
int a2; //переменная для а2
int da; //переменная для дельты
int k; //переменная для подсчета а1-а2-да
int n; //количество колебаний
int v; //переменная частоты
MPU6050 accel;
unsigned long int t_next;

void setup() {
    Serial.begin(9600);
    a1 = 0;
    accel.initialize();
    Serial.println(accel.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
  
        int16_t a1x_raw, a1y_raw, a1z_raw, g1x_raw, g1y_raw, g1z_raw; //вызываем в первый раз значения ускорений
        int16_t a2x_raw, a2y_raw, a2z_raw, g2x_raw, g2y_raw, g2z_raw; //вызываем во второй раз их
 
        accel.getMotion6(&a1x_raw, &a1y_raw, &a1z_raw, &g1x_raw, &g1y_raw, &g1z_raw); //запрашиваем значения ускорений с датчика
        accel.getMotion6(&a2x_raw, &a2y_raw, &a2z_raw, &g2x_raw, &g2y_raw, &g2z_raw);

       a1=a1x_raw; //иду по алгоритму статьи
       a2=a2x_raw;

       da=a1-a2;
       abs(da);
       k=a1 - a2 - da;
       abs(k);

       if (k!=0) {
        n=  2 * k;
       }

       v=n/1000;
 
        Serial.println(v);
        delay(50); 
}

 

nik182
Offline
Зарегистрирован: 04.05.2015

Мы с коллегой аndriano пытались донести, что формула расчета несколько бредовая. Иначальная формула приводит к условию  if(abs(a1-a2 ) > da) . Её и надо использовать для выбора.

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

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Думаю, что если пациента колотит, то хватит измерения и по одной оси ))

nail2007
Offline
Зарегистрирован: 08.12.2017

nik182 ,можно с Вами связаться в вконтакте? 

nik182
Offline
Зарегистрирован: 04.05.2015

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

nik182
Offline
Зарегистрирован: 04.05.2015

У меня нет вконтакте. Только здесь. Помочь могу советами. Я разлучен с компами ещё на неделю. Только телефон с лимитом интернета. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Надо бы у студента-медика спросить чего он там фиксировать собрался. Боюсь, что будет как всегда: вы тут теорий настроите, а ему нужно просто мотания крышечки на кипящем чайнике померять.

nail2007
Offline
Зарегистрирован: 08.12.2017

sadman41, мерять я собрался колебания руки (тремор). на счет сложения ускорений я задумался. но я врядли смогу это реализовать..

nik182
Offline
Зарегистрирован: 04.05.2015

Ну то что я писал про полное ускорение датчика и на крышечке будет работать правильно. Нет никаких препятствий. 

nail2007
Offline
Зарегистрирован: 08.12.2017

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

Как я понял, нужно их еще делить на 16384 из-за частоты дискретизации

nail2007
Offline
Зарегистрирован: 08.12.2017

хотя нет, по сути тремор в двух осях. например по Z и Х

sadman41
Offline
Зарегистрирован: 19.10.2016

Мне вот какой вопрос интересен: есть какой-то стандартный тремор, чтобы на нем откалиброваться? Т.е. в чем прикладное значение этой петрушки - автоматически определять пациента с белой горячкой?

nail2007
Offline
Зарегистрирован: 08.12.2017

sadman41, нет. стандартного тремора нет. их несколько подвидов.

значение моей петрушки состоит в том, чтобы просто узнать частоту колебаний руки.

мне не важна большая точность. мне нужно, чтобы я получил частоту, по таблице определил примерный вид тремора.

по поводу ускорений - да, возможно стоит по теореме пифагора находить общее из двух. 

 

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

Поэтому у меня сейчас самая главная проблема - измерение частоты

nail2007
Offline
Зарегистрирован: 08.12.2017

если только откалиброваться на известном пациенте. Но такие найдутся после того, как я запущу шайтан петрушку) 

nik182
Offline
Зарегистрирован: 04.05.2015

nail2007 пишет:

sadman41, мерять я собрался колебания руки (тремор). на счет сложения ускорений я задумался. но я врядли смогу это реализовать..

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Т.е. придётся не просто два измерения делать, а постоянно измерять и на некий экстремум опираться. В противном случае дельта может ничего и не дать. На сколько там за 8мс рука передвинется, к примеру?

nail2007
Offline
Зарегистрирован: 08.12.2017

такие данные получаю с помощью скетча-примера

-7000
-7104
-7036
-6048
-6504
-7528
-5652
-2284
572
1044
3140
4000
3372
3080
2876
 
 
nail2007
Offline
Зарегистрирован: 08.12.2017

sadman41 ,с Вами можно связаться помимо этого форума?

sadman41
Offline
Зарегистрирован: 19.10.2016

А что вы хотите узнать там, чего не можете спросить тут? Я таких задач не решал, поэтому мне тоже интересно узнать как можно частоту колебаний сложной механической системы вычислить.

nail2007
Offline
Зарегистрирован: 08.12.2017

sadman41, хотел уточнить вопрос про данные с акселерометра.

они голые, не стандартизированные. я нашел пар формул, там вроде люди переводят в человеч. вид

(((float)ax/(float)16384)*9.8*0.05*0.05)

и просто деление на 16384.

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

Думаю, что если пациента колотит, то хватит измерения и по одной оси ))

 о чём и речь...да и дельта с датчика закреплённого на столе и на руке будет совсем разная

nik182
Offline
Зарегистрирован: 04.05.2015

В данном случае получить частоту достаточно просто. Не нужно даже второго измерения. В цикле считаем полное ускорение по сумме квадратов трёх осей. Ищем и запоминаем максимальное значение и его время. Одновременно ищем и запоминаем минимальное время. Разница времени максимума и минимума равна четверти периода частоты. Делим 4 на период и получаем частоту. Выводим. 

Обнуляем все и ищем снова. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

sadman41 пишет:

А что вы хотите узнать там, чего не можете спросить тут? Я таких задач не решал, поэтому мне тоже интересно узнать как можно частоту колебаний сложной механической системы вычислить.

теорема Котельникова она универсальная )))

nik182
Offline
Зарегистрирован: 04.05.2015

Вам не нужно абсолютное значение ускорения. Забудьте о нем. Вам нужны максимумы и минимумы. Их время, от того вы их будете умножать на коэффициенты не изменится.

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

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

nik182 пишет:

В данном случае получить частоту достаточно просто. Не нужно даже второго измерения. В цикле считаем полное ускорение по сумме квадратов трёх осей. Ищем и запоминаем максимальное значение и его время. Одновременно ищем и запоминаем минимальное время. Разница времени максимума и минимума равна четверти периода частоты. Делим 4 на период и получаем частоту. Выводим. 

Обнуляем все и ищем снова. 

пол периода, умножать надо на два

sadman41
Offline
Зарегистрирован: 19.10.2016

В идеальном случае да - есть и монотонность нарастания значения и максимумы более-менее близки по значению. Но тут же тремор - т.е. даже монотонности может не быть. Как это обойти?

nik182
Offline
Зарегистрирован: 04.05.2015

ua6em пишет:

sadman41 пишет:

А что вы хотите узнать там, чего не можете спросить тут? Я таких задач не решал, поэтому мне тоже интересно узнать как можно частоту колебаний сложной механической системы вычислить.

теорема Котельникова она универсальная )))

Простите ещё раз. Объясните пожалуйста какую конкретно информацию Вы хотели донести в рамках обсуждения текущего вопроса? В отвлеченных темах есть про шутки. Может быть лучше было написать туда? Судя по представленному выводу данных до критерия Котельникова ещё настолько далеко, что упоминание его теореммы больше как попытку пошуть больше ни как не воспринимается. 

nik182
Offline
Зарегистрирован: 04.05.2015

ua6em пишет:

nik182 пишет:

В данном случае получить частоту достаточно просто. Не нужно даже второго измерения. В цикле считаем полное ускорение по сумме квадратов трёх осей. Ищем и запоминаем максимальное значение и его время. Одновременно ищем и запоминаем минимальное время. Разница времени максимума и минимума равна четверти периода частоты. Делим 4 на период и получаем частоту. Выводим. 

Обнуляем все и ищем снова. 

пол периода, умножать надо на два

И снова мимо. Это ускорение. Производная. Квадрат. Максимум и минимум в нулях и максимумах амплитуды. 4 раза за период. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

я датчик не сильно пытал, если действительно выдаёт ускорения, тогда да, но всё равно умножить на 4 и далее 1/тау будет частота...
а по теореме, в скетче задержка в 50 миллисекунд, а тремор он разный, частотный диапазон мы не услышали, в идеале частота измерений должна быть выше хотя бы на порядок, а по ускорению, то минимум в 8 раз

nik182
Offline
Зарегистрирован: 04.05.2015

Посмотрите на свою руку при попытке подрожать. Сотни милисекнд. Вы даже кистью потрясти быстрее 200 мс на период не сможете. В скетче нет задержки. Я еще не смотрел датчик, но в приведенном выводе 20 точет на пол периода. Хватит ещё и верхние гармоники.

P.S. Вот скажите, зачем умножать и делить, если можно один раз разделить четверку? 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

по задержке - строка 45 скетча...
на ручном ключе я передавал со скоростью до 170 знаков в минуту, 170/60 = около 3 знаков в секунду, если это цифра то это 10 полных колебаний маятникового типа всей кисти руки, то есть период около 35 миллисекунд, и замечу, это не на мандраже )))
Это так - к слову, первый разряд это 120 знаков всего )))

nail2007
Offline
Зарегистрирован: 08.12.2017

Прошу прощения, что не озвучил диапазон частот. Для моих целей диапазон от 1 до 15Гц

 

nail2007
Offline
Зарегистрирован: 08.12.2017

nik182, каким образом мне посчитать макс и мин значения и еще времена их? Я просто сейчас ищу в интернете и не могу найти. Скорее всего неправильно забиваю ключевые слова. Может быть посоветуете какой-нибудь скетч или как найти такой?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

не знаю как nik182, а  я для надёжного определения пиковых значений измеряю их на четверть периоде 16 раз, то-есть для вашей пороговой частоты делал бы это с частотой 15*16*4 раз как - зацепил бы за таймер работающий с ткой периодичностью, вопрос только в том, способна ли эта гира отдавать значения с такой частотой, вроде бы должна, так сдедующее поколение гир работает на частоте аж 32 килогерца

sadman41
Offline
Зарегистрирован: 19.10.2016

nail2007 пишет:

nik182, каким образом мне посчитать макс и мин значения и еще времена их? 

Если я идею правильно понял, то вот так:

const uint32_t samplingTime = 1500; // ms

uint32_t startTime, nowTime, minValueDetectTime, maxValueDetectTime, detectTimeDelta;
int16_t minValue, maxValue, currentValue; 

minValue = INT_MAX;
maxValue = INT_MIN;

minValueDetectTime = maxValueDetectTime = 0x00
startTime = nowTime = millis();

while (nowTime - startTime >= samplingTime) {
   delay(???);
   currentValue = ...; // Some kind of Gyro magic
   nowTime = millis();
   if (maxValue < currentValue) {
      maxValueDetectTime = nowTime;
      maxValue = currentValue;
   }
   if (minValue > currentValue) {
      minValueDetectTime = nowTime; 
      minValue = currentValue;
   }
}

detectTimeDelta = abs(maxValueDetectTime - minValueDetectTime);

 

nik182
Offline
Зарегистрирован: 04.05.2015

Исправил вставку половины текста ниже. 

nik182
Offline
Зарегистрирован: 04.05.2015

Во блин! В сообщение пердало только половину текста. Обидно.

SADMAN41 почти точное попадание! 

nik182
Offline
Зарегистрирован: 04.05.2015

Зачем скетч. Напишите сам, а поправлю. Буду писать словами, а Вы просто постарайтесь это в программе. 

Обьявляем 3 перемные типа int  a amax amin, 2 переменные типа unsigned long tmax tmin, типа byte nmax nmin, типа bool fmax fmin. Ну и float частоту с любым именем. 

В сетапе amin присваиваем 32000, остальным нули.

В лупе

Вызываем п.п. акселерометра и расчитываем амплитуду а как сумму квадратов трёх измерений ускорения. 

Проверяем (if) флаг fmax, если false то делаем кучу работы: проверяем (if) amax, если а больше то присваиваем amax значение а, запоминаем через микрос значени tmax, обнуляем nmax. Иначе (else) величиваем nmax на 1 и проверяем. Если больше 50 (это чило в последствии уточним посмотрев на работу) то fmax=true;

Все тоже делаем с переменными с индексом min, только проверка а должа быть меньше аmin. 

Проверяем флаги fmax и fmin. Если оба true, то мы нашли все что надо, расчитываем и выводим частоту как 4. 0/(tmax-tmin), обнуляем все переменные, amin снова 32000

Это собственно все, в выводе будет частота максимальных колебаний. 

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

 

nik182
Offline
Зарегистрирован: 04.05.2015

Ещё, частота будет в мегагерцах. Чтобы получалось в герцах надо 4000000.0 делить ;-) 

nail2007
Offline
Зарегистрирован: 08.12.2017

nik182, проверьте, пожалуйста! еще раз прошу прощения, если вдруг там много глупых на Ваш взгляд ошибок

#include <I2Cdev.h>
#include <MPU6050.h>

int a; //переменная для полного ускорения
int amax;
int amin;
unsigned long tmax;
unsigned long tmin;
byte nmax;
byte nmin;
boolean fmax;
boolean fmin;
float v; 
MPU6050 accel;

void setup() {
    Serial.begin(9600);
    amin=32000;
    a=0;
    amax=0;
    tmax=0;
    tmin=0;
    nmax=0;
    nmin=0;
    fmax=0;
    fmin=0;
    v=0;
    accel.initialize();
    Serial.println(accel.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {

     int16_t ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw; //вызываем значения ускорений 
     accel.getMotion6(&ax_raw, &ay_raw, &az_raw, &gx_raw, &gy_raw, &gz_raw); //запрашиваем значения ускорений с датчика
     
     a=ax_raw*ax_raw+ay_raw*ay_raw+az_raw*az_raw; //сумма трех квадратов
     if (!fmax){
      if (a>amax){
        amax=a;
        tmax=micros();
        nmax=0;}
      }
     else{
      nmax++;
      if (nmax>50){
        fmax == true;}
      }

     if (!fmin){
      if (a<amin){
        amin=a;
        tmin=micros();
        nmin=0;}
      }
     else{
      nmin++;
      if (nmin>50){//тут так же оставить или меньше 50??
        fmin == true;}
      }
if (fmax == true && fmin == true){
 v=4000000.0/(tmax-tmin);
 Serial.println(v);   
    amin=32000;
    a=0;
    amax=0;
    tmax=0;
    tmin=0;
    nmax=0;
    nmin=0;
    fmax=0;
    fmin=0; 
 } 
}

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Ошибки в строках: 38, 50, 61, 45, 57... Это безотносительно алгоритма.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

sadman41 пишет:

Ошибки в строках: 38, 50, 61, 45, 57... Это безотносительно алгоритма.

Уважаемый ТС, чтобы избежать подобных ошибок стоит запомнить, что !true==false и наоборот !false==true и правильно записывать:

не if(fmin=false){ , а if(!fmin){