Raspberry Pi Pico: обнаружение движения с помощью PIR-датчика (MicroPython)
Узнайте, как подключить PIR-датчик движения к Raspberry Pi Pico для обнаружения движения в вашем окружении. Мы покажем, как подключить датчик к плате Pico, и напишем программу на прошивке MicroPython для выполнения определенного действия при обнаружении движения.
В этом руководстве мы рассмотрим следующие темы:
Предварительные требования – прошивка MicroPython
Для работы с этим руководством вам необходимо установить прошивку MicroPython на вашу плату Raspberry Pi Pico. Вам также потребуется IDE для написания и загрузки кода на плату.
Рекомендуемой IDE для MicroPython на Raspberry Pi Pico является Thonny IDE. Следуйте приведённому ниже руководству, чтобы узнать, как установить Thonny IDE, прошить прошивку MicroPython и загрузить код на плату.
Знакомство с PIR-датчиком движения
PIR-датчик движения обнаруживает изменения инфракрасного излучения в своём поле зрения. Это делает его идеальным для обнаружения людей или животных, поскольку он улавливает живые существа (или объекты, излучающие тепло), которые перемещаются в пределах его зоны действия, но не реагирует на неодушевлённые предметы.
Вы можете запрограммировать Pi на реакцию при изменении инфракрасного излучения, запустив событие, например, включение света, подачу сигнала тревоги, отправку уведомления или любое другое действие. В этом руководстве мы будем выводить сообщение в консоль и включать светодиод.
Существуют различные модули PIR-датчиков движения, но все они работают по одному принципу. У них есть вывод питания, GND и вывод данных.
PIR-датчик движения выдаёт HIGH сигнал на выводе Data при обнаружении движения или LOW сигнал, если движение не обнаружено. У него всего три вывода: VCC, GND и Data.
Некоторые модели, например HC-SR501, могут иметь два потенциометра (те два оранжевых потенциометра на изображении ниже) для настройки чувствительности и задержки по времени.
Потенциометр чувствительности: регулирует дальность обнаружения датчика. Поворот по часовой стрелке увеличивает чувствительность, против часовой стрелки – уменьшает.
Потенциометр задержки по времени: контролирует, как долго датчик остаётся в срабатывающем состоянии после обнаружения движения. Поворот по часовой стрелке увеличивает задержку, против часовой стрелки – уменьшает.
Подключение PIR-датчика движения к Pi Pico
PIR-датчик движения имеет три вывода: VCC, GND и Data. Вам нужно подключить VCC к выводу 3V3 (или 5V в зависимости от модели), GND к выводу GND, а вывод Data к подходящему GPIO Raspberry Pi Pico – мы подключим его к GPIO 22 (ознакомьтесь с распиновкой Raspberry Pi Pico). Мы также добавим светодиод к GPIO 21 для визуальной обратной связи в вашем проекте.
PIR-датчик движения |
Raspberry Pi Pico |
|---|---|
Vin/3v3 |
3.3V или 5V в зависимости от модели |
Data |
GPIO 22 (или другой GPIO по вашему выбору) |
GND |
GND |
Мы будем использовать мини PIR-датчик движения AM312, потому что он работает от 3.3V, что идеально подходит для Raspberry Pi. Но вы можете использовать любой другой модуль PIR-датчика движения. Принцип работы одинаковый.
Вот список компонентов, необходимых для этого проекта:
Плата Raspberry Pi Pico
Мини PIR-датчик движения
Светодиод
Резистор 220 Ом
Макетная плата
Соединительные провода
PIR-датчик движения – обнаружение движения (MicroPython)
Существует множество различных способов написать программу для обнаружения движения с помощью PIR-датчика. Самый простой способ – просто считывать состояние PIR-датчика, как вы бы считывали любой другой цифровой вход.
Например:
from machine import Pin
from time import sleep
pir_pin = Pin(22, Pin.IN)
led_pin = Pin (21, Pin.OUT)
while True:
if pir_pin.value():
print("Motion detected!")
led_pin.value(1)
sleep(1)
led_pin.value(0)
Однако это может быть не лучшим решением, потому что вывод данных PIR-датчика движения остаётся в состоянии HIGH в течение нескольких секунд, прежде чем вернуться в LOW. Лучший способ – обнаружить точный момент, когда состояние переходит из LOW в HIGH (режим нарастающего фронта), и обеспечить лучшую отзывчивость. Для этого мы можем использовать прерывания.
Знакомство с прерываниями
Прерывания полезны для автоматического выполнения действий в программах микроконтроллеров и могут помочь решить проблемы синхронизации. С помощью прерываний вам не нужно постоянно проверять текущее значение вывода. При обнаружении изменения запускается событие (вызывается функция – эта функция часто называется ISR (процедура обработки прерывания)).
Когда происходит прерывание, процессор приостанавливает выполнение основной программы для выполнения задачи, а затем возвращается к основной программе, как показано на рисунке ниже.
Это особенно полезно для запуска действия при обнаружении движения или при нажатии кнопки без необходимости постоянно проверять их состояние.
Настройка прерывания на Raspberry Pi Pico в MicroPython
Чтобы настроить прерывание в MicroPython, необходимо выполнить следующие шаги:
1. Определите функцию обработки прерывания (ISR). Функция обработки прерывания должна быть как можно проще, чтобы процессор быстро вернулся к выполнению основной программы. Лучший подход – сигнализировать основному коду о том, что прерывание произошло, используя, например, глобальную переменную.
Функция обработки прерывания должна принимать параметр типа Pin. Этот параметр передаётся в функцию обратного вызова и указывает на GPIO, который вызвал прерывание. Следует избегать выполнения длительных задач внутри ISR. Также не следует использовать обычную функцию print внутри неё.
def handle_interrupt(pin):
2. Настройте GPIO, который будет действовать как вывод прерывания, как вход. Например, в нашем случае мы используем GPIO 22:
pir = Pin(22, Pin.IN)
3. Привяжите прерывание к этому выводу, вызвав метод irq():
pir.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
Метод irq() принимает следующие аргументы:
trigger: определяет режим срабатывания. В MicroPython существуют различные условия:
Pin.IRQ_FALLING: запуск прерывания при переходе вывода из HIGH в LOW;
Pin.IRQ_RISING: запуск прерывания при переходе вывода из LOW в HIGH.
Pin.IRQ_LOW_LEVEL: прерывание происходит, когда вывод находится в состоянии LOW (не поддерживается на плате Pico на момент написания этой статьи).
Pin.IRQ_HIGH_LEVEL: прерывание происходит, когда вывод находится в состоянии HIGH (не поддерживается на плате Pico на момент написания этой статьи).
Pin.IRQ_FALLING | Pin.IRQ_RISING: прерывание как по нарастающему, так и по спадающему фронту.
handler: это функция, которая будет вызвана при обнаружении прерывания, в данном случае функция handle_interrupt().
Raspberry Pi Pico с PIR-датчиком движения и прерываниями – код MicroPython
Следующий код MicroPython для Raspberry Pi Pico отслеживает подключённый PIR-датчик движения. Когда PIR-датчик обнаруживает движение, он включает светодиод для визуальной обратной связи и выводит «Motion detected!» в консоль. Когда движение прекращается, он выключает светодиод и выводит «Motion stopped» в консоль. Код непрерывно выполняется в цикле до тех пор, пока не будет прерван командой клавиатуры или когда возникнет исключение.
from machine import Pin
from time import sleep
# Определяем вывод PIR-датчика как вход
pir_pin = Pin(22, Pin.IN)
# Определяем вывод светодиода (опционально, для визуальной обратной связи)
led_pin = Pin(21, Pin.OUT)
# Флаги для отслеживания состояния обнаружения движения
motion_detected = False
motion_stopped_printed = False
# Функция обратного вызова для обработки обнаружения движения
def pir_interrupt(pin):
global motion_detected
if pin.value() == 1: # Нарастающий фронт (движение обнаружено)
motion_detected = True
led_pin.value(1) # Включаем светодиод
else: # Спадающий фронт (движение прекратилось)
motion_detected = False
led_pin.value(0) # Выключаем светодиод
# Настраиваем прерывание на выводе PIR для обоих фронтов — нарастающего и спадающего
pir_pin.irq(trigger=(Pin.IRQ_RISING | Pin.IRQ_FALLING), handler=pir_interrupt)
try:
while True:
if motion_detected and not motion_stopped_printed:
print("Motion detected!")
motion_stopped_printed = True # Устанавливаем флаг обнаружения движения
elif not motion_detected and motion_stopped_printed:
print("Motion stopped")
motion_stopped_printed = False # Сбрасываем флаг
sleep(0.1) # Задержка основного цикла
except KeyboardInterrupt:
print("Keyboard interrupt")
pir_pin.irq(trigger=0) # Отключаем прерывание
led_pin.value(0) # Выключаем светодиод
except Exception as e:
print("An unexpected exception occurred:", e)
Как работает код?
Продолжайте чтение, чтобы узнать, как работает код, или перейдите к разделу Демонстрация.
Импорт библиотек
Следующие строки импортируют необходимые библиотеки для работы с выводами GPIO и реализации задержек по времени.
from machine import Pin
from time import sleep
Определение выводов
В этом разделе код определяет выводы для входа PIR-датчика и опционального светодиода для визуальной обратной связи. Мы подключаем датчик к GPIO 22, а светодиод к GPIO 21. В качестве альтернативы вы можете использовать любые другие подходящие выводы (просто убедитесь, что вы изменили код с учётом используемых выводов).
# Определяем вывод PIR-датчика как вход
pir_pin = Pin(22, Pin.IN)
# Определяем вывод светодиода (опционально, для визуальной обратной связи)
led_pin = Pin(21, Pin.OUT)
Флаги обнаружения движения
Мы создаём две переменные для отслеживания состояния обнаружения движения. Переменная motion_detected устанавливается в True при обнаружении движения, а motion_stopped_printed используется для отслеживания того, было ли выведено сообщение «Motion stopped» в консоль (это нужно для предотвращения многократного вывода одного и того же сообщения, когда движение не обнаруживается).
# Флаги для отслеживания состояния обнаружения движения
motion_detected = False
motion_stopped_printed = False
Функция обратного вызова для обнаружения движения
Определяется функция обратного вызова с именем pir_interrupt для обработки прерываний, генерируемых PIR-датчиком. Эта функция будет вызываться каждый раз при обнаружении движения.
# Функция обратного вызова для обработки обнаружения движения
def pir_interrupt(pin):
global motion_detected
if pin.value() == 1: # Нарастающий фронт (движение обнаружено)
motion_detected = True
led_pin.value(1) # Включаем светодиод
else: # Спадающий фронт (движение прекратилось)
motion_detected = False
led_pin.value(0) # Выключаем светодиод
Функция pir_interrupt имеет входной параметр (pin), в который при возникновении прерывания передаётся объект класса Pin (он указывает, какой вывод вызвал прерывание).
Эта функция переключает переменную motion_detected и управляет светодиодом в зависимости от нарастающего и спадающего фронтов сигнала PIR-датчика. Если pin.value() равно 1, что означает, что вывод данных PIR-датчика находится в состоянии HIGH, мы устанавливаем переменную motion_detected в True и включаем светодиод.
if pin.value() == 1: # Нарастающий фронт (движение обнаружено)
motion_detected = True
led_pin.value(1) # Включаем светодиод
Если pin.value() не равно 1, это означает, что вывод данных PIR-датчика перешёл из HIGH в LOW. Поэтому мы можем установить переменную motion_detected в False и выключить светодиод, потому что движение больше не обнаруживается.
else: # Спадающий фронт (движение прекратилось)
motion_detected = False
led_pin.value(0) # Выключаем светодиод
Настройка прерываний
Следующая строка настраивает прерывание на выводе PIR для срабатывания как по нарастающему, так и по спадающему фронту. Функция pir_interrupt будет вызвана при обнаружении этих фронтов. Это означает, что мы будем обнаруживать как момент начала движения, так и момент его прекращения.
pir_pin.irq(trigger=(Pin.IRQ_RISING | Pin.IRQ_FALLING), handler=pir_interrupt)
Цикл While
Основной цикл непрерывно проверяет состояние переменной motion_detected и предоставляет обратную связь соответственно. Он выводит сообщения при обнаружении или прекращении движения. Чтобы предотвратить многократный вывод одного и того же сообщения, мы также проверяем состояние переменной motion_stopped_printed.
try:
while True:
if motion_detected and not motion_stopped_printed:
print("Motion detected!")
motion_stopped_printed = True # Устанавливаем флаг обнаружения движения
elif not motion_detected and motion_stopped_printed:
print("Motion stopped")
motion_stopped_printed = False # Сбрасываем флаг
sleep(0.1) # Задержка основного цикла
Обработка исключений
Код включает обработку исключений для обработки прерываний клавиатуры (например, при остановке скрипта) и других непредвиденных исключений. При остановке скрипта он отключает прерывание и выключает светодиод.
except KeyboardInterrupt:
print("Keyboard interrupt")
pir_pin.irq(trigger=0) # Отключаем прерывание
led_pin.value(0) # Выключаем светодиод
except Exception as e:
print("An unexpected exception occurred:", e)
Демонстрация
Сохраните код на вашу плату Raspberry Pi Pico с помощью Thonny IDE или любой другой IDE для MicroPython по вашему выбору.
Скопируйте предоставленный код в новый файл в Thonny IDE.
Скопировав код в файл, нажмите на иконку Save. Затем выберите Raspberry Pi Pico.
Сохраните файл под именем: main.py.
Примечание
Когда вы называете файл main.py, Raspberry Pi Pico будет запускать этот файл автоматически при загрузке. Если вы дадите ему другое имя, он всё равно будет сохранён в файловой системе платы, но не будет запускаться автоматически при загрузке.
Нажмите маленькую зелёную кнопку «Run Current Script» или нажмите F5.
Теперь протестируйте вашу установку. Помашите рукой перед датчиком движения. В консоли появится сообщение «Motion Detected!».
И светодиод загорится. Светодиод будет гореть до тех пор, пока вывод данных PIR-датчика находится в состоянии HIGH (это может зависеть от модели используемого вами PIR-датчика).
Через несколько секунд, если движение больше не обнаруживается, вы получите сообщение «motion stopped» и светодиод погаснет.
Заключение
В этом руководстве вы узнали, как использовать PIR-датчик с Raspberry Pi Pico для обнаружения движения. Вы научились использовать прерывания для выполнения задач при обнаружении движения.
Для простоты мы просто включали и выключали светодиод. В реальном сценарии вы можете захотеть отправить уведомление на свой смартфон, отправить электронное письмо, включить лампу, отправить сообщение по MQTT или выполнить любое другое действие.
Надеемся, что это руководство было вам полезно. У нас есть другие руководства по Raspberry Pi Pico, которые могут вас заинтересовать:
Raspberry Pi Pico: управление цифровыми выходами и чтение цифровых входов (MicroPython)
Raspberry Pi Pico: ШИМ-управление яркостью светодиода (MicroPython)
Raspberry Pi Pico: датчик температуры и влажности DHT11/DHT22 (MicroPython)
Raspberry Pi Pico: датчик температуры DS18B20 (MicroPython) – одиночный и множественный