ARDUINO Датчик движения необычный сценарий!

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
Оформи код соответствующим тэгом, см. Правила
Ребят приветствую!. помогите гуру скетчеры) Работаю слаботочником СВН СКС СКД. Клиентом была поставлена задача:
Не хорошие ребята, в центре Питера заходят погреться попить пивка и поболтать о том о сем громко и непристойно , на лестничную площадку.
Квартира, на этаже одна так как центр ,старый фонд.
Хозяин вроде не против тусы ,но чтоб ненадолго!
Так вот! Нужно что бы датчик движения, фиксировал эти посиделки примерно 5-7 минут , а затем кинул эту инфу на пин реле, которое, в свою очередь запустит
модуль воспроизведения. Где будут предупреждены и мягко посланы далеко и надолго. Но если в течении этого времени произойдет движение равное допустим 1 минуты(хозяин уходит из дома) реле не сработает, а счетчик времени при этом обнулится и будет считать следующую сработку датчика. Так как я новичок, в вашем деле переконопатил столько инфы ,что лопается голова. понял что написать такой скетч можно 10-ми вариаций. Смог придумать только во это, файл прилагаю к описанию и кину еще на всякий случай вот так. При таком раскладе датчик работает не очень корректно как будто что то его притормаживает даже с учетом указанного время сработка происходит через 35 секунд беспрерывного махания) датчик движения использовал -HC-SR501

#define RELAY_PIN 3
#define SENSOR_PIN 2
#define TRIGGER_TIME 10000 // 5 минут
unsigned long start_time = 0;
long current_time = 0;
unsigned long trigger_duration = 0;
bool relay_state = false;
void setup() {
pinMode(RELAY_PIN, OUTPUT);
pinMode(SENSOR_PIN, INPUT);
}
void loop() {
int sensor_value = digitalRead(SENSOR_PIN);
if (sensor_value == HIGH) {
if (start_time == 0) {
start_time = millis();
}
current_time = millis();
trigger_duration = current_time - start_time;
if (trigger_duration >= TRIGGER_TIME) {
digitalWrite(RELAY_PIN, HIGH);
relay_state = true;
start_time = 0;
}
}
else {
if (relay_state == true) {
digitalWrite(RELAY_PIN, LOW);
relay_state = false;
}
start_time = 0;
}
}
 

Вложения

viktor1703

★★★✩✩✩✩
9 Дек 2021
712
173
C++:
#define RELAY_PIN 3
#define SENSOR_PIN 2
#define TRIGGER_TIME 10000 // 5 минут
unsigned long start_time = 0;
long current_time = 0;
unsigned long trigger_duration = 0;
bool relay_state = false;
void setup() {
pinMode(RELAY_PIN, OUTPUT);
pinMode(SENSOR_PIN, INPUT);
}
void loop() {
int sensor_value = digitalRead(SENSOR_PIN);
if (sensor_value == HIGH) {
if (start_time == 0) {
start_time = millis();
}
current_time = millis();
trigger_duration = current_time - start_time;
if (trigger_duration >= TRIGGER_TIME) {
digitalWrite(RELAY_PIN, HIGH);
relay_state = true;
start_time = 0;
}
}
else {
if (relay_state == true) {
digitalWrite(RELAY_PIN, LOW);
relay_state = false;
}
start_time = 0;
}
}
Так получше будет читать.

датчик движения использовал -HC-SR501
как будто что то его притормаживает даже с учетом указанного время сработка происходит через 35 секунд беспрерывного махания
Так у него же настраивается время от 5 секунд до 5 минут. Кстати, на какое время он настроен? Он заметил движение и удерживает выход заданное время в сработанном состоянии. Зачем вы его считываете несколько сотен тысяч раз в секунду?
А еще, через несколько суток беспрерывной работы вы снова начнете ломать голову, почему некорректно работает. Почему у вас переменные разных типов?
C++:
unsigned long start_time
long current_time
unsigned long trigger_duration
 

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@viktor1703, Спасибо что ответили. Он настроен на самое минимальное значение (5 сек).

@viktor1703,
Определить переменную для хранения времени запуска триггера
unsigned long start_time = 0;

