How to use a force-sensing resistor (FSR) with an Arduino
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
An FSR is a resistor that drops as you press it. Wire one leg to 5 V and the other to A0, put a 10k resistor from A0 to GND, and read it with analogRead(). The harder the press, the higher the number. Without the 10k it does not work at all, which is the most common first mistake.
The circuit above is a round FSR 402 and its 10k on an Uno. Press Run and drag the slider on the pad. Untouched, the serial monitor prints "A0 = 1 (4 mV)". At 20 g, about the weight of a light fingertip, it jumps to "A0 = 221 (1080 mV)". At 100 g it reads 512, at 1 kg 883 and at the pad’s top of 2 kg it reads 938.
Below is how the pad works, the wiring, a sketch that sorts presses into light and hard, a drum pad that counts each hit once, how to choose the resistor, and how close you can get to grams.
What you need
- An Arduino Uno
- A force-sensing resistor, such as the round FSR 402 or the square FSR 406
- A 10k resistor (brown, black, orange)
- A breadboard and jumper wires
Wiring
| Part and pin | Goes to | Note |
|---|---|---|
| FSR, either leg | 5 V | An FSR has no polarity |
| FSR, other leg | A0 | |
| 10k resistor | From A0 to GND | Makes the divider; without it A0 reads 1023 always |
How an FSR works
Inside the pad are two thin layers with a gap between them. One is printed with fingers of metal, the other with a carbon ink. Press, and the ink touches more of the fingers, so the resistance falls. Under about 20 g the layers do not touch at all and the pad is open. Then it switches on at around 36k and keeps falling: about 10k at 100 g, 1.6k at 1 kg and under 1k at 2 kg.
That is why the reading jumps from 1 to 221 instead of creeping up. An FSR is best at "harder" and "softer". It is not a scale: two pads from the same bag can read quite differently, and a real one drifts down a little under a steady load. For weight, use a load cell and an HX711 instead.
Light touch, squeeze or hard press
This sketch reads A0 twice a second and sorts the reading into four bands. We pressed the pad in the simulator at each weight in turn. Untouched it printed "1 no press", at 20 g "221 light touch", at 100 g "512 squeeze" and at 1 kg "883 hard press".
The bands are yours to move. Print the raw number first, press the pad the way your project will, and pick the limits from what you see.
const int FSR = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
int reading = analogRead(FSR);
Serial.print(reading);
if (reading < 10) {
Serial.println(" no press");
} else if (reading < 300) {
Serial.println(" light touch");
} else if (reading < 700) {
Serial.println(" squeeze");
} else {
Serial.println(" hard press");
}
delay(500);
}A drum pad that counts each hit once
The obvious drum sketch, if (analogRead(A0) > 400) Serial.println("hit");, prints "hit" every time around the loop for as long as the pad is down. We pressed with 500 g, let go, pressed with 1 kg, eased off to 100 g without letting go, pressed hard again and let go. That printed "hit" 156 times.
The fix is to remember whether the pad is down. The sketch below counts a hit when the reading rises past 400, and will not count another until it falls back under 100. The gap between the two numbers is what stops a press that wobbles around 400 from counting twice. The same presses printed "hit 1" and "hit 2", and nothing else: the ease off never fell under 100, so it was still the same hit.
const int HIT = 400; // a press has to rise past this
const int RELEASE = 100; // and fall back under this before the next one
bool down = false;
int hits = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
int reading = analogRead(A0);
if (!down && reading > HIT) {
down = true;
hits++;
Serial.print("hit ");
Serial.println(hits);
} else if (down && reading < RELEASE) {
down = false;
}
delay(5);
}Picking the resistor
The fixed resistor sets which part of the pad’s range lands in the middle of the ADC. With the 10k, 20 g read 221 and 2 kg read 938, which spreads the whole range across the scale. A 47k is better for a light touch: 20 g read 578, but 1 kg already read 990 and the top end is squashed flat. A 3.3k is the other way around: 20 g read only 85, and 2 kg read 802 with room to spare.
So use 47k for a touch pad you tap with a finger, 10k for most projects, and 3.3k for something you stand on.
From the reading to grams
The divider gives the pad’s resistance: R = 10000 * (1023 - raw) / raw. The FSR 402’s typical curve turns that into force. The sketch below does both. At 100 g it printed "9980 ohms, about 100 g" and at 1 kg "1586 ohms, about 1000 g".
It matches so well here because the simulated pad follows the typical curve exactly. A real pad does not, and two pads from the same bag can disagree about the same press. Use the grams to compare one press with another on the same pad, not to weigh things.
const float R_FIXED = 10000.0; // the resistor from A0 to GND
void setup() {
Serial.begin(9600);
}
void loop() {
int raw = analogRead(A0);
if (raw < 10) {
Serial.println("no press");
} else {
float ohms = R_FIXED * (1023 - raw) / raw;
// The FSR 402's typical curve: 10k at 100 g, falling as force^0.8.
float grams = 100.0 * pow(10000.0 / ohms, 1.25);
Serial.print(ohms, 0);
Serial.print(" ohms, about ");
Serial.print(grams, 0);
Serial.println(" g");
}
delay(500);
}Common mistakes
Leaving out the 10k. With the FSR from 5 V to A0 and nothing else, A0 read 1023 untouched and 1023 at 100 g. There is no divider, so there is nothing for the press to change.
Expecting a reading under 20 g. The pad is open until the layers touch, so a feather does nothing at all.
Treating it as a scale. It tells harder from softer well and grams badly. A load cell is the part for weight.
Bending the tail or soldering it hot. The leads are printed on plastic; clamp them in a connector or a breadboard instead.
Pressing with a fingertip on a big pad. Only the part that is pressed counts, so put a small rubber bump or a coin on the pad to spread the force evenly.
Questions
How do I connect an FSR to an Arduino?
One leg to 5 V, the other to A0, and a 10k resistor from A0 to GND. Read it with analogRead(A0): about 1 untouched, rising as you press.
Why does my FSR always read 1023?
The resistor from A0 to GND is missing, so A0 just sees 5 V through the pad. Add a 10k from A0 to GND and the reading falls to about 1 when nothing presses.
What resistor should I use with an FSR?
10k for most projects. 47k makes a light touch read higher but runs out of range for a hard press; 3.3k is the other way around, for heavy loads.
Can an FSR measure weight?
Only roughly. Its curve gives an estimate in grams, but real pads differ from each other and drift under a steady load. For weight, use a load cell with an HX711.
Does an FSR work the same on an Arduino Nano?
Yes. The Nano has the same 10-bit converter on a 5 V rail, so the same 10k divider gives the same numbers: with 100 g on the pad, a Nano here read 512 on A0, as the Uno does.
Keep going
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.