Raspberry Pi Pico: обнаружение движения с помощью PIR-датчика (Arduino IDE)

Узнайте, как подключить PIR-датчик движения к Raspberry Pi Pico для обнаружения движения в окружающем пространстве. Мы покажем, как подключить датчик к плате Pico, и напишем скетч Arduino для выполнения определённой задачи при обнаружении движения.

Raspberry Pi Pico: обнаружение движения с помощью PIR-датчика Arduino IDE

В этом руководстве мы рассмотрим следующие темы:

Необходимые условия

Вам нужно установить платы Raspberry Pi Pico в Arduino IDE и знать, как загружать код на плату. Если вы ещё этого не сделали, ознакомьтесь со следующим руководством:

Знакомство с PIR-датчиком движения

PIR-датчик движения обнаруживает изменения инфракрасного излучения в своём поле зрения. Это делает его идеальным для обнаружения людей или животных, поскольку он улавливает живые существа (или объекты, излучающие тепло), которые перемещаются в пределах его зоны действия, но не обнаруживает неодушевлённые предметы.

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

Мини PIR-датчик движения AM312 с подписанными выводами

Существуют различные модули PIR-датчиков движения, но все они работают одинаково. У них есть вывод питания, GND и вывод данных.

PIR-датчик движения выдаёт сигнал HIGH на выводе Data при обнаружении движения или сигнал LOW, если движения нет. У него всего три вывода: VCC, GND и Data.

Как работает PIR-датчик движения

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

PIR-датчик движения HC-SR501
  • Потенциометр чувствительности: настраивает дальность обнаружения датчика. Вращение по часовой стрелке увеличивает чувствительность, против часовой стрелки — уменьшает.

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

Подключение PIR-датчика движения к Pi Pico

PIR-датчик движения имеет три вывода: VCC, GND и Data. Подключите VCC к выводу 3V3 (или 5V в зависимости от модели), GND к выводу GND, а вывод Data к подходящему GPIO Raspberry Pi Pico — мы подключим его к GPIO 22 (ознакомьтесь с распиновкой Raspberry Pi Pico).

Схема подключения PIR-датчика движения к Raspberry Pi Pico

PIR-датчик движения

Raspberry Pi Pico

Vin/3v3

3.3V или 5V (в зависимости от модели)

Data

GPIO 22 (или другой GPIO по вашему выбору)

GND

GND

Мы будем использовать мини PIR-датчик движения AM312, потому что он работает от 3.3V, что идеально подходит для Raspberry Pi. Но вы можете использовать любой другой модуль PIR-датчика движения. Принцип работы одинаковый.

Мы также подключим светодиод к GPIO 21 для визуальной обратной связи в нашем проекте.

Вот список компонентов, необходимых для этого проекта:

  • Плата Raspberry Pi Pico

  • Мини PIR-датчик движения

  • Светодиод

  • Резистор 220 Ом

  • Макетная плата

  • Соединительные провода

Схема подключения PIR-датчика движения к Raspberry Pi Pico

PIR-датчик движения – обнаружение движения (Arduino IDE)

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

Например:

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-motion-pir-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

int led = 21;                // the pin that the LED is atteched to
int sensor = 22;              // the pin that the sensor is atteched to
int state = LOW;             // by default, no motion detected
int val = 0;                 // variable to store the sensor status (value)

void setup() {
  pinMode(led, OUTPUT);      // initalize LED as an output
  pinMode(sensor, INPUT);    // initialize sensor as an input
  Serial.begin(9600);        // initialize serial
}

void loop(){
  val = digitalRead(sensor);   // read sensor value
  if (val == HIGH) {           // check if the sensor is HIGH
    digitalWrite(led, HIGH);   // turn LED ON
    delay(100);                // delay 100 milliseconds

    if (state == LOW) {
      Serial.println("Motion detected!");
      state = HIGH;       // update variable state to HIGH
    }
  }
  else {
      digitalWrite(led, LOW); // turn LED OFF
      delay(200);             // delay 200 milliseconds

      if (state == HIGH){
        Serial.println("Motion stopped!");
        state = LOW;       // update variable state to LOW
    }
  }
}

Однако это может быть не лучшим решением, поскольку вам нужно постоянно опрашивать состояние вывода, к которому подключён датчик. Обычно лучший способ обнаружить точный момент, когда состояние переходит из LOW в HIGH (режим RISING), и получить лучшую отзывчивость — это использовать прерывания. Но в упрощённом коде выше нет ничего плохого, если он хорошо работает для вашего проекта.

