Open source · ESP32 · Offline-first · No subscriptions

The cheap air rower that learned to coach.

SmartRower Pro turns a plain V‑Fit Tornado into an instrumented ergometer: a 24‑bit load cell where the handle used to be, an encoder on the cord, a laser watching the seat — and a digital coach built from rowing literature that races you against your own ghost. No cloud. No account. The rower itself serves the app.

Live demo — the onboard Web-app
SmartRower ProESP-NOW LIVE
force (kg)handle cable (m)seat (m)
Stroke rate
spm
Power
W
Pace
/500m
Distance
0 m
Heart rate
bpm
Peak force
kg
COACHSettle in — analysing your first strokes…

A faithful replica of the validation rig in tools/simulator: the simulator serves the real onboard UI and feeds it synthetic strokes with injected technique faults. The same generator drives this demo — Beta-shaped force at 20–24 spm, cable and seat kinematics, metrics computed exactly like the firmware (work = ∫F·dx, pace from W = 2.8·v³).

The build story

Gamifying a dumb machine

An air rower is honest but mute: a fan, a cord, a seat. It never tells you whether the stroke was good — and without feedback, training decays into pulling hard. This project is the story of giving that machine a voice, in five chapters.

Chapter 1 · The transplant

Hang a scale where the handle was

An S‑type load cell replaces the handle mount, read by an ADS1220 24‑bit ADC at 100 Hz. First revelation: the force curve of every stroke, live in a browser. The machine starts talking.

Chapter 2 · Going wireless

Two boards, one boat

A second ESP32 moves onto the frame and the handle node streams force over ESP‑NOW — 14‑byte packets, 100 times a second, millisecond latency. The frame serves the whole app from its own Wi‑Fi access point: metric cards, adjustable stroke thresholds, firmware updates from the browser. The rower works in a basement with no internet, forever — and if the frame is off, the handle alone is still a complete rower.

Chapter 3 · Learning to see length

An encoder on the cord, a laser on the seat

Force tells you how hard; it can't tell you how far or in what order. A rotary encoder on the drive cord turns work into a true ∫F·dx integral, and a time‑of‑flight laser starts tracking the seat. The app grows with the hardware: live cable and seat traces next to the force curve, real stroke length, and a watchdog that quietly falls back to force‑only metrics if the encoder ever dies mid‑session.

Chapter 4 · Listening to the body

A heart in the loop

The frame learns to pair with any standard BLE chest strap. The app gains a five‑zone heart‑rate bar that fills as you row, a TRIMP load score per session, three independent calorie estimates and the W′ anaerobic battery — effort and recovery become visible, not just watts.

Chapter 5 · The coach

From telemetry to gameplay

Physics‑generated ghost curves to chase, literature‑based stroke scoring with one prioritised cue per stroke, a W′ anaerobic battery, personal bests, and ghost replay: race the recorded wattage of a past session and watch the ±metres gap live. The machine is no longer mute — it argues with you.

Electronics & sensors

Three signals, one stroke

Force alone is blind to coordination — it only sees the sum of what legs, trunk and arms do. The sensor choice follows directly from that: the handle position is the sum of the segments, the seat position is the legs alone, so their difference isolates the upper body. That decomposition powers all coordination metrics.

HANDLE NODE — ESP32‑S3S‑type load cell · ADS1220 24‑bit ΔΣ ADC on SPI · 100 Hz sampling · battery powered · standalone mode with its own AP + OTA when the frame is off
ESP‑NOW
100 Hz · 14 B
FRAME NODE — ESP32‑S3Cord encoder (handle position) · ToF laser on seat rail · BLE client for HR strap · 200 Hz physics task · ghost curve engine · OTA
Wi‑Fi AP
WebSocket
YOUR PHONESingle‑file web app, canvas charts, no CDN, no internet required · sessions and PBs live in localStorage / IndexedDB
Force

Load cell + ADS1220

A 24‑bit delta‑sigma ADC gives clean kilograms at 100 Hz over SPI — enough headroom that the firmware spends its effort on physics, not filtering.

Handle position

Cord encoder

Signed ticks on the drive cord give position and velocity, so work is a true ∫F·dx integral, not an estimate. Direction is auto‑learned; a diagnostic watchdog falls back to force‑only metrics if the encoder dies mid‑session.

Seat position

ToF laser

A time‑of‑flight ranger tracks the seat — the signal that unmasks shooting the slide and early trunk opening, invisible to force alone.

Heart rate

BLE chest strap

The frame node is a BLE client for any standard HR strap, feeding zones, TRIMP load and the power‑to‑HR decoupling fatigue signal.

Radio link

ESP‑NOW, not Wi‑Fi

Connectionless unicast with heartbeat pairing: 100 packets per second with millisecond latency and no association dance. If the frame vanishes, the handle notices in 500 ms and becomes a complete standalone rower.

Maintenance

OTA everywhere

