Simple firmware for reading force/pressure data from an FSR sensor using ESP32 and Arduino IDE.
- Smooth readings with Exponential Moving Average (EMA) filter
- Multi-sample averaging for noise reduction
- Real-time data output via serial monitor
- Automatic calculations for voltage, resistance, conductance, and relative force
- Optimized for GPIO34 (ADC1 channel, works with WiFi enabled)
| Component | Specification | Notes |
|---|---|---|
| ESP32 Dev Board | Any ESP32 board | ESP32-WROOM, DevKit V1, NodeMCU-32S, etc. |
| FSR Sensor | Force Sensitive Resistor | Interlink FSR402, FSR406, or similar |
| Fixed Resistor | 10kΩ (±5%) | Pull-down resistor for voltage divider |
| Breadboard | Standard size | For prototyping |
| Jumper Wires | Male-to-male | 3 wires minimum |
| USB Cable | Data cable | Must support data transfer (not charge-only) |
| Optional: Capacitor | 0.1µF (100nF) | For additional noise filtering |
ESP32
+3.3V ────┬──── FSR ────┬──── 10kΩ Resistor ──── GND
│ │
│ └──── GPIO34 (ADC1_CH6)
│ │
│ [Optional: 0.1µF capacitor to GND]
-
Connect FSR:
- One leg to ESP32 3.3V pin
- Other leg to GPIO34 pin
-
Connect 10kΩ resistor:
- One leg to GPIO34 pin (same point as FSR)
- Other leg to GND pin
-
Optional - Add capacitor for filtering:
- Connect 0.1µF capacitor between GPIO34 and GND
| ESP32 Pin | Connection | Purpose |
|---|---|---|
| 3.3V | FSR (one side) | Power supply |
| GPIO34 | FSR + 10kΩ junction | Analog input (ADC1_CH6) |
| GND | 10kΩ resistor | Ground reference |
Important Notes:
- GPIO34 is input-only - perfect for analog sensors
- GPIO34 is on ADC1, so it works even when WiFi is enabled
- Do NOT exceed 3.3V on GPIO34 (ESP32 is not 5V tolerant!)
┌──────────────────┐
│ │
│ ESP32 Board │
│ │
│ ┌────────────┐ │
│ │ GPIO34 │◄─┼──┬─── [FSR] ─── 3.3V
│ └────────────┘ │ │
│ │ │
│ ┌────────────┐ │ │
│ │ GND │◄─┼──┴─── [10kΩ] ───┘
│ └────────────┘ │
│ │
│ ┌────────────┐ │
│ │ USB Port │◄─┼─── USB Cable ─── Computer
│ └────────────┘ │
│ │
└──────────────────┘
Before uploading the firmware, ensure you have:
- USB Driver installed (CP2102 or CH340)
- Arduino IDE installed (version 1.8.19+ or 2.x)
- ESP32 board support installed in Arduino IDE
- Correct board and port selected
Need help? See SETUP.md for detailed driver and Arduino IDE installation instructions.
- Install USB driver (see SETUP.md)
- Open Arduino IDE
- Add ESP32 board URL:
- File → Preferences
- Add:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- Install ESP32 boards:
- Tools → Board → Boards Manager
- Search "esp32", install "esp32 by Espressif Systems"
- Select board:
- Tools → Board → ESP32 Arduino → ESP32 Dev Module
- Select port:
- Tools → Port → COM# (your port)
- Connect ESP32 to computer via USB
- Open
fsr_reader.inoin Arduino IDE - Select board: Tools → Board → ESP32 Dev Module
- Select port: Tools → Port → COM# (your port number)
- Set upload speed: Tools → Upload Speed → 115200
- Click Upload button (→ arrow icon)
- Wait for "Done uploading" message
Troubleshooting upload issues: See SETUP.md - Common Upload Issues section
- Open Serial Monitor: Tools → Serial Monitor (or
Ctrl + Shift + M) - Set baud rate to 115200 (dropdown at bottom-right)
- Set line ending to "Both NL & CR" or "Newline" (optional)
You should see output like this:
========================================
ESP32 FSR Sensor Reader
========================================
Pin: GPIO34 (ADC1_CH6)
Fixed Resistor: 10kΩ
Filter: Exponential Moving Average
========================================
Raw ADC Smoothed Voltage(V) FSR Res(Ω) Conductance(µS) Force(%)
------- -------- ---------- ---------- -------------- --------
45 48.2 [No pressure detected]
52 49.8 [No pressure detected]
1203 845.3 0.687 3925 254.78 42.3
2156 1567.2 1.273 15890 62.93 18.5
3421 2894.7 2.351 38234 26.15 5.2
| Column | Description | Usage |
|---|---|---|
| Raw ADC | Instantaneous ADC reading (0-4095) | Shows sensor noise/variation |
| Smoothed | Filtered value using EMA | Stable reading, use this for decisions |
| Voltage(V) | Measured voltage at GPIO34 (0-3.3V) | Useful for circuit verification |
| FSR Res(Ω) | Calculated FSR resistance | Lower = more pressure applied |
| Conductance(µS) | Inverse of resistance | Higher = more pressure (easier to interpret) |
| Force(%) | Estimated relative force (0-100%) | Simplified pressure indication |
FSR Resistance Guide:
- >100kΩ - No pressure / very light touch
- 10kΩ - 100kΩ - Light pressure
- 1kΩ - 10kΩ - Medium pressure
- <1kΩ - Heavy pressure
All configuration parameters are at the top of fsr_reader.ino:
Change pressure detection threshold:
const int PRESSURE_THRESHOLD = 50; // Increase to ignore light touchesAdjust smoothing (filter responsiveness):
const float ALPHA = 0.15; // Range: 0.0 to 1.0
// Lower = smoother but slower response
// Higher = more responsive but noisierModify sampling:
const int NUM_SAMPLES = 15; // More samples = smoother but slower
// Fewer samples = faster but noisierIn the loop() function:
delay(100); // Change this value
// 100 = 10 readings/second
// 50 = 20 readings/second
// 1000 = 1 reading/secondMeasure actual 3.3V rail:
const float V_REF = 3.3; // Change to measured voltage (e.g., 3.28)Verify fixed resistor value:
const int R_FIXED = 10000; // Change if using different resistor
// e.g., 4700 for 4.7kΩOutput can be easily parsed for data logging:
Python example to capture data:
import serial
import csv
ser = serial.Serial('COM3', 115200) # Change COM port
with open('fsr_data.csv', 'w', newline='') as file:
writer = csv.writer(file)
while True:
line = ser.readline().decode('utf-8').strip()
print(line)
# Parse and write to CSVAdd code in loop() after force calculation:
// Example: Turn on LED when force exceeds 50%
const int LED_PIN = 2;
if (force > 50) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}The code uses ADC1 (GPIO34), so WiFi and Bluetooth work without conflicts:
#include <WiFi.h>
// Add to setup():
WiFi.begin("YourSSID", "YourPassword");
// Add to loop() to send data over WiFi
// ... your WiFi code here ...Causes & Solutions:
| Problem | Check | Solution |
|---|---|---|
| Wiring error | Verify connections | Recheck circuit diagram |
| Wrong pin | Using wrong GPIO | Ensure using GPIO34, not D34 label |
| Bad FSR | FSR might be damaged | Test FSR with multimeter |
| No Serial Monitor | Forgot to open monitor | Tools → Serial Monitor |
| Wrong baud rate | Serial mismatch | Set to 115200 in Serial Monitor |
Solutions:
- Lower threshold:
const int PRESSURE_THRESHOLD = 20; // Try lower value
- Check FSR orientation - FSR might be connected backwards (shouldn't matter, but try flipping)
- Verify FSR works - Measure resistance with multimeter while pressing
Solutions:
- Increase smoothing:
const float ALPHA = 0.1; // Lower = smoother (was 0.15)
- More samples:
const int NUM_SAMPLES = 25; // Increase from 15
- Add hardware filter - Install 0.1µF capacitor between GPIO34 and GND
- Check wiring - Loose connections cause noise
- Use shorter wires - Long wires act as antennas picking up interference
Causes:
- FSR or resistor value mismatch
- FSR always compressed
Solutions:
- Check resistor value - Verify it's 10kΩ, not 10Ω or 100kΩ
- Try different resistor - Use 4.7kΩ or 22kΩ instead
- Verify FSR is not stuck pressed
See SETUP.md - "Common Upload Issues & Solutions"
Verify voltage divider:
-
No pressure applied:
- Measure voltage at GPIO34: Should be close to 0V
- Measure FSR resistance: Should be >100kΩ
-
Light pressure applied:
- Measure voltage at GPIO34: Should be 0.5V - 2.0V
- Measure FSR resistance: Should be 1kΩ - 50kΩ
-
Heavy pressure applied:
- Measure voltage at GPIO34: Should be 2.0V - 3.1V
- Measure FSR resistance: Should be <1kΩ
Voltage NOT in expected range?
- Check resistor value (should be 10kΩ, color code: Brown-Black-Orange)
- Verify 3.3V power supply is present
- Check for short circuits or bad connections
setup()
- Initializes serial communication (115200 baud)
- Configures ADC for 0-3.3V range (11dB attenuation)
- Sets 12-bit resolution (0-4095)
- Prints startup information
loop()
- Reads sensor with averaging
- Applies exponential moving average filter
- Calculates voltage, resistance, conductance, and force
- Prints formatted data to serial monitor
- Repeats every 100ms (10 Hz)
averageRead()
- Takes multiple ADC samples (reduces noise)
- Returns average value
- Adds small delays between samples for stability
calculateFSRResistance()
- Converts measured voltage to FSR resistance
- Uses voltage divider formula
- Handles edge cases (short/open circuit)
estimateForce()
- Converts resistance to 0-100% force estimate
- Uses logarithmic mapping (FSRs respond logarithmically)
- Simplified model - calibrate for accurate force measurement
Exponential Moving Average (EMA):
smoothedValue = (ALPHA * rawValue) + ((1.0 - ALPHA) * smoothedValue);- ALPHA = 0.15 means 15% new data, 85% old data
- Removes high-frequency noise while preserving trends
- Fast and memory-efficient (no arrays needed)
- Adjust ALPHA to tune responsiveness vs smoothness
The estimateForce() function provides a simplified estimate. For accurate force measurement:
- Apply known weights to FSR (e.g., 100g, 200g, 500g, 1kg)
- Record resistance for each weight
- Create lookup table or fit curve
Replace the logarithmic approximation with your calibration data:
float estimateForce(float resistance) {
// Example calibration data (replace with your measurements)
if (resistance > 50000) return 0; // 0g
if (resistance > 10000) return 100; // 100g
if (resistance > 3000) return 250; // 250g
if (resistance > 1000) return 500; // 500g
if (resistance > 500) return 1000; // 1kg
return 2000; // >2kg
}Or use interpolation for smooth curve fitting.
- Reading rate: ~10 Hz (100ms delay)
- Filter lag: ~500ms to stabilize (depends on ALPHA)
- Memory usage: Minimal (~1KB)
- CPU usage: <1% (plenty of resources for other tasks)
Can be used alongside:
- WiFi communication
- Bluetooth
- Display updates
- Motor control
- Other sensors
- Pressure-sensitive LED - Brightness changes with force
- Door knock detector - Trigger when force exceeds threshold
- Musical instrument - FSR controls pitch/volume
- Smart mat - Detect when someone steps on surface
- Grip strength meter - Measure and log hand strength
- Pressure mapping - Multiple FSRs to create heatmap
- IoT weight scale - Send weight data to cloud
- Game controller - Analog pressure-sensitive buttons
- Prosthetic feedback - Pressure sensing for robotic hands
ESP32 Documentation:
- Official ESP32 Arduino Core: https://docs.espressif.com/projects/arduino-esp32/
FSR Datasheets:
- Interlink FSR Integration Guide: https://www.interlinkelectronics.com/fsr-guide
- FSR 402 Datasheet: Search "FSR402 datasheet" for resistance vs force curves
Arduino References:
- analogRead(): https://www.arduino.cc/reference/en/language/functions/analog-io/analogread/
- Serial communication: https://www.arduino.cc/reference/en/language/functions/communication/serial/
This project is provided as-is for educational and hobbyist purposes. Feel free to modify and use in your projects!
Issues with hardware setup? Check SETUP.md
Questions or problems?
- Check the Troubleshooting section above
- Review your wiring against the circuit diagram
- Verify all configuration settings in the code
- Test components individually with multimeter
Happy building! You now have a working pressure sensor system ready for integration into your projects.