Что делаем?
Делаем простую сигнализацию на ультразвуковом датчике расстояния HC-SR04. Когда датчик обнаруживает препятствие, мы получаем уведомление в мобильном приложении IFTTT о срабатывании сигнализации, а камера делает 3 снимка, которые отправляются с Gmail-почты на любую другую почту.
IFTTT – платформа, связывающая сервисы, системы умного дома для создания автоматических процессов. Например, включить музыку в Spotify в 9:55 минут, если температура за окном меньше 10°C и в Google-календаре нет событий. В IFTTT доступны тысячи готовых апплетов.
Что понадобится?
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
Характеристики датчика HC-SR04:
Напряжение питания: 5 В.
Диапазон расстояний: 2-400 см.
Эффективный угол наблюдения: 15°.
Рабочий угол наблюдения: 30°.
Диаграмма направленности ультразвукового датчика расстояния HC-SR04
Как вычислить пройденное расстояние?
Зная скорость распространения звука в среде и временной интервал, можем вычислить расстояние:
S=V×t
Датчик считает расстояние туда-обратно. Нам нужна половина этого значения:
S=V×t2
Скорость звука при температуре 20°C составляет 34 300 см/с.
После подстановки значений получаем:
S=17150×t
Нумерация пинов Raspberry Pi
В Малине используют две системы нумерации пинов:
GPIO.BOARD
– пины нумеруются слева направо и сверху вниз от 1 до 40.
GPIO.BCM
– пины нумеруются по Broadcom SOC и называются GPIO [номер]. На рис. в скобках указаны альтернативные значения пинов.
Мы будем использовать нумерацию GPIO.BCM со значениями пинов по умолчанию.
Распиновка GPIO на Raspberry Pi 4
Схема подключения HC-SR04 к Raspberry Pi
Пин питания VCC
подключаем к пину 5V
на Малине (красная линия).
Пин земли GND
подключаем к пину GND
на Малине (синяя линия).
Пин Echo
подключаем к GPIO 26
(зеленая линия).
Пин Trig
подключаем к GPIO 19
(оранжевая линия).
Схема подключения ультразвукового датчика расстояния HC-SR04 к Raspberry Pi 4
После получения импульса на пине Echo
устанавливается логический уровень 5 В, а Малина работает с логикой 3.3 В. Чтобы понизить напряжение добавим в схему два резистора разных номиналов, образующих делитель напряжения. Для расчета номиналов воспользуемся онлайн-калькулятором:
Расчет делителя напряжения
Нам нужны резисторы 1 и 2 кОм. Можно подобрать резисторы других номиналов. Главное – получить напряжение не выше 3.3 В, чтобы не испортить Малину.
На макетной плате поменяем положение датчика на «от» Raspberry Pi:
Подключения датчика расстояния HC-SR04 к Raspberry Pi 4 на монтажной плате
Подключение камеры
Установим шлейф камеры в Малину:
Подключение камеры к Raspberry Pi 4
Присоединим шлейф к камере аналогичным образом:
Камера по умолчанию отключена. Для активации камеры зайдем в Меню
→ Preferences
→ Raspberry Pi Configuration
:
Перейдем во вкладку Interfaces
и активируем камеру:
Активация камеры в Raspberry Pi 4
Создание апплета IFTTT
Зарегистрируемся на сайте IFTTT и перейдем на страницу создания апплета.
В условие If This добавим Receive a web request
, в условие Then That
– Send a notification from IFTTT app
.
Создание апплета IFTTT
В условии 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 очереди с приоритетом