Помогите с частью кода: "выключатель освещения счетчик людей в помещении"

krepton85
Offline
Зарегистрирован: 02.02.2016

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

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

Есть два датчика HC-SR04 которые мониторят 2 дистанции от датчика до противостоящей стены.

Светадиоды подключенные к пинам 8 и 9 сигнализируют работу датчиков. Пока я сделал если дистанция меньше 20 см, то считается что датчик сработал, в идеале нужно как то сделать что бы каждому датчику была присвоена переменная, значения для каторой берутся по начальным данным, ОДНАКРАТНО, с датчиков при включении, далее эти значения не изменяются при работе. И затем просто идет сравнение текущих значений с датчиков с значениями с переменных, если меньше этих значений - считается датчик сработал. (как это сделать однакратно я не понял).

А теперь оснавной вопрос, как указать последовательность событий:

Если выполняется сначало событие "А" потом "Б" то прибовляем +1 к переменной counts, если сначало событие "Б" потом "А", то убовляем 1 у переменной counts.

Если counts >0 то зажигаем светадиод на 7 пине, иначе тушим. как то так.

 

long duration_1, cm1;
long duration_2, cm2;

long counts;
long cm1_1;
long cm2_1;
int var;
void setup() {
pinMode(3, OUTPUT);// trig 1
pinMode(6, OUTPUT);// trig 2
pinMode(4, INPUT); // echo 1
pinMode(5, INPUT); // echo 2
pinMode(7, OUTPUT); // реле пин
pinMode(8, OUTPUT); // out 1
pinMode(9, OUTPUT); // out 2



}

void loop() {

digitalWrite(3, LOW);
delayMicroseconds(2);
digitalWrite(3, HIGH);
delayMicroseconds(10);
digitalWrite(3, LOW);

digitalWrite(7, LOW);
Serial.begin(115200);
duration_1 = pulseIn (4, HIGH);
cm1_1 = duration_1/29/2;
Serial.print("out_1:  ");
Serial.print(cm1_1);
Serial.print("cm");
Serial.println ();

 


digitalWrite(6, LOW);
delayMicroseconds(2);
digitalWrite(6, HIGH);
delayMicroseconds(10);
digitalWrite(6, LOW);

duration_2 = pulseIn (5, HIGH);
cm2_1 = duration_2/29/2;
Serial.print("out_2:  ");
Serial.print(cm2_1);
Serial.print("cm");
Serial.println ();



if(cm1_1 < 20)// 20 - дистанция на каторой срабатывает датчик 20 см и ниже.
{
  cm1 = 1;
  digitalWrite(8, HIGH);
}
else
{
  //delay(100);
  cm1 = 0;
  digitalWrite(8, LOW);
}



if(cm2_1 < 20 )// 20 - дистанция на каторой срабатывает датчик 20 см и ниже.
{
  cm2 = 1;
  digitalWrite(9, HIGH);
}
else
{
  //delay(100);
  cm2 = 0;
  digitalWrite(9, LOW);
}
/*  
Здесь нужно дописать код.






 

*/
if(counts > 0)
{
  digitalWrite(7, HIGH);
}
else
{
  digitalWrite(7, LOW);
}
Serial.println (counts);
delay(10);
}

 

Я новичок в Ардуино, так что строго не судите, ни знаю даже С++.

Araris
Offline
Зарегистрирован: 09.11.2012

krepton85 пишет:

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

Разберётесь с алгоритмом и скетчем - узнаете, почему на HC-SR04 такие устройства никто не делает.

krepton85 пишет:

/*  
Здесь нужно дописать код.


*/
 

А попробуйте самостоятельно. Вот здесь - http://arduino.ru/forum/proekty/datchik-napravleniya-dvizheniya - готовая реализация алгоритма.

krepton85 пишет:

Я новичок в Ардуино, так что строго не судите, ни знаю даже С++.

Здесь это ничего не значит, было бы желание и Гугл.

krepton85
Offline
Зарегистрирован: 02.02.2016

В общем сам решил этих 2 задачи, код работает четко, притензий не имеею к своему коду. :)

long duration_1, cm1;
long duration_2, cm2;