Both boards accept firmware uploads from the browser at /update. The web UI ships inside the firmware, gzip‑compressed at build time from one HTML source file.

The physics

Ghost curves are computed, not drawn

The target curve you chase is not a designer's sketch. It is the force that physics predicts when an ideal body rows this machine at your chosen rhythm.

F(t) = b₂·v(t)² + M_eff·a(t) + F_cord(x) · measured on the V‑Fit Tornado: b₂ ≈ 110 N·s²/m², M_eff ≈ 0, cord ≈ 0 → air is everything

The quadratic air-drag model and the cube law it implies are the standard physics of ergometers[4]. The shape comes from kinematics: each body segment follows a minimum‑jerk profile — the velocity profile experimentally confirmed for skilled human movement[5] — sequenced the way rowing technique demands: legs 0–60 % of the drive, trunk 30–85 %, arms 55–100 %[1].

S(p) = 10p³ − 15p⁴ + 6p⁵ · minimum-jerk displacement per segment; v_handle = v_legs + v_trunk + v_arms

You prescribe the rhythm (stroke rate and drive:recovery ratio), never the power — power falls out of the model with the cube law P ∝ R³/d². And because force is blind to coordination, the firmware generates three coupled ghosts: force (how much, what shape), seat (when the legs drive), arms (when the upper body closes). Same clock, three answers.

Shape comes from kinematics; amplitude from the fan; duration from rhythm; watts are an output, not an input.
The digital coach

One cue per stroke, straight from the literature

Every metric is judged against reference bands published in rowing biomechanics research: the force‑curve shape bands and catch‑factor/RSF optima come from Kleshnev's Biorow work[1], the link between stroke technique and performance from Holt et al.[2], and the phase‑normalised curve analysis from Warmenhoven's functional data studies[3]. And like a real coach, the system never shouts five corrections at once: faults are ranked — sequence first, then loading, then shape — and only the highest‑priority one speaks.

MetricReference bandWhat it unmasks
Fullness (F_mean/F_peak)0.50 – 0.65a spiky curve — connection lost mid‑drive
Peak position32 – 40 % of drivelate effort, wasted length
Catch factor−15 to −35 msseat must reverse before the handle; worse = shooting the slide
Rowing style factor≈ 0.90> 1.0 bum‑shoving · < 0.80 opening the back too early
Drive : recovery≈ 1 : 2rushing the slide back
RFD drift, CV, Pw:HRper‑session trendfatigue creeping into technique

The target shape itself is the Beta family φ(u; p,q) on normalised drive fraction — preset Technique (peak 33 %, Φ 0.56) for low rates, Race (peak 40 %, Φ 0.61) for 30+ spm. A Python analyzer replays every session offline with the same model, plus functional PCA: your stroke is compared to your own best modes, not to a population ideal.

From physics to training

The workouts are written by the same equations

Most training libraries are folklore: someone's favourite intervals, copied forever. Here the pipeline runs the other way — every model this page describes was turned into a generator, and the generator wrote the training library: 148 workouts and four multi‑week plans, in EXR and Zwift formats, loaded in the Web‑app below and downloadable from the repo.

Model we learnedWhat it predictsWorkout family it wrote
Cube law P ∝ R³/d² [4]the power cost of rating up at constant stroke shapeRate Ladders — every step's power target is computed from R³, so the ladder tests the stroke, not the maths
W′‑balance [6][7]how deep each interval drains the anaerobic battery, and how fast rest refills itW‑Prime Intervals & HIIT — each session simulated segment by segment before being written; the description states its predicted W′ floor
Beta target curve & literature bands [1][2][3]what a good stroke looks like at a given rateTechnique & Form — 18–26 spm on the “technique” ghost, catch and RSF drills the coach can actually grade
TRIMP & Pw:HR decoupling [8]session load and aerobic base qualityEndurance — steady UT2/UT1 volume with decoupling as the weekly pass/fail; plans periodised on TRIMP
Critical‑power framework [7]your personal CP and W′ from two time trialsRace Prep — 1k and 5k tests feed the athlete card; 2k pieces ride the “race” ghost

And the loop closes on the machine: the coach that grades your strokes uses the same models that wrote the workout you are doing. Browse the library →

Hands on

This is the actual onboard Web-app

Not a mockup: the frame below runs the very web/index.html the ESP32 serves on the rower, connected to a simulated machine instead of the real sensors. Try every mode — Dashboard with live force, cable and seat traces, the Coach tab with per‑stroke cues and catch factor, History with saved sessions and ghost replay, Setup with thresholds, ghost parameters and athlete profile. Every control speaks the same command protocol as the firmware.

http://192.168.4.1 — Wi‑Fi: RP_AP (the rower's own network, no internet needed)

This is what your phone shows when you sit on the machine — here fed by a simulated rower. Prefer a full window? Open the Web-app full-screen → (a small pill takes you back here). Sessions you save land in your browser's local storage, exactly as on the rower.

Gamification

Racing yourself is the oldest game in rowing

Ghost replay

Race a past session

Pick a saved workout and hit CHALLENGE: the ghost's distance is re‑integrated live from its recorded wattage, and a ±metres chip on the dashboard tells you exactly how far ahead — or behind — you are of the rower you were last Tuesday.

W′ battery

An anaerobic fuel gauge

The Skiba W′‑balance model[6] built on the critical‑power framework[7] runs live: ride above critical power and the battery drains, back off and it recharges. Interval pacing stops being guesswork.

Load & zones

Five HR zones, TRIMP, decoupling

A time‑in‑zone bar fills as you row; each session gets a Banister TRIMP score[8] and three independent calorie estimates — the Concept2 convention[10] and the Keytel heart‑rate regression[9] beside the firmware's own. Power‑to‑HR decoupling flags the day fatigue wins.

History & PBs

All of it on your phone

Sessions, trends and personal bests live in the browser's own storage — export a CSV and the dashboard repo turns it into long‑term biomechanics via a GitHub Action. Still no cloud.

Resources

White papers & deep dives

Every design choice was written down before it became code. These documents live in the repo and read as small white papers — key extracts below.

White paper · Physics

Ghost curve generation

The machine model measured on the V‑Fit Tornado, minimum‑jerk segment kinematics, rhythm‑first parametrisation and the SPM scaling laws (force ∝ (R/d)², power ∝ R³/d²).

“Shape comes from kinematics; force amplitude from b₂; duration from rate and rhythm; watts are an output — and coordination lives in the seat and arms, not in the force.”

Read the spec →

White paper · Coaching model

The virtual coach

The Beta target family, Tier A (force only) vs Tier B (force + position), per‑stroke features, tolerance scoring, and why the RFD is a regression — not a two‑point difference — at 100 Hz.

“Return the cue of the FIRST group below threshold: sequence first, then loading, then shape — a coach gives one correction, not five.”

Read the spec →

Blueprint

Instrumented‑erg coach, in general

The hardware‑agnostic version of the model: athlete calibration from slow strokes, CSV schema, feature extraction, and cross‑language consistency tests between firmware and analyzer.

Read the spec →

Tooling

Session analyzer & fPCA

Post‑session Python analysis sharing the coach's scoring model, plus functional PCA: your personal modes of stroke variation instead of a population ideal — validated on synthetic sessions with injected faults.

Browse the analyzer →

Training

Workout library

150+ structured workouts and four multi‑week training plans generated from the models on this page: intervals engineered on the W′‑balance equations, rate ladders built on the cube law, technique sessions at the Beta “technique” preset, threshold and race‑prep pieces — periodised from “Foundation” to “2k Breakthrough”. Exported in EXR (.xsr) and Zwift (.zwo) formats.

Browse the workouts →

Scientific references

  1. Kleshnev, V. — The Biomechanics of Rowing, Crowood Press, 2016; and the Biorow technical newsletters (force‑curve shape, peak position 32–40 %, catch factor, Rowing Style Factor). biorow.com
  2. Holt, A. C., Aughey, R. J., Ball, K., Hopkins, W. G., Siegel, R. — “Technical Determinants of On‑Water Rowing Performance”, Frontiers in Sports and Active Living, 2020.
  3. Warmenhoven, J., et al. — functional data analysis of rowing force–angle profiles: Journal of Science and Medicine in Sport (2018) and Sports Biomechanics (2017‑19); basis of the phase‑normalised ensemble curves used here.
  4. Dudhia, A. — The Physics of Ergometers, Oxford University (online monograph): quadratic air drag F = k·v², drag‑factor independence, the power–pace cube law.
  5. Flash, T., Hogan, N. — “The Coordination of Arm Movements: An Experimentally Confirmed Mathematical Model”, Journal of Neuroscience, 5(7), 1985 (minimum‑jerk velocity profiles).
  6. Skiba, P. F., Chidnok, W., Vanhatalo, A., Jones, A. M. — “Modeling the Expenditure and Reconstitution of Work Capacity above Critical Power”, Medicine & Science in Sports & Exercise, 44(8), 2012 (W′‑balance).
  7. Monod, H., Scherrer, J. — “The Work Capacity of a Synergic Muscular Group”, Ergonomics, 8(3), 1965 (the critical‑power / W′ framework).
  8. Banister, E. W. — “Modeling Elite Athletic Performance”, in Physiological Testing of the High‑Performance Athlete, Human Kinetics, 1991 (TRIMP training impulse).
  9. Keytel, L. R., et al. — “Prediction of Energy Expenditure from Heart Rate Monitoring during Submaximal Exercise”, Journal of Sports Sciences, 23(3), 2005.
  10. Concept2 — “Watts Calculator / How Calories Are Calculated” (technical documentation): the pace–power convention W = 2.80 / pace³ used by all ergometer displays.