Умный компаньон для больных Альцгеймером: система оповещений на Arduino
Компоненты и материалы
| Arduino MKR1000 | ×1 |
| Infineon Sensor Hub Nano | ×1 |
| Nokia 5110 LCD | ×1 |
| Bluetooth-модуль HC-05 | ×1 |
| Макетная плата (универсальная) | ×1 |
| Перемычки (универсальные) | ×1 |
| Тактильная кнопка 12мм (SparkFun) | ×1 |
| Зуммер | ×1 |
| Передатчик FT1235 5W | ×1 |
| Приёмник FT1236 5W | ×1 |
Необходимые инструменты и станки
| Паяльник (универсальный) |
Приложения и онлайн-сервисы
| Arduino IDE |
| Blynk |
| IFTTT Maker service |
О проекте
Эти факты с сайта Альцгеймер-ассоциации (сентябрь 2017) достаточно, чтобы понять проблемы, через которые проходит человек, если он или его близкие страдают болезнью Альцгеймера.
Как мейкер, я подумал об этом и решил создать носимое устройство — систему, помогающую и пациентам, и их опекунам.
Система должна уметь:
- Напоминать пациенту о ежедневных задачах (лекарства, упражнения и т.д.)
- Отслеживать, где находится пациент в доме
- Оповещать опекунов в чрезвычайных ситуациях
- Показывать время (в конце концов, это часы!)
- Быть портативной и простой в использовании даже для пожилых
- Иметь минимальную стоимость
Когда я увидел Infineon Sensor Hub Nano, он показался хорошим кандидатом благодаря сверхмалому размеру и BLE. С точным давлением можно детектировать падения и определять точное местоположение пациента в доме.
Для базового проекта использую:
- Infineon Sensor Hub Nano
- Arduino MKR1000
- HC-05 Bluetooth Module
- Nokia 5110 Display

Что значит «базовый проект» — вы поймёте в разделе «Персонализация Alzheimer's Assistant».
Как это работает
Infineon Sensor Hub Nano содержит барометрический датчик давления DPS310, передающий данные через Bluetooth. Давление, высота и температуру можно просматривать в Android-приложении Infineon или ПО SES2G. Пользователи могут создавать свои Android-приложения с библиотекой Infineon.

Подробнее о Sensor Hub Nano здесь.

Но я хочу, чтобы Alzheimer's Assistant работал без Android-телефона между ними. Это должно быть носимое устройство, работающее автономно, но с возможностью подключения к смартфону для просмотра данных. Поэтому выбрал Arduino MKR1000 за компактность и Wi-Fi, и соединил его с Sensor Hub Nano.
Распиновка Arduino MKR1000, которая пригодится:

У меня был HC-05, поэтому использовал его для связи MKR1000 и Sensor Hub Nano. Сначала нужно правильно подключить HC-05 к аппаратным Tx/Rx пинам Arduino с учётом логических уровней. Мой Bluetooth работает на 3.3В, как и MKR1000, поэтому сдвигатель уровней не нужен. Если ваш модуль на 5В — может понадобиться сдвигатель уровня, как показано:

После согласования уровней нужно спарить HC-05 с Sensor Hub Nano для начала обмена данными и найти способ автоматического спаривания каждый раз, когда Sensor Hub Nano входит в зону Bluetooth HC-05.
Для этого настроил HC-05 как Bluetooth-«мастер», спаривающийся только с конкретным MAC-адресом — адресом Sensor Hub Nano. Так при включении HC-05 ищет устройство с этим MAC и автоматически сопрягается, оставляя пользователю только отправку/приём данных.
Это делается AT-командами HC-05, описано в разделе «Настройка Bluetooth-модуля».
Примечание: Приложен документ со всеми AT-командами HC-05, используйте по необходимости.
После спаривания отправка команд Sensor Hub Nano работает как Bluetooth-терминал. Команды можно отправлять просто печатая их как строку через аппаратный последовательный порт, к которому подключён HC-05. Например, команда для запуска потока данных датчика:
$start_sensor id=1 // Запуск потока данных датчика
Список известных команд:
$hello id= // Приветствие
$info id= // Информация
$sinfo id=1 // Информация о датчике
$set_mode sid=1;md=mode;val=bg // Низкое энергопотребление
$set_mode sid=1;md=prs_osr;val=16 // Стандартный режим
$set_mode sid=1;md=prs_mr;val=32 // Высокая точность
$start_sensor id=1 // Старт
$stop id= // Стоп
Данные сенсора приходят в формате:
$1,t,36.9299,1154206 // Температура
$1,p,997.6813,1154206 // Давление
$1,a,130.4305,1154206 // Высота
Примечание: Хочу отдать дань блогу Peter Smith, который помог начать общение с Sensor Hub Nano через Bluetooth.
Получив поток данных, нужно разобрать его. Это была, признаюсь, самая сложная часть: после команды старта Sensor Hub Nano просто посылает поток, оставляя приёмнику разбирать полезное. После множества попыток нашёл самый простой и эффективный метод парсинга:
void getSensorValues() {
// Получает значения сенсоров от Sensor Hub Nano через Serial1
String junkVal;
if (Serial1.available()) {
junkVal = Serial1.readStringUntil('\n');
junkVal = Serial1.readStringUntil('t');
t = Serial1.parseFloat();
junkVal = Serial1.readStringUntil('p');
p = Serial1.parseFloat();
junkVal = Serial1.readStringUntil('a');
a = Serial1.parseFloat();
junkVal = Serial1.readStringUntil('\n');
}
}
Дисплей также подключается к Arduino для взаимодействия с пользователем, вывода сообщений, времени или данных сенсора.

