Project

Pulse Oximeter and Heart Rate Monitor with MAX30102

Pulse oximetry got a lot of attention during the pandemic. Most consumer devices use chips made by Maxim Integrated or similar competitors, packaged neatly with a finger-clip mechanism. The hobbyist version of the same hardware costs $5 in parts and produces results that are, with care, comparable to the consumer products. Not medical-grade, not certified, but genuinely useful for fitness experiments and learning how the underlying signal processing works.

This article builds the project end-to-end: hardware, signal processing, and an ESP32 firmware that displays heart rate and SpO2 on an OLED in real time.

Important caveat: this is a hobby project. Do not use it to make medical decisions, do not pretend it is calibrated against medical reference devices, and do not give the resulting numbers to anyone as if they came from a certified pulse oximeter. With that said, the underlying physics is identical to medical-grade devices, and the results are good enough to learn from.

How pulse oximetry works (briefly)

Two LEDs (red at 660 nm, infrared at 940 nm) shine through your fingertip. A photodiode on the other side measures how much light passes through. The amount changes with each heartbeat as oxygenated blood pulses into the tissue.

Two facts make the measurement possible:

  1. Oxygenated haemoglobin absorbs IR more than red. Deoxygenated haemoglobin absorbs red more than IR. The ratio of red-to-IR absorption tells you the oxygen saturation.
  2. The pulsatile component of the signal (the part that changes with heartbeat) tells you the heart rate. The non-pulsatile component (skin, bone, tissue) tells you the baseline.

The MAX30102 packages the LEDs, photodiode, and a 18-bit ADC into a single chip with an I2C interface. It does the hardware part of the measurement; your firmware does the signal processing.

Bill of materials

  • ESP32 DevKit — $8
  • MAX30102 breakout board (genuine Maxim chip from SparkFun or Adafruit, or a clone for $3) — $5–15
  • 128×64 SSD1306 OLED, I2C — $4
  • Wires, breadboard — $3

About $20. Cheap clones of the MAX30102 are inconsistent — some have wrong pull-up values, some have less precise ADC calibration. For learning, a $3 clone works. For results you can compare across builds, spend the extra on a SparkFun or Adafruit breakout.

Wiring

MAX30102        ESP32
--------        -----
VCC          --> 3.3V
GND          --> GND
SDA          --> GPIO 21
SCL          --> GPIO 22
INT          --> GPIO 23 (optional, used for sample-ready interrupt)

OLED
----
VCC          --> 3.3V
GND          --> GND
SDA          --> GPIO 21 (shared with sensor)
SCL          --> GPIO 22 (shared with sensor)

The MAX30102 default I2C address is 0x57. The OLED is 0x3C. They share the bus without conflict.

Signal processing flow

flowchart LR Sensor[MAX30102] -->|raw red + IR
~100 Hz samples| Filter[Bandpass filter
0.5 - 4 Hz
removes DC and high-frequency noise] Filter --> Peak[Peak detector
identifies heartbeat peaks] Peak --> HR[Heart rate calculation
60 / time between peaks] Filter --> Ratio[Ratio of red AC to IR AC
over rolling window] Ratio --> SpO2[SpO2 lookup table
or empirical formula] HR --> Display[Display on OLED] SpO2 --> Display

The signal flow from raw sensor samples to displayed values. The bandpass filter removes the slowly-changing baseline and high-frequency noise; what is left is the heartbeat.

Firmware

The complete sketch — full setup, error handling, retries, deep-sleep wake, and configuration — is in the project package. Request it free using the form at the bottom of this article. We email it back within 24 hours.

The library by SparkFun (SparkFun_MAX3010x_Pulse_and_Proximity_Sensor_Library) provides the heart-rate and SpO2 algorithms based on Maxim's reference code. Writing your own is a good learning exercise; using the library lets you focus on getting the project working first.

Why your readings might be off

  • Finger pressure. Too light: ambient light leaks into the photodiode. Too heavy: blood flow is restricted, signal flattens. Resting your finger gently on the sensor with no movement is the right amount.
  • Cold fingers. Constricted blood vessels mean low signal-to-noise. Warm your hands before measuring.
  • Movement artifacts. Even small finger twitches dwarf the real pulse signal. Stay still during the measurement window.
  • Nail polish or dirt. Dark nail polish absorbs the LEDs unevenly. Use a clean fingertip.
  • Wrong sensor placement. The LEDs and photodiode must be aligned with the same blood-bearing tissue. The breakout board's pad placement is correct; clones occasionally have it wrong.

Going further

  • Real-time waveform on the OLED. Plot the IR signal as it pulses; visually striking and a good debug tool when something looks off.
  • Bluetooth Low Energy. Expose the readings as a standard Heart Rate Profile so any fitness app can display them.
  • Local data logging. Save readings to SD card or NVS flash, post to cloud later.
  • Custom algorithm. Implement your own bandpass filter and peak detector to learn the signal processing rather than treating Maxim's code as a black box.
  • Other vital signs. The same chip can measure heart rate variability and rough respiration rate from the IR baseline modulation.

Frequently Asked Questions

How accurate is this compared to a medical device?

Heart rate, when readings are valid, is typically within 2–3 BPM of a medical pulse oximeter. SpO2 is much harder — consumer/hobby measurements can be 2–5% off, which is medically significant. Treat both as approximate trend indicators, not absolute values.

Why do I sometimes get 0 BPM or impossible readings?

The algorithm rejects data it cannot interpret confidently. The valid flags exist for exactly this reason. Display only when valid; show "--" when not.

Can the same chip measure SpO2 on a wrist?

Theoretically yes (this is what fitness watches do), but the signal-to-noise is dramatically worse on the wrist than the fingertip. Consumer devices use multiple LEDs, larger photodiodes, and proprietary algorithms tuned for wrist measurement. The hobby setup with a finger gives much better results.

Are the cheap MAX30102 clones from AliExpress reliable?Mixed. Some are genuine Maxim chips on poor-quality breakout boards (work fine after fixing pull-ups). Some are functional clones with slightly different ADC calibration (results are usable but slightly biased). Some are completely non-functional. For consistent results, buy from SparkFun or Adafruit; for tinkering, the cheap ones are fine and you learn to work around their quirks.

Can I add ECG capability?

Different sensor entirely. The AD8232 ECG front-end is the typical hobby choice, requires medical electrodes (gel patches), and produces a different signal. Combining a MAX30102 fingertip oximeter with an AD8232 ECG gives you a multi-vital-sign monitor; the project complexity roughly triples.

Project package

Get the complete project package

The article above shows the core firmware and the principles behind it. The complete project package — assembled, tested, and ready to flash — is available by email request. We send it manually, and we read every request.

  • Complete Arduino sketch (.ino) with full error handling
  • List of required libraries with version numbers
  • Printable wiring diagram (PDF)
  • Bill of materials with current part numbers
  • Build guide and troubleshooting tips
  • Configuration template (WiFi, MQTT, etc.)

We send the package by email within 24 hours, usually faster. Free, no spam, no mailing list. Your email is used once, for this reply.

Share your thoughts

Worked with this in production and have a story to share, or disagree with a tradeoff? Email us at support@mybytenest.com — we read everything.