Знакомство с прерываниями

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

Когда происходит прерывание, процессор останавливает выполнение основной программы для выполнения задачи, а затем возвращается к основной программе, как показано на рисунке ниже.

Прерывания Raspberry Pi Pico — схема работы

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

Настройка прерывания в Arduino IDE для Raspberry Pi Pico

Прежде чем перейти к полному примеру, давайте кратко рассмотрим, как настроить прерывание на одном из GPIO Raspberry Pi Pico.

Функция attachInterrupt()

Для настройки прерывания в Arduino IDE используется функция attachInterrupt(), которая принимает в качестве аргументов: вывод GPIO прерывания, имя вызываемой функции и режим.

attachInterrupt(digitalPinToInterrupt(GPIO), ISR, mode);
Вывод GPIO прерывания

Первый аргумент — это GPIO прерывания. Следует использовать digitalPinToInterrupt(GPIO) для установки фактического GPIO в качестве вывода прерывания. Например, если вы хотите использовать GPIO 22 в качестве прерывания, используйте:

digitalPinToInterrupt(22)
ISR

Второй аргумент функции attachInterrupt() — это имя функции, которая будет вызываться каждый раз при срабатывании прерывания — подпрограмма обработки прерывания (ISR).

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

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

Режимы прерываний

Третий аргумент — это режим, и существуют 3 различных режима:

  • CHANGE: для запуска прерывания при любом изменении значения на выводе — например, с HIGH на LOW или с LOW на HIGH;

  • FALLING: когда вывод переходит из HIGH в LOW;

  • RISING: для запуска при переходе вывода из LOW в HIGH.

Для нашего примера мы будем использовать режим RISING, потому что когда PIR-датчик движения обнаруживает движение, GPIO, к которому он подключён, переходит из LOW в HIGH.

Raspberry Pi Pico с PIR-датчиком движения и прерываниями – код Arduino

Следующий скетч Arduino для Raspberry Pi Pico отслеживает PIR-датчик движения, подключённый к GPIO 22. Когда PIR-датчик обнаруживает движение, Pico включает светодиод для визуальной обратной связи и выводит «Motion detected!» в консоль. Когда движение прекращается, он выключает светодиод и выводит «Motion stopped» в консоль.

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-motion-pir-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

#define timeSeconds 10

// Set GPIOs for LED and PIR Motion Sensor
const int led = 21;
const int motionSensor = 22;

// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;
boolean motion = false;

// Runs when motion is detected, sets LED HIGH and starts a timer
void detectsMovement() {
  digitalWrite(led, HIGH);
  startTimer = true;
  lastTrigger = millis();
}

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);

  // PIR Motion Sensor mode INPUT_PULLUP
  pinMode(motionSensor, INPUT_PULLUP);
  // Set motionSensor pin as interrupt, assign interrupt function and set RISING mode
  attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

  // Set LED to LOW
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
}

void loop() {
  // Current time
  now = millis();
  if((digitalRead(led) == HIGH) && (motion == false)) {
    Serial.println("MOTION DETECTED!!!");
    motion = true;
  }
  // Turn off the LED after the number of seconds defined in the timeSeconds variable
  if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
    Serial.println("Motion stopped...");
    digitalWrite(led, LOW);
    startTimer = false;
    motion = false;
  }
}

Как работает код?

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

Предыдущий код обнаруживает движение с помощью PIR-датчика движения. При обнаружении движения Pico включает светодиод и запускает таймер. Если в течение определённого периода времени дальнейшее движение не обнаружено, светодиод выключается. Давайте разберём код шаг за шагом.

Константы и переменные

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

#define timeSeconds 10

// Set GPIOs for LED and PIR Motion Sensor
const int led = 21;
const int motionSensor = 22;

// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;
boolean motion = false;

Переменная timeSeconds определяет продолжительность (в секундах), в течение которой светодиод будет гореть при обнаружении движения — вы можете изменить это значение.

#define timeSeconds 10

Мы также создаём переменные для хранения номеров GPIO, к которым подключены светодиод и датчик. Мы подключаем датчик к GPIO 22, а светодиод к GPIO 21, но вы можете использовать любые другие подходящие выводы Raspberry Pi Pico.

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

// Timer: Auxiliar variables
long now = millis();
long lastTrigger = 0;
boolean startTimer = false;