Определить переменную для хранения текущего времени
без знака long current_time = 0;

Определить переменную для хранения длительности триггера
unsigned long trigger_duration = 0;

а как поправить? вроде логично))) но это не точно)
 

poty

★★★★★★✩
19 Фев 2020
3,478
994

@kvagon1, а в чём логика разных типов данных для переменных времени? Время хранится в переменных разных типов, при присвоении, сравнении и т.п. будете получать странные данные.
Даже если датчик настроен на 5 секунд (Вы это проверяли?) обращаться к нему в десятки тысяч раз чаще смысла не вижу.
 

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@kvagon1,нужно что бы заданный таймер постоянно обнулялся если непрерывное движение прерывалось, а если движение не прерывалось ,то сигнал на пин реле.

@poty, я уже готов заплатить за код раз я так туп.

@poty, я попробовал 100 вариаций и ни одна не подошла, а эта последняя работает по принципу например: подвигался 20 сек время запомнилось ушел с радаров а в памяти 20 сек есть. опять прошел под датчиком еще секунд 30 опять в память ушло и до тех пор пока не накопится 5 мин после этого сработка и таймер обнуляется
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
712
173
эта последняя работает по принципу например: подвигался 20 сек время запомнилось ушел с радаров а в памяти 20 сек есть
Нет, эта вариация не так работает. Во-первых, не нужно двигаться 20 секунд, достаточно одного движения. Есть движение датчик выдает HIGH, таймер запустился. Проходит
самое минимальное значение (5 сек)
Датчик сбрасывает сигнал в LOW, не важно есть движение или нет, если есть дальше движение, то опять выдаст HIGH. Вот Ардуино этот LOW заметит, так как опрос пина идет много сотен тысяч раз в секунду, и согласно вашей программе, если на входе не HIGH, тогда выполняется всё что после else, а именно: так как флаг reley_state=true, то выход RELEY_PIN сбросить, счетчик start_time обнулить. А как только появится HIGH на входе всё начнется сначала.
Во-вторых, это датчик движения, если расстояния нескольких сантиметров он видит движения рук, ног, головы, то с двух-трех метров этих движений уже может быть недостаточно для их обнаружения. Здесь лучше применять датчик присутствия и, в любом случае, уменьшать частоту опроса датчика, и логику программы подгонять под вашеописание.
без знака long current_time
А у вас он просто long, со знаком,
максимальное значение в два раза меньше
 
Изменено:

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@viktor1703,похоже я затупок не учел .что датчик по-любому выдаст LOW ,он не может постоянно, непрерывно выдавать сигнал HIGT так как у него есть свой таймер по истечению которого он на …… нннное короткое время все равно обнулится . Нужно было писать с этим учетом. Я думал что пока есть движение всегда будет HIGT. Спасибо буду завтра пробовать.
 

poty

★★★★★★✩
19 Фев 2020
3,478
994
Проще сделать что-то типа подавления дребезга кнопки. Т.е., если через n мс уровень снова стал HIGH - игнорировать LOW.
Но опрос делать существенно реже!
 

Мишутк

★✩✩✩✩✩✩
29 Мар 2025
54
17
Существуют видеокамеры с обнаружением движения. Там чувствительность лучше, чем у просто датчиков. У камеры есть включение встроенного света или звука по движению - это задействовать как сигнал присутствия (а саму видимую подсветку отключить, оставить ИК). Заодно сразу получаете запись всего движущегося. При наличии сети еще и обратную связь.
 

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
Оформи код соответствующим тэгом, см. Правила
@viktor1703, А если вот так, только увеличить количество сигналов с датчика и время за которое они могут случиться