long counts;
long cm1_1;
long cm2_1;
int var;
int State;
void setup() {
pinMode(3, OUTPUT);// trig 1
pinMode(6, OUTPUT);// trig 2
pinMode(4, INPUT); // echo 1
pinMode(5, INPUT); // echo 2
pinMode(7, OUTPUT); // реле пин
pinMode(8, OUTPUT); // out 1
pinMode(9, OUTPUT); // out 2

var = 0;
counts =0;
}

void loop() {

digitalWrite(3, LOW);
delayMicroseconds(2);
digitalWrite(3, HIGH);
delayMicroseconds(10);
digitalWrite(3, LOW);

digitalWrite(7, LOW);
Serial.begin(115200);
duration_1 = pulseIn (4, HIGH);
cm1_1 = duration_1/29/2;
Serial.print("out_1:  ");
Serial.print(cm1_1);
Serial.print("cm");
Serial.println ();




digitalWrite(6, LOW);
delayMicroseconds(2);
digitalWrite(6, HIGH);
delayMicroseconds(10);
digitalWrite(6, LOW);

duration_2 = pulseIn (5, HIGH);
cm2_1 = duration_2/29/2;
Serial.print("out_2:  ");
Serial.print(cm2_1);
Serial.print("cm");
Serial.println ();

///////////////////////////////////////////////////// Вариант А - автоматическая калибровка радиуса действия датчиков ////////////////////////////
/* 
if (var == 0) {
  cm1 = cm1_1;
  cm2 = cm2_1;
  var = 1;
}

if (cm1_1 < (cm1 - 10))   // - 10 -- минимальное расстояние от проходящего человека до стены, каторая напротив от датчиков (для большей стабильности колибровки)
{
  digitalWrite(8, HIGH);
}
else
{
  digitalWrite(8, LOW);
}

if (cm2_1 < (cm2 - 10))   // - 10 -- минимальное расстояние от проходящего человека до стены, каторая напротив от датчиков (для большей стабильности колибровки)
{
  digitalWrite(9, HIGH);
}
else
{
  digitalWrite(9, LOW);
}
*/   ////////////////////////////////////////////////Конец Варианта А  /////////////////////////////////////////////////////////////////////////



////////////////////////////////////////Вариант Б - ручная настройка радиуса действия датчиков /////////////////////////////////////////////////


if(cm1_1 < 100)// 100 - дистанция на которой срабатывает датчик 100 см и ниже.
{
  cm1 = 1;
  digitalWrite(8, HIGH);
}
else
{
  
  cm1 = 0;
  digitalWrite(8, LOW);
}



if(cm2_1 < 100 )// 100 - дистанция на которой срабатывает датчик 100 см и ниже.
{
  cm2 = 1;
  digitalWrite(9, HIGH);
}
else
{
  
  cm2 = 0;
  digitalWrite(9, LOW);
}
  
///////////////////////////////////////////////////////////Конец Варианта Б ////////////////////////////////////////////////////////////////

if(digitalRead(8) == LOW && digitalRead(9) == LOW) State = 0;

if(digitalRead(8) == HIGH && digitalRead(9) == HIGH && State == 0) State = 1;

if(digitalRead(8) == LOW && digitalRead(9) == HIGH && State == 1 ) State = 2;

if(digitalRead(8) == HIGH && digitalRead(9) == LOW && State == 1 ) State = 3;
 
if (State == 3) {
  counts = counts -1;
  //delay(2);
  State = 0;
}  

if (State == 2) {
  counts = counts +1;
  //delay(2);
  State = 0;
}  

if(counts > 0)
{
  digitalWrite(7, HIGH);
}
else
{
  digitalWrite(7, LOW);
}
Serial.println (counts);
delay(500);
}

 

 

Но вот датчики это что то, 1 из их нормально работаеn, чувствительность просто супер, угол абзора чуть ли не 180 градусов, работает на все подрят: на твердые предметы, мягкие предметы (одежда), а вот со вторым беда, он савсем какой то вялый с какой то задержкой срабатывает, на мягкие предменты вообще не реагирут - сигнал угасает в майке и расстояние ввыводит до майки 3,3 км :). И дело точно не в коде, думал что в нем, но местами менял датчики в итоге все тоже менялось.