Получив данные в MKR1000, благодаря Wi-Fi можно отправлять их на IoT-платформы: Cayenne или Blynk.

Сначала выбрал Cayenne за красивый интерфейс и простую настройку. Но были баги с Wi-Fi MKR1000, мешавшие выбору пинов. Команда Cayenne была очень полезна, но проблема не решилась. Перешёл на Blynk — они похожи, достаточно поменять пару строк кода. Единственное преимущество Cayenne — доступ с ПК, Blynk только на смартфонах.

Теперь у нас есть данные от Sensor Hub Nano, они в Arduino, переданы на IoT-платформу (далее буду говорить Blynk). Остаётся персонализировать Alzheimer's Assistant под конкретного пациента — об этом в следующем разделе (обнаружение падений и локации там).
Примечание: Старался описать каждый шаг подробно, но если чего-то не знаете (например, как загрузить код на Arduino), лучше сначала ознакомиться с основами на сайте Arduino, а потом возвращаться сюда.
Настройка Bluetooth-модуля
Сначала нужно получить MAC-адрес вашего Sensor Hub Nano Evaluation Kit. Способов много, расскажу свой.
Спариваем Sensor Hub Nano со смартфоном:

Скачайте приложение Infineon Sensor Hub Nano Evaluation (Android) здесь, включите Sensor Hub Nano. Приложение покажет «IFX_NANOHUB» с MAC-адресом под ним.

Запишите его — понадобится позже.
Примечание: Лучше отсоединить Sensor Hub Nano от телефона, если не используете сейчас, иначе телефон автоматически подключится, и HC-05 не сможет спарриться.
Перевод HC-05 в AT-режим:
AT-режим позволяет настраивать HC-05: бодрейт, режим slave/master и т.д. Нужно изменить настройки для успешного получения данных от Sensor Hub Nano.

Сначала загрузите скетч «AT Commands» на MKR1000. Он позволяет давать команды Bluetooth-модулю в AT-режиме через Arduino.
// Оригинальный скетч с блога Martyn Currey:
// https://www.martyncurrey.com/arduino-with-hc-05-bluetooth-module-at-mode/
// Скетч модифицирован мной для Arduino MKR1000!
// Базовый Bluetooth-скетч
// Подключите HC-05 и общайтесь через Serial Monitor
// HC-05 по умолчанию в режиме связи при подаче питания.
// Нужно перевести в AT-режим.
// После сброса настройки бодрейт для режима связи 38400
char c = ' ';
void setup() {
Serial.begin(9600);
Serial.println("Arduino with HC-05 is ready");
Serial1.begin(38400);
Serial.println("Serial1 started at 38400");
}
void loop() {
if (Serial1.available()) {
c = Serial1.read();
Serial.write(c);
}
if (Serial.available()) {
c = Serial.read();
Serial.write(c);
Serial1.write(c);
}
}
Подключите только Bluetooth-модуль к MKR1000 по схеме.

Примечание: Лучше сначала собрать на макетке, а потом переходить к постоянной проводке.