int motionSensorPin = 13; //Контакт, подключенный к датчику движения
int relayPin = 3; //Контакт, подключенный к реле
int motionCount = 0; //Переменная для подсчета количества детектов движения
long timer = 0;
//Переменная для хранения времени с момента последнего обнаружения движения
void setup() {
pinMode(motionSensorPin, INPUT); // Установка контакта датчика движения на вход
pinMode(relayPin, OUTPUT); // Установка контакта реле на выходе
Serial.begin(9600); // Инициализация последовательной связи
}
void loop() {
// Проверка датчика движения каждую секунду
if (millis() - timer >= 1000) {
//Если обнаружено движение, увеличиваем количество движений и сбрасываем таймер
if (digitalRead(motionSensorPin) == HIGH) {
motionCount++;
timer = millis();
}
//Если в течение 1 минуты движение не обнаружено, обнуляем счетчик движений и таймер
else {
motionCount = 0;
timer = 0;
}
}
// Если движение обнаружено несколько раз в течение 2 минут, включите реле
if (motionCount > 10 & motionCount <= 120) {
digitalWrite(relayPin, HIGH);
}
//Если движение не обнаружено в течение 2 минут, выключите реле
else if (motionCount == 0) {
digitalWrite(relayPin, LOW);
}
}
 

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@Мишутк, @Мишутк, я с вами согласен, но охранные сценарии в вк не такие гибкие без тонких настроек. сеть может отвалиться и не передаст сигнал тревоги и там стоит камера и она не оказывает влияния на этих личностей. Если же сигнал будет высокочастотный и много децибел думаю им просто надоест и они поменяют локацию. да и не жалко будет эту сборку такт как ценник ее копейки.
 

bort707

★★★★★★✩
21 Сен 2020
3,217
941
датчик по-любому выдаст LOW ,он не может постоянно, непрерывно выдавать сигнал HIGT так как у него есть свой таймер по истечению которого он на …… нннное короткое время все равно обнулится
нужно учитывать оба интервала - и ХАЙ и ЛОУ. Реле должно сработать, если датчик 5 минут подряд выдает сигналы. При этом короткие периоды отсуствия сигнала, скажем 20-30 сек, не считаются выключением. Это связано не только с тем, что датчик периодически выдает ЛОУ, но и с тем, что злоумышленники не будут непрерывно двигаться, как муравьи - у них вполне могут быть периоды, когда они сидят споскойно.

А если вот так,
так не будет работать. У вас один и тот же таймер и на опрос датчика и на длительность движения. Нужно на каждый интервал отдельную переменную.
 
Изменено:

bort707

★★★★★★✩
21 Сен 2020
3,217
941
как вы вставляете оформленный код в сообщения?
почитайте инструкцию, полезно

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

Тема интересна с технической точки зрения, но как средство реальной борьбы с проблемой это полная туфта.
 
Изменено:

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@bort707, а что можете предложить сделать, может есть идеи? такого неприятного для них. девушка хрупкая по щам отпадает, на ментов надежды нет.:)
 

bort707

★★★★★★✩
21 Сен 2020
3,217
941
Так от того и тема, что нет у клиента реально действующих методов. И установка подобных "игрушек" только подтверждает слабость . Противоположная сторона это сразу почувтвует.
 
  • Лойс +1
Реакции: kvagon1

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@bort707, 220 на перила пустить или газ балон как в туалете чтоб освежал:ROFLMAO: нужно пробовать собирать схему а там посмотрим спасибо за ответ буду дальше пробовать писать код
 

viktor1703

★★★✩✩✩✩
9 Дек 2021
712
173
@kvagon1,
unsigned long timer = 0
C++:
if (millis() - timer >= 1000) {
//Если обнаружено движение, увеличиваем количество движений и сбрасываем таймер
if (digitalRead(motionSensorPin) == HIGH) {
motionCount++;
timer = millis();
}
Тут нормально, если прошла 1 секунда, если на входе HIGH, то счетчик движений +1, timer = millis(). Идем дальше,
//Если в течение 1 минуты движение не обнаружено, обнуляем счетчик движений и таймер
else {
motionCount = 0;
timer = 0;
}
}
Иначе, то есть если на входе LOW, причем не в течение 1 минуты, а всё так же через 1 секунду, то счетчик движений = 0, таймер = 0, и получается, что через какое-то время удержания таймера датчика движения счетчик будет сбрасываться и условие
if (motionCount > 10 & motionCount <= 120)
кстати, тут ошибка, нужно &&, а не &, может никогда не наступить
 

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
@viktor1703,
C++:
const int sensorPin = 2;    // Пин подключения датчика движения
const int relayPin = 8;     // Пин управления реле

