Помогите пожалуйста! Это очень срочно! Цель такая: Есть велотренажёр. Его задача - считывать вращение педалей и посылать сигнал на комп, от которого будет ехать вперёд гоночная машина. Причём ехать она должна тем быстрее, чем выше нагрузка(а значит и пульс). Также есть штраф на случай, если педали не крутят. И есть кнопка, которая отключает движение вперёд но не штраф. В итоге получается такая импровизированная приставка. Это всё представляется на конкурс, дедлайн уже совсем скоро - 28 января. Итого: есть код с вот такими задачами: - Он должен имитировать зажатие W(именно зажатие, не нажатие), если по порядку замыкаются герконы(посредством вращения магнита), подключённые к трём контактам. - Делать предыдущее действие он должен делать с перерывом, который высчитывается по формуле, которая там вписана в код. Зависеть этот перерыв должен от показаний датчика пульса, выходным сигналом которого является кардиограмма. - В случае, если отпущена кнопка первое действие не выполнять - Если в течение некоторого времени не замыкаются герконы, он должен делать штраф в виде имитации зажатия S, A, D Проблема заключается в том, что, почему то, он через небольшое время он просто берёт и перестаёт что-либо делать - как будто в ардуино загрузили пустой код. Я пробовал менять номера пинов и сами ардуины. Я даже на всякий случай менял провода. Но это всё не помогло. Вот такой код: Код (C++): #include <TimerThree.h> //Это библиотека, которая позволяет использовать таймер с целью каждые n микросекунд обращаться к какой-то функции. Подробнее про неё можно почитать здесь: https://www.pjrc.com/teensy/td_libs_TimerOne.html #include <Keyboard.h> #define butPin 4 #define DELT 75 #define waiting1 10000 #define waiting2 80 #define waiting3 5500 #define waiting4 9000 #define chislitel 2000 #define x 30 #define pulsePin A0 #define pokazatel_stepenyi 3 unsigned long puls_ex; //saadsadsadsadsa unsigned long puls = 0; volatile int pulse[2] = {0, 0}; volatile bool vect[2]; volatile unsigned long lastTimerPuls = 0; volatile unsigned long currTimerPuls = 0; bool ochko[4]; long t; int j; int i; // void setup() { Timer3.initialize(40000); Timer3.attachInterrupt(pulsFunction); Serial.begin(9600); for (i = 3; i < 12; i++) { pinMode(i, INPUT_PULLUP); } delay(waiting1); } //saddssadssadsad void loop() { bool flag = false; //Назовём флагом факт вращения магнита вокруг герконов for (i = 7; i < 10; i++) { if (digitalRead(i) == LOW) { //Если i-й геркон замкнут bool was_Active = !digitalRead(i + 1); //Тогда проверить, не замкнут ли ещё и i+1-й bool is_Active = false; //Назовём факт замкнутости i+1-го геркона именем is_Active for (j = 1; j <= x; j++) { //Этот цикл For является ожиданием, пока магнит не сдвинут if (digitalRead(i + 1) == LOW) { is_Active = true; break; } delay(waiting2); } if (is_Active != was_Active) { //Если магнит сдвинулся(т.е. i+1-й геркон поменял состояние) flag = true; //Считать, что магнит вращают Serial.println("Ok"); //Сообщить об этом break; } } } if (flag) //Если таки магнит вращали { t = millis(); //Засечь время(это дальше понадобится) puls_ex = 0; noInterrupts(); //Дабы исключить возможность обращения к puls в момент присвония, запртим прерывания puls_ex = puls; //Назовём конечные обработанные показания датчика puls_ex interrupts(); Serial.println(puls_ex); //Вывести конечнгые и бработанные показания датчика Serial.println(digitalRead(butPin)); //Если нажат переключатель if (digitalRead(butPin) == LOW) //Отчитаться об этом { Serial.println("the button is high"); Keyboard.press('w'); //Зажать(именно зажать, а не нажать) "W" Serial.print(chislitel / (pow((puls_ex + 1), pokazatel_stepenyi))); //Вывести преобразование, которое произойдёт через несколько строк Serial.println(" secund ne budet nazhato W, a istcho papa lutshiy");// delay(waiting3); //В течение всего этого времени не будет зажато "W" Keyboard.release('w'); //Отпустить "W" delay(1000 * chislitel / (pow((puls_ex + 1), pokazatel_stepenyi))); //Ждать до следующего нажатия определённое время. Единица добавляется для исключения деления на ноль } } else { //Если же магнит не вращали if (millis() - t >= waiting4) { //И с последнего момента вращения прошло достаточно времени shtraf(); //Тогда штрафовать } } } void shtraf() { //Процедура штрафа for (j = 7; j <= 9; j++) { //Здесь идёт проверка на замкнутость каждого геркона if (digitalRead(j) == LOW) { //В случае, если геркон замкнут, ochko[j-6] = true; //Назовём этот факт очком этой цепи } } if ((ochko[1] == false) || (ochko[2] == false) || (ochko[3] == false)) { //Если хотя бы одна цепь не разу не замыкалась, Serial.println("shtrafuem"); //Отчитаться Serial.println(ochko[1]); //В этой последующих двух строчках выводятся очки цепей с целью определить, что именно не замкнуто Serial.println(ochko[2]); Serial.println(ochko[3]); 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(100); shtraf(); } if ((ochko[1] == true) && (ochko[2] == true) && (ochko[3] == true)) { //А если же все цепи уже замыкались ochko[1] = false; //На этой и двух последующих строках обнуляются все очки ochko[2] = false; ochko[3] = false; Serial.println("konets shtrafa"); //Отчёт о конце штрафа } } void pulsFunction() { //Датчик пульса выдаёт показания в виде цифр, обозначающих, так сказть, кардиаграмму vect[0] = (pulse[1] > (pulse[0] + DELT)); //Назовём vect[0] старое направление кардиограммы, pulse[0] - старые конкретные показания, pulse[1] - новые. Тогда, pulse[0] = pulse[1]; //Обновить показания датчика pulse[1] = analogRead(pulsePin); //Считать показания датчика vect[1] = (pulse[1] > (pulse[0] + DELT)); if (vect[0] && !vect[1]) { //Если старое направление кардиограмамы - вверх, а новое - вниз, т.е. произошёл пик кардиограммы currTimerPuls = millis(); //Засечь время puls = (60000 / (currTimerPuls - lastTimerPuls + 5)); /*По сути, пульс - это частота сердечных сокращений(а значит и обращений к нашей функции) в минуту, тоесть можно считать, что если 60 секунд разделить на время, прошедшее с последнего обращения, мы получим пульс*/ lastTimerPuls = currTimerPuls; //Обновить временной счётчик } }
Я так понял, что плохо работает именно определитель вращения. Смотрим по коду. Вы не написали, по коду разбираю, что герконы подключены к 7,8 и 9 пинам. Тогда вот этот код if (digitalRead(i + 1) == LOW) будет запрашивать 10 пин, что совсем не туда. Но я бы полностью переделал процедуру определения вращения. На велотренажере крутить педали в обратку не выйдет. Составляем таблицу возможных состояний герконов (опрашиваем каждый вход и собираем из битов байт). Состояний будет несколько: 011, 101, 110, 111(ни один не замкнут). Значит если предыдущее состояние было 101, а вновь считанное 110 (ну или другое, в зависимости какой геркон к какой ноге подключен), то педали крутят. Состояния 111 пропускаем. Идея понятна?
Может вручную прерывание по таймеру запустить? Недоверяю я этим библиотекам. Опять же может быть третий таймер с чем то другим пересекается? И вот тут уверены, что нукцию без скобок надо указывать? Timer3.attachInterrupt(pulsFunction);
Я, наверное, не очень хорошо объяснил. Всё работает, однако почему-то вырубается через несколько минут использования. А насчёт определения вращения - состояний больше: Назовём нулём замкнутость, а 1 - незамкнутость: 111 - на практике его нет 011 101 110 001 010 100 000 - его тоже на практике нет Те состояния, где замкнуто по два геркона - самые частые. И ещё - по каким-то мистическим причинам работает вот такой код(причём нормально и правильно): Код (C++): // // // // // //sasaadsaddsadsad #include <TimerThree.h> #include <Keyboard.h> #define butPin 4 #define DELT 70 #define waiting1 10000 #define waiting2 80 #define waiting3 6000 #define waiting4 9000 #define chislitel 2000 #define x 30 #define pulsePin A0 #define pokazatel_stepenyi 3.2 unsigned long puls_ex; //saadsadsadsadsa unsigned long puls = 0; int pulse[2] = {0, 0}; bool vect[2]; unsigned long lastTimerPuls = 0; unsigned long currTimerPuls = 0; bool ochko1; bool ochko3; bool ochko2; long t; int j; int i; // void setup() { Timer3.initialize(50000); Timer3.attachInterrupt(pulsFunction); Serial.begin(9600); for (i = 3; i < 12; i++) { pinMode(i, INPUT_PULLUP); } delay(waiting1); } //saddssadssadsad void loop() { bool flag = false; for (i = 7; i < 10; i++) { if (digitalRead(i) == LOW) { bool was_Active = !digitalRead(i + 1); bool is_Active = false; for (j = 1; j <= x; j++) { if (digitalRead(i + 1) == LOW) { is_Active = true; } delay(waiting2); } if (is_Active != was_Active) { flag = true; Serial.println("Ok"); break; } } } if (flag) { t = millis(); puls_ex = 0; for (int s = 1; s <= 45; s++) { puls_ex += puls; } puls_ex /= 45; Serial.println(puls_ex); Serial.println(digitalRead(butPin)); if (digitalRead(butPin) == LOW) { Serial.println("the button is high"); Keyboard.press('w'); Serial.print(chislitel / (pow((puls_ex + 1), pokazatel_stepenyi))); Serial.println(" secund ne budet nazhato W, a istcho papa lutshiy"); delay(waiting3); Keyboard.release('w'); delay(1000 * chislitel / (pow((puls_ex + 1), pokazatel_stepenyi))); } } else { if (millis() - t >= waiting4) { shtraf(); } } } void shtraf() { if (digitalRead(7) == LOW) { ochko1 = true; delay(100); } if (digitalRead(8) == LOW) { ochko2 = true; delay(100); } if (digitalRead(9) == LOW) { 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; Serial.println("konets shtrafa"); } } void pulsFunction() { vect[0] = (pulse[1] > (pulse[0] + DELT)); pulse[0] = pulse[1]; pulse[1] = analogRead(pulsePin); vect[1] = (pulse[1] > (pulse[0] + DELT)); if (vect[0] && !vect[1]) { currTimerPuls = millis() + 1; puls = (60000 / (currTimerPuls - lastTimerPuls + 1)); lastTimerPuls = currTimerPuls; } } Тоесть я вернул резервный вариант кода и он заработал, теперь всё не так срочно. Но я всё равно не понимаю, в чём прикол. Объясните пожалуйста. Заранее спасибо!
Я 7 пин подключил также и к 10-му, т.е. там перемычка. А вообще для недопускания вращения назад такой код и сделано. Впринципе, вращения назад он не считывает, что и требуется. Всё равно спасибо!
1. Очень сомневаюсь, что здесь кто-то будет досконально разбирать весь ваш код и искать ошибку, причем не имея под руками самого железа. 2. Я описал сам принцип как работают с вращающимися переключателями, будь то герконы или энкодеры. А какие там у вас положения получаются - я не знаю, механику я не вижу. Если есть одновременное замыкание нескольких герконов, это алгоритм не меняет. Составляйте карту состояний и по переходу из одного состояния в другое определяйте вращение и скорость. У вас система сильно инерционная, поэтому можно даже отслеживать всего 2-3 равноудаленных друг от друга состояния. 3. Вижу, что у вас две задачи - вращение и пульс. А что именно не работает - вы не описали. Повесьте светодиоды в каждой задаче и по миганию определите какая из них работает, а какая висит.
Уверены что ошибка в коде а не аппаратная? Может элементарно питания не хватает? Или что то перегревается?
Нет, конечно не уверен на 100%. Но если другой скетч работает, то вряд ли он добавил питания или пересоединил проводники.
Вот что получается, когда автор не прорабатывает алгоритм работы программы и ее частей. Делать на хапке , авось кривая выведет, не всегда успешная стратегия. Если бы все было разложено по полочкам, то и места ошибки не было. А искать в бардаке косяки это ... для специфических любителей.
Вот я про это и говорю. Ведь конкурс показывает не умение слепить с помощью Ардуины что-то, а умение внятно поставить цель, найти способ решения и довести до реализации. Причем последнее это так , что бы исполнитель убедился в правильности подхода. Да и герконов хватит два и стоящих рядом. Так направление и скорость найти проще. И выявить сачков с невращающими колесами.