Если включить Sensor Hub Nano и HC-05, они не соединятся автоматически. Вы увидите:
Чтобы изменить настройки HC-05, нужно войти в AT-режим. Способ зависит от платы — если другая, читайте блог Martyn Currey здесь. Если застряли — гуглите или пишите в комментариях.
Мой модуль с кнопкой, поэтому для входа в AT-режим (не забыв загрузить код AT-команд):
- Отключите питание модуля. (TX/RX остаются подключёнными!)
- Зажмите кнопку на модуле
- Подайте питание, удерживая кнопку
- Когда загорится LED, отпустите кнопку
Видео входа в AT-режим:
В AT-режиме вы заметите разницу в мигании LED: в режиме связи — быстро, ~5 раз в сек; в AT — раз в пару секунд.
Настройка HC-05:
Откройте Serial Monitor, бодрейт 9600, выберите «Both NL & CR».

Примечание: Нужно настроить newline и carriage return, иначе AT-команды не сработают.
Введите «AT» — должен прийти «OK». Если да — продолжайте.

Нужно изменить в AT-режиме:
- Удалить все текущие спаренные устройства
- Настроить подключение только к указанному MAC-адресу
- Установить режим Bluetooth-соединения в «Master»
- Указать нужный MAC-адрес
- Установить бодрейт 115200, стоп-бит 2, чётная паритетность
Команды для HC-05 для спаривания с Sensor Hub Nano:
- AT+RMAAD
- AT+CMODE=0
- AT+ROLE=1
- AT+BIND=1234,56,abcdef (Замените на MAC Sensor Hub Nano)
- AT+UART=115200,0,0
Лог моих AT-команд для справки:

Теперь отключите Arduino, чтобы выключить Bluetooth-модуль. Это вернёт его в режим связи.
Примечание: Если что-то пошло не так, сбросьте модуль к настройкам по умолчанию командой: AT+ORGL
Тестирование соединения:
Проверим успех последнего шага: включите Sensor Hub Nano. Синий LED будет мигать очень медленно, раз в пару секунд. Подключите Arduino к ПК, обратите внимание на изменение мигания LED на обоих модулях.
Сравните мигание сейчас и до этого:
Разница заметна, и вы поймёте, что модули соединены. Переходим к следующей части — сборке и тестированию.
Примечание: Если ранее спаривали смартфон с Sensor Hub Nano, возможно, придётся отсоединить — он может подключиться только к одному устройству за раз.
Тестирование базового проекта
Подтвердив правильное соединение HC-05 и Sensor Hub Nano по миганию LED, настраиваем Blynk в смартфоне.
Настройка приложения Blynk:
Скачайте Blynk (ещё нет) для iOS/Android здесь, отсканируйте QR-код через Blynk — автоматически создадутся базовые виджеты.

Увидите похожий экран:

Не меняйте ничего сейчас, читайте дальше.
Установка необходимых библиотек:
Нужны две библиотеки для Arduino IDE, чтобы код компилировался без ошибок:
- Blynk — для подключения к смартфону
- u8g2lib — для дисплея
Два способа установки: через «Library Manager» в новых версиях Arduino IDE или вручную. Оба описаны здесь.

Загрузка кода и тестирование:
Установив библиотеки, скачайте прикреплённый код и внесите изменения. Добавьте ваш токен аутентификации из Blynk (приходит на email при создании проекта), а также SSID и пароль Wi-Fi. Загрузите код на MKR1000.
После загрузки соберите схему по схеме.

Откройте Blynk-приложение, проект Alzheimer's Assistant, нажмите Play. Подключите MKR1000 (с HC-05 и дисплеем), на дисплее появится логотип «Alzheimer's Assistant». Через момент — «Waiting for Sensor Hub Nano». Включите переключатель на Sensor Hub Nano в радиусе Bluetooth HC-05. Должно появиться «Connected to Infineon's Sensor Hub Nano», через несколько секунд — значения давления, температуры, высоты на смартфоне.

Через несколько секунд также появится время в 24-часовом формате и дата, синхронизированные с интернетом.
Видео тестирования:
Если всё работает — поздравляю, сложная часть пройдена, теперь персонализация под конкретного пациента.
Персонализация Alzheimer's Assistant
До сих пор мы получаем данные с DPS310 в аккуратной схеме, но для пользы нужно настроить под индивидуальные требования. В этом разделе расскажу о коде и как модифицировать Alzheimer's Assistant под предпочтения пользователя. Дам фрагменты кода для каждой «фичи» — их можно добавить в основной код с небольшими правками.
Примечание: В коде базового проекта используются функции, обёрнутые в BlynkTimer. Хорошо использовать их для кастомизации — они выполняют задачи с заданным интервалом и предотвращают ошибку флуда Blynk при частых запросах. Код «базовый» в том смысле, что все функции есть, но не включены в основной цикл; пользователь редактирует основной код под свои нужды и может подправить интервалы запуска функций.
Датчик DPS310:-

