Итак, сегодня мы будем делать охранную систему для моей любимой ручки. Вы удивлены почему именно ручка? Секрет прост, я весьма неопытен во всяких там вопросах электроники и поэтому, когда заказывал датчик давления думал, что он будет действовать по всей площади, а оказалось, что он работает только для определенной контактной площадки. Как ни странно, но во всём доме не оказалось ничего достаточно увесистого, устойчивого и подходящего по размерам, кроме этой ручки. Ну и кроме моего пальца, но экспериментировать с ним я был не готов .
В статье я поделюсь своим опытом подключения датчика давления и доплеровского датчика движения, к микроконтроллерам. Сами контроллеры через проводной интерфейс UART подключим к GPIO Raspberry PI 3. Затем напишем на Python простенькую программку для отображения статуса охранной системы, а в конце подключим смартфон к «малине» с помощью VNC, чтобы следить за охранной системой на удалении от компьютера.
Хотите оставить Индиану Джонса не у дел? Тогда милости прошу под кат.

Часть I: Введение Часть II: Подключение схемы и программа для Canny 3 tiny Часть III: Подключение схемы и программа для Arduino Uno Часть IV: Raspberry PI и программа для мониторинга на Python Часть V: Заключение
Часть I: Введение
Внимательный читатель может задать вопрос: «А почему ты купил Arduino, если до этого упоминал CraftDuino?», все весьма банально. CraftDuino опять сломалась. Один раз DrZugrik мне её починил, а сейчас «самоизоляция», да и не хотелось мне человека беспокоить по пустякам.
Вот так, мы плавно подошли к материальной базе. Для этой статьи я использовал:
- Резистор давления FSR402:
- Доплеровский датчик движения RCWL-0516:
В магазине, где я покупал оба датчика в описании на сайте было написано, что они для Arduino, но на практике оказалось, что никаких специальных библиотек не надо и на Canny всё запустилось без проблем. - Микроконтроллер Arduino Uno:
- Микроконтроллер Canny 3 Tiny — версия с клеммой колодкой и кабельным жгутом:
- Одноплатный компьютер Raspberry PI 3 Model B:
- Прочее: макетные платы Breboard, провода и зажимы «крокодилы», адаптер питания для «Малины»
Перейдем к делу.
Часть II: Подключение схемы и программа для Canny 3 tiny
В интернете есть много примеров, как подключить Arduino по UART, про Canny примеров существенно меньше, поэтому начнем с него.
Чтобы не раздувать объем статьи и не повторяться, напомню, что самые основные вопросы, того, как работать с Canny и средой разработки CannyLab я рассмотрел в этой статье, а пример подключения датчиков к аналого-цифровому преобразователю (АЦП) и передачу сообщения через Virtual COM-порт, я разобрал в этой статье.
Для тех, кто не станет это читать, а сразу попробует подключить датчики к АЦП, есть важное замечание. Не повторяйте мою ошибку, для того, чтобы выходы контроллера № 5 и №6, смогли работать в режиме АЦП надо поставить перемычки, как на картинке ниже. Это не сложно, даже я справился.

Обратите внимание на клеммную колодку, в стандартной комплектации для этой версии контроллера идет родной кабельный жгут, он жесткий и наверняка удобный если использовать внутри автомобиля, а вот для опытов за столом — не очень. Я придумал ноу-хау, заменил родной жгут на жгуты, которые часто идут в комплекте с компьютерной техникой, ну или продаются в магазинах, торгующих DIY электроникой и это оказалось очень удобно. Они не плохо сидят в колодке, мягкие и при этом дают дополнительное удлинение.
Перейдем к схеме подключения:

Датчик давления подключается очень просто. По сути — это резистор. К одной его «ноге» подводим питание, а от второй «ноги» заводим провод на вход контроллера, подключенный к АЦП (либо № 5 либо № 6). Я выбрал № 6.
Кстати с датчиком давления я прогадал дважды. Вторым моим просчетом стало подключение датчика. Он не влезает в макетную плату, оказывается его надо подключать в винтовой клеммник или что-то похожее. Пришлось выкручиваться с «крокодилами».
Датчик движения подключается не намного сложней, в гнездо «Vin» подводим +5В с платы, в гнездо «GND» соединяем с «землей» на макетной плате, а гнездо OUT соединяем с любым цифровым входом контроллера, я соединил с выходом № 5 (мы не будем переключать его в режим АЦП).
Осталось подключить контроллер к «Малине» через UART. Для этого выход № 2 контроллера, который в режиме «UART» у нас становится выходом «TX», надо подключить к входу GPIO RX «Малины», также надо соединить «землю» на плате и GPIO «GND» Raspberry PI.
Многие советуют согласовать уровень напряжения до 3.3 В, и я даже пробовал подключать Canny через делитель, напряжения, но с ним работает хуже чем без него (или вообще не работает), поэтому в данном случае я подсоединился к UART «Малины» напрямую. Вроде ничего не сгорело. Все работает.

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


