Velocity-based training for powerlifters and strength-athletes, built on two off-the-shelf Movesense sensors and a web app for athletes and coaches.
Why VBT Β· The problem Β· How it works Β· The app Β· Results Β· Get started Β· Team
![]() Back squat |
![]() Front squat |
![]() Bench press |
![]() Deadlift |
β¬οΈ Click a section below to open it β¬οΈ
Every set is classified by its mean bar speed:
| Zone | Mean velocity | Typical % 1RM | Training effect |
|---|---|---|---|
| π΅ Starting strength | > 1.30 m/s | bodyweight | Overcoming inertia: jumps and throws |
| π’ Speed-strength | 1.00β1.30 m/s | 20β40% | Speed first, strength second |
| π’ Strength-speed | 0.75β1.00 m/s | 40β60% | Moderately heavy loads, as fast as possible |
| π‘ Accelerative strength | 0.50β0.75 m/s | 65β80% | Driving heavy loads as fast as possible |
| π Absolute strength | < 0.50 m/s | 80β100% | Maximal force: heavy triples, doubles, singles |
Coaches report three barriers to using VBT today:
| πΈ Expensive The most accurate devices, linear position transducers, cost a lot. |
π Hard to use Cables and setup get in the way of the lift. |
π Limited accuracy Cheaper wireless IMUs suffer from drift and bar rotation. |
βΉοΈ Our research question: Can two end-mounted IMUs give accurate enough mean concentric velocity for feedback during training, despite irregular barbell rotation?
- Integration drift. Velocity comes from integrating acceleration, so small errors add up over time.
- Irregular bar rotation. The bar tilts and rotates mid-lift, so the sensor axes stop lining up with the movement.
- One side only. A single sensor can't tell whether the left and right sides of the bar move differently.
V-LO puts one Movesense sensor on each end of the bar. The velocitydrift of both sensors are compared and the data from the sensor with the most linear drift are used for velocity estimations.
|
From acceleration to velocity
|
Why Movesense, not a custom board? A custom IMU would mean building our own firmware, Bluetooth stack and enclosure. That time would come out of the data analysis and the user experience, which are our core contributions. Movesense is commercially available, with a 9-axis IMU and Bluetooth Low Energy. |
- Save. You press β Stop & save. The web app saves the sensor data and adds a row to the
sessionstable in Supabase. - Trigger. A Supabase webhook fires on the new row and sends the recording to our app on Azure.
- Analyze. Azure queues the recording, runs the analysis code (
Squats2) and saves the reps and velocities back to Supabase. - Show. The web app checks for results every 2 seconds and shows the set's velocity, whether it hit the target zone, and a suggested next weight. No refresh needed.
- Cold start: if Azure has been idle, the first set can take 10β30 s.
- Retries: missed sets are resent automatically every minute.
- Errors: if a set can't be analyzed, it shows the reason instead of a result.
Coaches get a team view with training volume, average bar speed per lift, and PR leaderboards for each velocity zone.
![]() Team dashboard |
![]() Top PRs per velocity zone |
β‘οΈ More screenshots: Website walkthrough
We validated V-LO against a GymAware RS linear position transducer, a gold-standard reference that recorded the same reps at the same time.
| participants, 6 squats in each of 3 velocity zones | error in the zones where powerlifters train | median time from saved set to feedback |
The table shows the mean absolute error (Β± SD) between V-LO and GymAware, in m/s:
| Zone (by peak velocity) | Mean velocity | Peak velocity | Error below 0.10 m/s? |
|---|---|---|---|
| Absolute strength (< 0.5 m/s) | 0.03 Β± 0.02 | 0.04 Β± 0.02 | β Yes |
| Speed strength (0.5β1.3 m/s) | 0.05 Β± 0.16 | 0.06 Β± 0.03 | β Yes |
| Starting strength (> 1.3 m/s) | 0.33 Β± 0.17 | 0.21 Β± 0.13 | β No |
![]() Mean velocity |
![]() Peak velocity |
V-LO doesn't measure velocity directly. It integrates acceleration over each rep, and that approach works best for slower, heavier lifts:
- Fast reps are short. At 104 Hz, a very fast rep contains fewer samples, so each small measurement error carries more weight in the result.
- Fast reps have bigger, sharper accelerations. Quick changes in speed and more bar vibration make the signal harder to follow, and errors build up faster during integration.
- The drift correction assumes the drift is linear. That holds well over a controlled lift, but less well when the movement is very explosive.
This matters less than it sounds: peak velocities above 1.3 m/s only happen with very light loads, which powerlifters rarely train with. In the zones where powerlifting training happens, the error stays below 0.10 m/s.
| median processing time | range over 7 recorded sets |
Measured from the moment a recording is saved until its results appear in the app. Results usually arrive well before the next set starts, since rest between sets in powerlifting is typically a few minutes. The spread comes mainly from the analysis app on Azure: when it has been idle, it needs a few extra seconds to start up. This is a preliminary test.
python -m http.server 8080Then open localhost:8080/vlo.html in Chrome or Edge (they support Web Bluetooth, which connects to the sensors) and log in with your own account.
β οΈ Warning: The analysis runs on Azure, so changes to the analysis code also need a deploy. Check with the team before deploying.
Standing still at the start gives a clean baseline, gaps between reps help separate them, and a firm rack marks the end of the set.
|
Known limitations
|
|
.github/ βββ README.md β this page βββ code/ β all source code β βββ analysis/ β Azure app that analyses each set β β βββ squat/ β squat analysis (Squats2.py) β β βββ function_app.py β entry point Azure runs β β βββ requirements.txt β Python packages β βββ database/ β Supabase database β β βββ migrations/ β changes to the tables, by date β β βββ queries/ β useful SQL queries β βββ website/ β the V-LO web app β βββ css/ β styling (vlo.css) β βββ js/ β app logic: sensors, recording, charts βββ data/ β recorded sensor data and test results βββ docs/ β βββ images/ β β βββ readme/ β banners, diagrams and 3D lifters β β βββ website/ β screenshots of the V-LO website β βββ papers/ β final paper and presentation βββ Issue_Template/ β templates for reporting issues
| Path | What's inside |
|---|---|
code/analysis/ |
The Azure app that runs after every saved set. function_app.py is the entry point, and supabase_api.py reads recordings from and writes results back to Supabase. |
code/analysis/squat/ |
The squat analysis: MagdwickFilter.py (orientation), ValidatePeaks.py (rep detection), VelocityCalculations.py (velocity) and Squats2.py, which ties them together. |
code/database/migrations/ |
SQL files that build and change the Supabase tables, named by date so they run in order. |
code/database/queries/ |
Saved SQL queries, such as processing-timing.sql for checking how long the analysis takes. |
code/website/ |
The V-LO web app. Start it with python -m http.server 8080. |
code/website/css/ |
The styling for the whole app, in vlo.css. |
code/website/js/ |
The app logic: sensors.js (Bluetooth), recorder.js (recording sets), charts.js, vbt.js, team.js, plans.js and more. |
data/ |
Recorded sensor data from test sessions, plus the GymAware reference data used in the validation. |
docs/images/readme/ |
The banners, diagrams and 3D lifter images used in this README. |
docs/images/website/ |
Screenshots of the V-LO website, with a walkthrough explaining each page. |
docs/papers/ |
The final paper and the final presentation. |
Issue_Template/ |
Templates for reporting bugs and suggesting features. |
![]() Arvid |
![]() Greipur |
![]() Hugo |
![]() Silje |
![]() Svanberg |
|
Svanberg (Addi) |
|
|
Designed and built the web app: the dashboard, the flow for connecting sensors and picking a lift, and how feedback is shown after each set. |
Wrote the Python code that processes the sensor data: filtering, orientation, rep detection and velocity estimation. |















