В обзорной части было рассмотрено устройство и принципы работы. В этой части рассмотрим варианты использования, как отдельно, так и при подключении к Arduino.
У ИК датчика движения, так же, как и у других типов датчиков, есть свои особенности и ограничения, которые нужно учитывать. Нужно понимать, подходит данный датчик движения для данных условий или нет. Что бы минимизировать возможность ложных срабатываний, и он с достаточной чувствительностью определял движения нужных объектов, его нужно правильно разместить и настроить.
Датчик может срабатывать и на домашних животных, например, кошку или небольшую собаку. Если нужно что бы датчик реагировал на их движения, его можно разместить не очень высоко от пола и направить в сторону, где движение нужно определять. И на оборот, если не нужно, датчик стоит разместить повыше. Если размеры, допустим собаки достаточно большие, может не получиться разместить и настроить чувствительность так, чтобы датчик не срабатывал на её движения.
Модуль HC-SR501 и подобные датчики движения не могут быть использованы как датчик присутствия. Когда будете экспериментировать, попробуйте на разных расстояниях от датчика встать неподвижно – после последнего движения датчик перестанет реагировать. Так же можете попробовать разные настройки чувствительности и посмотреть на каких расстояниях на какие движения реагирует датчик. Если стать далеко и движения будут недостаточно быстрые, датчик не будет реагировать. До некоторой степени можно увеличивать чувствительность, что бы детектировалось движение, но не было ложных срабатываний из-за сквозняков, вибраций и т.д.
Так же учтите, что ресурс у используемых подстроечных резисторов составляет десятки подстроек. Если HC-SR501 будет подключаться как датчик к плате с микроконтроллером, лучше выставить время срабатывания на минимум и экспериментировать, меняя код – Flash память обычно можно записывать тысячи или даже более сотни тысяч раз.
Для проверки работоспособности и экспериментов можно начать с самых простых вариантов подключения со светодиодом (не подключайте мощные светодиоды, выводы датчика и Arduino не рассчитаны на большие токи):
На Arduino Nano кроме светодиода, подключенного к 13му выводу, рядом есть ещё три для индикации наличия питания и приёма-передачи на линиях UART. Если из-за них использовать светодиод на 13ом выводе не удобно, можно подключить внешний к другому выводу:
Если выход HC-SR501 подключен не ко второму выводу Arduino или светодиод не к 13ому, не забудьте в скетче задать соответствующие значения переменным ledPin и pirPin.
int ledPin = 13; int pirPin = 2; void setup() { pinMode(ledPin, OUTPUT); pinMode(pirPin, INPUT); digitalWrite(ledPin, LOW); delay(1000); } void loop() { digitalWrite(ledPin, digitalRead(pirPin)); delay(100); }
Инфракрасный датчик движения можно использовать для создания очень многих устройств. Это может быть охранная система. Можно использовать для создания игрушек, предметов в квест румах, интерактивных арт инсталляциях и т.д.
В зависимости от того, что нужно сделать, при использовании микроконтроллера можно учитывать его срабатывание только при определённых условиях (к примеру, после одного или нескольких срабатываний на некоторое время игнорировать данные с датчика).
Из игрушек, к примеру, на Хэллоуин что-нибудь на подобие такого:
Кто-то входит в комнату и включаются светодиоды, начинают воспроизводиться звуки или сервоприводами производятся движения. Можно сделать коробочку, внутри которой будут светиться светодиоды и крышка будет открыта, пока нет движения. Только кто-то начал слишком резкие движения, светодиоды выключаются, а крышка коробочки закрывается.
Вот пример использования в арт инсталляции (ИК датчик движения используется для активации):
Можно реализовать управление фотоаппаратом с использованием микроконтроллера или без. Это пример реализации без микроконтроллера (HC-SR501 через оптопару «нажимает» кнопку пульта).
Инфракрасные датчики движения ещё очень удобны для управления освещением. На улице использовать иногда можно, но могут быть проблемы с ложными срабатываниями. Что бы не протягивать провода, можно использовать солнечную панель, от которой будет заряжаться аккумулятор. Есть готовые уличные светильники с датчиками движения, но, если по каким-либо причинам они не подходят, можно сделать свой взяв нужные детали по отдельности. Если уже есть светильник без датчика движения, его можно переделать, добавив датчик движения.
Датчик движения удобен если нужно ненадолго включать фоновое или основное освещение. Для фоновой подсветки можно разместить ленту или небольшой светильник возле или под кроватью:
В коридоре или на лестнице:
Освещаемая зона может быть несколько метров, а движение начинаться с разных сторон или из разных комнат, поэтому может понадобиться использовать несколько датчиков в разных местах.
Подсветку можно сделать в выдвижных полках различной мебели, в шкафу освещать полностью или только отдельные его части:
Если обеспечить герметичность, можно использовать для освещения раковины в ванной:
На длительное время освещение будет включаться только если перед датчиком есть постоянное движение. Иногда для удобства можно дополнительно использовать переключатель, который будет принудительно включать или выключать освещение. Некоторые модули емкостных кнопок могут быть использованы как автономный переключатель или как датчик, подключаемый к плате с микроконтроллером.
Когда нет принудительного включения, это иногда немного неудобно. Вышел из зоны видимости датчика или на некотором расстоянии датчик уже плохо реагирует на движения и приходится подойти к датчику или немного помахать перед датчиком ногой или рукой. С этим неудобством можно столкнуться при освещении коридора, полок в шкафу и т.д.
Возможность принудительно включать или выключать особенно актуальна для переносных ночников, которые можно использовать как для кратковременного включения освещения при движении, так и длительного, когда в зоне видимости датчика может не быть движения, но желательно что бы ночник не выключался:
Рассмотрим некоторые варианты реализации. Для подсветки с помощью 12В светодиодной ленты (потребляемый ток несколько десятков миллиампер) можно использовать очень простую схему без микроконтроллера:
Сделано по такой схеме несколько лет назад:
Всё исправно работает до сих пор.
Схему при необходимости можно немного изменить, заменив биполярный транзистор на полевой, чтобы управлять длинной лентой с намного большим потребляемым током. Или добавить фоторезистор, чтобы свет не включался, когда не нужно. Так же можно реализовать регулировку яркости или принудительное включение.
При использовании Arduino можно реализовать всё тоже самое, но иногда это будет проще и быстрей. Ещё можно сделать то, что не доступно для без микроконтроллерного варианта.
Автоматическое включение подсветки, это удобно. Возможность принудительного включения ещё удобней. Но если это, допустим освещение полок, с которых нужно что-то взять, то выключать руками уже может быть не очень удобно. В таких случаях можно использовать одну или несколько кнопок (тактовых или сенсорных).
Рассмотрим пример использования сенсорной кнопки, при нажатии на которую свет после последнего срабатывания датчика движения, будет выключаться немного позже, чем в обычном режиме. Сенсорные кнопки можно реализовать как на самой Arduino, так и с помощью внешнего модуля. Модули выпускаются разными фирмами.
Могут отличаться используемыми микросхемами, режимами работы, есть ли возможность и как настраивать режимы. Режим одиночного нажатия это когда нажали и на выходе установится один уровень, как только отпустили, другой. В режиме переключателя при каждом нажатии на выводе уровень меняется на противоположный. Так же может отличаться, какой уровень устанавливается. К примеру, в режиме одиночного нажатия, при нажатой кнопке может устанавливаться или высокий логический уровень или низкий.
В данном примере будет использован синий модуль, что на фото выше. Он работает в режиме одиночного нажатия. При нажатии, на выводе устанавливается низкий уровень, когда кнопка не нажата, устанавливается высокий уровень.
Схема подключения:
В данном случае, более удобным будет использовать аппаратные прерывания (для Uno, Nano и других плат на ATMega328p их можно настроить для цифровых выводов 2 и 3). Возможно сразу использование прерываний будет сложно для понимания, поэтому начнём с более простого кода и постепенно будем переделывать.
Загрузим такой скетч:
int ledPin = 13; int pirPin = 2; int buttonPin = 3; void setup() { pinMode(ledPin, OUTPUT); pinMode(pirPin, INPUT); pinMode(buttonPin, INPUT); digitalWrite(ledPin, LOW); delay(1000); } void loop() { if (digitalRead(pirPin) == HIGH) { do { digitalWrite(ledPin, HIGH); delay(250); digitalWrite(ledPin, LOW); delay(250); } while (digitalRead(pirPin) == HIGH); digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); } digitalWrite(ledPin, !digitalRead(buttonPin)); }
Пока нажата кнопка, светодиод светится. При срабатывании датчика движения светодиод будет мигать, затем на секунду включится, после чего выключится. Если всё подключено и работает нормально, можно загрузить следующий скетч:
int ledPin = 13; int pirPin = 2; int buttonPin = 3; volatile byte pirState = LOW; volatile byte buttonState = LOW; void setup() { pinMode(ledPin, OUTPUT); pinMode(pirPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(pirPin), onPir, CHANGE); pinMode(buttonPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(buttonPin), onButton, CHANGE); digitalWrite(ledPin, LOW); delay(1000); } void loop() { if (pirState) { do { digitalWrite(ledPin, HIGH); delay(250); digitalWrite(ledPin, LOW); delay(250); } while (pirState == HIGH); digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); } digitalWrite(ledPin, buttonState); } void onPir() { pirState = digitalRead(pirPin); } void onButton() { buttonState = !digitalRead(buttonPin); }
В нём реализовано тоже самое, но уже с прерываниями. Теперь можно загрузить скетч, в котором реализовано то, что изначально планировалось:
int ledPin = 13; int pirPin = 2; int buttonPin = 3; volatile byte motionDetected = false; const unsigned long shortTime = 1000; const unsigned long longTime = 3000; volatile unsigned long waitTime = shortTime; unsigned long lastMotion = 0; void setup() { pinMode(ledPin, OUTPUT); pinMode(pirPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(pirPin), onPir, CHANGE); pinMode(buttonPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(buttonPin), onButton, CHANGE); digitalWrite(ledPin, LOW); delay(1000); } void loop() { while (motionDetected) { digitalWrite(ledPin, HIGH); lastMotion = millis(); while (waitTime > (millis() - lastMotion)) if (digitalRead(pirPin) == HIGH || digitalRead(buttonPin) != HIGH) lastMotion = millis(); if (digitalRead(pirPin) != HIGH) { digitalWrite(ledPin, LOW); motionDetected = false; waitTime = shortTime; } } } void onPir() { if (digitalRead(pirPin) == HIGH) motionDetected = true; lastMotion = millis(); } void onButton() { motionDetected = true; { waitTime = longTime; lastMotion = millis(); } }
При нажатии на кнопку, светодиод включится на время longTime. Пока нажата кнопка, время будет продлеваться. При срабатывании датчика движения светодиод включится на время, на которое настроен сам датчик. Если датчик работает в «перезапускаемом» режиме, это время будет продлеваться до тех пор, пока датчик фиксирует движение. Если в константе shortTime задано значение больше 0, после установки низкого уровня на выходе датчика, светодиод будет светиться дополнительно на это заданное время. Время shortTime и longTime задаётся в миллисекундах (1 секунда = 1000 миллисекунд).
Что бы освещение не включалось, когда в нужном месте уже достаточно светло (светит лампа или солнце), к Arduino можно подключить фоторезистор. Соберём такой макет:
Схема:
С такой схемой, чем меньше будет освещён фоторезистор, тем меньшее значение будет считываться с АЦП. И наоборот, чем больше освещён, тем большее значение считывается.
Тестовый скетч:
int photoPin = A0; int ledPin = 13; int photoData; void setup(void) { Serial.begin(115200); } void loop(void) { photoData = analogRead(photoPin); Serial.print("Analog reading = "); Serial.println(photoData); delay(500); }
Фоторезисторы бывают с разными параметрами. С использованным фоторезистором, если поднести под лампу или посветить фонариком, считывается значение около 1000. Комната освещена, убираю фонарик и считывается значение около 600. Теперь закрываю фоторезистор пальцем, считывается около 200. Много, часть света похоже проходит. Накрываю колпачком от фломастера и значение падает до 0.
В реальных условиях возможно будет не полная темнота, немного света может попадать с улицы, из соседней комнаты и т.д. При каких значениях считать, что освещённость не достаточна и можно включить освещение, нужно определять в каждом конкретном случае. Для удобства, считываемые данные можно передавать на компьютер по Bluetooth или подключить к Arduino модуль экрана и выводить на экран. Посмотреть данные с фоторезистора и внести изменения в код в месте установки, будет очень легко если есть ноутбук. Некоторые смартфоны или планшеты для этого тоже можно использовать.
В следующем примере совместим фоторезистор и HC-SR501. В реальной задаче будет задействован мощный светодиод, светодиодная лента с адресуемыми или нет светодиодами, 220В лампа и т.д. С помощью чего управлять (реле, транзистор, симистор и т.д.), как подключать и управлять, может сильно отличаться. Что бы не усложнять, для примера будем включать и выключать светодиод на 13ом выводе Arduino.
Первые тесты Вы будете делать скорей всего возле компьютера явно не в полной темноте, для имитации отсутствия освещения можно использовать колпачок от фломастера или чем-то ещё прикрывать фоторезистор. В данном примере, когда с фоторезистора считывается число менее 80, будем считать, что слишком темно и при обнаружении движения нужно включить свет. Когда при обнаружении движения включится освещение, часть света может попадать на фоторезистор. Что бы свет сразу же не включался, это надо учитывать.
int ledPin = 13; int pirPin = 2; int photoPin = A0; int photoData = 0; bool isMotion = false; bool lightIsOn = false; void setup() { pinMode(ledPin, OUTPUT); pinMode(pirPin, INPUT); digitalWrite(ledPin, LOW); delay(1000); } void loop() { photoData = analogRead(photoPin); isMotion = digitalRead(pirPin); if (!lightIsOn) { if (photoData < 80 && isMotion) { digitalWrite(ledPin, HIGH); lightIsOn = true; } } else { if (!isMotion) { digitalWrite(ledPin, LOW); lightIsOn = false; } } delay(100); }
Из практики: С наступлением минусовой температуры освещение может включатся самопроизвольно