Незнакомы нам только параметры настройки UART. Благо тут всё просто. У Canny 3 tiny всего 1 интерфейс UART (например, у Canny 7 их два). При включения режима UART выход № 1 становится RX, выход № 2 TX. Мы выберем привычную многим скорость передачи 9600 бод, а вот режим передачи данных ограничен. Доступное количество бит данных только 8 байт и 1 стоповый бит(у «старших» моделей контроллеров выбор побольше), Для того, чтобы включить UART необходимо в соответствующий регистр «Регистр установки конфиг UART1» записать заранее заданную константу:

В сообщении мы будем отправлять 10 символов (включая 2 проблема), поэтому запишем в В регистр установки длинны сообщения константу равную 10.
Про подтяжку 1 TX к единице я не уверен, но на всякий случай включил этот пункт, я так понимаю он нужен, чтобы не подтягивать резистором.
В блоке «Периодическая отправка по UART и VCP»
Мы с помощью генератора ШИМ задаем отправку 1 раз в 2 секунды для того, чтобы в течение секунды контроллер не забивал канал постоянной отправкой сообщения, мы используем «Детектор заднего фронта». Который сработает только один раз в момент переключения с единицы на ноль, если контроллер готов в этот момент передать сообщение по UART, то на вход блока логического умножение придут две единицы на выходе соответственно тоже буде «1», которая даст команду контроллеру отправить сообщение через UART, а также на всякий случай для отладки в USB-COM порт (об этом я подробно писал в прошлой статье).
В блоке «Индикация» все совсем просто, если значения с датчика давления меньше определённого порога и при этом датчик движения сработал (даст «1» на выход), то мы включим зеленый светодиод контроллера как сигнал о тревоге.
Было бы круто, если бы система работала как в кино:


Мы получаем данные с АЦП, разрешение АЦП от 0 до 1023. ПО UART мы посылаем символы, а значит показания от датчика давления, надо преобразовать в строку. Поскольку максимальное число 1023 (4 цифры) значит нам потребуется 4 байта. «Конвертер числа в строку» на выходах выдает пару символов, у нас будет 2 пары символов, каждую из них мы отправим в регистры установки сообщения UART и VCP. Дальше нам надо записать разделитель, чтобы показания не сливались, рас уж CannyLab использует пару символов, то возьмем в качестве разделителя два символа «пробел». Аналогичным образом преобразуем показания датчика движения, он дискретный выдает либо 00 либо 01, значит нам нужна только одна пара символов. В самом конце сообщения запишем символы перевода каретки и новой строки.
Как я уже писал в статье про фоторезистор, у Canny нет своего монитора COM-порта, но можно использовать любой сторонний, а рас уж мы чуть позже будем использовать Arduino IDE, то воспользуемся встроенным в него монитором COM-порта.
Вот, я давлю пальцем на датчик давления и попутно двигаюсь:

Часть III: Подключение схемы и программа для Arduino Uno
Про Arduino я не буду, так подробно рассказывать, ибо всё достаточно тривиально.
Схема подключения:

5*0.66=3.3 В
. Хотя напрямую Arduino к UART Raspberry PI я тоже подключал и вроде все работало.
Датчик давление подключим к «+» и к аналоговому входу «А1». Датчик движения к питанию и цифровому входу № 5.
Вот так схема выглядит в сборе:

byte photoPin = A0;
void setup() {
Serial.begin(9600);
pinMode(photoPin, INPUT);
pinMode(5, INPUT);
pinMode(13, OUTPUT);
}
void loop() {
int adjustment = 250;
int pressure_sensor = analogRead(A1) - adjustment;
int motion_sensor = digitalRead(5);
Serial.print(pressure_sensor);
Serial.print(" ");
Serial.println(motion_sensor);
if ((pressure_sensor<380) && (motion_sensor==1))
{
digitalWrite(LED_BUILTIN, HIGH);
}
else {
digitalWrite(LED_BUILTIN, LOW);
}
delay(1000);
}
Код простой, единственное, что стоит объяснить это переменную «adjustment». Дело в том, что при подключении к Arduino датчик давления, даже без нагрузки временами показывал не нулевые значения, и я ничего лучше не придумал, как вычесть усредненное значение «шума», для унификации показаний с Canny.
Также, как и в прошлом случае, мы реализовали индикацию встроенным светодиодом, в том случае если датчики сработали:

Часть IV: Raspberry PI и программа для мониторинга на Python
Для начала, надо включить UART, а также SSH и VNC, чтобы потом подключаться к «Малине» с помощью смартфона
Зайдите в настройки Raspberry PI и включите SSH, VNC, UART, как на картинке:

