A prototype system for non-invasive glucose level estimation using PPG (Photoplethysmography) signals from the MAX30102/MAX30105 sensor and machine learning algorithms.
This is a research prototype only. NOT for medical use.
Accuracy depends on individual calibration and has not been clinically validated.
- Introduction
- Features
- Hardware Requirements
- Circuit Diagram
- Software Requirements
- Setup Instructions
- Data Collection Process
- Machine Learning Training
- Deployment
- Usage
- Project Structure
- How It Works
- Future Improvements
This project demonstrates a proof-of-concept for non-invasive glucose monitoring using photoplethysmography (PPG) signals. The system captures infrared (IR) and red light absorption data from a MAX30102 sensor, processes the signals to extract meaningful features, and uses a machine learning model (Linear Regression) to estimate glucose levels.
Blood glucose levels affect the optical properties of blood, particularly the absorption characteristics at different wavelengths. By measuring the ratio of IR to red light absorption and analyzing signal variability, we can correlate these features with glucose concentrations.
- ✅ Real-time PPG signal acquisition from MAX30102/MAX30105 sensor
- ✅ Dual-wavelength (IR + Red) optical measurement
- ✅ Feature extraction (IR/Red ratio, signal variability, waveform slope)
- ✅ Glucose level prediction using Linear Regression model
- ✅ SSD1306 OLED display for real-time readings
- ✅ Serial output for data logging
- ✅ CSV data storage for training data collection
- ✅ Finger detection with "No Finger" alert
| Component | Specification | Purpose |
|---|---|---|
| ESP32 DevKit | 30-pin or 38-pin | Main microcontroller |
| MAX30102/MAX30105 | PPG Sensor Module | Measures IR and Red light |
| SSD1306 OLED | 128x64, I2C interface | Display glucose readings |
| Jumper Wires | Male-to-Female | Connections |
| Breadboard | Standard | Prototyping (optional) |
| USB Cable | Micro-USB | Power and programming |
ESP32 DevKit MAX30102/MAX30105
----------- -----------------
3.3V ─────────────── VIN
GND ─────────────── GND
GPIO18 (SDA) ──────── SDA
GPIO19 (SCL) ──────── SCL
ESP32 DevKit SSD1306 OLED
----------- ------------
3.3V ─────────────── VCC
GND ─────────────── GND
GPIO18 (SDA) ──────── SDA
GPIO19 (SCL) ──────── SCL
Note: Both the MAX30102 and SSD1306 share the same I2C bus. The MAX30102 typically uses I2C address
0x57and SSD1306 uses0x3C.
┌─────────────────────┐
│ ESP32 │
│ │
┌───────────────┤ GPIO18 (SDA) │
│ ┌───────────┤ GPIO19 (SCL) │
│ │ ┌───────┤ 3.3V │
│ │ │ ┌───┤ GND │
│ │ │ │ └─────────────────────┘
│ │ │ │
│ │ │ │ ┌─────────────────────┐
├───┼───┼───┼───┤ SDA MAX30102 │
│ ├───┼───┼───┤ SCL │
│ │ ├───┼───┤ VIN │
│ │ │ ├───┤ GND │
│ │ │ │ └─────────────────────┘
│ │ │ │
│ │ │ │ ┌─────────────────────┐
├───┼───┼───┼───┤ SDA SSD1306 │
├───┼───┼───┤ SCL │
├───┼───┤ VCC │
├───┤ GND │
└─────────────────────┘
-
Install Arduino IDE (v1.8.x or newer, or Arduino IDE 2.x)
-
Add ESP32 Board Support:
- Go to
File→Preferences - Add this URL to "Additional Boards Manager URLs":
https://dl.espressif.com/dl/package_esp32_index.json - Go to
Tools→Board→Boards Manager - Search for "ESP32" and install "ESP32 by Espressif Systems"
- Go to
-
Install Required Libraries:
- Go to
Sketch→Include Library→Manage Libraries - Install the following:
SparkFun MAX3010x Pulse and Proximity Sensor LibraryAdafruit SSD1306Adafruit GFX Library
- Go to
pip install pandas numpy scikit-learn matplotlibgit clone https://github.com/austin-dev-dot/Non-Invasive-Glucometer.git- Open
glucosemonitor.inoin Arduino IDE
- Board: ESP32 Dev Module
- Upload Speed: 921600
- Flash Frequency: 80MHz
- Flash Mode: QIO
- Partition Scheme: Default 4MB with spiffs
- Port: Select your COM port
- Click the Upload button or press
Ctrl + U
To train your own model, you need to collect PPG data alongside reference glucose measurements from a commercial glucometer.
- Connect the hardware as per the circuit diagram
- Upload
glucosemonitor.inoto ESP32 - Open Serial Monitor (115200 baud)
- Place finger on the MAX30102 sensor
- Record the following from Serial output:
- IR Mean value
- Red Mean value
- Calculated Ratio
- Variability (RMSSD)
- Slope
Simultaneously measure glucose using a commercial glucometer and record the value.
Create a CSV file glucose_training_data.csv on your Desktop with the following format:
ratio,variability,slope,glucose
1.2534,5104.5,4472.3,110
1.2612,4892.1,3821.5,125
1.2489,5321.8,5102.4,98
...Note: The script also accepts alternative column names:
ir_red_ratio→ automatically renamed toratioreference_glucose→ automatically renamed toglucose
- Collect data at various times: fasting, post-meal (1hr, 2hr)
- Minimum 50-100 data points recommended
- Ensure finger is placed consistently
- Wait for stable readings (10-20 seconds)
- Keep finger still during measurement
- Valid glucose range: 40-400 mg/dL (outliers are filtered)
The training script uses Leave-One-Out Cross-Validation (LOOCV) for robust model evaluation, especially useful with small datasets.
| File | Path |
|---|---|
| Input CSV | C:\Users\AUSTIN PAUL\OneDrive\Desktop\glucose_training_data.csv |
| Output Directory | C:\Users\AUSTIN PAUL\OneDrive\Desktop\glucose_training_data\model_output\ |
python train_model.py- Loads and cleans data from the CSV file
- Filters outliers (glucose values outside 40-400 mg/dL)
- Runs Leave-One-Out Cross-Validation for rigorous evaluation
- Calculates performance metrics:
- MAE - Mean Absolute Error (mg/dL)
- RMSE - Root Mean Square Error (mg/dL)
- MARD - Mean Absolute Relative Difference (%) - standard metric for glucose monitors
- Within ±20 mg/dL - Clinical accuracy percentage
- Trains final model on all data
- Exports coefficients to
model_coefficients.h - Generates prediction plot saved as
prediction_plot.png
Running Cross-Validation...
===== MODEL PERFORMANCE =====
MAE : 12.45 mg/dL
RMSE : 15.32 mg/dL
MARD : 10.25 %
Within ±20 mg/dL : 78.5%
Training complete. Header and Plot saved to: C:\Users\...\model_output
| File | Description |
|---|---|
model_coefficients.h |
Arduino header with trained coefficients |
prediction_plot.png |
Scatter plot of actual vs predicted glucose |
Copy the generated model_coefficients.h from the output directory to your Arduino project folder, replacing the existing file.
- Update
model_coefficients.hwith your trained model coefficients - Upload the updated code to ESP32
- System will automatically use the new model for predictions
- Power On: Connect ESP32 to power via USB
- Wait for Initialization: Display shows "Glucose Monitor Initializing..."
- Place Finger: Position finger steadily on the MAX30102 sensor
- Wait: System needs ~2 seconds to fill the buffer
- Read Results: Glucose prediction updates every 5 seconds
| Message | Meaning |
|---|---|
Initializing... |
System starting up |
Place finger |
Ready for measurement |
No Finger |
Finger not detected or poor contact |
XXX.X mg/dL |
Predicted glucose level |
Open Serial Monitor at 115200 baud to see:
System Ready
Glucose: 115.2 mg/dL
Glucose: 118.5 mg/dL
...
Non Invasive Glucometer/
├── glucosemonitor.ino # Main Arduino sketch
├── model_coefficients.h # ML model coefficients
├── train_model.py # Python training script (LOOCV)
└── README.md # This file
Desktop/
├── glucose_training_data.csv # Your collected training data
└── glucose_training_data/
└── model_output/
├── model_coefficients.h # Generated coefficients
└── prediction_plot.png # Training results plot
The MAX30102 sensor emits both infrared (IR) and red LED light into the fingertip. The reflected light is measured by a photodetector. Blood volume changes during heartbeat cause variations in light absorption.
Three key features are extracted from the PPG signals:
| Feature | Calculation | Physiological Basis |
|---|---|---|
| Ratio | IR Mean / Red Mean | Related to oxygen saturation and blood composition |
| Variability | RMSSD of IR signal | Heart rate variability, blood flow dynamics |
| Slope | (Max - Min) / Time | Rate of blood volume change |
Features are standardized using the training data statistics, then passed through a linear regression model:
glucose = intercept + (c1 × z_ratio) + (c2 × z_variability) + (c3 × z_slope)
Where z_* represents standardized (z-score) features.
- Add temperature compensation
- Implement motion artifact detection and rejection
- Add heart rate variability (HRV) features
- Develop TinyML model with TensorFlow Lite
- Create mobile app for calibration and visualization
- Add SD card logging for long-term monitoring
- Implement cloud data upload via WiFi
- Add battery management for portable use
- Design 3D-printed enclosure
- Implement per-user calibration
| Issue | Solution |
|---|---|
| "OLED not found" | Check I2C connections, verify 0x3C address |
| "MAX30102 not found" | Check wiring, try I2C scanner sketch |
| Unstable readings | Ensure steady finger placement |
| "No Finger" message | Apply more pressure, check sensor alignment |
| Prediction accuracy low | Collect more calibration data |
Austin Paul