DPS310 от Infineon — дешёвый цифровой барометрический датчик с высокой точностью в микроскопическом корпусе. Идеален для такого проекта — значения позволяют детектировать падения пожилых или определять комнату.
Примечание: Корпус умных часов ещё не сделан, поэтому тестирую Sensor Hub Nano на руке, соединённом с Arduino через Bluetooth, как на фото:

Обнаружение падений: Нужно задать значение падения (разница давления между двумя измерениями за заданное время) и допуск. Например, если изменение высоты между двумя последовательными значениями (за секунду) в пределах значение_падения ± допуск — падение детектировано.

Провел тесты: значение падения 0.7, допуск ±0.2, но могут не работать во всех случаях. Причина проста: падение может происходить по-разному. Нужен вторичный датчик (акселерометр) для большей точности — будет в будущих работах. Но, возможно, есть более точные алгоритмы — открыт для идей, пишите в комментариях.
Видео демонстрации обнаружения падения:
Определение местоположения пациента: Работает похоже на детекцию падений. Чтобы узнать, на каком этаже пациент, возьмите текущее значение высоты и вычтите предыдущее. Сравните разницу с заданным значением — это покажет этаж.

Просто if/else логика для определения этажа (значения высоты уже в основном коде). Можно индицировать через LED-виджеты в Blynk.
Примечание: Определение локации не включено в основной код, пользователи могут добавить по необходимости, не забыв использовать как функцию BlynkTimer.
Та же техника для определения комнаты. Нужен вторичный датчик (например, датчик движения), иначе много ложных срабатываний.
Температура: DPS310 показывает температуру, можно использовать для оповещений о чрезвычайных ситуациях, например пожаре. Если температура поднимается выше заданного значения, скажем 45℃ — оповещаем опекуна.

Но так как DPS310 не приклеен к коже (в данном случае) — это не температура тела, а температура Sensor Hub Nano.
Код прост (вставьте в основной цикл):
if (t > maxTemp) {
// Действия при превышении температуры
} else {
// Действия при нормальной температуре
}
Примечание: Все графики созданы с ПО SESG2 Evaluation от Infineon.
Зуммер и кнопка:-
Ранее не упоминал, но зуммер и кнопка тоже должны быть в системе — очень полезны. Зуммер привлекает внимание пациента, например, когда пора принимать лекарства. Кнопка — устройство безопасности.

Так как используем Blynk, кнопку можно настроить так: при нажатии уведомление на телефоне опекуна или звонок/SMS (через IFTTT, см. ниже). Фрагмент кода:
void emailOnButtonPress()
{
// *** ВНИМАНИЕ: Ограничение — ТОЛЬКО ОДНО E-MAIL ЗА 15 СЕКУНД! ***
// Отправка e-mail при нажатии кнопки
// на цифровом пине 2 Arduino
int isButtonPressed = !digitalRead(2); // Инвертируем, так как кнопка «Active LOW»
if (isButtonPressed) // Любое условие для триггера email
{
Serial.println("Button is pressed."); // Видно в Serial Monitor
Blynk.email("your_email@mail.com", "Subject: Button Logger", "You just pushed the button...");
// Или, если хотите использовать email из приложения (для экспорта приложения):
// Blynk.email("Subject: Button Logger", "You just pushed the button...");
}
}
Взято из примеров Blynk, использует прерывание для проверки кнопки. Пациент может оповестить опекуна в чрезвычайной ситуации, например падении, не детектированном алгоритмом. Полный пример здесь.
Зуммер может генерировать тоны (Arduino tone() — подробнее), напоминая о задачах: лекарства, упражнения.
Дисплей:-
Важная часть проекта — то, на что смотрит пользователь. Nokia 5110 — доступны, легко настраиваются, дешёвы, но не очень ярки для такой системы. OLED с высоким разрешением — отличная альтернатива, код легко адаптировать, так как использовал u8g2 (github). Выберите модель здесь, добавьте в начало скетча (удалив строку Nokia 5110). Подключите согласно коду и готово. Можно использовать bitmap-картинки с высоким разрешением. Можно менять шрифты — огромный список здесь, меняйте имя шрифта в коде.
Примечание: Может потребоваться изменить пиксельные позиции текста при использовании дисплея с другим разрешением.
Это кратко о библиотеке для дисплея. Теперь — как редактировать код для отображения времени или данных Sensor Hub Nano (температура, высота, давление).
Отображение времени: Можно использовать RTC-модуль, но так как мы в интернете — проще синхронизировать время через него. А с Blynk — ещё проще. Нужен виджет RTC в проекте. Несколько строк кода автоматически получают время с сервера Blynk (не забудьте установить часовой пояс в виджете). Основной код по умолчанию показывает время (не значения сенсоров).
Примечание: Время на экране может отличаться на минуту, так как синхронизируется из интернета, но я тестировал долго — очень точно (разница пару секунд).

