Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Беспроводной ECG-монитор пульса: носимое устройство на Arduino Nano и nRF24

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

Компонент Количество
uECG-устройство (измеряет BPM, передаёт по nRF24-совместимому протоколу) 1
Arduino Nano R3 1
Модуль nRF24L01 (любой) 1
Кольцо NeoPixel WS2812 5050 RGB (16 светодиодов) 1
LiPo аккумулятор 200+ мАч 1

Инструменты

О проекте

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

1. Компоненты

uECG делает всю сложную работу: измеряет ЭКГ, считает BPM. В режиме «direct link» отправляет пакеты (BPM + сырой ЭКГ) по протоколу, совместимому с nRF24. Arduino Nano получает пакеты, фильтрует, визуализирует на кольце NeoPixel.

2. Схема подключения

nRF24 требует 7 проводов (SPI + CE + CSN + питание). Пинхэдеры лучше снять, паять прямо к пятам для компактности.

nRF24 пин Arduino Nano
1 GND GND
2 VCC 3.3V
3 CE D9
4 CSN D8
5 SCK D13
6 MOSI D11
7 MISO D12

NeoPixel: VCC→5V, GND→GND, DI→D5. Батарея: + → 5V, - → GND (через разъём для зарядки).

Важно: SPI (MOSI/MISO/SCK) жестко завязан на D11/D12/D13. Остальные пины можно переназначить в коде.

3. Программа

Сложность — настройка RF-канала. uECG и nRF24 используют разный порядок бит в адресе pipe — нужна функция swapbits(). CRC отключён для совместимости, поэтому вводится фильтр: берём BPM только если 5 последних пакетов дали одно значение (uECG шлёт ~100 пакетов/сек — задержки нет).

Визуализация: BPM → цвет (синий→зелёный→жёлтый→розовый→красный) и число зажжённых пикселей. База 80 BPM, шаг 25 BPM. Ниже 80 — всё погасено (фокус на нагрузке).

Исходный код (bpm_watch.ino)

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#include <SPI.h>
#include <RF24.h>
#include <RF24_config.h>
#include <nRF24L01.h>

int rf_cen = 9;
int rf_cs = 8;
RF24 rf(rf_cen, rf_cs);

// Адрес pipe (hardcoded в uECG), биты перевёрнуты
uint8_t pipe_rx[8] = {0x0E, 0xE6, 0x0D, 0xA7, 0, 0, 0, 0};

#define PIN 5
#define NUMPIXELS 16
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

uint8_t swapbits(uint8_t a) {
  uint8_t v = 0;
  if (a & 0x80) v |= 0x01;
  if (a & 0x40) v |= 0x02;
  if (a & 0x20) v |= 0x04;
  if (a & 0x10) v |= 0x08;
  if (a & 0x08) v |= 0x10;
  if (a & 0x04) v |= 0x20;
  if (a & 0x02) v |= 0x40;
  if (a & 0x01) v |= 0x80;
  return v;
}

void setup() {
  pixels.begin();
  for (int i = 0; i < NUMPIXELS; i++) pixels.setPixelColor(i, pixels.Color(1,1,1));
  pixels.show();

  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));

  for (int x = 0; x < 8; x++) pipe_rx[x] = swapbits(pipe_rx[x]);

  rf.begin();
  rf.setDataRate(RF24_1MBPS);
  rf.setAddressWidth(4);
  rf.setChannel(22);
  rf.setRetries(0, 0);
  rf.setAutoAck(0);
  rf.disableDynamicPayloads();
  rf.setPayloadSize(32);
  rf.openReadingPipe(0, pipe_rx);
  rf.setCRCLength(RF24_CRC_DISABLED);
  rf.disableCRC();
  rf.startListening();

  // uECG должен быть в raw data mode (длинное нажатие кнопки)
}

long last_pix_upd = 0;
byte in_pack[32];
int rf_bpm = 0;
int bpm_hist[5];

void loop() {
  if (rf.available()) {
    rf.read(in_pack, 32);
    int bb = in_pack[5]; // BPM в 5-м байте

    // Фильтр: сдвиг истории
    for (int n = 0; n < 4; n++) bpm_hist[n] = bpm_hist[n+1];
    bpm_hist[4] = bb;
    for (int n = 0; n < 5; n++) if (bpm_hist[n] != bb) bb = -1;
    if (bb > 0) rf_bpm = bb;
  }

  long ms = millis();
  if (ms - last_pix_upd > 10) {
    last_pix_upd = ms;
    int bpm = rf_bpm;
    int max_bright = 160;
    float dd = 25;
    float t1 = 90, t2 = t1+dd, t3 = t2+dd, t4 = t3+dd;
    int r, g, b;

    if (bpm < t1) { r=0; g=0; b=max_bright; }
    else if (bpm < t2) { r=0; g=max_bright*(bpm-t1)/dd; b=max_bright-g; }
    else if (bpm < t3) { r=max_bright*(bpm-t2)/dd; g=max_bright-r; b=r/4; }
    else if (bpm < t4) { r=max_bright; g=0; b=max_bright/2 - max_bright*(bpm-t3)/(2*dd); }
    else { r=max_bright; g=0; b=0; }

    int on_pixels = (bpm - 80) / 8;
    for (int i = 0; i < NUMPIXELS; i++) {
      if (i < on_pixels) pixels.setPixelColor(NUMPIXELS-i-1, pixels.Color(r,g,b));
      else pixels.setPixelColor(NUMPIXELS-i-1, pixels.Color(0,0,0));
    }
    pixels.show();
  }
}

4. Сборка браслета

Все детали клеятся термоклеем: Nano по внешнему диаметру кольца, nRF24 внутрь, батарея — где влезет. Пришито к ремешку от антистатического браслета.

5. Тестирование

Автор пробежал — работает. Удивило: пульс достиг 192 BPM (все 16 LED загорелись) через пару минут бега. Датчик надёжен (при остановке пульс плавно снижался). Вопрос: так ли это из-за перенесённых проблем с сердцем в юности, или нагрузка слишком высока? Понадобится либо поднять порог, либо снизить интенсивность.

P.S. uECG хорошо работает и как ЭМГ — см. проект «Robotic Hand Control».

Схемы

Производственный процесс

  1. Renesas и Altran выпускают первые UWB-наручные часы с низкоимпульсной архитектурой для социального дистанцирования
  2. Сборка станции качества воздуха и погоды на Raspberry Pi с InfluxDB и Grafana
  3. Создание удалённого датчика температуры на Raspberry Pi и Python — пошаговое руководство
  4. Мониторинг домашней температуры с панелью управления на Raspberry Pi
  5. Система удалённого мониторинга сердечного ритма с алертами AWS IoT
  6. Создание потрясающей системы Ambilight для монитора на Arduino
  7. Умный вольтметр на Arduino и смартфоне — простое DIY-проект
  8. IoT-монитор пульса в реальном времени на Arduino и MAX30100
  9. Интегрированные датчики сердечного ритма в умной одежде: надежный носимый мониторинг
  10. CNC-обработка: прецизионное изготовление материалов и компонентов