Siddhant Kumar
Project 026 Β· Health & Wearables

Smart Insole Gait Analyzer.

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.

Advanced 18–26 hours 33 min read PressureWearableAnalytics
Jump to source Bill of materials
Smart Insole Gait Analyzer β€” reference build illustration MCU VCC Β· GND Β· SIG Β· NC
Difficulty
Advanced
Build time
18–26 hours
Indicative cost
β‚Ή5,400 – β‚Ή7,000 (both insoles)
Platform
ESP32 DevKit V1 (ESP-WROOM-32)
Category
Health & Wearables
Last updated
28 July 2026
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

SettingHow it is used
Rehabilitation monitoringObjective, real-world tracking of gait recovery after injury or surgery, between clinic visits.
Running injury preventionLoading patterns and asymmetries associated with overuse injury, captured during actual runs.
Prosthetic and orthotic fittingQuantifying how load distributes, to guide device adjustment.
Neurological gait assessmentConditions like Parkinson's and post-stroke produce characteristic gait changes.
Fall-risk screening in older adultsGait variability and asymmetry are established fall-risk indicators.
Biomechanics researchA 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

AttributeValue
Difficulty levelAdvanced
Estimated completion time18–26 hours
Indicative build costβ‚Ή5,400 – β‚Ή7,000 (both insoles)
Primary disciplineHealth & Wearables
Reference platformESP32 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.

ComponentKey specificationQtyApprox. 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 DAC2β‚Ή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 response8β‚Ή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 Hz1β‚Ή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 discharge1β‚Ή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 protection1β‚Ή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 grid1β‚Ή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 regions2β‚Ή5,600
Analogue multiplexer (CD74HC4067)
One ADC pin reads all 8 FSRs through the mux.
16-channel, per insole2β‚Ή240
Flexible insole substrateFoam or silicone, cut to shoe size, with sensor pockets2β‚Ή600
400 mAh LiPo cells3.7 V protected, thin2β‚Ή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

PartSpecificationSupplyInterfaceReference
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 DAC3.3 V logic / 5 V USBUART, SPI, IΒ²C, IΒ²S, CAN, PWMDatasheet
FSR-402 force-sensitive resistor0.2–20 N, 12.7 mm active area, 100 kΩ–2 kΞ© swing, < 1 ms responsepassiveAnalogue dividerDatasheet
ADXL345 3-axis accelerometerΒ±2/4/8/16 g, 13-bit, 0.004 g/LSB, tap and free-fall interrupts, 3200 Hz2.0–3.6 VIΒ²C / SPIDatasheet
18650 Li-ion cell 3400 mAh + holder3.7 V nominal, 4.2 V full, 3400 mAh, ~12.6 Wh, 2 C discharge3.0–4.2 VHolder / spot-welded tabsDatasheet
TP4056 Li-ion charger + DW01 protection1 A programmable CC/CV charge to 4.2 V Β±1 %, over-discharge and short protection4.5–5.5 V inmicro-USB / padsDatasheet
Double-sided perfboard 7 Γ— 9 cm + headersFR-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.

LoadSupply railTypical current (mA)Notes
ESP32 DevKit V1 (ESP-WROOM-32)3.3 V logic / 5 V USB320Wi-Fi transmit bursts peak near 500 mA β€” size the regulator accordingly.
FSR-402 force-sensitive resistorpassive8Not a precision scale β€” good for presence and relative pressure only.
ADXL345 3-axis accelerometer2.0–3.6 V0.14Built-in activity/free-fall interrupts let the MCU deep-sleep until something moves.
TP4056 Li-ion charger + DW01 protection4.5–5.5 V in1000Buy 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.json under 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 dialout group: sudo usermod -aG dialout $USER and 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

LibraryWhy it is neededInstall
ArduinoJson 7.xZero-allocation JSON serialisation and parsing.Library Manager β†’ "ArduinoJson" by Benoit Blanchon
Preferences (NVS) bundledWear-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.