Отображение данных Sensor Hub Nano: Можно выводить данные сенсора на дисплей. Не для пациента, а для отладки. Фрагмент кода:
void showSensorValues() {
char bufT[10];
char bufP[10];
char bufA[10];
String(t).toCharArray(bufT, 10);
String(p).toCharArray(bufP, 10);
String(a).toCharArray(bufA, 10);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x10_tf );
// Температура
u8g2.drawStr(0, 10, "T:");
u8g2.drawStr(12, 10, bufT);
u8g2.drawStr(73, 10, "C");
u8g2.drawCircle(70, 4, 1, U8G2_DRAW_ALL);
u8g2.drawHLine(0, 12, 85);
// Давление
u8g2.drawStr(0, 26, "P:");
u8g2.drawStr(12, 26, bufP);
u8g2.drawStr(60, 26, "mBar");
u8g2.drawHLine(0, 28, 85);
// Высота
u8g2.drawStr(0, 42, "A:");
u8g2.drawStr(12, 42, bufA);
u8g2.drawStr(72, 42, "m");
u8g2.drawHLine(0, 44, 85);
u8g2.sendBuffer();
}
Не забудьте вызвать ниже команду для получения данных сенсора:
getSensorValues();
Но это не всё для дисплея. Как сказано в начале, Alzheimer's Assistant должен напоминать о ежедневных задачах: приём лекарств, упражнения.

Использование виджета Eventor для напоминаний:-
Для этого используем виджет Eventor в Blynk (детали).
Добавьте Eventor в проект (уже есть, если сканировали QR-код выше), следуйте скриншотам:

В примере Eventor настраивает уведомление об обнаружении падения.
Использование Eventor для напоминаний делается так:
BLYNK_WRITE(vEVENTOR_PIN) {
int currentValue = param.asInt(); // 0 to 1
if (currentValue == 1) {
showPillReminder();
playBuzzerReminder();
// Это просто тон, в основном коде не реализован, но можете добавить!
} else {
// Если не время лекарств — ничего не делаем
}
}
Результат на дисплее когда пора принимать лекарства:

То же для упражнений:

Для этого вызывайте:
showExerciseReminder();
Вместо:
showPillReminder();
Eventor может использоваться для многого. Например, рост температуры → отправка email без изменения кода!
Использование разных режимов Sensor Hub Nano:-
Можно тестировать режимы Sensor Hub Nano командами:
sendCommand(LOW_ENERGY);
sendCommand(STANDARD_MODE);
sendCommand(HIGH_PRECISION);
Переключение режимов через Blynk эффективнее. Настройте Blynk так:

Это не нужно мне, не добавил в основной код, но можете сами (команды есть, нужно добавить логику в скетч).
Использование Blynk и IFTTT:-
Blynk позволяет любому Arduino-проекту легко использовать силу IFTTT.

Можно использовать Blynk для отправки webhook-запроса в IFTTT Webhooks (раннее Maker channel), создать апплет IFTTT, ждущий вебхук (от Blynk/Arduino) и запускающий что-то в ответ.
Простой пример IFTTT и Blynk с webhooks:
Виджет Webhook Blynk может отправлять запрос так:

IFTTT webhook канал:

Webhooks — не единственный способ. IFTTT можно триггерить email и твитами через Blynk.

Апплет создан. Время тестировать.
Откройте «Services» в IFTTT → «Webhooks» → «Settings» — увидите URL. Скопируйте, откройте в новой вкладке. Вместо {event} введите имя события (у меня «button_pressed»), нажмите «Test it» — через несколько секунд результат:

