Прерывания и сравнение скорости: то работает, то не работает

Disel
Offline
Зарегистрирован: 25.02.2017

Доброго дня всем!

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

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

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

дайте совет, что может быть не так? может зря я вообще связался с прерываниями, может надо было делать менее точно на простых таймерах?

Заранее благодарен за помощь

/* реле выставляется в низкое положение, при разнице оборотов больше чем толеранс - включается в высокое */
const int tolerance = 60; //примерный допуск на разницу во времени
#define stopSignal 13 //пин для включения/выключения тревоги
#define sensorPIN_L 2 // Установка контакта оптопары Л
#define sensorPIN_R 3 // Установка контакта оптопары П
#define sensorLED_L 8 // светодиод срабатования оптопары  Л
#define sensorLED_R 9 // светодиод срабатования оптопары  П
#define HOLES_DISC 9 //число дырок в диске
volatile unsigned int pulsesL; 
volatile unsigned int pulsesR;
float rpmL;
float rpmR;
unsigned long timeOldL;
unsigned long timeOldR;
float rpmDiff; 
void counterL()
{
 pulsesL++;
}
void counterR()
{
 pulsesR++;
}
void setup()
{
 pinMode(sensorPIN_L, INPUT);
 pulsesL = 0;
 timeOldL = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_L), counterL, FALLING);
 pinMode(sensorPIN_R, INPUT);
 pulsesR = 0;
 timeOldR = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_R), counterR, FALLING);
 pinMode(stopSignal, OUTPUT);
 digitalWrite (stopSignal, LOW);
 pinMode(sensorLED_L , OUTPUT);
 pinMode(sensorLED_R , OUTPUT);
 digitalWrite (sensorLED_L, LOW);
 digitalWrite (sensorLED_R, LOW);
}
void loop()
{
  
if (millis() - timeOldL >= tolerance)
 {
 detachInterrupt(digitalPinToInterrupt(sensorPIN_L));
 rpmL = (pulsesL * 60) / (HOLES_DISC);
 timeOldL = millis();
 pulsesL = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_L), counterL, FALLING);
 }
 if (millis() - timeOldR >= tolerance)
 {
 detachInterrupt(digitalPinToInterrupt(sensorPIN_R));
 rpmR = (pulsesR * 60) / (HOLES_DISC);
 timeOldR = millis();
 pulsesR = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_R), counterR, FALLING);
 }
   if (digitalRead(sensorPIN_L) == LOW){
    digitalWrite (sensorLED_L, HIGH);
   }else{
   digitalWrite (sensorLED_L, LOW);
   }
    if (digitalRead(sensorPIN_R) == LOW){
    digitalWrite (sensorLED_R, HIGH);
    }else{
     digitalWrite (sensorLED_R, LOW);
    }
 rpmDiff = abs(rpmL-rpmR);
 if (tolerance < (rpmDiff))
  {
    digitalWrite (stopSignal, HIGH);
  }
}

 

anarch
Offline
Зарегистрирован: 10.09.2017
const int tolerance = 60; //примерный допуск на разницу во времени
#define HOLES_DISC 9 //число дырок в диске

С этими параметрами разобраться, на вашем диске 9 отверстий?

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

SLKH
Offline
Зарегистрирован: 17.08.2015

"если диск вращается медленно"

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

 

"может надо было делать менее точно на простых таймерах"

возможно, просто pulseIn() может хватить. 

 

 

Disel
Offline
Зарегистрирован: 25.02.2017

anarch пишет:

const int tolerance = 60; //примерный допуск на разницу во времени
#define HOLES_DISC 9 //число дырок в диске

С этими параметрами разобраться, на вашем диске 9 отверстий?

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

да. сейчас это диск от "болгарки" для бетона. примерно такой:

и оптопара трехпиновая , типа такой

