👮 Raspberry Pi начеку: делаем за час охранную систему с помощью датчика расстояния и камеры
Создаем охранную систему с помощью Raspberry Pi, датчика расстояния HC-SR04 и камеры. Снимки нарушителя границ безопасности отправляем на почту и получаем уведомление в мобильное приложение IFTTT.
Что делаем?
Делаем простую сигнализацию на ультразвуковом датчике расстояния HC-SR04. Когда датчик обнаруживает препятствие, мы получаем уведомление в мобильном приложении IFTTT о срабатывании сигнализации, а камера делает 3 снимка, которые отправляются с Gmail-почты на любую другую почту.
Что понадобится?
- Raspberry Pi 3/4.
- Резисторы 1 кОм и 2 кОм по 1 шт.
- Ультразвуковой датчик расстояния HC-SR04.
- Модуль камеры Raspberry Pi Camera v1.3 или v2.1.
Установка операционной системы
Скачаем операционную систему Raspberry Pi OS и установим ее на microSD-карту с помощью balenaEtcher.
Ультразвуковой датчик HC-SR04
Что такое ультразвук?
Человек слышит звуки в диапазоне от 20 (низкий бас) до 20 000 Гц (высокочастотный свист). Ультразвук имеет частоту более 20 000 Гц и поэтому человек его не слышит.
Датчик HC-SR04 работает, как сонар:
- Отправляет ультразвуковой импульс.
- Ловит отраженный от препятствия импульс.
- Вычисляет сколько времени потребовалось импульсу, чтобы достигнуть препятствия и вернуться обратно.
Характеристики датчика HC-SR04:
- Напряжение питания: 5 В.
- Диапазон расстояний: 2-400 см.
- Эффективный угол наблюдения: 15°.
- Рабочий угол наблюдения: 30°.
Как вычислить пройденное расстояние?
Зная скорость распространения звука в среде и временной интервал, можем вычислить расстояние:
Датчик считает расстояние туда-обратно. Нам нужна половина этого значения:
Скорость звука при температуре 20°C составляет 34 300 см/с.
После подстановки значений получаем:
Нумерация пинов Raspberry Pi
В Малине используют две системы нумерации пинов:
GPIO.BOARD– пины нумеруются слева направо и сверху вниз от 1 до 40.GPIO.BCM– пины нумеруются по Broadcom SOC и называются GPIO [номер]. На рис. в скобках указаны альтернативные значения пинов.
Мы будем использовать нумерацию GPIO.BCM со значениями пинов по умолчанию.
Схема подключения HC-SR04 к Raspberry Pi
- Пин питания
VCCподключаем к пину5Vна Малине (красная линия). - Пин земли
GNDподключаем к пинуGNDна Малине (синяя линия). - Пин
Echoподключаем кGPIO 26(зеленая линия). - Пин
Trigподключаем кGPIO 19(оранжевая линия).
После получения импульса на пине Echo устанавливается логический уровень 5 В, а Малина работает с логикой 3.3 В. Чтобы понизить напряжение добавим в схему два резистора разных номиналов, образующих делитель напряжения. Для расчета номиналов воспользуемся онлайн-калькулятором:
Нам нужны резисторы 1 и 2 кОм. Можно подобрать резисторы других номиналов. Главное – получить напряжение не выше 3.3 В, чтобы не испортить Малину.
На макетной плате поменяем положение датчика на «от» Raspberry Pi:
Подключение камеры
Установим шлейф камеры в Малину:
Присоединим шлейф к камере аналогичным образом:
Камера по умолчанию отключена. Для активации камеры зайдем в Меню → Preferences → Raspberry Pi Configuration:
Перейдем во вкладку Interfaces и активируем камеру:
Создание апплета IFTTT
Зарегистрируемся на сайте IFTTT и перейдем на страницу создания апплета.
В условие If This добавим Receive a web request, в условие Then That – Send a notification from IFTTT app.
В условии If This назовем событие signal:
Теперь перейдем на страницу Вебхуков и кликнем по кнопке Documentation:
Впишем название события signal и получим ссылку, которая активирует наше событие.
Установим мобильное приложение IFTTT на Android или iOS, чтобы получать уведомления.
Установка библиотек
Установим библиотеку yagmail для отправки почты с аккаунта Gmail:
pip3 install yagmail
Остальные библиотеки – RPi.GPIO для работы с пинами и picamera для управления камерой – предустановлены.
Запускаем код
Импортируем необходимые библиотеки:
from picamera import PiCamera import RPi.GPIO as GPIO import datetime import requests import yagmail import time import os
Напишем функцию create_shots_folder(), которая создает папку для снимков:
# функция, проверяющая наличие/создающая папку shots
def create_shots_folder():
# если папки shots не существует
if not os.path.exists('shots'):
# то создать папку shots в текущем каталоге
os.mkdir('shots')
Функция take_shots(number_of_shots) управляет камерой и принимает на вход в качестве аргумента количество снимков number_of_shots:
# функция, управляющая камерой
def take_shots(number_of_shots):
# инициализация камеры
camera = PiCamera()
# задаем разрешение снимка
camera.resolution = (1024, 768)
# список, в который добавим пути к снимкам
shots = []
# цикл, который number_of_shots-раз сделает снимки с паузой 0.5 сек
for i in range(number_of_shots):
# получим текущую дату и время без миллисекунд
time_of_the_crime = datetime.datetime.today().replace(microsecond=0)
# присвоим снимку имя: текущая дата и время плюс расширение .jpg
shot_name = str(time_of_the_crime) + '.jpg'
# получим путь к снимку
shot_path = os.path.join(os.getcwd(), 'shots', shot_name)
# сделаем снимок и сохраним его в папку shots под именем shot_name
camera.capture(shot_path)
print('Сделал снимок:', shot_name)
# добавим путь к снимку в список снимков shots
shots.append(shot_path)
# пауза между снимками в секундах
pause = 0.5
time.sleep(pause)
# отключим камеру
camera.close()
return shots
Здесь:
shot_name– название снимка: текущая дата и время без миллисекунд.shot_path– путь к снимку.shots– список с путями.pause– пауза между снимками.
Функция send_email() отправляет снимки с Gmail-почты на любую другую почту:
def send_email(sender_email, sender_email_password, recipient_email, number_of_shots):
# список с путями снимков
shots = take_shots(number_of_shots)
# senders_email - Gmail-адрес отправителя
# senders_email_password - пароль от Gmail
email = yagmail.SMTP(user=sender_email, password=sender_email_password)
# subject - тема письма
# contents - содержимое письма
# attachments - вложения (снимки)
email.send(to=recipient_email, subject='Проникновение в помещение', contents='Тревога!', attachments=shots)
print('Снимки отправлены на почту.\n')
sender_email– адрес Gmail-почты и пароль от нееsender_email_password.recipient_email– почтовый адрес получателя.
Чтобы отправить почту через скрипт, нужно открыть доступ для небезопасных приложений. Для этого зайдите в профиль Гугл-почты → Безопасность → Ненадежные приложения, у которых есть доступ к аккаунту и откройте доступ ненадежным приложениям.
Функция send_ifttt_notification() отправляет POST-запрос в IFTTT, активируя апплет:
def send_ifttt_notification():
# ссылка на апплет IFTTT
link = 'https://maker.ifttt.com/trigger/НАЗВАНИЕ_ПРИЛОЖЕНИЯ/with/key/КЛЮЧ'
# отправляем post-запрос в IFTTT, чтобы сработал апплет
requests.post(link)
print('Уведомление отправлено в приложение IFTTT.')
Пины нужно объявлять один раз, поэтому напишем отдельную функцию setup_GPIO() и вызовем ее в начале работы отдельно один раз:
def setup_GPIO():
# отключим уведомления об ошибках
GPIO.setwarnings(False)
# используем нумерацию выводов BCM
GPIO.setmode(GPIO.BCM)
# пин Trig
TRIGGER = 19
# пин Echo
ECHO = 26
# установим режим работы пина TRIGGER на Выход
GPIO.setup(TRIGGER, GPIO.OUT)
# установим режим работы пина ECHO на Вход со стягивающим резистором
GPIO.setup(ECHO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
return TRIGGER, ECHO
Здесь:
TRIGGERиECHOподключены к пинамGPIO 19и26соответственно.GPIO.setup(TRIGGER, GPIO.OUT)– пинTRIGGERустановлен на выходной сигнал.GPIO.setup(ECHO, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)– пинECHOустановлен на входной сигнал со стягивающим резисторомGPIO.PUD_DOWN, который устанавливает на пине изначальное значениеLOW. Без этой опции на пине из-за помех может появиться логическая единица и мы получим ложное срабатывание и первый циклwhileв функцииultrasonic_detection()не сработает.
Функция pause() добавляет паузу после объявления пинов. Без паузы датчик работает некорректно.
def ultrasonic_detection(TRIGGER, ECHO):
# подадим импульс, т . е. установим состояние пина на HIGH
GPIO.output(TRIGGER, GPIO.HIGH)
# длительность импульса 0.00001 сек
time.sleep(0.00001)
# установим состояние пина TRIGGER на LOW
GPIO.output(TRIGGER, GPIO.LOW)
# считываем состояние пина ECHO
# пока ничего не происходит, фиксируем текущее время start
while GPIO.input(ECHO) == 0:
start = time.time()
# если обнаружено движение, зафиксируем время end
while GPIO.input(ECHO) == 1:
end = time.time()
Здесь:
GPIO.output(TRIGGER, GPIO.HIGH)– чтобы запустить датчик в работу, подаем на пинTriggerимпульс длительностью 10 микросекунд (time.sleep(0.00001))while GPIO.input(ECHO) == 0– пока отраженного сигнала нет, присваиваем переменнойstartтекущее время.while GPIO.input(ECHO) == 1– при получении отраженного сигнала, фиксируем времяend.
# рассчитаем длительность сигнала
signal_duration = end - start
# рассчитаем расстояние до объекта
distance = round(signal_duration * 17150, 2)
distance– длительность сигнала, округленная до второго значения после запятой.
# если объект обнаружен на расстоянии от 3 до 15 см
if 3 < distance < 15:
print("Замечено движение на расстоянии", distance, "см. от датчика.")
# отправим уведомление в приложение IFTTT
send_ifttt_notification()
# отправим снимки на почту
send_email(sender_email='gmail', sender_email_password='gmail_password',
recipient_email='email', number_of_shots=3)
Если препятствие обнаружено на расстоянии 3-15 см, то в приложение IFTTT отправляется уведомление, а на почту – снимки.
def main():
create_shots_folder()
TRIGGER, ECHO = setup_GPIO()
pause(10)
while True:
try:
ultrasonic_detection(TRIGGER, ECHO)
except KeyboardInterrupt:
GPIO.cleanup()
if __name__ == "__main__":
main()
Здесь:
except KeyboardInterrupt: GPIO.cleanup()– возвращает пины в начальное состояние при выходе из программы черезCTRL + C.
При обнаружение движения скрипт будет выводить следующее:
У меня ничего не работает
На СтакОверфлоу у многих возникает проблема с тем, что второй цикл while GPIO.input(ECHO) == 1: не срабатывает, то есть сигнал ECHO всегда равен 0. Возможно, резисторы не касаются дорожек макетной платы. Установите ножки строго вертикально, чтобы они не изгибались и попадали на дорожку.
Если и это не помогло, то запустите скрипт и завершите работу, нажав Ctrl + C, чтобы сработало исключение KeyboardInterrupt: GPIO.cleanup() и пины вернулись к исходным значениям.
Если температура окружающей среды изменилась, то подкорректируйте скорость звука в среде.
Со звукопоглощающими материалами датчик HC-SR04 работать не будет.
GitHub
Код лежит в репозитории ultrasonic-rpi-alarm.
В этой статье мы:
- научились программировать Raspberry Pi 3/4;
- работать с пинами GPIO;
- управлять камерой Raspberry Pi Camera и датчиком расстояния HC-SR04;
- отправлять почту с вложениями;
- создавать апплеты IFTTT.
Материалы по теме
- Что должен знать начинающий IoT-разработчик в 2021 году?
- 25 ресурсов для изучения IoT-разработки в 2021 году: онлайн-университеты, каналы, блоги и подкасты
- 37 лучших каналов YouTube про робототехнику: от новичка до профессионала
- Планирование маршрута роботом при помощи RRT
- Робот в лабиринте: обрабатываем в Python очереди с приоритетом