В нашей программе для мониторинга, мы будем использовать для вывода информации как консоль, так и графический интерфейс. Для реализации GUI я решил использовать Tkinter. Я правда пользуюсь им второй раз в жизни, но мне и надо было всего пару текстовых полей и диалоговое окно.
Вот код программы:
import serial import time from tkinter import * from tkinter import ttk from tkinter import messagebox serialport = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=1.0) window = Tk() window.title("Security system for my pen") window.geometry('400x170') #Presure sensor label lbl_ps = ttk.Label(window, text="Pressure sensor", font=("Arial Bold", 20)) lbl_ps.grid(column=0, row=0) lbl_ps_status = ttk.Label(window, text=" ", font=("Arial Bold", 20)) lbl_ps_status.grid(column=1, row=0) #Motion sensor label lbl_ms = ttk.Label(window, text="Motion sensor", font=("Arial Bold", 20)) lbl_ms.grid(column=0, row=1) lbl_ms_status = ttk.Label(window, text=" ", font=("Arial Bold", 20)) lbl_ms_status.grid(column=1, row=1) while True: counter = 0 rcv = serialport.readline().decode('utf-8').replace(" ","").split(' ') if (len(rcv)==2): ps=rcv[0] ms=rcv[1] print (ps+ " " +ms) if (int(ps)<380): lbl_ps_status.config(text = " Warning!") counter += 1 else: lbl_ps_status.config(text = " Ok") if (int(ms)>0): lbl_ms_status['text']=" Warning!" counter += 1 else: lbl_ms_status['text']=" Ok" window.update_idletasks() window.update() if (counter == 2): messagebox.showinfo("Alarm!", "Сheck your pen!") time.sleep(1)
Импорт библиотек я, пожалуй, пропущу.
После импорта мы задаем установки для UART, сам порт, скорость и время ожидания.
serialport = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=1.0)
Дальше размещаем по табличной верстке (по сетке) текстовые поля (Label)
У нас будет 4 поля из них 2 неизменных, а в двух других будет отображен статус датчика.
window.title("Security system for my pen") window.geometry('400x170') #Presure sensor label lbl_ps = ttk.Label(window, text="Pressure sensor", font=("Arial Bold", 20)) lbl_ps.grid(column=0, row=0) lbl_ps_status = ttk.Label(window, text=" ", font=("Arial Bold", 20)) lbl_ps_status.grid(column=1, row=0) #Motion sensor label lbl_ms = ttk.Label(window, text="Motion sensor", font=("Arial Bold", 20)) lbl_ms.grid(column=0, row=1) lbl_ms_status = ttk.Label(window, text=" ", font=("Arial Bold", 20)) lbl_ms_status.grid(column=1, row=1)
Далее создадим бесконечный цикл.
В начале цикла будем обнулять метку тревоги
counter
.Затем прочитаем, данные из последовательного порта.
Чтобы не смотреть на всяике записи типа “x00”, перекодируем сообщение в UTF-8.
Затем уберем начало и конец строки, чтобы остались только цифры.
Далее разделим строку, обратите внимание разделитель 2 пробела, а не 1.
Чтобы программа не вылетала при некорректном сообщении дальнейший код, который завязан на получение сообщение запихнем в условную конструкцию, которая сработает, только если сообщение можно разделить на 2 части.
Ну и выведем в консоль показания датчика давления и датчика движения.
while True: counter = 0 rcv = serialport.readline().decode('utf-8').replace(" ","").split(' ') if (len(rcv)==2): ps=rcv[0] ms=rcv[1] print (ps+ " " +ms)
Проверяем сработал датчики, если всё нормально, то система пишет «ОК», если один из датчиков сработал счетчик увеличивается на 1 и выдается предупреждение.
if (int(ps)<380): lbl_ps_status.config(text = " Warning!") counter += 1 else: lbl_ps_status.config(text = " Ok") if (int(ms)>0): lbl_ms_status['text']=" Warning!" counter += 1 else: lbl_ms_status['text']=" Ok"
В последнем блоке мы обновляем элементы формы Tkinter, после чего проверяем, сколько датчиков сработало. Если в цикле сработало оба датчика то появляется модальное окно с сообщением о тревоге.
window.update_idletasks() window.update() if (counter == 2): messagebox.showinfo("Alarm!", "Сheck your pen!") time.sleep(1)
Здесь важно отметить, что датчик движения держит на выходе «1» в течение двух секунд с момента фиксации движения. Так, что как правило система успевает сработать.
Ниже снимки экрана, демонстрирующие работу программы:
Все датчики спокойны:



Заключение
В заключение рассмотрим подключение к Raspberry PI со смартфона. В принципе сложного ничего нет, если вы можете подключиться с компьютера, то и с телефона сможете. Вам надо знать только IP «Малины», имя пользователя и пароль. На своём смартфоне под управлением ОС Android я установил VNC Viewer, но наверняка можно и другой клиент.
Пользоваться, не очень удобно, но работает:

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