Smart Insole Gait Analyzer β€” system block diagramFunctional block diagram of the Smart Insole Gait Analyzer system. SenseFSR array Γ—8plantar pressureADXL345foot motionSegmentHeel-strike / toe-offgait eventsStance / swingphase timingParameteriseTemporal paramsstride, cadenceCentre of pressureload trajectoryCompareSymmetry indexleft vs rightClassify / logpatternpressure/stepcycleL + R (synced)
Smart Insole Gait Analyzer β€” system block diagram

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.

Smart Insole Gait Analyzer β€” wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsESP32 DevKit V1(ESP-WROOM-32)3.3 V logic / 5 V USBFSR array via CD74HC4067GPIO 34Analogue, onechannel at a timeMux selectGPIO 25 26 27 14Channel selectADXL345GPIO 21 / 22Foot acceleration,IΒ²CESP-NOW sync (to otherinsole)radioTime alignmentbetween feetStatus LEDGPIO 2Recording indicatorButtonGPIO 33Start/stop session
Smart Insole Gait Analyzer β€” wiring schematic
PeripheralPeripheral pinController pinSignal
FSR array via CD74HC4067SIGGPIO 34Analogue, one channel at a time
Mux selectS0–S3GPIO 25 26 27 14Channel select
ADXL345SDA / SCLGPIO 21 / 22Foot acceleration, IΒ²C
ESP-NOW sync (to other insole)β€”radioTime alignment between feet
Status LEDAnodeGPIO 2Recording indicator
ButtonNOGPIO 33Start/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.
An ESP32 development board with the ESP-WROOM-32 module and USB connector
An ESP32 development board. One runs per insole, the two synchronised over ESP-NOW so left and right can be compared. Photograph sourced from Wikimedia Commons β€” ESP32 Espressif ESP-WROOM-32 Dev Board.jpg. Reused under the licence stated on that page; please check it before republishing.

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.

Smart Insole Gait Analyzer β€” architecture stackLayered architecture from hardware to user interface. Hardware layerESP32 DevKit V1 (ESP-WROOM-32) Β· sensors and actuatorsDriver layerarduinojson Β· preferencesApplication logicsampling loop Β· filtering Β· thresholds Β· state machinePresentation layerlocal display Β· serial console Β· logged output
Smart Insole Gait Analyzer β€” architecture stack

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

plainGait 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

plainCentre 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

plainSymmetry 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.

Smart Insole Gait Analyzer β€” firmware flowchartControl flow through the main program loop. Boot: sync clocks betweeninsoles (ESP-NOW)Scan all FSRs at 100 Hz viathe muxHeel pressure rising (heelstrike)?start stancecontinueTrack load through stance,compute CoPForefoot pressure released(toe-off)?end stance, start swingcontinue stanceCompute stride time, stance %,peaksCompare with the other foot(synced)Update symmetry, log, streamover BLE
Smart Insole Gait Analyzer β€” firmware flowchart

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.

cppgait-insole.ino
/* ═══════════════════════════════════════════════════════════════
   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");
  }
}
scanFSRs() through the muxEight FSRs are read through one analogue multiplexer and one ADC pin, selecting each channel in turn with a settling delay. This keeps the pin count low while sampling the whole array fast enough (100 Hz) to resolve the gait cycle.
segment() heel-strike and toe-off eventsThe gait cycle is segmented by two events: heel pressure rising (heel strike, stance begins) and forefoot pressure releasing (toe-off, stance ends). From these two events per step, all the temporal parameters follow β€” stride time, stance percentage, cadence.
computeCoP() weighted by pressureThe centre of pressure is the pressure-weighted average of the sensor positions. Its trajectory through stance is a compact, informative summary of how load moves through the foot β€” the load path a clinician would look at.
ESP-NOW FootMsg exchangeEach insole is a separate device. On every completed step, an insole sends its step parameters to the other over ESP-NOW. This is what makes symmetry analysis possible β€” you cannot compare left and right without both being measured and time-aligned.
symmetryIndex()The symmetry index normalises the left-right difference by the mean, giving a percentage. Below about 10 % is typically considered normal; sustained asymmetry above that accompanies injury, pain and pathology, and is the most clinically useful output of the whole device.
Asymmetry note in the outputThe device flags asymmetry above 10 % as "worth attention" β€” deliberately not "abnormal" or a diagnosis. It is a screening indicator that quantifies a pattern; interpreting what it means clinically requires expertise the device does not claim.
__attribute__((packed)) FootMsgThe struct exchanged over ESP-NOW must have an identical byte layout on both insoles, so it is packed to prevent the compiler inserting alignment padding that would differ between builds.

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.

DatasetSizeLicenceUse here
PhysioNet Gait in Parkinson's Disease~300 recordingsODC-By 1.0Reference gait patterns and features for a neurological condition.
CASIA / plantar-pressure datasetsVariesResearchReference pressure distributions (different sensors β€” features only).
Your own labelled sessionsYou collectYoursThe 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.

MetricValueWhat it tells you
Heel-strike timing errorΒ±15 msAgainst a force plate, at 100 Hz sampling. Higher sampling improves this; it bounds the temporal-parameter accuracy.
Stance-time accuracyΒ±25 msDepends on the toe-off threshold; the forefoot release is less sharp than heel strike, so timing it is harder.
Cadence accuracyΒ±2 steps/minCadence 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 repeatabilitygood (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.

TestWhat you should see
Press each FSR region by handThe corresponding channel responds; confirm the mux is reading the right sensor for each channel.
Walk a few steps with one insoleClear heel-strike and toe-off events, plausible stride time (roughly 1–1.2 s) and stance percentage (~60 %).
Check the centre-of-pressure trajectoryA path from heel through midfoot to forefoot during stance, matching the expected load roll.
Walk with both insoles synchronisedBoth 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 cadencesCadence and stride time track the change; stance percentage stays around 60 % at walking speeds.
Compare two sessions of normal walkingSymmetry indices repeatable within a few percent β€” establishing the noise floor for detecting real asymmetry.
Check ESP-NOW syncBoth 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.

A wrist-worn fitness tracker
A wearable device. An instrumented insole captures real-world gait over thousands of steps, complementing rather than replacing a gait lab. Photograph sourced from Wikimedia Commons β€” Fitness tracker.jpg. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

Gait events are missed or spurious

Likely cause. Thresholds wrong, or FSR placement off the loading regions.

Fix. Calibrate the heel and forefoot thresholds from actual walking data β€” record the pressure traces and set thresholds at clear transitions. Confirm the heel FSR is under the heel and the forefoot FSRs under the metatarsal heads, where load actually concentrates.

The insole itself changes how the person walks

Likely cause. Hard sensors or a bulky electronics package underfoot.

Fix. Use thin-film FSRs, not round FSR-402 pucks, which create pressure points. Mount the electronics at the arch or on the ankle where there is least load. An insole that alters gait invalidates the measurement.

Symmetry values are unstable

Likely cause. Insoles not time-synchronised, or placement differs between feet.

Fix. Verify the ESP-NOW sync is working and both insoles share a time reference. Place the sensors as identically as possible in both insoles. Compare only like conditions β€” same shoes, same speed, same surface.

Absolute pressure values seem wrong

Likely cause. FSRs are not calibrated force sensors.

Fix. This is expected. FSRs are pressure-indicating with a nonlinear, hysteretic, drifting response. Use them for relative loading, timing and symmetry, which they do reproducibly. For absolute pressure you need calibrated sensors (capacitive arrays or load cells), which are far more expensive.

Readings drift over a long session

Likely cause. FSR creep under sustained load, and temperature.

Fix. FSRs exhibit creep (slowly changing resistance under constant load). For gait this matters less because loading is cyclic, but re-zero between sessions and rely on event timing and relative comparisons rather than absolute levels over long periods.

The sketch will not upload β€” "Failed to connect" or "avrdude: stk500_recv()"

Likely cause. The bootloader is not being reached: wrong port, wrong board, a serial monitor holding the port open, or a USB cable that only carries power.

Fix. Close every serial monitor, confirm Tools β†’ Board and Port, and swap to a known data-capable USB cable. On an ESP32 hold BOOT while the IDE prints "Connecting…", then release. If a peripheral is wired to the UART pins (GPIO 1/3 on ESP32, D0/D1 on Uno) unplug it β€” it fights the programmer.

The board resets in a loop, or the serial monitor prints "Brownout detector was triggered"

Likely cause. The supply cannot deliver peak current. Wi-Fi transmit bursts, relay coils and servos all pull far more than their average draw.

Fix. Power peripherals from a separate regulated supply with a common ground rather than from the board 5 V pin. Add a 470–1000 Β΅F electrolytic capacitor across the supply near the load, and use a real power adapter rather than a laptop USB port.

Serial monitor shows garbage characters

Likely cause. Baud rate mismatch between Serial.begin() and the monitor, or a floating/shared UART line.

Fix. Set the monitor to 115200 to match the sketch. If it still garbles, the crystal or the USB bridge is being confused by noise β€” shorten the cable and keep motor wiring away from the USB lead.

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 a millis() 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_t where 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

Can this diagnose a gait problem?

No. It quantifies gait parameters and asymmetries β€” objectively and over real-world walking, which is valuable β€” but interpreting what those patterns mean clinically requires a physiotherapist or physician. It is a data-collection and screening tool. An asymmetry index tells you something is different between your left and right; it does not tell you why, or whether it matters, which requires expertise.

Why FSRs if they are not accurate?

Because they are cheap, thin, and reproducibly capture the pattern and timing of loading, which is what gait analysis actually needs. Absolute pressure in real units would require calibrated capacitive arrays costing many times more. FSRs measure relative loading and timing well; the device is honest that absolute pressure is approximate and builds its useful outputs β€” segmentation, symmetry, CoP path β€” on the things FSRs do reliably.

Why does the insole itself matter so much?

Because gait is easily perturbed. A hard sensor underfoot, or a bulky electronics package, creates a pressure point or discomfort that changes how you walk β€” and then you are measuring the altered gait, not your natural one. This is why the build insists on thin-film sensors and mounting the electronics where there is least load. The measurement device must not change the thing it measures.

How is this better than a gait lab?

It is not more accurate β€” a lab with force plates and motion capture is the gold standard for a few strides. What the insole does that a lab cannot is measure real-world walking over thousands of steps, on real surfaces, during real activity, including fatigue and variability that a few corridor strides miss. The two are complementary: the lab for precise biomechanics, the insole for real-world patterns and monitoring over time.

What does an asymmetry mean?

That your two sides are doing something measurably different. Common causes are pain or injury (you unload and spend less time on the affected side), a leg-length difference, a neurological condition, or a prosthetic. A small asymmetry is normal β€” perfect symmetry is rare. A symmetry index above about 10 %, sustained, is worth investigating with a professional. The number is a prompt, not an answer.

Do I need two insoles?

For symmetry analysis β€” the most useful output β€” yes. A single insole gives you the temporal parameters and CoP for one foot, which is useful for tracking one side over time, but the comparison between left and right is where most of the clinical value lies. And that comparison requires both insoles time-synchronised, which is why they talk to each other over ESP-NOW.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Perry & Burnfield, "Gait Analysis: Normal and Pathological Function"SLACK Incorporated
  2. Tao et al., "Gait Analysis Using Wearable Sensors"Sensors, 2012
  3. FSR-402 force-sensitive resistor β€” datasheet and integration guideInterlink Electronics
  4. Patterson et al., "Gait asymmetry in community-ambulating stroke survivors"Arch Phys Med Rehabil, 2008
  5. PhysioNet β€” Gait in Parkinson's Disease DatabasePhysioNet
  6. ESP-NOW β€” ESP-IDF programming guideEspressif