Connected wristband with Arduino

We made a connected wrsitband using an arduino Nano 33 BLE and a PPG sensor MAX30100 form Mikroe to measure Hear Rate, HRV and SPO2 values

IntermediateShowcase (no instructions)Over 1 day668
Connected wristband with Arduino

Things used in this project

Hardware components

Nano 33 BLE Sense
Arduino Nano 33 BLE Sense
×1
MIKROE MAX 30100
×1
pololu
×1
Chargeur LiPo mini-USB MR1012
×1
Li-Ion Battery 1000mAh
Li-Ion Battery 1000mAh
×1

Software apps and online services

Arduino IDE
Arduino IDE
nRF Connect SDK
Nordic Semiconductor nRF Connect SDK

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Specifically a laser engraver
Soldering iron (generic)
Soldering iron (generic)
Breadboard, 170 Pin
Breadboard, 170 Pin
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
10 Pc. Jumper Wire Kit, 5 cm Long
10 Pc. Jumper Wire Kit, 5 cm Long

Story

Read more

Code

Prototype_v2

Arduino
We use the MAX30100 library for the PPG sensor, which include all the needed functions. The onBeatDetected() function allows us to notice when a new beat is detected and update the time for the last reported beat. Thanks to this function, you can measure the time between 2 succesive beats and deduce the HRV. We use a similar method to get the Heart Rate, which gives us a correct answer. We also had the SpO2 measure thanks to the library dunction getSpO2
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#include <ArduinoBLE.h>           // Bluetooth Library

#define REPORTING_PERIOD_MS     1000

// Initalizing global variables for sensor data to pass onto BLE
String h, t, v, s;
// Create a PulseOximeter object
PulseOximeter pox;
MAX30100 sensor;

// Time at which the last beat occurred
uint32_t tsLastReport = 0;
uint32_t tsLastReport_av = 0;

//Hear rate
uint32_t calcul_HR=0;
float time_HR=0;

//HRV
uint32_t HRV=0;

void onBeatDetected() {
    //Serial.println("♥ Beat!");
    tsLastReport=millis();
}

// BLE Service Name
BLEService customService("180C");

// BLE Characteristics
// Syntax: BLE<DATATYPE>Characteristic <NAME>(<UUID>, <PROPERTIES>, <DATA LENGTH>)
BLEStringCharacteristic ble_heartrate("0xFC", BLERead | BLENotify, 30);
BLEStringCharacteristic ble_temperature("0x0C", BLERead | BLENotify, 13);
BLEStringCharacteristic ble_HRV("0xFC", BLERead | BLENotify, 13);
BLEStringCharacteristic ble_spo("0x02", BLERead | BLENotify, 13);

// Function prototype
void readValues();

void setup() {
  
  //Initializing all the sensors
  //Serial.begin(9600);
  //while (!Serial);
  if (!BLE.begin())
  {
      //Serial.println("BLE failed to Initiate");
      //delay(500);
      while (1);
  }

  // Setting BLE Name
  BLE.setLocalName("Arduino Environment Sensor");
  
  // Setting BLE Service Advertisment
  BLE.setAdvertisedService(customService);
  
  // Adding characteristics to BLE Service Advertisment
  customService.addCharacteristic(ble_heartrate);
  customService.addCharacteristic(ble_temperature);
  customService.addCharacteristic(ble_HRV);
  customService.addCharacteristic(ble_spo);

  // Adding the service to the BLE stack
  BLE.addService(customService);

  // Start advertising
  BLE.advertise();
  Serial.println("Bluetooth device is now active, waiting for connections...");

  digitalWrite(LED_PWR, LOW);

  //Serial.print("Initializing pulse oximeter..");
  // Initialize sensor
  if (!pox.begin() || !sensor.begin()){   //PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT
      //Serial.println("FAILED");
      for(;;);
  }else{
      //Serial.println("SUCCESS");
  }

  // Configure sensor to use 7.6mA for LED drive
  //pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
  //sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_0MA);
  configureMax30100();

  pox.setOnBeatDetectedCallback(onBeatDetected);
}

void loop(){

  pox.update();
  // Variable to check if cetral device is connected
  BLEDevice central = BLE.central();
  if (central){
    //Serial.print("Connected to central: ");
    //Serial.println(central.address());
    while (central.connected()){
      
      // Read values from sensors
      readValues();

      // Writing sensor values to the characteristic
      ble_heartrate.writeValue(h);
      ble_temperature.writeValue(t);
      ble_HRV.writeValue(v);
      ble_spo.writeValue(s);

      // Displaying the sensor values on the Serial Monitor
      //Serial.println("Reading Sensors");
      //Serial.println(h);
      //Serial.println(t);
      //Serial.println(v);
      //delay(1000);
    }
    //Serial.print("Disconnected from central: ");
    //Serial.println(central.address());
  }
}