Переменная now хранит текущее время. Переменная lastTrigger хранит время, когда PIR-датчик обнаружил движение. Переменная startTimer — это логическая переменная, которая запускает таймер при обнаружении движения.

Функция detectsMovement()

Функция detectsMovement() будет вызвана при обнаружении движения PIR-датчиком. Она включает светодиод, устанавливает флаг startTimer в true (чтобы таймер начал отсчёт) и записывает текущее время в переменную lastTrigger.

// Runs when motion is detected, sets LED HIGH and starts a timer
void detectsMovement() {
  digitalWrite(led, HIGH);
  startTimer = true;
  lastTrigger = millis();
}

Функция setup()

В функции setup() начинаем с инициализации последовательного порта на скорости 115200 бод.

Serial.begin(115200);

Устанавливаем PIR-датчик движения как INPUT_PULLUP.

pinMode(motionSensor, INPUT_PULLUP);

Для установки вывода PIR-датчика в качестве прерывания используем функцию attachInterrupt(), как описано ранее.

attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);

Вывод, который будет обнаруживать движение, — это GPIO 22, и он вызовет функцию detectsMovement() в режиме RISING.

Светодиод является OUTPUT, и его начальное состояние — LOW.

pinMode(led, OUTPUT);
digitalWrite(led, LOW);

Функция loop()

Функция loop() постоянно выполняется снова и снова. В каждом цикле переменная now обновляется текущим временем.

now = millis();

Больше ничего в loop() не происходит. Но при обнаружении движения вызывается функция detectsMovement(), потому что мы ранее в setup() настроили прерывание.

Функция detectsMovement(), как мы упоминали ранее, выводит сообщение в монитор порта, включает светодиод, устанавливает логическую переменную startTimer в true и обновляет переменную lastTrigger текущим временем.

void IRAM_ATTR detectsMovement() {
  Serial.println("MOTION DETECTED!!!");
  digitalWrite(led, HIGH);
  startTimer = true;
  lastTrigger = millis();
}

После этого шага код возвращается к loop().

На этот раз переменная startTimer имеет значение true. Поэтому, когда определённое в секундах время прошло (с момента обнаружения движения), следующее условие if станет истинным.

if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
  Serial.println("Motion stopped...");
  digitalWrite(led, LOW);
  startTimer = false;
}

Сообщение «Motion stopped…» будет выведено в монитор порта, светодиод выключится, и переменная startTimer будет установлена в false.

Вот краткое описание того, как работает код.

Загрузка кода на Raspberry Pi Pico

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

Если Raspberry Pi в данный момент работает с прошивкой MicroPython, вам нужно вручную перевести её в режим загрузчика. Для этого подключите Raspberry Pi Pico к компьютеру, одновременно удерживая кнопку BOOTSEL.

Raspberry Pi Pico — режим загрузчика

Для последующих загрузок с помощью Arduino IDE плата должна автоматически переходить в режим загрузчика без необходимости нажимать кнопку BOOTSEL.

Теперь выберите COM-порт в меню Tools > Port. Возможно, COM-порт будет неактивен (серым цветом). Если это так, не беспокойтесь — он автоматически найдёт порт, когда вы нажмёте кнопку загрузки.

Raspberry Pi Pico — COM-порт не найден в Arduino IDE

Загрузите код.

Вы должны получить сообщение об успешной загрузке.

Успешная загрузка кода на Raspberry Pi Pico в Arduino IDE

Демонстрация

После загрузки кода откройте монитор порта на скорости 115200 бод. Теперь протестируйте вашу установку. Помашите рукой перед датчиком движения. В мониторе порта появится сообщение «MOTION DETECTED!».

И светодиод загорится на 10 секунд (или на время, указанное в переменной timeSeconds).

Raspberry Pi Pico — демонстрация обнаружения движения PIR-датчиком

Через 10 секунд (или указанное время) светодиод погаснет, и вы получите сообщение «Motion stopped…».

Обнаружение движения Raspberry Pi Pico — вывод в мониторе порта Arduino IDE

Заключение

В этом руководстве вы узнали, как использовать PIR-датчик с Raspberry Pi Pico для обнаружения движения. Вы научились использовать прерывания для выполнения задач при обнаружении движения.

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

Надеемся, это руководство было для вас полезным. У нас есть другие руководства по Raspberry Pi Pico, которые могут вас заинтересовать: