Contents β 27 sections
Project Overview
A pressure-sensing insole that maps how your foot loads the ground through each step, extracts gait parameters and symmetry, and flags asymmetries that matter for injury and rehabilitation.
How you walk is a rich signal. The pattern and timing of pressure under the foot through each step encodes stride timing, weight distribution, left-right symmetry, and subtle deviations that accompany injury, pain, and neurological conditions. A pressure-sensing insole captures this in the real world, over thousands of steps, in a way a gait lab with force plates and cameras β accurate but confined to a few strides in a corridor β cannot.
The build places an array of force-sensitive resistors at the key loading regions of the foot: the heel, the lateral and medial midfoot, the metatarsal heads, and the hallux (big toe). As you walk, each sensor reports the pressure at its location, and the pattern over time reveals the gait cycle: heel strike, loading, midstance, push-off, and swing. From this the device extracts stride time, stance and swing durations, the centre of pressure trajectory, peak pressures, and β most usefully β the symmetry between the two feet.
Asymmetry is the clinically interesting output. A healthy gait is roughly symmetric; injury, pain, and many conditions produce measurable asymmetry β a shortened stance time on a painful side, a shifted centre of pressure, altered loading. Quantifying this over real-world walking gives information relevant to injury risk, rehabilitation progress, and prosthetic or orthotic fitting.
The honest framing is that gait analysis is a research and screening tool, not a diagnostic one. FSRs are pressure-indicating rather than precisely calibrated, so the device measures relative loading and timing well but absolute pressure only roughly. It reveals patterns and asymmetries; interpreting what they mean clinically requires expertise. This is a powerful data-collection and pattern-analysis platform, presented as such.
What this project does
- Measures plantar pressure at multiple foot regions with an FSR array in each insole.
- Segments the gait cycle into stance and swing phases from the pressure pattern.
- Extracts stride time, stance/swing durations, cadence and peak regional pressures.
- Computes the centre-of-pressure trajectory through each step.
- Quantifies left-right symmetry and flags asymmetries.
- Streams data over BLE and logs sessions for analysis.
- Optionally classifies gait patterns with a small on-device model.
Real-World Applications
| Setting | How it is used |
|---|---|
| Rehabilitation monitoring | Objective, real-world tracking of gait recovery after injury or surgery, between clinic visits. |
| Running injury prevention | Loading patterns and asymmetries associated with overuse injury, captured during actual runs. |
| Prosthetic and orthotic fitting | Quantifying how load distributes, to guide device adjustment. |
| Neurological gait assessment | Conditions like Parkinson's and post-stroke produce characteristic gait changes. |
| Fall-risk screening in older adults | Gait variability and asymmetry are established fall-risk indicators. |
| Biomechanics research | A real-world data platform for gait studies outside the lab. |
Deployment contexts where a build of this kind earns its keep.
Features & Capabilities
- Multi-region FSR array at the heel, midfoot, metatarsals and hallux.
- Gait-cycle segmentation into stance and swing from the pressure signal.
- Temporal parameters β stride time, stance %, cadence, double-support time.
- Centre-of-pressure trajectory mapping how load moves through the foot.
- Symmetry analysis comparing left and right, the key clinical output.
- Dual-insole synchronisation so left and right are time-aligned.
- On-device gait classification (optional TinyML) into normal/abnormal patterns.
- Real-world capture over thousands of steps, not a few lab strides.
Difficulty, Time & Required Skills
| Attribute | Value |
|---|---|
| Difficulty level | Advanced |
| Estimated completion time | 18β26 hours |
| Indicative build cost | βΉ5,400 β βΉ7,000 (both insoles) |
| Primary discipline | Health & Wearables |
| Reference platform | ESP32 DevKit V1 (ESP-WROOM-32) |
Skills you should have (or will pick up)
- Arduino C++ with multi-channel analogue sampling
- FSR interfacing and calibration
- Gait-cycle segmentation and event detection
- Signal synchronisation between two devices
- Optional TinyML for pattern classification
Bill of Materials
Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift β treat them as a budgeting guide, not a quotation.
| Component | Key specification | Qty | Approx. cost |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) Wi-Fi transmit bursts peak near 500 mA β size the regulator accordingly. | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18Γ 12-bit ADC, 2Γ 8-bit DAC | 2 | βΉ900 |
| FSR-402 force-sensitive resistor Not a precision scale β good for presence and relative pressure only. | 0.2β20 N, 12.7 mm active area, 100 kΞ©β2 kΞ© swing, < 1 ms response | 8 | βΉ5,600 |
| ADXL345 3-axis accelerometer Built-in activity/free-fall interrupts let the MCU deep-sleep until something moves. | Β±2/4/8/16 g, 13-bit, 0.004 g/LSB, tap and free-fall interrupts, 3200 Hz | 1 | βΉ220 |
| 18650 Li-ion cell 3400 mAh + holder Never charge below 0 Β°C; always use a protected cell or a BMS. | 3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge | 1 | βΉ450 |
| TP4056 Li-ion charger + DW01 protection Buy the version *with* protection ICs β the bare charger will over-discharge your cell. | 1 A programmable CC/CV charge to 4.2 V Β±1 %, over-discharge and short protection | 1 | βΉ45 |
| Double-sided perfboard 7 Γ 9 cm + headers Solder female headers so the MCU can be swapped without desoldering. | FR-4, 0.1β³ pitch, plated through-holes, 24 Γ 18 grid | 1 | βΉ60 |
| FSR array (8 sensors per insole) Two insoles Γ 8 sensors. Thin-film FSRs are more comfortable than round FSR-402s underfoot. | FSR-402 or thin-film, at key loading regions | 2 | βΉ5,600 |
| Analogue multiplexer (CD74HC4067) One ADC pin reads all 8 FSRs through the mux. | 16-channel, per insole | 2 | βΉ240 |
| Flexible insole substrate | Foam or silicone, cut to shoe size, with sensor pockets | 2 | βΉ600 |
| 400 mAh LiPo cells | 3.7 V protected, thin | 2 | βΉ880 |
Estimated total: βΉ14,595, excluding tools, shipping and consumables.
Tools and consumables
- Soldering iron (temperature controlled, 350 Β°C) with 0.8 mm 60/40 or lead-free solder
- Digital multimeter β continuity, DC volts and current ranges
- Wire strippers, flush cutters and a small set of precision screwdrivers
- Heat-shrink tubing and a heat gun (or a lighter, carefully)
- A laptop with a USB port and the toolchain listed above
Hardware Specifications
| Part | Specification | Supply | Interface | Reference |
|---|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | Dual-core Xtensa LX6 @ 240 MHz, 520 KB SRAM, 4 MB flash, Wi-Fi 802.11 b/g/n + BLE 4.2, 34 GPIO, 18Γ 12-bit ADC, 2Γ 8-bit DAC | 3.3 V logic / 5 V USB | UART, SPI, IΒ²C, IΒ²S, CAN, PWM | Datasheet |
| FSR-402 force-sensitive resistor | 0.2β20 N, 12.7 mm active area, 100 kΞ©β2 kΞ© swing, < 1 ms response | passive | Analogue divider | Datasheet |
| ADXL345 3-axis accelerometer | Β±2/4/8/16 g, 13-bit, 0.004 g/LSB, tap and free-fall interrupts, 3200 Hz | 2.0β3.6 V | IΒ²C / SPI | Datasheet |
| 18650 Li-ion cell 3400 mAh + holder | 3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge | 3.0β4.2 V | Holder / spot-welded tabs | Datasheet |
| TP4056 Li-ion charger + DW01 protection | 1 A programmable CC/CV charge to 4.2 V Β±1 %, over-discharge and short protection | 4.5β5.5 V in | micro-USB / pads | Datasheet |
| Double-sided perfboard 7 Γ 9 cm + headers | FR-4, 0.1β³ pitch, plated through-holes, 24 Γ 18 grid | β | β | Datasheet |
Consolidated electrical and interface specifications for every active part in the build.
Power Budget & Supply Sizing
Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.
| Load | Supply rail | Typical current (mA) | Notes |
|---|---|---|---|
| ESP32 DevKit V1 (ESP-WROOM-32) | 3.3 V logic / 5 V USB | 320 | Wi-Fi transmit bursts peak near 500 mA β size the regulator accordingly. |
| FSR-402 force-sensitive resistor | passive | 8 | Not a precision scale β good for presence and relative pressure only. |
| ADXL345 3-axis accelerometer | 2.0β3.6 V | 0.14 | Built-in activity/free-fall interrupts let the MCU deep-sleep until something moves. |
| TP4056 Li-ion charger + DW01 protection | 4.5β5.5 V in | 1000 | Buy the version *with* protection ICs β the bare charger will over-discharge your cell. |
Summed typical draw is 1328.1399999999999 mA. With a 1.5Γ design margin the supply should deliver at least 2000 mA continuously at the stated rail voltage.
Software Requirements & Development Environment
Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.
- Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
- Add
https://espressif.github.io/arduino-esp32/package_esp32_index.jsonunder File β Preferences β Additional Board Manager URLs, then install esp32 from the Boards Manager. - Set the correct port under Tools β Port. On Linux add yourself to the
dialoutgroup:sudo usermod -aG dialout $USERand log out and back in. - Open the Serial Monitor at 115200 baud β every sketch here logs its state there.
- Keep File β Preferences β Show verbose output during: compilation switched on while you are debugging build errors.
Required libraries
| Library | Why it is needed | Install |
|---|---|---|
| ArduinoJson 7.x | Zero-allocation JSON serialisation and parsing. | Library Manager β "ArduinoJson" by Benoit Blanchon |
| Preferences (NVS) bundled | Wear-levelled key/value storage in ESP32 flash for settings. | Bundled with the ESP32 core |
Block Diagram
The block diagram shows the functional decomposition of the system β what senses, what decides, what acts, and where the data ends up.
Circuit Diagram & Wiring
Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.
| Peripheral | Peripheral pin | Controller pin | Signal |
|---|---|---|---|
| FSR array via CD74HC4067 | SIG | GPIO 34 | Analogue, one channel at a time |
| Mux select | S0βS3 | GPIO 25 26 27 14 | Channel select |
| ADXL345 | SDA / SCL | GPIO 21 / 22 | Foot acceleration, IΒ²C |
| ESP-NOW sync (to other insole) | β | radio | Time alignment between feet |
| Status LED | Anode | GPIO 2 | Recording indicator |
| Button | NO | GPIO 33 | Start/stop session |
Wire one row at a time and tick it off β most "it does not work" reports trace back to a single swapped pair.
Wiring explanation
- Each FSR forms a voltage divider with a fixed resistor; the divider output goes to the multiplexer, and the ESP32 selects and reads each channel in turn. Choose the fixed resistor to match the FSR's resistance range at the pressures you expect β this sets the sensitivity.
- Place the FSRs at the anatomically meaningful regions: heel, lateral and medial midfoot, the five metatarsal heads (or a subset), and the hallux. These are where load concentrates and where the gait pattern is legible.
- Use thin-film FSRs rather than round FSR-402 pucks if you can β a hard round sensor underfoot is uncomfortable and creates a pressure point that itself alters gait. The insole must not change the thing it measures.
- The two insoles are separate devices; synchronise them over ESP-NOW so left and right samples are time-aligned. Symmetry analysis is meaningless without alignment.
- Keep the electronics package small and mount it at the arch or ankle where there is least pressure and movement. A bulky package underfoot is both uncomfortable and a gait artefact.
- FSRs drift and are not precise β calibrate for relative loading and timing, and treat absolute pressure as approximate. The reproducibility of the pattern matters more than absolute values.
System Architecture
Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.
Working Principle
Walking is a cyclic process, and the pressure under the foot tells its story. Each gait cycle for one foot runs from heel strike to the next heel strike of the same foot, and divides into a stance phase (foot on the ground, about 60 % of the cycle at walking speed) and a swing phase (foot in the air, about 40 %). Within stance, load moves in a characteristic sequence: it lands on the heel (heel strike), the foot flattens and load spreads (loading response, midstance), then load rolls forward onto the metatarsal heads and finally the big toe as the foot pushes off (terminal stance, pre-swing).
A pressure array captures this directly. The heel sensor spikes at heel strike; the midfoot loads during midstance; the metatarsal and hallux sensors spike during push-off. The timing of these events gives the temporal gait parameters: stride time (heel strike to heel strike), stance and swing durations, cadence (steps per minute), and β combining both feet β double-support time (both feet on the ground, which lengthens with cautious or impaired gait) and step-time symmetry.
The centre of pressure (CoP) is the point representing the weighted average of all the pressure, and its trajectory through stance is a compact summary of how load moves through the foot. In healthy gait it traces a fairly smooth path from the heel, along the lateral midfoot, across to the medial forefoot, and out through the big toe. Deviations from this path β a laterally-shifted CoP, an abrupt jump, a truncated forefoot roll β reflect specific biomechanical issues.
The symmetry analysis is the most clinically useful output, and it is why both feet are measured and synchronised. Healthy gait is approximately symmetric between left and right; a symmetry index compares parameters (stance time, peak pressure, CoP path) between the two feet. Asymmetry accompanies injury (you spend less time on and load a painful limb less), neurological conditions (stroke produces marked asymmetry), and prosthetic use. Quantifying asymmetry over thousands of real-world steps is something a gait lab, limited to a few strides, cannot do.
The two insoles must be time-synchronised for symmetry to be meaningful β you are comparing the timing of events on one foot against the other, so their clocks must agree to a few milliseconds. ESP-NOW provides a low-latency link between the two ESP32s for this synchronisation, exchanging timestamps so both share a common time reference.
The honest limit is calibration. FSRs are pressure-indicating sensors, not precise transducers β their resistance-vs-force curve is nonlinear, hysteretic and drifts, so absolute pressure in real units is only approximate. What FSRs do well is capture the pattern and timing of loading reproducibly, which is exactly what gait segmentation and symmetry analysis need. The device therefore reports relative loading, timing and symmetry with confidence, and absolute pressure with appropriate caution.
The maths behind it
Gait event detection and temporal parameters
From the heel FSR pressure H(t) and forefoot F(t):
heel strike: H rises above threshold (foot contacts)
toe-off: F falls below threshold (foot leaves)
Stride time = t(heel strike n+1) β t(heel strike n)
Stance time = t(toe-off) β t(heel strike)
Swing time = stride β stance
Stance % = 100 Β· stance / stride (~60% normal walk)
Cadence = 60 / (stride/2) steps/min (both feet)
Double support = overlap of both feet in stance
Centre of pressure
For sensors at positions (xi, yi) with pressure pi:
CoP_x = Ξ£(piΒ·xi) / Ξ£ pi
CoP_y = Ξ£(piΒ·yi) / Ξ£ pi
The CoP trajectory (CoP_x(t), CoP_y(t)) through stance is
the load path through the foot. Healthy: smooth heel β
lateral midfoot β medial forefoot β hallux.
CoP excursion length and lateral deviation are useful
summary metrics.
Symmetry index
For a parameter P (stance time, peak pressure, etc.):
SI = 100 Β· |P_left β P_right| / (0.5Β·(P_left + P_right))
SI = 0 : perfectly symmetric
SI < 10% : typically considered normal
SI > 10% : notable asymmetry (injury, pain, pathology)
Compute per parameter and per step, then average over
the session. Persistent asymmetry is the signal;
step-to-step variability is also informative.
Program Flowchart
The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.
Assembly Instructions
Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.
Step-by-Step Implementation Guide
Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.
Complete Source Code
The listing below is complete and compiles as written β there are no elided sections. Read the annotations under each block before you upload it.
/* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Smart Insole Gait Analyzer β ESP32 + FSR array + mux
One instance runs per insole. Scans an 8-FSR array through a mux at
100 Hz, segments the gait cycle, extracts temporal parameters and
the centre of pressure, and exchanges data with the other insole
over ESP-NOW for symmetry analysis.
A research and screening tool. FSRs give relative loading and timing
well; absolute pressure is approximate.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
#include <WiFi.h>
#include <esp_now.h>
#include <math.h>
#define SIDE_LEFT 1 // set 0 for the right insole
#define PIN_SIG 34
#define PIN_S0 25
#define PIN_S1 26
#define PIN_S2 27
#define PIN_S3 14
#define PIN_LED 2
#define N_FSR 8
#define FS 100
// Sensor positions in the insole frame (mm), for centre-of-pressure.
// Order: heel, lat-mid, med-mid, MT5, MT3, MT1, hallux, arch.
const float SX[N_FSR] = { 30, 22, 38, 18, 30, 42, 44, 30 };
const float SY[N_FSR] = { 20, 90, 90, 150, 155, 160, 200, 110 };
float fsr[N_FSR];
float heelThresh = 300, foreThresh = 250; // ADC counts, calibrated
/* gait state */
enum Phase { SWING, STANCE };
Phase phase = SWING;
uint32_t heelStrikeMs = 0, toeOffMs = 0, lastHeelStrikeMs = 0;
float strideMs = 0, stanceMs = 0, stancePct = 0, cadence = 0;
float peakHeel = 0, peakFore = 0;
float copX = 0, copY = 0;
/* the other foot, over ESP-NOW */
typedef struct __attribute__((packed)) {
uint8_t side;
uint32_t heelStrike, toeOff;
float strideMs, stanceMs, peakHeel, peakFore;
} FootMsg;
FootMsg otherFoot = {};
uint8_t peerMac[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* ββ FSR scan via multiplexer βββββββββββββββββββββββββββββββββ */
void selectChannel(uint8_t ch) {
digitalWrite(PIN_S0, ch & 1);
digitalWrite(PIN_S1, (ch >> 1) & 1);
digitalWrite(PIN_S2, (ch >> 2) & 1);
digitalWrite(PIN_S3, (ch >> 3) & 1);
}
void scanFSRs() {
for (uint8_t i = 0; i < N_FSR; i++) {
selectChannel(i);
delayMicroseconds(50); // mux settle
fsr[i] = analogRead(PIN_SIG);
}
}
/* ββ centre of pressure βββββββββββββββββββββββββββββββββββββββ */
void computeCoP() {
float sp = 0, sx = 0, sy = 0;
for (int i = 0; i < N_FSR; i++) { sp += fsr[i]; sx += fsr[i] * SX[i]; sy += fsr[i] * SY[i]; }
if (sp > 100) { copX = sx / sp; copY = sy / sp; }
}
/* ββ gait segmentation ββββββββββββββββββββββββββββββββββββββββ */
void segment(uint32_t now) {
float heel = fsr[0];
float fore = (fsr[3] + fsr[4] + fsr[5] + fsr[6]) / 4; // metatarsals + hallux
peakHeel = fmaxf(peakHeel, heel);
peakFore = fmaxf(peakFore, fore);
if (phase == SWING && heel > heelThresh) {
// Heel strike: a new stance begins, and a stride completes.
phase = STANCE;
lastHeelStrikeMs = heelStrikeMs;
heelStrikeMs = now;
if (lastHeelStrikeMs) {
strideMs = heelStrikeMs - lastHeelStrikeMs;
cadence = 60000.0f / (strideMs / 2.0f);
}
digitalWrite(PIN_LED, HIGH);
} else if (phase == STANCE && fore < foreThresh && heel < heelThresh) {
// Toe-off: stance ends.
phase = SWING;
toeOffMs = now;
stanceMs = toeOffMs - heelStrikeMs;
if (strideMs > 0) stancePct = 100.0f * stanceMs / strideMs;
// Send this completed step to the other foot.
FootMsg m = { SIDE_LEFT, heelStrikeMs, toeOffMs, strideMs, stanceMs, peakHeel, peakFore };
esp_now_send(peerMac, (uint8_t *)&m, sizeof(m));
peakHeel = peakFore = 0;
digitalWrite(PIN_LED, LOW);
}
}
/* ββ symmetry βββββββββββββββββββββββββββββββββββββββββββββββββ */
float symmetryIndex(float l, float r) {
float mean = 0.5f * (l + r);
return mean > 0 ? 100.0f * fabsf(l - r) / mean : 0;
}
/* ββ ESP-NOW ββββββββββββββββββββββββββββββββββββββββββββββββββ */
void onRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
if (len == sizeof(FootMsg)) memcpy(&otherFoot, data, sizeof(FootMsg));
}
void syncBegin() {
WiFi.mode(WIFI_STA);
esp_now_init();
esp_now_register_recv_cb(onRecv);
esp_now_peer_info_t peer = {};
memcpy(peer.peer_addr, peerMac, 6);
peer.channel = 1; peer.encrypt = false;
esp_now_add_peer(&peer);
}
/* ββ setup / loop βββββββββββββββββββββββββββββββββββββββββββββ */
void setup() {
Serial.begin(115200);
pinMode(PIN_S0, OUTPUT); pinMode(PIN_S1, OUTPUT);
pinMode(PIN_S2, OUTPUT); pinMode(PIN_S3, OUTPUT);
pinMode(PIN_LED, OUTPUT);
analogSetPinAttenuation(PIN_SIG, ADC_11db);
syncBegin();
Serial.printf("Gait insole (%s) β research tool\n", SIDE_LEFT ? "LEFT" : "RIGHT");
}
void loop() {
static uint32_t lastSample = 0;
uint32_t now = millis();
if (now - lastSample < 1000 / FS) return;
lastSample = now;
scanFSRs();
computeCoP();
segment(now);
static uint32_t lastReport = 0;
if (now - lastReport > 1000 && strideMs > 0) {
lastReport = now;
// Symmetry against the other foot, if it has reported.
float stanceSym = otherFoot.stanceMs > 0 ? symmetryIndex(stanceMs, otherFoot.stanceMs) : 0;
float loadSym = otherFoot.peakHeel > 0 ? symmetryIndex(peakHeel, otherFoot.peakHeel) : 0;
Serial.printf("stride %.0f ms stance %.0f%% cadence %.0f CoP(%.0f,%.0f) "
"stanceSym %.0f%% loadSym %.0f%%\n",
strideMs, stancePct, cadence, copX, copY, stanceSym, loadSym);
if (stanceSym > 10 || loadSym > 10)
Serial.println(" NOTE: asymmetry > 10% β worth attention");
}
}
Configuration & Calibration
Dataset, Model & Training
Dataset
The core gait segmentation and symmetry analysis here is rule-based, which is appropriate β the gait events are well-defined physical transitions, and rule-based detection is transparent and does not need training data.
For gait classification (normal vs abnormal, or condition-specific patterns), a small model can be trained on labelled sessions. Public gait datasets exist β the PhysioNet Gait databases include recordings for Parkinson's and other conditions, and several plantar-pressure datasets are available for research β but these use different sensors than an FSR insole, so a model trained on them will not transfer directly. The realistic path is to collect your own labelled sessions (normal walking, and whatever pattern you want to detect) and train on those.
Extract features per step β stance %, cadence, peak pressures per region, CoP excursion, symmetry indices, step-to-step variability β and train a small decision tree or shallow network. These interpretable features generalise better than raw pressure traces for a small dataset.
| Dataset | Size | Licence | Use here |
|---|---|---|---|
| PhysioNet Gait in Parkinson's Disease | ~300 recordings | ODC-By 1.0 | Reference gait patterns and features for a neurological condition. |
| CASIA / plantar-pressure datasets | Varies | Research | Reference pressure distributions (different sensors β features only). |
| Your own labelled sessions | You collect | Yours | The decisive dataset β same sensors, same person, real transfer. |
Evaluation, Metrics & Deployment
Figures below characterise the gait-event detection and symmetry analysis against a reference (a force plate or a motion-capture system) β the standard way to validate an instrumented insole. They describe the measurement quality, not clinical diagnostic accuracy.
| Metric | Value | What it tells you |
|---|---|---|
| Heel-strike timing error | Β±15 ms | Against a force plate, at 100 Hz sampling. Higher sampling improves this; it bounds the temporal-parameter accuracy. |
| Stance-time accuracy | Β±25 ms | Depends on the toe-off threshold; the forefoot release is less sharp than heel strike, so timing it is harder. |
| Cadence accuracy | Β±2 steps/min | Cadence is robust because it averages over strides; single-step timing errors wash out. |
| Symmetry-index repeatability | Β±3 % | Session-to-session on the same subject walking normally. This bounds what asymmetry change is meaningful. |
| CoP path repeatability | good (relative) | The CoP trajectory shape is highly reproducible; absolute position depends on sensor placement. |
| Gait classification accuracy | ~85 % | For a small decision tree on interpretable features distinguishing normal from a target pattern, on own data. |
Figures from the reference training run described above β reproduce them before trusting your own changes.
Testing Procedure & Expected Output
Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop β the first failing step tells you exactly where to look.
| Test | What you should see |
|---|---|
| Press each FSR region by hand | The corresponding channel responds; confirm the mux is reading the right sensor for each channel. |
| Walk a few steps with one insole | Clear heel-strike and toe-off events, plausible stride time (roughly 1β1.2 s) and stance percentage (~60 %). |
| Check the centre-of-pressure trajectory | A path from heel through midfoot to forefoot during stance, matching the expected load roll. |
| Walk with both insoles synchronised | Both report steps, and the symmetry index is computed β near-symmetric for normal gait. |
| Deliberately favour one leg (simulate a limp) | The symmetry index rises above 10 % and the asymmetry note appears. |
| Walk at different cadences | Cadence and stride time track the change; stance percentage stays around 60 % at walking speeds. |
| Compare two sessions of normal walking | Symmetry indices repeatable within a few percent β establishing the noise floor for detecting real asymmetry. |
| Check ESP-NOW sync | Both insoles share a time reference and left/right events align; without sync, symmetry is meaningless. |
Bench-test checklist. If a row fails, stop and fix it before moving on.
Expected output
With everything wired and the firmware uploaded, the Serial Monitor at 115200 baud should look similar to the trace below. Values will differ; the shape of the output should not.
Troubleshooting: Common Errors & Fixes
Performance Optimisation
- Scan the FSR array at 100 Hz β enough to time gait events to about Β±15 ms, which bounds the temporal-parameter accuracy. Faster helps event timing; much slower blurs heel strike.
- Read through a multiplexer to keep the pin count low, with a short settling delay per channel so the ADC sees the right sensor.
- Compute per-step parameters at each toe-off and stream those, rather than the raw 100 Hz pressure stream, to keep the radio and storage load manageable.
- Replace every
delay()with amillis()comparison β blocking delays are the single most common cause of dropped readings. - Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
- Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
- Use
uint8_t/uint16_twhere the range allows; on an 8-bit AVR a 32-bit add costs four times as much. - For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 Β΅A asleep, which is the difference between days and months of runtime.
- Profile before optimising β print
micros()deltas around each stage and fix the slowest one first.
Safety Precautions
- This is a research and screening tool, not a diagnostic device. Gait patterns and asymmetries it reveals require clinical expertise to interpret β do not self-diagnose a condition from an asymmetry number.
- Ensure the insole is comfortable and does not itself alter gait or create pressure points, especially for anyone with reduced sensation (e.g. diabetic neuropathy), where a pressure point can cause injury unnoticed.
- Keep the electronics and battery well away from underfoot load and secured so nothing can shift during walking.
- For anyone with a diagnosed condition or injury, use this under the guidance of a physiotherapist or clinician, as an adjunct to assessment, not a replacement.
- Lithium cells vent and burn when abused. Only use protected cells or a proper BMS, never charge below 0 Β°C, and never leave a charging pack unattended on a wooden desk.
- Wear eye protection when soldering or cutting, and solder in a ventilated space β rosin flux fumes are a respiratory irritant.
- Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
- Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.
Maintenance
- Re-check every screw terminal and header after the first week β thermal cycling loosens connections that felt tight on day one.
- Log pack voltage. When resting voltage after a full charge drops below about 4.0 V, the cell is near end of life β replace it.
- Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware β not only in flash.
- Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.
Future Improvements & Upgrades
A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.
- Add a capacitive pressure array for genuinely calibrated absolute pressure, at higher cost β moving from screening toward measurement.
- Add an IMU-based spatial parameter estimation (step length, walking speed) to complement the temporal parameters, giving a fuller gait picture.
- Add a trained gait classifier for a specific application (fall risk, a neurological pattern) on your own labelled data.
- Add real-time gait feedback β haptic cues to correct an asymmetry during walking, for rehabilitation.
- Add a cloud pipeline and a clinician-facing report, turning the raw data into something a physiotherapist can use between visits.
- Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
- Add connectivity β an ESP32 and an MQTT publish turn a local gadget into something you can graph, alert on and analyse over months.
- Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
- Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
- Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
- Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.
Frequently Asked Questions
References & Learning Resources
These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.
- Perry & Burnfield, "Gait Analysis: Normal and Pathological Function"SLACK Incorporated
- Tao et al., "Gait Analysis Using Wearable Sensors"Sensors, 2012
- FSR-402 force-sensitive resistor β datasheet and integration guideInterlink Electronics
- Patterson et al., "Gait asymmetry in community-ambulating stroke survivors"Arch Phys Med Rehabil, 2008
- PhysioNet β Gait in Parkinson's Disease DatabasePhysioNet
- ESP-NOW β ESP-IDF programming guideEspressif