с дополнительным таймером попытаюсь сделать, если осилю. буду пробовать

 

 

 

 

 

 

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Проверьте сигнал с датчика. У меня было проблема, когда на малых скоростях вращения в подобной системе появлялся дребезг. Штатные процедуры подавления дребезга помогли.

MaksVV
Offline
Зарегистрирован: 06.08.2015

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

sadman41
Онлайн
Зарегистрирован: 19.10.2016

MaksVV пишет:

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

Блики, наверное, давали подобный эффект.

astwo
Offline
Зарегистрирован: 10.07.2019

MaksVV пишет:

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


Тени, полутени. Вибрация всей установки при медленно движущем объекте

SLKH
Offline
Зарегистрирован: 17.08.2015

MaksVV пишет:

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

у каскада с медленно изменяющимся входным сигналом на выходе может быть всякое.

Гриша
Offline
Зарегистрирован: 27.04.2014

astwo пишет:
MaksVV пишет:

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

Тени, полутени. Вибрация всей установки при медленно движущем объекте

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

 

anarch
Offline
Зарегистрирован: 10.09.2017

А я 10 отверстий насчитал на диске.

Disel
Offline
Зарегистрирован: 25.02.2017

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

Гриша
Offline
Зарегистрирован: 27.04.2014

Disel пишет:

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

 Осциллограф есть? сделайте 50 экспериментов с однократным запуском триггера. И осциллограф нужен не самый медленный, с полосой на 50МГц должно хватить.

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

Disel
Offline
Зарегистрирован: 25.02.2017

50 мгц??? зачем так много? У меня скорость ну максимум 2Гц. Минимум так вообще один оборот в 3 секунды. Моего зрения предостаточно чтоб это увидеть)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Можно подробнее, как именно Вы убедились, что нет дребезга? Вы смотрели осциллографом или выводили диагностику программно, тогда код покажите.

Disel
Offline
Зарегистрирован: 25.02.2017

Я вывел на индикацию. Осцилографом не смотрел.

вот сам текст проги

/* реле выставляется в низкое положение, при разнице оборотов больше чем толеранс - включается в высокое */
const int tolerance = 40; //примерный допуск на разницу во времени
#define stopSignal 13 //пин для включения/выключения тревоги
#define sensorPIN_L 2 // Установка контакта Л используемого в Arduino
#define sensorPIN_R 3 // Установка контакта П используемого в Arduino
#define sensorLED_L 8 // светодиод срабатования датчика Л
#define sensorLED_R 9 // светодиод срабатования датчика П
#define HOLES_DISC 9 //число дырок в диске
volatile unsigned int pulsesL; 
volatile unsigned int pulsesR;
float rpmL;
float rpmR;
unsigned long timeOldL;
unsigned long timeOldR;
float rpmDiff; 
void counterL()
{
 pulsesL++;
}
void counterR()
{
 pulsesR++;
}
void setup()                                                                         // сетап
{
 //Serial.begin(9600);//отключил чтоб не грузить порт
 pinMode(sensorPIN_L, INPUT);
 pulsesL = 0;
 timeOldL = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_L), counterL, FALLING);
 pinMode(sensorPIN_R, INPUT);
 pulsesR = 0;
 timeOldR = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_R), counterR, FALLING);
 pinMode(stopSignal, OUTPUT);
 digitalWrite (stopSignal, LOW);
 pinMode(sensorLED_L , OUTPUT);
 pinMode(sensorLED_R , OUTPUT);
 digitalWrite (sensorLED_L, LOW);
 digitalWrite (sensorLED_R, LOW);
}
void loop()                                                                         //основная программа
{
  
if (millis() - timeOldL >= tolerance)  // было: if (millis() - timeOldL >= 100)  не понятно почему именно 100
 {
 detachInterrupt(digitalPinToInterrupt(sensorPIN_L));
 rpmL = (pulsesL * 60) / (HOLES_DISC);
 timeOldL = millis();
 pulsesL = 0;
 
 attachInterrupt(digitalPinToInterrupt(sensorPIN_L), counterL, FALLING);
 
 
 }
 if (millis() - timeOldR >= tolerance)  // было: if (millis() - timeOldR >= 100)   не понятно почему именно 100
 {
 detachInterrupt(digitalPinToInterrupt(sensorPIN_R));
 rpmR = (pulsesR * 60) / (HOLES_DISC);
 timeOldR = millis();
 pulsesR = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_R), counterR, FALLING);
 }
     if (digitalRead(sensorPIN_L) == LOW){
    digitalWrite (sensorLED_L, HIGH);
   }else{
   digitalWrite (sensorLED_L, LOW);
   }
    if (digitalRead(sensorPIN_R) == LOW){
    digitalWrite (sensorLED_R, HIGH);
    }else{
     digitalWrite (sensorLED_R, LOW);
    }
 rpmDiff = abs(rpmL-rpmR);
 //Serial.println("DIFFERENCE");//отключил чтоб не грузить порт
 //Serial.println(rpmDiff);//отключил чтоб не грузить порт
 if (tolerance < (rpmDiff))
  {
    digitalWrite (stopSignal, HIGH);
    //Serial.println("stopSignal");//отключил чтоб не грузить порт
  }
}
Disel
Offline
Зарегистрирован: 25.02.2017

