Introduction: Accurate VO2 Max for Zwift and Strava
Human bodies are engines that utilize oxygen to burn fuel. Humans are not built with gauges and checking to see how the human engine is running is usually based on things we find easy to measure--pulse, Blood pressure. These do not directly tell us how the engine is burning its fuel. Measuring the amount of oxygen used with exertion provides better information on how hard the bodies engine is working--the equivalent of looking at the gauges on your cars dashboard. My previous work on measuring the components of exercise physiology were encumbering and not elegant enough to make them easily portable: https://www.instructables.com/Real-VO2Max-Measure... So after being introduced to the joys of Zwift bicycling with a Wahoo trainer I built a device that enables you to accurately add VO2 Max to the bluetooth information displayed on the Zwift screen animation while you are peddling along. The device also easily pairs with the Strava app for providing VO2 Max data for all your trail excursions. It substitutes VO2 max information for the heart rate sensor data in both of these popular exercise programs. The device is portable and lightweight with Wifi and Bluetooth capabilities and is easily worn with a modified 3M mask designed to be comfortable for long term use. I have tested the device for other sports including cross-country skiing and skating but its portability and wireless transmission capacity make it amenable to just about any sport other than swimming. The device also communicates with an App for the iPhone which enables graphing and long term data storage and download for ancillary calculations. The output includes continuous output of VO2, calories consumed, volumes of expired gas, as well as performing such functions as Basal Metabolic Rate. The device is easily made for about $100. Parts are all readily available and the case is 3D printed. It can be assembled in about 10 minutes. We tested the device in a physiology lab against a $60,000 machine and found it gave the about the same results.
Step 1: Gather Your Parts
There are only four main parts to the unit. A differential pressure sensor, an oxygen sensor--both connected by I2C to a TTGO Esp32 microcontroller with screen. A Lipo Battery with switch completes the unit. The original unit included a Laser CO2 sensor and an analogue version of the differential pressure sensor. The digital version of the sensor was found to be much more accurate and with a better range of 1--250 Pa.
1. TTGO T-Display ESP32 CP2104 WiFi bluetooth Module 1.14 Inch LCD Development Board $11
2. Omron--D6F-PH0025AD2--$40 from Digikey
3. Gravity: I2C Oxygen Sensor--$50 from DF Robot
4. Lipo Battery -- $5 1000 Mah
5. Switch ON/OFF ---$1
6. PARTICULATE RESPIRATR MASK -- 3M $20 Digikey (you don't really care about the filtration on this mask they are removed)
Step 2: 3D Print Your Parts
All parts are printed in PLA. All files are included. No support was used except for the computer housing. The body of the unit consists of three parts--the most important being the venturi tube with ports for both the differential pressure sensor and the oxygen sensor. The measurements of the internal structure of the throat are carefully laid out and measured and cannot be changed or it will drastically effect the results of the output. The venturi tube is nested into the body enclosure. The third part is the access door/ computer housing which is held on by two 3mm screws. A small retaining shield is also included to seal off the computer and make assembly easier.
Step 3: Wire It
The actual wiring for this project is minimal. It consists of connecting two I2C devices to the computer and supplying them with power and ground. They each have different I2C addresses and the pull-up resistors are included in the DF Robot O2 sensor. The O2 sensor is carefully marked for which wires go where, however, pay carefully attention to the wiring diagram included above for the Omron sensor before wiring. (Other Omron sensors of the same type have different wiring patterns!) Both of the sensors take 3 Volts which is obtained off of the TTGO board. This ESP32 board has I2C inputs on pins 21( SDA) and 22(SCL). Multiple options on the board are available for G and Power (3V). The battery supply for voltage is delivered to the small battery connector on the back of the board interrupted by a simple on/off switch. To enable charging you must have the button in the on position and provide power through the USB-C connector. I used a 1000Mah battery which easily powers the unit for several hours. The computer body is carefully designed to fit the battery snugly and you might want to measure it before ordering--there is some variation in size.
Step 4: Build It
The only unique part of the assembly is mounting of the Omron sensor. Two passages located in the venturi tube connect the sensor with the 3D printed ports within the venturi tube. These were built to accommodate two pieces of standard aquarium tubing with an inside diameter of 4mm. This tubing is designed to have a very snug fit into these holes. The tubes sink to a predetermined depth and are then trimmed to accommodate the two fluted ends of the sensor. Please see detailed pictures to clarify the description. There is also a polarity to these input tubes to the sensor--the sensor must be mounted per the photo to have a low and high pressure sensor input to be correct. A bead of hot glue on the tubes will hold them in position. The Oxygen sensor tube friction fits into its holder in the venturi tube--you might want to put a bead of hot glue on the unit to keep it in position. A defect of this sensor allows the chemical unit to separate very easily from the digital measuring unit. This is done on purpose as the O2 sensor head--like all O2 sensors must be replaced about every two years. Threaded inserts for 3 mm screws are heat inserted into the 3D printed holes in the body of the unit. The battery is placed into position in the wall of the main body. The On/Off switch is superglued into the hole in the bottom of the main body. When the two sensors are mounted into correct position in the venturi tube it is hot glued into the main body as shown. The TTGO board with attached wiring is hot glued into position in the side wall. Make sure the buttons are visible through their respective holes and the USB-C connector is open in the hole. The cover is placed over the wiring and sealed with hot glue. The wires are carefully organized and the case closed with two 3mm screws. The button housings are superglued over their respective holes after inserting the flanged buttons. The 3M mask is modified by removing the filters from the side holes which are input. The output valve at the center of the mask has a small plastic cover over it. This is clipped off and removed. The adapter unit that you printed is then glued to the front of the mask.
Step 5: Program It
There are two programs that run the unit. Both are Arduino IDE based. FinalZwiftConnect with files DFRobot_OxygenSensor.cpp and DFRobot_OxygenSensor.h are used when the unit is broadcasting VO2 max to either Zwift or Strava. This is based on Andress Spiess work in YouTube #174. After loading, the initial screen will request the users wt in pounds. Another screen with Zwift will appear and the button with "go" will initiate the session. The loop function checks the Omron sensor for a pressure drop and initiates a time function to calculate the total volume of air moving past the sensor using Bernoulli's equation. Every five seconds if there is no breath the seeO function is called to check the O2 level. At thirty second intervals the goFigure function calculates the minute volume of expired O2 and calculated levels of CO2 and VO2 Max. The program sends the bluetooth characteristic to the Zwift receiver on either your Mac or Apple TV masqueraded as the Heart Rate which approximates a typical VO2 max level. The ESP32 screen then presents alternatively Time, VO2, VO2Max, Cal burned, Max Cal/Day, O2 level and Volume(Liters of O2 used).
The alternative program is FinalSensirionScreen with above DFRobot_OxygenSensor.cpp and DFRobot_OxygenSensor.h as well as Sensirion_GadgetBle_Lib.cpp and Sensirion_GadgetBle_Lib.h. This is a wonderful App(https://apps.apple.com/us/app/sensirion-myambience/id1529131572) that allows you to connect the sensor to your iPhone and collect data, graph it and distribute the data by text or email. The App is designed for collecting data from a CO2 sensor so you have to spoof it by sending the Volume Minute of O2 to the CO2 level screen, the VO2 max to the Temp screen and the O2 level to the Humidity screen. These three pieces of data can then be saved and then downloaded to a spreadsheet program of your choice. The function of the two programs other than their output is identical including the screen output on the ESP32. The App sends out the data in a .edf format which is problematic from a Mac standpoint. Relabel the file as a ".csv" file and this allows you to import it in a regular fashion. Turn on the app only after the unit has been running otherwise it will tend to collect enormous amounts of empty data sets that have to be culled. The two graph screen shots above are from the Sensirion App. The first is treadmill output(VO2 max) the second is X-country skiing(Cal/Day).
Step 6: Testing It
Several compromises were made in the design of the unit: no CO2 sensor and it's totally compact and weights only 4 oz. Physiology labs that are normally used for testing VO2 max cost upwards of $60,000 and are certainly not portable. They have sensors that measure the same things only on a much finer level. But since what you're trying to study may not really require this degree of granularity perhaps our machine will be adequate. CO2 sensor data helps refine the difference between volume inhaled and exhaled which are not exactly the same. Volumes of these two gasses relative to unchanging amount of Nitrogen in room air makes this possible, but is this a really significant difference? Humans are a fairly subjective test animal and within the limits of testing humans do these things matter? We brought our unit to the University of Alaska physiology lab and compared it. All machines are benchmarked for checking a standardized volume with a 3 liter syringe. The labs unit passed with all measurements being +/- 50 cc. Our unit did very well with all measurements within +/- 100cc. An error this small over liters of air/min is not that significant. Standardized gas (O2 16%) was then passed through our O2 sensor and found to be off by only 0.16%. We then ran our test subject through two levels of testing on the treadmill. The results from both O2 volume and VO2 readings were nearly identical. While there was significant minute to minute variability in the VO2 output from the lab machine the averages per minute turned out to be about the same with each instrument. A more thorough test would involve more test subjects and extended periods of testing of each instrument.
Step 7: Using It
The adapter unit on the mask is threaded and allows the corresponding portion of the unit to be screwed into it. It is designed so that the computer unit and the oxygen sensor are off to the right when looking at the mask front on. This prevents fluid from dripping down into the O2 sensor head. Programing is done through the USB-C connector. Charging the battery is accomplished by turning on the unit and then plugging it in. When using the unit with either Strava or Zwift you have to pair the unit with the software that you are using. Make sure bluetooth is enabled on the phone that you have Strava on then go to the record function at the bottom of the screen. Once you push it a Heart icon will appear at the bottom--just push it to bring up the bluetooth pairing screen and find the unit. It will then pair. For the Zwift unit the pairing is just as simple. When the screen that pairs the bike trainer cadence and power meters appears the hear rate monitor will also appear. This will pair the unit with the screen output. On subsequent pairings it should automatically synch. The data from your bike ride can then be graphed and played with in the same manner as your power output and cadence. The graphs above are the VO2 max output graphed on the Zwift App. When using the unit with the Sensirion App for x-country skiing, biking and skating just turn on the device add your weight and push the go button. Then turn on the Sensirion App and it will automatically pair with the unit and start recording data. This is a way of studying many aspects of the human physiology engine that is now portable and cheaply done. How hard is any participant in a sport working? Soft data like pulse rate may offer some clues but the actual amount of energy being consumed will reveal much more about the function of the inner machine. Most VO2 max equations currently available on watches and trainers are based on these soft findings--now they can be based on real data. Since this type of testing has not been widely available due to limitations in size and expense this unit will open up the potential for studying how people improve with conditioning or reveal if they're truly working near their maximum output. The unit is also useful for studying basal metabolic rate. This is the amount of energy that is used by the body in doing nothing. The cost of just being alive. It is hard to study because it should be done with the participant sleeping or resting. Modern studies using doubly labeled water have revealed incredible incites to energy usage among hunter gatherers and office workers. These units could also be used to provide more insight to exertion than the counting of steps. I have found that with the calculations for energy expended from the Oxygen utilization algorithm is slightly higher than that calculated by the work/watt output of the Zwift App algorithm. So good news: more pizza slices from your ride!
This is an entry in the
Anything Goes Contest 2021