Вот как можно так делать обсалютно 2 адинаковых датчика но с разными параметрами? На вид оба идентичных, но микросхемы опрационных усилителей различаются производителями, в том где все супер работает LM324, а где хуже - SGM324ys14. Но не думаю что дело в операционниках, ведь отражающий эффект зависить от несущей частоты сомневаюсь, что она различается у обоих датчиков, должна быть 40 кГц.

krepton85
Offline
Зарегистрирован: 02.02.2016

Подпаялся к трансиверу (хотя хер его знает он ли это может китайцы и папутали местами) проблемного датчика, осцилогрофом и когда датчик выдает показания 3,3 км, на осцилографе исчезают пачки из 8 имульсов частатой 40 кГц, осюда собственно вопрос, а могут ли исчезать импульсы с трансивера при слишком большом расстоянии, разве что на риссивере?

krepton85
Offline
Зарегистрирован: 02.02.2016

Вот накидал тот же самый проект только на ИК фотоприемнике 1 шт и 2-х ИК - светодиодах находящихся на противоположной стене. Не знаю только заработает или нет.

int ledPin_1 = 4; // ИК света-диод 1
int ledPin_2 = 5;// ИК света-диод 2
int ledPin_3 = 8;// индикация сработки ик луча 1
int ledPin_4 = 9;// индикация сработки ик луча 2
long counts;
int ledPin_6 = 7; // реле пин
int ledPin_5 = 6; // вход ИК фото-приемника
boolean LED1;
boolean LED2;
int State;
void setup() {
pinMode(ledPin_1, OUTPUT);  
pinMode(ledPin_2, OUTPUT);
pinMode(ledPin_5, INPUT);
pinMode(ledPin_3, OUTPUT);
pinMode(ledPin_4, OUTPUT);
pinMode(ledPin_6, OUTPUT);
counts = 0;
LED1 = false;
LED2 = false;
}

void loop() {
//////////////////////////////////передатчик LED1 & LED2////////////////////////////////
LED1 = true;   
  delayMicroseconds(200);              
LED1 = false;
  delay(1);

LED2 = true;
  delayMicroseconds(200);
LED2 = false;
  delay(1);
  
if(LED1 == true) tone(ledPin_1, 40000); // 40кГц частота с каторой работает ИК фота - приемник
if(LED1 == false) noTone(ledPin_1);  
if(LED2 == true) tone(ledPin_2, 40000); // // 40кГц частота с каторой работает ИК фота - приемник
if(LED2 == false) noTone(ledPin_2);

//////////////////////////////// Ик приемник/////////////////////////////////////////////////

if (ledPin_5 == HIGH && LED1 == true) 
{
  digitalWrite(ledPin_3, HIGH);   
}
else
{
  digitalWrite(ledPin_3, LOW);
}



if (ledPin_5 == HIGH && LED2 == true) 
{
  digitalWrite(ledPin_4, HIGH);   
}
else
{
  digitalWrite(ledPin_4, LOW);
}

if(digitalRead(ledPin_3) == LOW && digitalRead(ledPin_4) == LOW) State = 0;

if(digitalRead(ledPin_3) == HIGH && digitalRead(ledPin_4) == HIGH && State == 0) State = 1;

if(digitalRead(ledPin_3) == LOW && digitalRead(ledPin_4) == HIGH && State == 1 ) State = 2;

if(digitalRead(ledPin_3) == HIGH && digitalRead(ledPin_4) == LOW && State == 1 ) State = 3;
 
if (State == 3) {
  counts = counts -1;
  State = 0;
}  

if (State == 2) {
  counts = counts +1;
  State = 0;
}  

if(counts > 0) digitalWrite(ledPin_6, HIGH);

if(counts <= 0) digitalWrite(ledPin_6, LOW);
//Serial.print("count: ");
//Serial.println (counts);
}

 

krepton85
Offline
Зарегистрирован: 02.02.2016

Вот практически рабочий код счетчика - выключателя на 2-х ИК светадиодах и 1-ом ИК фотоприемнике от систем ДУ работает с несущей частатой 38 кГц.