ответил выше.

Гриша
Offline
Зарегистрирован: 27.04.2014

Disel пишет:

50 мгц??? зачем так много? У меня скорость ну максимум 2Гц. Минимум так вообще один оборот в 3 секунды. Моего зрения предостаточно чтоб это увидеть)

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

UPD попробуйте вникнуть в эту статью

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

anarch пишет:

А я 10 отверстий насчитал на диске.

Нет, ну не все же умеют считать до 10!

anarch
Offline
Зарегистрирован: 10.09.2017

В сериал выведите (pulsesL, pulsesR) или (rpmL, rpmR) и посмотрите что насчитывает.

Гриша
Offline
Зарегистрирован: 27.04.2014

anarch пишет:

В сериал выведите (pulsesL, pulsesR) или (rpmL, rpmR) и посмотрите что насчитывает.

а что там можно увидеть? там сперва массив нужно записать с интервалами времени, потом только этот массив данных выводить и при этом останавливать работу с прерываниями на период вывода. и массив нужен из 20-30 значений интервалов времени. И дабы не перегружать вывод тормозить программу иначе потеряешься в массиве информации. И увидишь, что эти интервалы не одинаковые (сильно) - вот только эти знания сами по себе ничем особенным не помогут... ИМХО

SLKH
Offline
Зарегистрирован: 17.08.2015

andriano пишет:

anarch пишет:

А я 10 отверстий насчитал на диске.

Нет, ну не все же умеют считать до 10!

одно там отверстие.

Гриша
Offline
Зарегистрирован: 27.04.2014

SLKH пишет:

andriano пишет:

anarch пишет:

А я 10 отверстий насчитал на диске.

Нет, ну не все же умеют считать до 10!

одно там отверстие.

чего бы умного и мне сморозить....

Disel пишет:
 
да. сейчас это диск от "болгарки" для бетона. примерно такой
 
 
вероятно я один заметил слово ПРИМЕРНО....
:)))))))))))))
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Disel пишет:

Я вывел на индикацию. 

Код не смотрел, т.к. он неправильно вставлен. Но и так понятно, что дребезга Вы не заметите ни по какой индикации.

Нет осциллографа - выводите время в мили- (или микро-) секундах, так хоть что-то понять можно. 

Гриша
Offline
Зарегистрирован: 27.04.2014
ЕвгенийП пишет:
 
Disel пишет:
 
Я вывел на индикацию. 
 
 
Код не смотрел, т.к. он неправильно вставлен. Но и так понятно, что дребезга Вы не заметите ни по какой индикации.
 