void readValues(){

  // Read from the sensor
  pox.update();
  // Grab the updated heart rate and SpO2 levels
  
  if(tsLastReport != tsLastReport_av){
    time_HR += tsLastReport-tsLastReport_av;
    calcul_HR++;
    HRV=2.7*(tsLastReport-tsLastReport_av);
  }

  float SP=pox.getSpO2();
  if(SP != 0){
   if (time_HR >= 5000){
    time_HR=0;
    uint32_t final_HR = calcul_HR/2.95*12;
    //h = String(final_HR) + " BPM";
    calcul_HR = 0;
    if(final_HR>60 && final_HR<140){
      h = String(final_HR) + " BPM";
      v = String(HRV) + "ms";
    }else{
      h="0 BPM : not worn";
      v = "Not worn";
    }
  }
 }else{
  h="0 BPM : not worn";
  v = "Not worn";
 }

  sensor.startTemperatureSampling();
  //Serial.print("Temperature:");
  //Serial.println(temp);

  // Saving sensor values into a user presentable way with units
  t = String(sensor.retrieveTemperature()) + " C";
  s = String(SP) + "%";
  tsLastReport_av = tsLastReport;
}

void configureMax30100() {
  sensor.setMode(MAX30100_MODE_SPO2_HR);
  sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_27_1MA);
  sensor.setLedsPulseWidth(MAX30100_SPC_PW_1600US_16BITS);
  sensor.setSamplingRate(MAX30100_SAMPRATE_100HZ);
  sensor.setHighresModeEnabled(true);
}

Prototype_v1

Arduino
The simpliest version of the code which is close to the one given by The Last Minute Engineers. It give you the SPO2 and Hear Rate
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"

#define REPORTING_PERIOD_MS     1000

// Create a PulseOximeter object
PulseOximeter pox;

// Time at which the last beat occurred
uint32_t tsLastReport = 0;
uint32_t HR=0;
uint32_t cpt=0;

// Callback routine is executed when a pulse is detected
void onBeatDetected() {
    Serial.println("♥ Beat!");
    tsLastReport = millis();
}

void setup() {
    Serial.begin(9600);

    //Serial.print("Initializing pulse oximeter..");

    // Initialize sensor
    if (!pox.begin()) {
        Serial.println("FAILED");
        for(;;);
    } else {
        Serial.println("SUCCESS");
    }

    // Configure sensor to use 7.6mA for LED drive
    pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);

    // Register a callback routine
    pox.setOnBeatDetectedCallback(onBeatDetected);
}

void loop() {
    // Read from the sensor
    pox.update();

    // Grab the updated heart rate and SpO2 levels
    if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
        cpt++;
        HR+=pox.getHeartRate();
        if(cpt==10){
          HR=HR/10;
          cpt=0;
          if(pox.getSpO2() ==0){
            HR=0;
          }else{
            if(HR<50 && HR>10){
              HR=HR*1.75;
            }
          }
          Serial.print("Heart rate:");
          Serial.print(HR);
          Serial.print("bpm");
          Serial.print(" / SpO2:");
          Serial.println(pox.getSpO2());
        }
   }
}

Prototype with Serial print for CSV file

Arduino
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#include <ArduinoBLE.h>           // Bluetooth Library

#define REPORTING_PERIOD_MS     1000

// Initalizing global variables for sensor data to pass onto BLE
String h, t, v, s;
// Create a PulseOximeter object
PulseOximeter pox;
MAX30100 sensor;

// Time at which the last beat occurred
uint32_t tsLastReport = 0;
uint32_t tsLastReport_av = 0;

//Hear rate
uint32_t calcul_HR=0;
float time_HR=0;
uint32_t last_HR=0;
uint32_t HRV=0;

void onBeatDetected() {
    //Serial.println("♥ Beat!");
    tsLastReport=millis();
}

// BLE Service Name
BLEService customService("180C");