const int ledPin_1 = 10; // ИК света-диод 1
const int ledPin_2 = 11;// ИК света-диод 2
int ledPin_3 = 8;// индикация сработки ик луча 1 orange
int ledPin_4 = 9;// индикация сработки ик луча 2 red
long counts;
int ledPin_6 = 7; // реле пин
int ledPin_5 = 6; // вход ИК фото-приемника
boolean LED1;
boolean LED2;
int State;
long delay_PWM_LOW = 800;
long delay_PWM_HIGH = 200;
void setup() {
pinMode(ledPin_1, OUTPUT);  
pinMode(ledPin_2, OUTPUT);
pinMode(ledPin_5, INPUT);
pinMode(ledPin_3, OUTPUT);
pinMode(ledPin_4, OUTPUT);
pinMode(ledPin_6, OUTPUT);
counts = 0;

Serial.begin(115200);

}

void loop() {
//////////////////////////////////передатчик LED1 & LED2////////////////////////////////
tone(ledPin_1, 38000); //38кГц частота с каторой работает ИК фота - приемник
delayMicroseconds(delay_PWM_HIGH);
if (digitalRead(ledPin_5) == HIGH) 
{
  digitalWrite(ledPin_3, HIGH);
  LED1 = true;
}
noTone(ledPin_1);

delayMicroseconds(delay_PWM_LOW);

tone(ledPin_2, 38000); //38кГц частота с каторой работает ИК фота - приемник
delayMicroseconds(delay_PWM_HIGH);
if (digitalRead(ledPin_5) == HIGH) 
{
  digitalWrite(ledPin_4, HIGH);
  LED2 = true;
}
noTone(ledPin_2);

delayMicroseconds(delay_PWM_LOW);
  
//if(LED1 == true) tone(ledPin_1, 38000); // 38кГц частота с каторой работает ИК фота - приемник
//if(LED1 == false) noTone(ledPin_1);  
//if(LED2 == true) tone(ledPin_2, 38000); // // 38кГц частота с каторой работает ИК фота - приемник
//if(LED2 == false) noTone(ledPin_2);


//////////////////////////////// Ик приемник/////////////////////////////////////////////////

if(LED1 == false && LED2 == false) State = 0;
//if(LED1 == true && LED2 == true  && State == 0) State = 1;
if(LED1 == false && LED2 == true && State == 0 ) State = 2;
if(LED1 == true && LED2 == false && State == 2 ) State = 3;
if(LED1 == true && LED2 == false && State == 0 ) State = 4;
if(LED1 == false && LED2 == true && State == 4 ) State = 5;

//if(LED1 == true && State == 0) State = 1;
//if(LED2 == true && State == 1) State = 2;
//if(LED1 == false && State == 2) State = 3;

//if(LED2 == true && State == 0) State = 4;
//if(LED1 == true && State == 4) State = 5;
//if(LED2 == false && State == 5) State = 6;

if (State == 3) {
  counts = counts -1;
  //delay(1);
  State = 6;
}  

if (State == 5) {
  counts = counts +1;
  //delay(1);
  State = 6;
}
//if(LED1 == false && LED2 == false) {
  //digitalWrite(ledPin_3, LOW);
  //digitalWrite(ledPin_4, LOW);  
//}

//if(LED1 == true && LED2 == true) { //вот это условие почему то ни когда не выполняется
  //digitalWrite(ledPin_3, HIGH);
  //digitalWrite(ledPin_4, HIGH);  
//}

LED1 = false;
LED2 = false;
digitalWrite(ledPin_3, LOW);
digitalWrite(ledPin_4, LOW); 
if(counts > 0) digitalWrite(ledPin_6, HIGH);

if(counts <= 0) digitalWrite(ledPin_6, LOW);
Serial.print("count: ");
Serial.println (counts);
//State = 0;
}

Многие параметры тут очень критичны, например:  delay_PWM_LOW, и delay_PWM_HIGH методом подбора было определено что это самые оптимальные значения.

Так же имеет большое значение номиналы добавочных сопротивлений на ИК светадиоды, у меня 220 ом, подключены ИК светадиоды через транзисторы BC547 на базы сигнал подается через резисторы наминала 680 Ом.

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

      
Navigator
Navigator аватар
Offline
Зарегистрирован: 26.01.2016

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

krepton85
Offline
Зарегистрирован: 02.02.2016

Navigator пишет:

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


Увы это не тот случай и не тот проект. В данном помещении работают люди и что им постояноо нужно двигатся что бы у их свет был? :)
Ладно этот проэкт видимо обречен. Папробую то же сделать но с 2 -мя ИК фота приемниками.