Нет осциллографа - выводите время в мили- (или микро-) секундах, так хоть что-то понять можно. 
 
 
Петрович, посмотрите пост20, может дополните его... 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, чего дополнять, пусть ТС хоть что-то делать начнёт (хоть код вставит). Кстати, ещё раз использует слово "прога" (как в №15) меня в теме больше не будет. Я не прогер и в прогах не разбираюсь.

Disel
Offline
Зарегистрирован: 25.02.2017

ЕвгенийП пишет:

Проверьте сигнал с датчика. У меня было проблема, когда на малых скоростях вращения в подобной системе появлялся дребезг. Штатные процедуры подавления дребезга помогли.

я наверное неправильно понимаю суть команды Interrupt. по моему разумению при поступлении сигнала на этот вывод микропроцессор должен все бросать и начинать выполнять определенный код. применение антидребезга с прерыванием лишает эту команду всякого смысла, ибо код исполнится не сразу, а через время антидребезга. в моей практически пустой программе это не критично, но если будут циклы типа While или сложные вычисления , ожидания нажатия кнопки - то и обработка прерывания может задержаться. возможно я не прав, поправьте.

Disel
Offline
Зарегистрирован: 25.02.2017

Гриша пишет:

SLKH пишет:

andriano пишет:

anarch пишет:

А я 10 отверстий насчитал на диске.

Нет, ну не все же умеют считать до 10!

одно там отверстие.

чего бы умного и мне сморозить....

Disel пишет:
 
да. сейчас это диск от "болгарки" для бетона. примерно такой
 
 
вероятно я один заметил слово ПРИМЕРНО....
:)))))))))))))

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

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Disel пишет:

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

В идеальном мире, существующем в голове программиста, который с физикой не работает, всё именно так. Однако, давайте подумаем, что будет происходить с процедурой, вызываемой по прерыванию, в реальном мире: все случайно залетевшие помехи начнут дёргать её беспрестанно. Включили рядом лампочку - прилетел импульс длительностью в 200ns, клацнули кнопкой - получили пачку импульсов. Т.е. счетчик, если он есть в процедуре, с точки зрения внешнего наблюдателя, будет увеличиваться хаотически.

Как можно купировать данную проблему, на ваш взгляд?

Disel
Offline
Зарегистрирован: 25.02.2017

ЕвгенийП пишет:

Да, чего дополнять, пусть ТС хоть что-то делать начнёт (хоть код вставит). Кстати, ещё раз использует слово "прога" (как в №15) меня в теме больше не будет. Я не прогер и в прогах не разбираюсь.

вы однозначно разбираетесь в програмировании больше меня, сокращение было не с целью оскорбить. наверное это как теплотехника сантехником обозвать ))

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

посмотрите, будет ли работать счетчик импульсов, если его взять из подпрограммы attachInterrupt  ??

