A real-time embedded system for non-contact detection of elevated intraocular pressure (IOP) — a primary indicator of glaucoma — using an ESP32 microcontroller, ultrasonic proximity sensing, and barometric pressure acquisition, with live telemetry over a WiFi-hosted HTTP API.
- System Overview
- Hardware Requirements
- Pin Configuration
- Dependencies
- Sensor Architecture
- Detection Logic
- HTTP API
- OLED Display Output
- Setup & Flashing
- Configuration
- Known Limitations
The firmware runs on an ESP32 and integrates three peripheral subsystems:
- HC-SR04 Ultrasonic Sensor — measures distance to the target (e.g., eye/probe surface) in real time using pulse-echo timing.
- BMP280 Barometric Pressure Sensor (I²C, address
0x76) — reads ambient/contact pressure at 16x oversampling with a 16x IIR filter for stable readings. - SSD1306 OLED Display (I²C, address
0x3C, 128×64 px) — renders live diagnostic output: distance, pressure, and detection status.
A motorized pump (GPIO-controlled) is conditionally activated based on proximity threshold. The system also spins up a WiFi-connected HTTP server on port 80, exposing a JSON endpoint for remote sensor polling.
| Component | Part | Interface |
|---|---|---|
| Microcontroller | ESP32 (any variant) | — |
| Pressure Sensor | Bosch BMP280 | I²C |
| Display | SSD1306 128×64 OLED | I²C |
| Proximity Sensor | HC-SR04 Ultrasonic | GPIO |
| Actuator | DC Pump / Solenoid | GPIO (digital) |
| Signal | GPIO Pin |
|---|---|
| Ultrasonic TRIG | 5 |
| Ultrasonic ECHO | 4 |
| Pump Control | 18 |
| I²C SDA | Default (GPIO 21) |
| I²C SCL | Default (GPIO 22) |
I²C pins use ESP32 Arduino defaults. Override with
Wire.begin(SDA, SCL)if using alternate pins.
Install via Arduino Library Manager or PlatformIO:
| Library | Purpose |
|---|---|
Adafruit BMP280 |
Pressure sensor driver |
Adafruit SSD1306 |
OLED display driver |
Adafruit GFX |
Graphics abstraction layer |
WiFi (built-in ESP32) |
Network stack |
WebServer (built-in ESP32) |
HTTP server |
Distance is computed from the round-trip pulse duration using:
distance (cm) = (pulseIn_duration_µs × 0.0343) / 2
Where 0.0343 cm/µs is the speed of sound at room temperature. A 10 µs HIGH pulse on TRIG_PIN initiates the measurement; pulseIn() on ECHO_PIN captures the reflected pulse width.
The BMP280 is initialized in Normal Mode with the following oversampling configuration:
bmp.setSampling(
MODE_NORMAL,
SAMPLING_X2, // Temperature
SAMPLING_X16, // Pressure
FILTER_X16, // IIR coefficient
STANDBY_MS_500 // 500 ms standby between measurements
);Raw pressure is read in Pascals (Pa) and converted to hectopascals (hPa) for display and API output.
The system infers elevated IOP risk based on a distance threshold window:
| Distance (cm) | Interpretation | Pump State |
|---|---|---|
< 8 |
Contact / within activation range | HIGH (active) |
8 – 10 |
Glaucoma Detected (IOP threshold zone) | LOW |
> 10 |
Normal / no detection | LOW |
Note: The specific distance thresholds (
8 cm,10 cm) are calibrated to the physical probe geometry of the intended deployment. AdjustPUMP_PINlogic and display conditionals accordingly for alternate hardware configurations.
The ESP32 hosts a lightweight HTTP server on port 80. On successful WiFi connection, the assigned IP address is printed to the Serial monitor.
Returns a JSON object containing the latest ultrasonic distance and barometric pressure readings.
Response:
{
"distance_cm": 7.43,
"pressure": 1013.25
}| Field | Unit | Description |
|---|---|---|
distance_cm |
cm | Echo-derived distance to target |
pressure |
hPa | Barometric pressure from BMP280 |
Headers:
Access-Control-Allow-Origin: *
Content-Type: application/json
CORS is enabled on all responses to allow cross-origin polling from browser-based dashboards.
The 128×64 SSD1306 display refreshes every 500 ms with three data rows:
Distance:
7.43 cm
Glaucoma Detected ← or "Glaucoma Not Detected"
Pressure:
1013.25 hPa
- Clone or download this repository.
- Open
ESP32_Code.inoin the Arduino IDE (or PlatformIO). - Install all listed library dependencies.
- Set your WiFi credentials in the source:
const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASSWORD";
- Select your ESP32 board target under Tools → Board.
- Flash at 115200 baud.
- Open Serial Monitor to retrieve the assigned IP address.
- Navigate to
http://<device-ip>/to verify the JSON endpoint.
| Constant | Default | Description |
|---|---|---|
TRIG_PIN |
5 |
Ultrasonic trigger pin |
ECHO_PIN |
4 |
Ultrasonic echo pin |
PUMP_PIN |
18 |
Pump/actuator control pin |
SCREEN_WIDTH |
128 |
OLED horizontal resolution |
SCREEN_HEIGHT |
64 |
OLED vertical resolution |
| BMP280 I²C address | 0x76 |
Modify if using 0x77 variant |
| SSD1306 I²C address | 0x3C |
Standard address for most modules |
| Loop delay | 500 ms |
Sensor polling + display refresh interval |
- No persistent storage — sensor readings are not logged locally; polling the HTTP endpoint is required for data capture.
- Single-client HTTP server — the
WebServerlibrary handles one request at a time; concurrent polling may cause dropped requests. - No sensor fusion — glaucoma detection is based solely on distance thresholds; pressure readings are displayed but not incorporated into the detection algorithm.
- Speed of sound is temperature-uncorrected — the BMP280 temperature reading is not fed back into the distance calculation. For high-accuracy deployments, apply the temperature-compensated formula.
- WiFi credentials are hardcoded — consider integrating
WiFiManageror NVS-based credential storage for production builds.