const unsigned long interval = 120000;       // 2 минуты в миллисекундах
const unsigned long resetInterval = 60000;   // 1 минута в миллисекундах
const unsigned long relayOnTime = 10000;     // Время включения реле (10 секунд)
const unsigned long sensorPollInterval = 1000; // Интервал опроса датчика — 1 секунда

int motionCount = 0;
unsigned long firstMotionTime = 0;
unsigned long lastMotionTime = 0;
bool relayOn = false;
unsigned long relayTurnOnTime = 0;

unsigned long lastSensorPollTime = 0;

void setup() {
  pinMode(sensorPin, INPUT);
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, LOW); // Реле выключено в начале
  Serial.begin(9600);
}

void loop() {
  unsigned long currentTime = millis();

  // Опрос датчика раз в sensorPollInterval (1 секунда)
  if (currentTime - lastSensorPollTime >= sensorPollInterval) {
    lastSensorPollTime = currentTime;

    int sensorValue = digitalRead(sensorPin);

    if (sensorValue == HIGH) {
      if (motionCount == 0) {
        // Первая регистрация движения
        firstMotionTime = currentTime;
        motionCount = 1;
        lastMotionTime = currentTime;
        Serial.println("Первое движение зафиксировано");
      }
      else {
        // Проверяем перерыв
        if (currentTime - lastMotionTime > resetInterval) {
          // Сброс если был большой перерыв
          Serial.println("Перерыв более 1 минуты, счетчик сброшен");
          motionCount = 1;
          firstMotionTime = currentTime;
        }
        else {
          motionCount++;
          Serial.print("Движений: ");
          Serial.println(motionCount);
        }
        lastMotionTime = currentTime;
      }
    }
    else {
      // Проверяем, если прошла 1 минута без движений — сбросить счетчик
      if ((motionCount > 0) && (currentTime - lastMotionTime > resetInterval)) {
        Serial.println("Нет движений более 1 минуты, счетчик сброшен");
        motionCount = 0;
        firstMotionTime = 0;
        lastMotionTime = 0;
      }
    }
  }

  // Проверяем условие включения реле
  if (!relayOn && motionCount >= 10 && (currentTime - firstMotionTime <= interval)) {
    Serial.println("Условие выполнено, включаем реле");
    digitalWrite(relayPin, HIGH);
    relayOn = true;
    relayTurnOnTime = currentTime;

    // Сброс счетчиков чтобы начать новую серию
    motionCount = 0;
    firstMotionTime = 0;
    lastMotionTime = 0;
  }

  // Выключение реле через relayOnTime
  if (relayOn && (currentTime - relayTurnOnTime >= relayOnTime)) {
    digitalWrite(relayPin, LOW);
    relayOn = false;
    Serial.println("Реле выключено, цикл повторяется");
  }
}
Вот так нормально?

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

а время сработки реле норм 10 секунд?
 

bort707

★★★★★★✩
21 Сен 2020
3,217
941
Вот так нормально?
Значительно лучше чем было.
Грубых ошибок не вижу.

время сработки реле норм 10 секунд?
кто же это знает кроме вас и клиента?

Смотря что в это время делается. Если нападающих дерьмом поливать - то 10 секунд нормально :) , а если сирена или светосингнализация - то я бы не выключал пока есть движения в охраняемой зоне.
 
  • Лойс +1
Реакции: kvagon1

Мишутк

★✩✩✩✩✩✩
29 Мар 2025
54
17
@bort707, 220 на перила пустить или газ балон как в туалете чтоб освежал:ROFLMAO: нужно пробовать собирать схему а там посмотрим спасибо за ответ буду дальше пробовать писать код
Освежитель воздуха с вонючкой и задержкой. Саму конструкцию в железный ящик повыше и лучше за трубами, чтобы с размаха не снести. Будет тихо, вонько, незаметно, неприятно.
 

kvagon1

✩✩✩✩✩✩✩
9 Июн 2025
10
0
Всем спасибо за советы. Сборка проходит тест. Все работает корректно.