/* реле выставляется в низкое положение, при разнице оборотов больше чем толеранс - включается в высокое */
const int tolerance = 60; //примерный допуск на разницу во времени
#define stopSignal 13 //пин для включения/выключения тревоги
#define sensorPIN_L 2 // Установка контакта Л используемого в Arduino
#define sensorPIN_R 3 // Установка контакта П используемого в Arduino
#define sensorLED_L 8 // светодиод срабатования датчика Л
#define sensorLED_R 9 // светодиод срабатования датчика П
#define HOLES_DISC 9 //число дырок в диске
#define shiftHOLES 18// кол-во импульсов после проходов которых происходит остановка
volatile unsigned int pulsesL; 
volatile unsigned int pulsesR;
float rpmL;
float rpmR;
unsigned long timeOldL;
unsigned long timeOldR;
float rpmDiff; 
void counterL()
{
 pulsesL++;
}
void counterR()
{
 pulsesR++;
}
void setup()
{
 pinMode(sensorPIN_L, INPUT);
 pulsesL = 0;
 timeOldL = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_L), counterL, FALLING);
 pinMode(sensorPIN_R, INPUT);
 pulsesR = 0;
 timeOldR = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_R), counterR, FALLING);
 pinMode(stopSignal, OUTPUT);
 digitalWrite (stopSignal, LOW);
 pinMode(sensorLED_L , OUTPUT);
 pinMode(sensorLED_R , OUTPUT);
 digitalWrite (sensorLED_L, LOW);
 digitalWrite (sensorLED_R, LOW);
}
void loop() 
{
if (millis() - timeOldL >= tolerance)
 {
 detachInterrupt(digitalPinToInterrupt(sensorPIN_L));
 rpmL = (pulsesL * 60) / (HOLES_DISC);
 timeOldL = millis();
 pulsesL = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_L), counterL, FALLING);
 }
 if (millis() - timeOldR >= tolerance)
 {
 detachInterrupt(digitalPinToInterrupt(sensorPIN_R));
 rpmR = (pulsesR * 60) / (HOLES_DISC);
 timeOldR = millis();
 pulsesR = 0;
 attachInterrupt(digitalPinToInterrupt(sensorPIN_R), counterR, FALLING);
 }
 /*  начало попытки счета импульсов  */
 if (pulsesR - pulsesL >= shiftHOLES){
	 digitalWrite (stopSignal, HIGH);
 }
 /*  конец попытки счета импульсов  */ 
     if (digitalRead(sensorPIN_L) == LOW){
    digitalWrite (sensorLED_L, HIGH);
   }else{
   digitalWrite (sensorLED_L, LOW);
   }
    if (digitalRead(sensorPIN_R) == LOW){
    digitalWrite (sensorLED_R, HIGH);
    }else{
     digitalWrite (sensorLED_R, LOW);
    }
 rpmDiff = abs(rpmL-rpmR);
 if (tolerance < (rpmDiff))
  {
    digitalWrite (stopSignal, HIGH);
  }
}

 

Disel
Offline
Зарегистрирован: 25.02.2017

sadman41 пишет:

Disel пишет:

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

В идеальном мире, существующем в голове программиста, который с физикой не работает, всё именно так. Однако, давайте подумаем, что будет происходить с процедурой, вызываемой по прерыванию, в реальном мире: все случайно залетевшие помехи начнут дёргать её беспрестанно. Включили рядом лампочку - прилетел импульс длительностью в 200ns, клацнули кнопкой - получили пачку импульсов. Т.е. счетчик, если он есть в процедуре, с точки зрения внешнего наблюдателя, будет увеличиваться хаотически.

Как можно купировать данную проблему, на ваш взгляд?

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

а какой был правильный ответ?

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Вот и я спрашиваю - как, на ваш взгляд, решается дилемма выбора между скоростью и надежностью?

SLKH
Offline
Зарегистрирован: 17.08.2015

sadman41 пишет:

Вот и я спрашиваю - как, на ваш взгляд, решается дилемма выбора между скоростью и надежностью?

до этой дилеммы ещё далеко.

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

Гриша
Offline
Зарегистрирован: 27.04.2014

SLKH пишет:

sadman41 пишет:

Вот и я спрашиваю - как, на ваш взгляд, решается дилемма выбора между скоростью и надежностью?

до этой дилеммы ещё далеко.

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

поддерживаю, и не мешало бы знать схему этого конкретного девайса с номиналами элементов. Это я про всякую фильтрацию и гистерезис имею ввиду. абы куда и абы как ставить RC фильтр просто вредно. lm358 не любит низкоомную нагрузку...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Disel пишет:
применение антидребезга с прерыванием лишает эту команду всякого смысла, ибо код исполнится не сразу, а через время антидребезга.

Когда исполнится тогда и так, как Вы напишете.

Зачем Вам задерживать код? Запомнили время когда прилетело прерывание и пусть всё дальше работает. Прилетит новое, смотрим, сколько времени прошло и принимаем решение. основной код не тормозим никогда.