Подтвердив работу Webhook, впишите URL в настройки Blynk webhook и получайте GET/POST запросы (через виджет Blynk webhook).
Вместо SMS можно использовать звонки, Twitter, Facebook — так же просто. Вот сила IFTTT.
То же самое в моём проекте умного дома, подробно описано там, но это слишком круто, чтобы не упомянуть.
Финальные штрихи
К этому моменту электроника почти готова, но остаются нюансы. Читайте дальше, в конце — будущая работа для улучшения.
Батарея и зарядка:
MKR1000 имеет порт для LiPo — можно подключить. У меня нет сейчас, так что не рассматриваю, но смотрите сайт Arduino MKR1000 для информации.
Для зарядки два варианта: напрямую через USB MKR1000 или беспроводная зарядка, если есть. Буду использовать беспроводную — у меня уже есть приёмник и передатчик Futara Elettronica.

Для использования приёмника/передатчика — просто подайте указанное напряжение на передатчик. Это будет «док», где кладете Alzheimer's Assistant для зарядки. На стороне приёмника — отрежьте и припаяйте запасной USB micro B кабель (идёт в USB порт MKR1000) и соедините другую сторону с VCC и GND по распиновке.
Смотрите фото ниже для проводки:

Итоговый результат:

Корпус:
Как у любого проекта, нужен корпус. Так я вижу Alzheimer's Assistant:

Примечание: У меня нет доступа к лазерному резаку или 3D-принтеру, так что STL-файл просто для демонстрации вида, не в масштабе.
Это завершает документацию Alzheimer's Assistant, но хочу добавить раздел будущей работы — вещей, которые очень хотел сделать, но не смог по тем или иным причинам.
Будущая работа:
- Сделать нормальный корпус. Сейчас тестирую на макетке, но если получу доступ к лазеру или 3D-принтеру — обновлю документацию.
- Использовать Bluetooth 4.0 модуль вместо текущего.
- Или лучше — использовать только датчик DPS310 вместо Sensor Hub Nano. Это снизит стоимость, убрав Sensor Hub Nano и Bluetooth-модуль; DPS310 сам по себе дешёвый. Нужно только изменить основной код для получения температуры, давления, высоты от DPS310 напрямую, остальное готово.
- Добавить вторичный датчик для работы с DPS310 при детекции падений и локации. Уменьшит ложные срабатывания. Скорее всего понадобятся акселерометр и датчик движения.
- Добавить пульс-сенсор. Не было под рукой, но было бы отличным дополнением.
- Использовать дисплей с высшим разрешением, лучше OLED. Тогда можно добавить графику — очень красиво.
- Улучшить автономность: использовать deep sleep режим MKR1000, пока не использовал в коде.
Спасибо за чтение, надеюсь, проект понравился. Свободно делитесь мнением и идеями!
Код
AT Commands Arduino
Код для настройки HC-05 в AT-режиме. Детали входа в AT-режим в описании проекта.
// Original sketch from Martyn Currey's blog here:
// https://www.martyncurrey.com/arduino-with-hc-05-bluetooth-module-at-mode/
// Sketch modified by me to work with Arduino MKR1000!
// Basic Bluetooth sketch
// Connect the HC-05 module and communicate using the serial monitor
// The HC-05 defaults to commincation mode when first powered on.
// Needs to be placed in to AT mode
// After a factory reset the default baud rate for communication mode is 38400
char c = ' ';
void setup() {
Serial.begin(9600);
Serial.println("Arduino with HC-05 is ready");
Serial1.begin(38400);
Serial.println("Serial1 started at 38400");
}
void loop() {
if (Serial1.available()) {
c = Serial1.read();
Serial.write(c);
}
if (Serial.available()) {
c = Serial.read();
Serial.write(c);
Serial1.write(c);
}
}
Alzheimer's Assistant Arduino
Основной код проекта, используется после настройки HC-05 с Sensor Hub Nano.
//Including required libraries
#include <BlynkSimpleMKR1000.h>
#include <WidgetRTC.h>
#include <WiFi101.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = ""; // Enter your Blynk auth token here
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "";
char pass[] = "";
//Defining Sensor Hub Nano board commands
#define HELLO "$hello id="
#define INFO "$info id="
#define SENSOR_INFO "$sinfo id=1"
#define LOW_ENERGY "$set_mode sid=1;md=mode;val=bg"
#define STANDARD_MODE "$set_mode sid=1;md=prs_osr;val=16"
#define HIGH_PRECISION "$set_mode sid=1;md=prs_mr;val=32"
#define START "$start_sensor id=1"
#define STOP "$stop id="
//Defining fall and clearance thresholds
//You may need to change them, but I found these values to be good
#define FALL 0.7
#define CLEARANCE 0.2
//Defining Blynk virtual pins
#define vTEMPERATURE_PIN V0
#define vPRESSURE_PIN V1
#define vALTITUDE_PIN V2
#define vEVENTOR_PIN V3
#define vFALL_PIN V4
//Declaring required variables
float t, p, a, previousA;
//Boolean which tells tells if a fall is detected or not
boolean fallState;
//Variables needed for the fall detection algorithm
unsigned long previousMillis = 0;
const long interval = 1000;
//BTconnected is false when not connected and true when connected
boolean BTconnected = false;
//Defining BT state and LCD backlight pins
int btStatePin = 9;
int backlightPin = 2;
BlynkTimer timer;
WidgetRTC rtc;
//Nokia 5110 Display wiring
U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 7, /* data=*/ 8, /* cs=*/ 3, /* dc=*/ 5, /* reset=*/ 4);
void setup() {
Serial.begin(115200);
Serial1.begin(115200);
timer.setInterval(1000L, sendSensorValues);
timer.setInterval(3000L, showTimeAndDate);
pinMode(btStatePin, INPUT);
pinMode(backlightPin, OUTPUT);
digitalWrite(backlightPin, LOW);
u8g2.begin();
showStartMessage();
delay(2000);
while (!BTconnected) {
if (digitalRead(btStatePin) == HIGH) {
BTconnected = true;
} else {
showWaitingFor();
}
}
initSensorHub();
Blynk.begin(auth, ssid, pass);
rtc.begin();
setBlynkWidgets();
showTimeAndDate();
sendCommand(START);
}
void loop() {
Blynk.run();
timer.run();
getSensorValues();
checkIfFalling();
}
void sendCommand (String sensorCommand) {
Serial1.println(sensorCommand);
}
void initSensorHub() {
String junkVal;
sendCommand(INFO);
while (Serial1.find("IFX_NanoHub") == false) {
sendCommand(INFO);
Serial.println("ERROR");
showErrorMessage();
}
junkVal = Serial1.readStringUntil('\n');
junkVal = "";
showConnectedMessage();
delay(1500);
}
void getSensorValues() {
String junkVal;
if (Serial1.available()) {
junkVal = Serial1.readStringUntil('\n');
junkVal = Serial1.readStringUntil('t');
t = Serial1.parseFloat();
junkVal = Serial1.readStringUntil('p');
p = Serial1.parseFloat();
junkVal = Serial1.readStringUntil('a');
a = Serial1.parseFloat();
junkVal = Serial1.readStringUntil('\n');
}
}
void sendSensorValues() {
Blynk.virtualWrite(vTEMPERATURE_PIN, t);
Blynk.virtualWrite(vPRESSURE_PIN, p);
Blynk.virtualWrite(vALTITUDE_PIN, a);
}
void checkIfFalling() {
unsigned long currentMillis = millis();
if ((currentMillis - previousMillis) >= interval) {
float diff = previousA - a;
if ((diff >= (FALL - CLEARANCE)) && (diff <= (FALL + CLEARANCE))) {
fallState = true;
Serial.println("Falling");
showFallMessage();
Blynk.virtualWrite(vFALL_PIN, 255);
// Blynk.notify("DPS310 detected a fall!");
}
previousA = a;
previousMillis = currentMillis;
fallState = false;
Blynk.virtualWrite(vFALL_PIN, 0);
}
}
void showStartMessage() {
u8g2.clearBuffer();
u8g2.drawRFrame(3, 7, 75, 31, 7);
u8g2.setFont(u8g2_font_prospero_bold_nbp_tf);
u8g2.drawStr(8, 19, "Alzheimer's");
u8g2.drawStr(12, 35, "Assistant");
u8g2.sendBuffer();
}
void showWaitingFor() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_prospero_bold_nbp_tf);
u8g2.drawStr(9, 15, "Waiting for");
u8g2.drawStr(8, 28, "Sensor Hub");
u8g2.drawStr(22, 41, "Nano !!!");
u8g2.sendBuffer();
}
void showConnectedMessage() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x13B_tf);
u8g2.drawStr(0, 10, "Connected to");
u8g2.drawStr(8, 22, "Infineon's");
u8g2.drawStr(7, 34, "Sensor Hub");
u8g2.drawStr(29, 46, "Nano");
u8g2.sendBuffer();
}
void showErrorMessage() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_fub14_tf);
u8g2.drawStr(9, 30, "ERROR");
u8g2.sendBuffer();
}
void showSensorValues() {
char bufT[10];
char bufP[10];
char bufA[10];
String(t).toCharArray(bufT, 10);
String(p).toCharArray(bufP, 10);
String(a).toCharArray(bufA, 10);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x10_tf );
u8g2.drawStr(0, 10, "T:");
u8g2.drawStr(12, 10, bufT);
u8g2.drawStr(73, 10, "C");
u8g2.drawCircle(70, 4, 1, U8G2_DRAW_ALL);
u8g2.drawHLine(0, 12, 85);
u8g2.drawStr(0, 26, "P:");
u8g2.drawStr(12, 26, bufP);
u8g2.drawStr(60, 26, "mBar");
u8g2.drawHLine(0, 28, 85);
u8g2.drawStr(0, 42, "A:");
u8g2.drawStr(12, 42, bufA);
u8g2.drawStr(72, 42, "m");
u8g2.drawHLine(0, 44, 85);
u8g2.sendBuffer();
}
void showFallMessage() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x13B_tf);
u8g2.drawStr(27, 20, "Fall");
u8g2.drawStr(13, 32, "Detected!");
u8g2.sendBuffer();
delay(1000);
}
void showPillReminder() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x13B_tf);
u8g2.drawStr(0, 20, "Time to take");
u8g2.drawStr(5, 32, "your pills!");
u8g2.sendBuffer();
}
void showExerciseReminder() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_7x13B_tf);
u8g2.drawStr(16, 20, "Time to");
u8g2.drawStr(12, 32, "exercise!");
u8g2.sendBuffer();
}
void showTimeAndDate() {
if (year() == 1970) {
// Serial.println("Time not yet synced");
} else if (year() != 1970) {
char bufHours[3];
char bufColon[2];
char bufMinutes[3];
char bufDate[11];
String currentHours = String(hour());
String colon = ":";
String currentMinutes = String(minute());
String currentDate = String(day()) + "/" + month() + "/" + year();
String(currentHours).toCharArray(bufHours, 3);
String(colon).toCharArray(bufColon, 2);
String(currentMinutes).toCharArray(bufMinutes, 3);
String(currentDate).toCharArray(bufDate, 11);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_inr33_mf);
u8g2.drawStr(30, 30, bufColon);
u8g2.setFont(u8g2_font_logisoso32_tn);
u8g2.drawStr(0, 32, bufHours);
u8g2.drawStr(45, 32, bufMinutes);
u8g2.setFont(u8g2_font_saikyosansbold8_8n);
u8g2.drawHLine(0, 35, 85);
u8g2.drawStr(0, 46, bufDate);
u8g2.sendBuffer();
}
}
BLYNK_WRITE(vEVENTOR_PIN) {
int currentValue = param.asInt(); // 0 to 1
if (currentValue == 1) {
showPillReminder();
// Serial.println("Time to take your pills");
} else {
// Serial.println("Not the time to take pills");
}
}
void setBlynkWidgets() {
Blynk.setProperty(vTEMPERATURE_PIN, "color", "#FFFFFF");
Blynk.setProperty(vPRESSURE_PIN, "color", "#00BBFF");
Blynk.setProperty(vALTITUDE_PIN, "color", "#FFFF00");
}
BLYNK_CONNECTED() {
rtc.begin();
}
Пользовательские детали и корпуса
Это просто для демонстрации того, как я представляю корпус. Вообще не в масштабе!
Схемы
Эта схема используется для входа HC-05 в AT-режим и настройки через Arduino MKR1000.

Fritzing-схема для работы базового проекта:

Документ со списком AT-команд для HC-05
Производственный процесс
- TinyML-детектор языка на Arduino Nano 33 BLE Sense с Edge Impulse
- Создание игры в реальном времени на Arduino Nano с гироскопом MPU-6050 и OLED-дисплеем
- Цифровые кости на Arduino: генератор случайных чисел с LCD-дисплеем и кнопкой
- Создание рулетки на 37 светодиодов с Arduino Nano
- Мини-аркада на ATtiny85: Snake — ручная OLED-консоль своими руками
- Портативный дальномер на Arduino Nano: HC-SR04, питание 18650, 3D-корпус
- Сборка аудиореактивной настольной лампы на Arduino Nano
- Автономный робот-следопыт с распознаванием лиц на Arduino Nano и OpenCV
- Персональный помощник здоровья (PHA): Умное IoT-решение для сообщества
- Медное гальваническое покрытие: умная система на Arduino UNO