How to use a flex sensor with an Arduino
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
A flex sensor is a strip whose resistance goes up as it bends. Wire one leg to 5 V and the other to A0, put a 47k resistor from A0 to GND, and read it with analogRead(). Flat, it reads high; bent, it reads lower. It is the part inside every robot hand glove.
The circuit above is a 2.2 inch flex sensor and its 47k on an Uno. Press Run and drag the slider to bend the strip. Flat, the serial monitor prints "A0 = 668 (3264 mV)". At a right angle it reads "A0 = 439 (2145 mV)", and folded right over "A0 = 327 (1598 mV)".
Below is how the strip works, the wiring, two ways to turn the reading into an angle, a servo that copies your finger, and how to pick the resistor.
What you need
- An Arduino Uno
- A flex sensor, such as the 2.2 inch or 4.5 inch Spectra Symbol strip
- A 47k resistor (yellow, violet, orange)
- A servo, for the robot finger
- A breadboard and jumper wires
Wiring
| Part and pin | Goes to | Note |
|---|---|---|
| Flex sensor, either leg | 5 V | It has no polarity, but it bends one way |
| Flex sensor, other leg | A0 | |
| 47k resistor | From A0 to GND | Makes the divider |
| Servo signal | Pin 9 | For the robot finger; red to 5 V, brown to GND |
How a flex sensor works
One side of the strip is printed with a carbon ink. Bend it with the ink on the outside of the curve and the ink cracks into smaller islands, so the resistance goes up: about 25k flat, 62.5k at 90 degrees and 100k folded over, in the simulator. Bend it the other way and a real strip barely changes, so mount it with the printed side out.
The strip is the top half of a divider, so more resistance means less voltage on A0. That is why the reading falls as you bend.
From the reading to degrees with map()
The quick way is to measure the reading flat and folded, then let map() stretch it to 0 to 180. Flat it printed "668 -> 0 degrees" and folded "327 -> 180 degrees". So far so good. But a right angle printed "439 -> 120 degrees", not 90.
The strip’s resistance climbs in a straight line with the bend, but a divider does not turn resistance into voltage in a straight line, so map() bends the middle. For a glove that opens and closes a hand, that does not matter. For an angle you want to print, use the next sketch.
const int FLAT = 668; // the reading with the strip flat
const int BENT = 327; // and folded right over
void setup() {
Serial.begin(9600);
}
void loop() {
int reading = analogRead(A0);
int angle = map(reading, FLAT, BENT, 0, 180);
angle = constrain(angle, 0, 180);
Serial.print(reading);
Serial.print(" -> ");
Serial.print(angle);
Serial.println(" degrees");
delay(500);
}Degrees from the resistance
Work out the strip’s resistance from the divider first, R = 47000 * (1023 - raw) / raw, then turn the resistance into degrees. Flat it printed "24977 ohms -> 0 degrees", at a right angle "62523 ohms -> 90 degrees" and folded "100036 ohms -> 180 degrees". At 45 degrees it printed 44, which is as close as the ADC’s steps allow.
On a real strip, measure FLAT_OHMS and BENT_OHMS with your own strip, since every one is a little different.
const long R_FIXED = 47000; // the resistor from A0 to GND
const long FLAT_OHMS = 25000; // the strip flat
const long BENT_OHMS = 100000; // the strip folded over
void setup() {
Serial.begin(9600);
}
void loop() {
int raw = analogRead(A0);
long ohms = R_FIXED * (1023 - raw) / raw;
long angle = (ohms - FLAT_OHMS) * 180 / (BENT_OHMS - FLAT_OHMS);
angle = constrain(angle, 0, 180);
Serial.print(ohms);
Serial.print(" ohms -> ");
Serial.print(angle);
Serial.println(" degrees");
delay(500);
}A servo finger that copies yours
Add a servo on pin 9 and the strip can drive it. This is one finger of a robot hand: tape the strip along your finger and the servo follows as you bend it. Flat, the servo sat at 0 degrees, and folded it went to 180.
It uses the map() version, so a strip bent to 90 degrees put the servo at 120. For a hand that is fine; the finger still closes when yours does. Five strips on A0 to A4 and five servos make the whole hand; the robotic hand project does exactly that on a Mega.
#include <Servo.h>
Servo finger;
void setup() {
finger.attach(9);
}
void loop() {
int reading = analogRead(A0);
int angle = map(reading, 668, 327, 0, 180);
finger.write(constrain(angle, 0, 180));
delay(20);
}Picking the resistor
The best resistor is close to the strip’s own resistance across its range. With a 47k, the reading went from 668 flat to 327 folded, a swing of 341 counts. A 10k swung only from 292 to 93, and a 100k from 818 to 512. More swing means a smoother angle.
What the simulation leaves out
Every strip here is the typical one: 25k flat and 100k folded, with the resistance following the slider at once. A real strip can be 30 percent either side of 25k flat, which is why you measure your own. It also reads differently depending on where along its length the bend is and how tight it is, not just the angle, so a finger joint and a gentle curve to the same angle give different numbers.
A real strip creeps back slowly after you straighten it, so the reading takes a moment to settle, and it reads a little higher as it wears. Calibrate on the hand or the hinge it will live on, and check it again after a few weeks of use.
Common mistakes
Bending it the wrong way. Mount the strip with the printed side on the outside of the bend, or a real one hardly changes.
Bending it at the legs. The joint where the leads meet the strip is the weak spot; tape or glue that end down so it never bends.
Using a 10k because the FSR guide did. That only swings about 200 counts with this strip; use 47k.
Leaving out constrain(). A strip bent a little further than when you measured it gives map() a number outside the range, and the servo gets told more than 180 degrees.
Copying FLAT and BENT from someone else. Measure your own strip flat and folded, and use those numbers.
Questions
How do I connect a flex sensor to an Arduino?
One leg to 5 V, the other to A0, and a 47k resistor from A0 to GND. Read it with analogRead(A0): highest flat, lower as it bends.
What resistor do I use with a flex sensor?
Something near the strip’s own range, 47k for a 2.2 inch strip that goes from 25k to 100k. It gave a swing of 341 counts here, against 199 with a 10k.
How do I turn a flex sensor reading into an angle?
Measure the reading flat and folded and use map() and constrain(). For a true angle, work out the resistance from the divider first, then scale that to degrees.
Does a flex sensor work when bent both ways?
No. It is made to bend one way, with the printed side on the outside. Bent the other way, a real strip changes very little.
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.