Twitter icon
Facebook icon
LinkedIn icon
Google icon
Reddit icon
StumbleUpon icon
Del.icio.us icon

Open Source Pulse Oximeter for COVID-19

Added to IoTplaybook or last updated on: 05/18/2020
Open Source Pulse Oximeter for COVID-19

Story

The Challenges of COVID-19

COVID-19 is a disease caused by the SARS-CoV-2 virus that primarily attacks a person's respiratory system. Some milder symptoms can include fever, aches, and chills, but it can also lead to more serious conditions such as pneumonia. A person who has pneumonia or even slight shortness of breath might not know when to go to a hospital, especially as they start to get even more overwhelmed. This is why I created this open source pulse oximeter, which can assist in getting people the help they need and get accurate information about their current condition.

A Bit of a Disclaimer

This device/project is not to be used as an accurate medical diagnostic tool!

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
 
× 1

Newark

CPC

 
Maxim Integrated MAX30102 Pulse and Heartrate Sensor
 
× 1

Newark

Gravity I2C OLED-2864 Display
DFRobot Gravity I2C OLED-2864 Display
 
× 1

DFRobot

Software apps and online services

Arduino IDE
Arduino IDE
 
  Arduino
Fusion 360
Autodesk Fusion 360
 
 

Autodesk

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
 
   
Soldering iron (generic)
Soldering iron (generic)

The Electronics

MAX30102

Open Source Pulse Oximeter for COVID-19

128x64 Pixel OLED

Open Source Pulse Oximeter for COVID-19
1 of 2

Open Source Pulse Oximeter for COVID-19
2 of 2

Arduino Nano

Open Source Pulse Oximeter for COVID-19

Building the Device Step-By-Step

Here is a step-by-step walkthrough of how to build this project.

1. Print Out and Clean Parts

Begin by downloading each piece from the attachment section on this project and loading it into your slicer of choice. I used an infill of around 70-80% and medium supports, all with PLA. After they were done printing, I removed the supports and did some light sanding to ensure they all fit together nicely.

1. Print Out and Clean Parts Begin by downloading each piece from the attachment section on this project and loading it into your slicer of choice. I used an infill of around 70-80% and medium supports, all with PLA. After they were done printing, I removed the supports and did some light sanding to ensure they all fit together nicely.
1 / 4 • Fusion 360 Design


2 / 4 • Fusion 360 Design


3 / 4 • Fusion 360 Design


4/ 4 • Fusion 360 Design

 

2. Solder the Electronics

The entire device is designed around an Arduino Nano that is mounted on a piece of 44mm by 30mm perfboard. First, wires get soldered to the VIN, GND, SDA, and SCL pins of the sensor and then run underneath the bed piece to the Arduino Nano.

Open Source Pulse Oximeter for COVID-19

Next, the connector for the OLED is attached to the Nano and then run-up to the display itself.

Open Source Pulse Oximeter for COVID-19

And finally, the entire electronics assembly is slid into the housing and secured with a couple of 3mm screws.

3. Assemble the Device

After the electronics have been inserted, simply attach the OLED screen to the top piece and secure it to the rest of the chassis with a couple of 3mm screws. You can test its motion by gently articulating the lid up and down.

Open Source Pulse Oximeter for COVID-19
1 / 2

Open Source Pulse Oximeter for COVID-19
2 / 2

4. Uploading the Sketch

The included sketch performs a couple of actions to display the user's current heart rate and oxygen saturation. To upload it, simply install the required libraries and select Arduino Nano from the board list in the Tools menu and click Upload.

Open Source Pulse Oximeter for COVID-19

As for the sketch itself, it first initializes the OLED and MAX30102, whilst reporting any errors that might arise. Next, it reads in 100 values to calibrate the sensor and begins displaying them. The device then enters a loop where it reads in 25 new values and computes a moving average with them. Finally, it checks if the values are valid and prints them to the screen if they are.

5. Using It

To use the pulse oximeter, place your fingertip over the sensor and gently close the top lid. Then plug in a power source and simply wait until you see data being displayed.

Open Source Pulse Oximeter for COVID-19
1 / 3

 

Open Source Pulse Oximeter for COVID-19
2 / 3