// BLE Characteristics
// Syntax: BLE<DATATYPE>Characteristic <NAME>(<UUID>, <PROPERTIES>, <DATA LENGTH>)
BLEStringCharacteristic ble_heartrate("0xFC", BLERead | BLENotify, 30);
BLEStringCharacteristic ble_temperature("0x0C", BLERead | BLENotify, 13);
BLEStringCharacteristic ble_HRV("0xFC", BLERead | BLENotify, 13);
BLEStringCharacteristic ble_spo("0x02", BLERead | BLENotify, 13);

// Function prototype
void readValues();

void setup() {
  
  //Initializing all the sensors
  Serial.begin(9600);
  while (!Serial);
  if (!BLE.begin())
  {
      //Serial.println("BLE failed to Initiate");
      //delay(500);
      while (1);
  }

  // Setting BLE Name
  BLE.setLocalName("Arduino Environment Sensor");
  
  // Setting BLE Service Advertisment
  BLE.setAdvertisedService(customService);
  
  // Adding characteristics to BLE Service Advertisment
  customService.addCharacteristic(ble_heartrate);
  customService.addCharacteristic(ble_temperature);
  customService.addCharacteristic(ble_HRV);
  customService.addCharacteristic(ble_spo);

  // Adding the service to the BLE stack
  BLE.addService(customService);

  // Start advertising
  BLE.advertise();
  Serial.println("Bluetooth device is now active, waiting for connections...");

  digitalWrite(LED_PWR, LOW);

  //Serial.print("Initializing pulse oximeter..");
  // Initialize sensor
  if (!pox.begin() || !sensor.begin()){   //PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT
      //Serial.println("FAILED");
      for(;;);
  }else{
      //Serial.println("SUCCESS");
  }

  // Configure sensor to use 7.6mA for LED drive
  //pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
  //sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_0MA);
  configureMax30100();

  pox.setOnBeatDetectedCallback(onBeatDetected);

  Serial.println("HR, HRV, temp, SpO2");
}

void loop(){

  pox.update();
  // Variable to check if cetral device is connected
  BLEDevice central = BLE.central();
  if (central){
    //Serial.print("Connected to central: ");
    //Serial.println(central.address());
    while (central.connected()){
      
      // Read values from sensors
      readValues();

      // Writing sensor values to the characteristic
      ble_heartrate.writeValue(h);
      ble_temperature.writeValue(t);
      ble_HRV.writeValue(v);
      ble_spo.writeValue(s);
    }
    //Serial.print("Disconnected from central: ");
    //Serial.println(central.address());
  }
}

void readValues(){

  // Read from the sensor
  pox.update();
  // Grab the updated heart rate and SpO2 levels
  
  if(tsLastReport != tsLastReport_av){
    time_HR += tsLastReport-tsLastReport_av;
    calcul_HR++;
    HRV=2.7*(tsLastReport-tsLastReport_av);
  }

  float SP=pox.getSpO2();
  if(SP != 0){
   if (time_HR >= 5000){
    time_HR=0;
    uint32_t final_HR = calcul_HR/2.95*12;
    calcul_HR = 0;
    if(final_HR>60 && final_HR<140){
      h = String(final_HR) + " BPM";
      v = String(HRV) + "ms";
      last_HR = final_HR;
    }else{
      h="0 BPM : not worn";
      v = "Not worn";
    }
  }
  Serial.print(last_HR);
  Serial.print(", ");
  Serial.print(HRV);
  Serial.print(", ");
 }else{
  h="0 BPM : not worn";
  v = "Not worn";
  Serial.print("0, 0, ");
 }
  sensor.startTemperatureSampling();
  //Serial.print("Temperature:");
  //Serial.println(temp);

  // Saving sensor values into a user presentable way with units
  t = String(sensor.retrieveTemperature()) + " C";
  s = String(SP) + "%";
  Serial.print(sensor.retrieveTemperature());
  Serial.print(", ");
  Serial.println(SP);
  tsLastReport_av = tsLastReport;
}

void configureMax30100() {
  sensor.setMode(MAX30100_MODE_SPO2_HR);
  sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_27_1MA);
  sensor.setLedsPulseWidth(MAX30100_SPC_PW_1600US_16BITS);
  sensor.setSamplingRate(MAX30100_SAMPRATE_100HZ);
  sensor.setHighresModeEnabled(true);
}

Credits

MathieuSemenzato
2 projects • 1 follower
Contact
CestClaireTaWu
2 projects • 1 follower
Contact
Yasmine AMANGAR
2 projects • 0 followers
Contact
Thomas Korpal
2 projects • 1 follower
Contact

Comments

Please log in or sign up to comment.