krepton85
Offline
Зарегистрирован: 02.02.2016

Все сделал на 2-х Ик фотаприемниках и 1 ИК светадиоде, убрал все delay - работает практически на постоянном токе (не преривно мониторятся 2 ИК луча на наличие пересечений человеком).  Работает практически стабильно. Заказал еще дисплэй ТМ1637 для отображения количества.

const int ledPin_1 = 4; // ИК света-диод 1

const int ledPin_3 = 8;// индикация сработки ик луча 1 orange
const int ledPin_4 = 9;// индикация сработки ик луча 2 red
long counts; //количество людей в помещении

int ledPin_6 = 7; // реле пин
int IN_IR_1 = 6; // вход ИК фото-приемника 1
int IN_IR_2 = 10; // вход ИК фото-приемника 2

int State; //састоянии для алгоритма, определяющего направление движения

void setup() {
 
pinMode(ledPin_1, OUTPUT);  

pinMode(IN_IR_1, INPUT);
pinMode(IN_IR_2, INPUT);
pinMode(ledPin_3, OUTPUT);
pinMode(ledPin_4, OUTPUT);
pinMode(ledPin_6, OUTPUT);
counts = 0;
Serial.begin(9600);
}
void loop() {
  tone(ledPin_1, 36000); //36кГц частота с каторой работает ИК фота - приемник

if(digitalRead(IN_IR_1) == LOW) { // индикация работы ИК луча 1, если не пересечен то светадиод  ledPin_3 светит, иначе не светит
  digitalWrite(ledPin_3, HIGH);
}else{
  digitalWrite(ledPin_3, LOW);
}

if(digitalRead(IN_IR_2) == LOW) { // индикация работы ИК луча 2, если не пересечен то светадиод  ledPin_4 светит, иначе не светит
  digitalWrite(ledPin_4, HIGH);
}else{
  digitalWrite(ledPin_4, LOW);
}
//////////////Алгоритм опредиляющий направление движения/////////////
 
if(digitalRead(IN_IR_1) == LOW  && digitalRead(IN_IR_2) == LOW) State = 0;

if(digitalRead(IN_IR_1) == HIGH && digitalRead(IN_IR_2) == LOW && State == 0) State = 1;
if(digitalRead(IN_IR_2) == HIGH && digitalRead(IN_IR_1) == LOW && State == 1) State = 2;
if(digitalRead(IN_IR_1) == LOW && digitalRead(IN_IR_2) == HIGH && State == 2) State = 3; //1 человек вошел

if(digitalRead(IN_IR_2) == HIGH && digitalRead(IN_IR_1) == LOW && State == 0) State = 4;
if(digitalRead(IN_IR_1) == HIGH && digitalRead(IN_IR_2) == LOW && State == 4) State = 5;
if(digitalRead(IN_IR_2) == LOW && digitalRead(IN_IR_1) == HIGH && State == 5) State = 6; // 1 человек вышел

if (State == 3) {
  counts = counts +1;
  
   State = 0;
   } 

if (State == 6) {
  counts = counts -1;
  
  State = 0;
  }
  
if(counts > 0) digitalWrite(ledPin_6, HIGH);

if(counts <= 0) digitalWrite(ledPin_6, LOW);
if(counts < 0) counts = 0; //обнуляем отрицательные значения количества
Serial.print("counts:  ");
Serial.println(counts);
}

Оказывается чем проще, тем надежней. :)

krepton85
Offline
Зарегистрирован: 02.02.2016

Наконец то я его сделал, вот окончательный вариант: https://youtu.be/vbfXED8Dfuk

Araris
Offline
Зарегистрирован: 09.11.2012

Поздравляю, Вы упорный человек.

Фраза "Этот проект на Ардуино уникален в своем роде, такого еще никто на Ардуино не делал." - великолепна )).

krepton85
Offline
Зарегистрирован: 02.02.2016

Araris пишет:

Поздравляю, Вы упорный человек.

Фраза "Этот проект на Ардуино уникален в своем роде, такого еще никто на Ардуино не делал." - великолепна )).

Ну просто показалось, что мне это по силам и решил пойти до конца. На таких ИК фотоприемниках точно ни кто еще не делал. Есть конечно проекты с точно такими ИК фотоприемниками, но не на Ардуино.