Open Source Pulse Oximeter for COVID-19
2 / 3

Custom parts and enclosures

Bottom Shell

Front + Bed

Top PIece

Schematics

Open Source Pulse Oximeter for COVID-19

Code

Pulse Oximeter Code - C/C++

 

/*
  Hardware Connections (Breakoutboard to Arduino):
  -5V = 5V (3.3V is allowed)
  -GND = GND
  -SDA = A4 (or SDA)
  -SCL = A5 (or SCL)
  -INT = Not connected
 
  The MAX30105 Breakout can handle 5V or 3.3V I2C logic. We recommend powering the board with 5V
  but it will also run at 3.3V.
*/

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

MAX30105 particleSensor;
SSD1306AsciiWire oled;

#define MAX_BRIGHTNESS 255

#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//Arduino Uno doesn't have enough SRAM to store 50 samples of IR led data and red led data in 32-bit format
//To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
uint16_t irBuffer[50]; //infrared LED sensor data
uint16_t redBuffer[50];  //red LED sensor data
#else
uint32_t irBuffer[50]; //infrared LED sensor data
uint32_t redBuffer[50];  //red LED sensor data
#endif

int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid

void setup()
{
  Serial.begin(115200); // initialize serial communication at 115200 bits per second:

  oled.begin(&Adafruit128x64, 0x3C);
  oled.setFont(Arial14);

  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println(F("MAX30105 was not found. Please check wiring/power."));
    while (1);
  }

  particleSensor.setup(55, 4, 2, 200, 411, 4096); //Configure sensor with these settings
}

void loop()
{

  //read the first 50 samples, and determine the signal range
  for (byte i = 0 ; i < 50 ; i++)
  {
    while (particleSensor.available() == false) //do we have new data?
      particleSensor.check(); //Check the sensor for new data

    redBuffer[i] = particleSensor.getRed();
    irBuffer[i] = particleSensor.getIR();
    particleSensor.nextSample(); //We're finished with this sample so move to next sample
    Serial.print(F("red="));
    Serial.print(redBuffer[i], DEC);
    Serial.print(F(", ir="));
    Serial.println(irBuffer[i], DEC);
  }

  //calculate heart rate and SpO2 after first 50 samples (first 4 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, 50, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  while (1)
  {
    //dumping the first 25 sets of samples in the memory and shift the last 25 sets of samples to the top
    for (byte i = 25; i < 50; i++)
    {
      redBuffer[i - 25] = redBuffer[i];
      irBuffer[i - 25] = irBuffer[i];
    }

    //take 25 sets of samples before calculating the heart rate.
    for (byte i = 25; i < 50; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data

      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample
      Serial.print(F("red="));
      Serial.print(redBuffer[i], DEC);
      Serial.print(F(", ir="));
      Serial.print(irBuffer[i], DEC);

      Serial.print(F(", HR="));
      Serial.print(heartRate, DEC);

      Serial.print(F(", HRvalid="));
      Serial.print(validHeartRate, DEC);

      Serial.print(F(", SPO2="));
      Serial.print(spo2, DEC);

      Serial.print(F(", SPO2Valid="));
      Serial.println(validSPO2, DEC);
      
    }

    //After gathering 25 new samples recalculate HR and SP02
    maxim_heart_rate_and_oxygen_saturation(irBuffer, 50, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
    printToScreen();
  }
}

void printToScreen() {
  oled.clear();
  oled.setCursor(0,0);
  if(validSPO2 && validHeartRate) {
    oled.print(F("HR: ")); oled.println(heartRate, DEC);
    oled.print(F("SPO2: ")); oled.println(spo2, DEC);
  } else {
    oled.print(F("Not valid"));
  }
}

Credits

Arduino “having11” Guy

Arduino “having11” Guy

18-year-old IoT and embedded systems enthusiast. Also, an intern at Hackster.io who loves working on projects and sharing knowledge.

 

Hackster.io

This content is provided by our content partner Hackster.io, an Avnet developer community for learning, programming, and building hardware. Visit them online for more great content like this.

This article was originally published at Hackster.io. It was added to IoTplaybook or last modified on 05/18/2020.