Помогите с датчиком пульса разобраться, пожалуйста

Тема в разделе "Arduino & Shields", создана пользователем iBoy, 8 июл 2016.

  1. iBoy

    iBoy Гик

    Очень срочно, пожалуйста, помогите разобраться с датчиком пульса!!! Проблема такая: его сигнал преобразуется через функцию, которая прекрасно работает сама по себе, но с дополнительным кодом она выдаёт какие-то непонятные значения по нарастающей.
    Проект такой: к велотренажёру присоединяется кольцо, к которому присоединены 3 линии герконов. К педали тренажёра крепится магнит. Когда педаль вертится, магнит включает поочерёдно разные линии герконов. Сигнал герконов получает Ардуино Леонардо, который их обрабатывает, и, в случае если педаль вертят - он посылает на комп сигнал, аналогичный нажатию клавиши W. Это используется в играх: вместо клавиатуры играешь тренажёром и игровой мышкой(клавиша W отвечает за движение вперёд.). Также тренажёр должен штрафовать за то, что пользователь не крутит педали и подстраиваться под пульс(чем он больше, тем быстрее он пишет W). Вот код с комментариями:

    Код (C++):
    #include <Keyboard.h>
    #define butPin 4
    #define DELT 25
    #define ozhidaniye 70


    int pulse[2];
    bool vect[2];
    unsigned long timerPuls;
    boolean was_Active;
    boolean is_Active;
    const int x = 10;
    boolean ochko1;
    boolean ochko3;
    boolean ochko2;
    int i;
    int a;
    long t;
    long tt;
    long puls;

    void setup() {
      Serial.begin(9600);
      for (i = 3; i < 12; i++) {
        pinMode(i, INPUT);
      }
    }
    //

    void loop() {
      for (i = 7; i < 10; i++) {             //i - номер контакта
        if (digitalRead(i) == HIGH) {        //i-й контакт получает сигнал?
          was_Active = digitalRead(i+1);     //(i + 1)-й контакт активен? результат записать в переменную was_Active
          is_Active = false;                 //is_Active = false
          for(a=1; a<=x; a++){               //х раз
            if(digitalRead(i+1)==HIGH){      //Проверить, повернулись ли педали вперёд?
              is_Active = true;              //Если да, то is_Active = true
            }
            delay(ozhidaniye);               //Подождать(без этого ожидания пользователь, возможно, не успеет прокрутить педали)
          }
          if (is_Active != was_Active){      //Если правдивость того факта, что i-й контакт получает сигнал изменилась(т.е. педали повернулись вперёд), то
            t = millis();                    //засечь время и записать его в t
            label:                           //метка
            for(long r=1; r<=6; r++){        //6 раз
              int puls = pulsFunction();     //замерить пульс(это сделано 6 раз, т.к. функция измерения использует функцию millis(), но она не рассчитана на то, что кроме неё ещё что-то делают, поэтому на измерения уходит лишний круг. 3-4 круга программа тратит на стабилизацию показаний. 1-2 круга измерений в запасе.
            }
            if(puls==0){                     //если функция вернула 0, это значит, что она ничего не вернула(вроде бы). Поэтому в этом случае
              goto label;                    //функция возвращается к измерениям
            }
          Serial.println(puls);              //показать пульс
          if (digitalRead(butPin) == HIGH) { //если кнопка нажата,
            Keyboard.press('w');             //Зажать(не нажать, а именно зажать) "W"
            Serial.print(puls*7);            //Отчёт
            Serial.println(" secund budet nazhato W");
            delay(puls*7);                   //Ждать (значение пульса*7 милисекунд)
            Keyboard.release('w');           //И вот только теперь отпустить "W"
          }
        }
        else{
          tt = millis();                     //Засечь время
          if (tt - t >= 2500) {              //Если прошло много времени с момента, когда в последний раз крутились педали
            shtraf();                        //Тогда штрафовать
          }
        }
        }
      }
    }
    void shtraf() {                          //процедура штрафа работает, как часы, поэтому я не буду её комментировать
      if (digitalRead(7) == HIGH) {  
        ochko1 = true;
        delay(100);
      }
      if (digitalRead(8) == HIGH) {
        ochko2 = true;
        delay(100);
      }
      if (digitalRead(9) == HIGH) {
        ochko3 = true;
        delay(100);
      }
      if ((ochko1 == false) || (ochko2 == false) || (ochko3 == false)) {
        Serial.println("shtrafuem");
        Serial.println(ochko1);
        Serial.println(ochko2);
        Serial.println(ochko3);
        Keyboard.press('s');
        delay(200);
        Keyboard.press('a');
        delay(300);
        Keyboard.release('a');
        Keyboard.press('d');
        delay(500);
        Keyboard.release('s');
        Keyboard.release('d');
        delay(1000);
        shtraf();
      }
      if ((ochko1 == true) && (ochko2 == true) && (ochko3 == true)) {
        ochko1 = false;
        ochko2 = false;
        ochko3 = false;
      }
    }

    int pulsFunction(){                           //Датчик пульса выдаёт показания в виде цифр, обозначающих, так сказть, кардиаграмму
      vect[0] = (pulse[1] > (pulse[0] + DELT));   //В каком направлении изменился пульс? Записать в переменную vect0
      pulse[0] = pulse[1];                        //На этой и следующей строчках программы обновляются показания датчика
      pulse[1] = analogRead(A0);          
      vect[1] = (pulse[1] > (pulse[0] + DELT));   //В каком направлении изменился пульс? Записать в переменную vect1
      if (!vect[0] && vect[1]) {                  //Если показания датчика выглядят, как удар на кардиограмме(см. в конце программы),
        return(60000/(millis()-timerPuls));       //то передать вызывающей функции 60000(millis()-timerPuls) - это время, которое прошло с того момента, как в прошлый раз был засечён удар(см. следующую строку)
        timerPuls = millis();                     //Засечь время
      }
      delay(50);                                  //Подождать 50 милисекунд(иначе за каждый цикл функции изменения будут ничтожно малы, и их будет не отличить от шумов)
    }
    /*Представим себе кардиограмму. Она имеет примерно такой вид:

                0
               1 2
              1   2
             1     2
            1       2
      000000         2 00000000000000000000000000...
                      2
    Единицами я отметил те точки, которые функция засекает на 106-й строке, двойками - на 109-йЕсли сначала показания значительно росли, а потом значительно падали, это значит, что это удар

    */

     
    Заранее невероятное спасибо!!!!
     
    Последнее редактирование: 8 июл 2016
  2. ostrov

    ostrov Гуру

    Не проще и не правильнее ли скорость движения прикрутить к скорости вращения педалей?
     
  3. iBoy

    iBoy Гик

    Спасибо, но я тоже об этом думал. Но, к сожалению, у всех людей нагрузка для достижения одной скорости разная. Т.е. если человек, физически не очень выносливый начнёт крутить педали с нужной физически сильному скоростью, у него может быть перегрузка. Пульсометр нужен ещё и для защиты от перегрузки.
     
  4. ostrov

    ostrov Гуру

    А в случае с пульсом получися другая крайность. Тренированый будет быстро крутить и медленно ехать, а толстый или больной наоборот.
     
  5. iBoy

    iBoy Гик

    Кардиотренировка предполагает тренировку, как можно дольше при определённом пульсе. А нагрузки, требуемые одному и тому же человеку для достижения какого-то пульса, могут изменяться даже в течении дня.
     
  6. ostrov

    ostrov Гуру

    И вообще, если вы делаете имитатор велосипеда, то схема педали-скорость должна быть сложнее чем прямая зависимость. На велике то крутишь, то едешь по инерции, программа это должна учитывать.
     
  7. ostrov

    ostrov Гуру

    А, так у вас медицинское, по сути, оборудование? Не боитесь доверять этому, вобщем то, не очень точному и надежному датчику?
     
    iBoy нравится это.
  8. iBoy

    iBoy Гик

    Это не совсем имитация велика. Это присоединяется к компу с целью имитировать движение в играх, а не с целью имитировать велик. Клавиша W отвечает за движение вперёд в большинстве игр. Т.е. Вам, например, скучно тренироваться в зале, а вы вместо этого садитесь и, играя в игру, тренируетесь. Крутите педали и бежите вперёд в RPG или едете в гонке.
     
  9. iBoy

    iBoy Гик

    Ну, ошибка этого датчика +- 10 ударов. В моих целях это - приемлемая ошибка. Всё таки, это не медицинское оборудование.
     
  10. ostrov

    ostrov Гуру

    Еще руль задействовать и можно в танчики играть. ))
     
  11. iBoy

    iBoy Гик

    Ну да. Я вместо этого взял игровую мышку.
     
  12. iBoy

    iBoy Гик

    Только с пульсом такая проблема:(
     
  13. ostrov

    ostrov Гуру

    Леонардо может и мышку эмулировать.
     
    iBoy нравится это.
  14. iBoy

    iBoy Гик

    Да. Только мне не нужно мышь имитировать - только движение вперёд. Помогите мне, пожалуйста. Мне этот проект надо сдавать, а у меня осталось только 9 дней. Есть другая версия, с другим датчиком, но она крайне корявая.
     
  15. ostrov

    ostrov Гуру

    У вас изначально программа не правильно построена. У вас действия последовательные, одно за другим. А надо одновременно. Чтобы все измерения пролетали без задержки и реакции на них тоже.
     
    iBoy нравится это.
  16. iBoy

    iBoy Гик

    Спасибо огромное за помощь, заранее. Правда, как показала практика, это происходит всё достаточно быстро, чтобы пользователь не заметил, что всё происходит по порядку.
     
  17. iBoy

    iBoy Гик

    Меня, впринципе, устраивает в проге всё, кроме работы датчика
     
  18. ostrov

    ostrov Гуру

    Делеи не дадут сделать все гладко.
     
    iBoy нравится это.
  19. ostrov

    ostrov Гуру

    Датчик должен считываться каждые 25мс, а у вас задержки по секунде.
     
    iBoy нравится это.
  20. iBoy

    iBoy Гик

    Спасибо, но пока что это не самая насущная проблема - леонардо достаточно быстро всё пробегает, даже с делэями. А там где они есть, и должно быть торможение(в процедуре штрафования и когда печатается W