Pułap tlenowy - VO2max, to interesująca koncepcja, która sugeruje, że istnieje naturalnie ograniczona zdolność do wydobywania tlenu z powietrza i zużywania go przez nasz organizm. To tak jakby IQ dla zajęć sportowych - jakiś parametr, który określa, jak bardzo jesteś utalentowany w różnych zawodach sportowych. Pracowano nad nim od początku ubiegłego wieku i polegano na zbieraniu wydychanego powietrza do worków, celem dalszej ich analizy. Współcześnie stosuje się skomplikowany sprzęt, co przekłada się na wysoki koszt tego rodzaju badań.
Alternatywnie można użyć prostej aplikacji na smartfona, która korzysta z pomiarów z naszej opaski fitness/smartwatcha i algorytmu - ktoś kiedyś skorelował kosztowny pomiar pułapu tlenowego np. z pomiarem tętna w czasie wysiłku itp. Taki pomiar nie jest z kolei zbyt precyzyjny i niekoniecznie działa dla szerszej populacji w różnym wieku itd. Aby zmierzyć pułap tlenowy, trzeba dokładnie zmierzyć ilość gazu wchodzącego i wychodzącego z płuc, poziom CO2 i tlenu w tym gazie, jego wilgotność i temperaturę oraz użyć sporej liczby wzorów.
W artykule opisujemy, jak zbudować przenośne urządzenie, pozwalające wykonać pomiary z rozsądną dokładnością, pozwalającą na realne zastosowanie np. przy testach sportowców. Jego koszt to około 150 dolarów. Może nie jest to mała kwota, ale w porównaniu do profesjonalnego sprzętu, gdzie tylko pojedyncze badanie może tyle kosztować, jest to metoda pełni osiągalne dla hobbystów i amatorów. System może być podłączony przez Bluetooth lub Wi-Fi i zapewniać bogactwo informacji podczas użytkowania. Komponenty do oddychania można łatwo oddzielić od drogich czujników, aby ograniczyć obawy związane z przenoszeniem wirusów itp. Tego rodzaju urządzenie może być np. tanio oferowane do użytku w klubach fitness czy dla indywidualnych użytkowników w celu oceny postępów treningowych czy też ogólnej diagnostyki kondycji fizycznej.
Moduł bazuje częściowo na innym projekcie - spirometrze z druku 3D (linki na końcu artykułu). Instrukcja jego montażu itp. może być pomocna w zakresie budowy tego układu.
Potrzebne elementy
Układ nie wymaga egzotycznych, czy trudnych do zdobycia elementów, a główny koszt, to bardzo precyzyjne sensory, jakie są wymagane w tych analizach. Istnieją oczywiście tańsze alternatywy na rynku, jednak, jak wskazuje autor, mają liczne wady znacznie utrudniające stosowanie ich w tym układzie. Dotyczy to w szczególności sensorów tlenu - ten wybrany do projektu jest zintegrowany i ma wyjście cyfrowe (interfejs I²C), gdzie inne - tańsze - wymagają dodatkowych przetwornic do zasilania i zewnętrznego przetwornika analogowo-cyfrowego (ADC) do digitalizacji pomiaru.
Do zestawienia projektu potrzebne są:
- różnicowy czujnik ciśnienia SDP816-125PA CMOSens z skalą pomiarową do 125 Pa,
- płytka deweloperska TTGO T-Display ESP32 z CP2104, obsługą Wi-Fi i Bluetooth zintegrowana z wyświetlaczem LCD o przekątnej 1,14”,
- sensor tlenu Gravity z interfejsem I²C,
- detektor gazu SCD30 do detekcji dwutlenku węgla, zakres pomiarowy 40000 ppm, dokładność 3%,
- bateria litowo-polimerowa 600 mAh,
- przełącznik,
- złącza i wtyczki,
- ustnik od fajki do nurkowania,
- arkusz wysokotemperaturowej folii do wycinania uszczelek z gumy silikonowej o wymiarach 12×19”, grubość ok. 0,8 mm,
- komponenty mechaniczne z druku 3D.
Projekt bazuje na wcześniejszym projekcie elementu układu powietrznego, który zawiera zawory zwrotne, aby uniknąć gromadzenia się powietrza w układzie (link na końcu artykułu) - minimalizuje to objętość martwą układu i znacznie poprawia jakość pomiarów.
Wcześniej, układ ten zastosowany został w fajce do nurkowania, wykonanej w technice druku 3D.
W tym przypadku budowany jest aparat oddechowy, który zasysa powietrze z jednej strony i wypuszcza je giętką rurką zapożyczoną z fajki do oddychania pod wodą z drugiej strony. Rurka ta łączy się z miernikiem gazu w systemie. W ten sposób mierzona jest jedynie ilość wydychanego gazu oraz poziom CO2 i O2 w części wydychanej powietrza. Bez zaworu jednokierunkowego następowałoby mieszanie się strumienia dopływającego i wychodzącego powietrza.
Projekt zaworów jednokierunkowych i sposób ich budowy można znaleźć w projekcie wspomnianej fajki do oddychania. Gotowe zawory pokazano na fotografii 1. Zawór zawiera wydrukowaną w 3D ramkę, na której zamontowano silikonowy arkusz w taki sposób, że mógł on się tylko odchylać w jedną stronę. To bardzo prosty mechanizm i jego budowa powinna być zrozumiała dla każdego. Dysza Venturiego ma taką samą konstrukcję jak w spirometrze (link na końcu artykułu) z dodatkowymi obudowami dodanymi dla czujników tlenu i dwutlenku węgla z wbudowanymi osłonami, które zapewniają ich szczelność i nie zakłócają laminarnego przepływu gazów. Jedyną modyfikacją jest zmiana obudowy elektroniki, która zawiera różnicowy czujnik ciśnienia - jest ona nieznacznie powiększona, aby pomieścić dodatkowe miejsce potrzebne na dwa przewody magistrali I²C dla sensorów.
Wszystkie pliki STP potrzebne do druku elementów układu można znaleźć na stronie z projektem. Na rysunku 1 pokazano układ zaworów zwrotnych, które zapewniają jednokierunkowy przepływ powietrza. Wylotową stroną tego modułu łączymy go, za pomocą elastycznej rurki z modułem z dyszą Venturiego, pokazanym na rysunku 2.
Zwężka w przewodzie powoduje zmianę ciśnienia, która jest proporcjonalna do przepływu. Różnica ciśnień przed i w zwężonym kanale mierzona jest za pomocą specjalnego ciśnieniomierza różnicowego. W module tym osadzone są także sensory mierzące zawartość tlenu i dwutlenku węgla w wydychanym gazie. Wyjścia tych sensorów podłączone są do elektroniki, znajdującej się w obudowie, pokazanej na rysunku 3.
Komponenty elektroniczne
Ma rysunku 4 pokazany jest schemat elektryczny przyrządu. Jest on bardzo prosty i w zasadzie składa się z dwóch sensorów podłączonych do interfejsu I²C modułu z mikrokontrolerem. Jako ten ostatni zastosowano płytkę deweloperska TTGO T-Display z mikrokontrolerem ESP32 i wyświetlaczem OLED. Podłączone moduły mają różne adresy, dzięki czemu można podłączyć je do wspólnego interfejsu (piny 21 i 22 GPIO). Oprócz linii I²C podłączyć należy tylko zasilanie (3,3 V) oraz masę, aby sensor mógł działać.
Sensor ciśnienia (czujnik SDP816-125PA) z wyjściem analogowym musi być podłączony do przetwornika ADC w układzie. Należy go podłączyć do wyprowadzenia 33 GPIO (wejście A5) oraz linii zasilania i masy. Ostatnim elementem, podłączanym do modułu z mikrokontrolerem jest przycisk, który należy wpiąć tak, jak pokazano na schemacie - w dodatnią linię zasilania, pomiędzy baterię a moduł. Układ zasilany jest z baterii, może jednak zasilany być przez port USB-C z zasilacza wtyczkowego. W ten sam sposób należy także ładować baterie, pamiętając jednocześnie, że układ musi być włączony w czasie ładowania. W projekcie zastosowano baterie o pojemności 600 mAh, ale jest szansa, że i większa zmieściłaby się w obudowie układu, co jest podstawowym czynnikiem ograniczającym pojemność zastosowanego akumulatora.
Oprogramowanie
Ostatnim etapem budowy, jest instalacja oprogramowania układowego. Zostało ono opracowane w Arduino IDE. Fragmenty szkicu Arduino, kontrolującego działanie urządzenia, pokazane są na listingu 1. Kompletny szkic można pobrać ze strony z projektem. Obliczanie VO2max nie jest trywialną sprawą. Autor projektu podaje w opisie odniesienia do konkretnych opisów algorytmów, jakie wypróbował podczas tworzenia swojej implementacji. Dzięki temu możemy dokładnie przeanalizować naukowe podstawy metodologii wyznaczania pułapu tlenowego, jeśli nas to interesuje.
void loop() {
if(totalBreath == 0) minuteTotal = millis();
// Wyświetlenie wartości maksymalnej na ekranie
if(!digitalRead(buttonPin2) screenMax();
// Obliczanie wartości po 30 s pomiaru
if((millis()- minuteTotal) > 30000){
minuteTotal = millis();
totalBreath = 0;
goFigure();
volumeMinute = 0;
}
// Odczyt wartości analogowej
sensorValue = analogRead(analogInPin);
// Mapowanie odczytu ADC na napięcie
voltage =( 3.3 * (( sensorValue )/4095.0));
// Wyliczenie ciśnienia z wartości napięcia
Pa = (190.0 * voltage/3.3) - 31.0;
if( Pa > 5 ) {
if (newBreath < 1) {
timerBreath = millis();
if(volumeTotal > 300) totalBreath = totalBreath + 1;
volumeMinute = volumeMinute + volumeTotal;
volumeTotal = 0;
newBreath = 1;
}
massFlow = 1000*sqrt(
(abs(Pa)*2*rho)/((1/(pow(area_2,2)))-(1/(pow(area_1,2)))));
// Objętościowy przepływ powietrza
volFlow = massFlow/rho;
volumeTotal = volFlow * (millis() - TimerNow) + volumeTotal;
} else if(newBreath){
newBreath = 0;
secondsBreath = (millis() - timerBreath)/1000;
if(secondsBreath > 0.1){
// Pomiar średniej ilości tlenu
O2dump();
// Pomiar średniej ilości CO2
CO2dump();
// Aktualizacja danych na ekranie
screen();
}
}
TimerNow = millis();
delay(20);
}
void CO2dump(){
if (airSensor.dataAvailable()){
lastCotwo = airSensor.getCO2();
lastTemp = airSensor.getTemperature();
// Odejmij poprzedni pomiar
coTotal = coTotal - coReadings[coreadIndex];
// Odczyt z sensora
coReadings[coreadIndex] = lastCotwo;
// Dodaj nowy pomiar
coTotal = coTotal + coReadings[coreadIndex];
// Inkrementacja indeksu
coreadIndex = coreadIndex + 1;
// Jeśli koniec macierzy - reset indeksu
if (coreadIndex >= numReadings) coreadIndex = 0;
// Obliczanie średniej
coAverage = coTotal / numReadings;
lastCotwo = coAverage;
}
delay(500);
}
void O2dump(){
float oxygenData = Oxygen.ReadOxygenData(COLLECT_NUMBER);
// Odejmujemy ostatni pomiar
oTotal = oTotal - oReadings[oreadIndex];
// Odczyt z sensiras
oReadings[oreadIndex] = oxygenData;
// Dodanie nowego pomiaru
oTotal = oTotal + oReadings[oreadIndex];
// Inkrementacja indeksu
oreadIndex = oreadIndex + 1;
// Jeśli koniec macierzy - reset indeksu
if (oreadIndex >= numReadings) oreadIndex = 0;
oAverage = oTotal / numReadings;
lastOtwo = oAverage;
}
void goFigure(){
float percentN2exp;
float co2;
volumeMinute = volumeMinute * 2.0;
volumeMinute = volumeMinute/1000.0; //gives liters of air VE
co2 = lastCotwo/10000.0;
percentN2exp = (100.0 - (co2 + lastOtwo));
volumeMinute = volumeMinute * (273/(273 + lastTemp)) * ((760.0 - 25.2)/760);
vo2Max = volumeMinute * (((percentN2exp/100.0) * 0.265) - (lastOtwo/100.0));
vo2Max = (vo2Max * 1000.0)/(float(wtTotal)/2.2);
tft.fillScreen(TFT_RED);
tft.setTextColor(TFT_GREEN, TFT_RED);
tft.drawCentreString("VO2Max= ",60,10,4);
tft.setTextColor(TFT_RED, TFT_RED);
tft.drawString("888888",70,40,7);
tft.setTextColor(TFT_WHITE, TFT_RED); // Orange
tft.setCursor(70, 40, 7);
if(vo2Max > vo2MaxMax) vo2MaxMax = vo2Max;
tft.println(vo2MaxMax);
tft.setCursor(160, 115, 4);
tft.setTextColor(TFT_GREEN, TFT_RED);
tft.println("RESET");
}
void wtRead(){
buttonState1 = digitalRead(buttonPin1);
// Jeśli zmienił się stan inkrementowany jest licznik (na zboczu)
if (buttonState1 != lastButtonState1) {
// Jeśli obecny stan jest niski, to znaczy, że puszczono przycisk
if (buttonState1 == LOW) {
buttonPushCounter1++;
if(buttonPushCounter1 == 10) buttonPushCounter1 = 0;
}
// Opóźnienie eliminujące efekty drgania styków przycisku
delay(50);
}
lastButtonState1 = buttonState1;
buttonState2 = digitalRead(buttonPin2);
// Analogicznie drugi przycisk, który przełącza pola wagi
if (buttonState2 != lastButtonState2) {
if (buttonState2 == LOW) {
buttonPushCounter2++;
wtTotal = wtTotal + 1000/pow(10, buttonPushCounter2) * buttonPushCounter1;
buttonPushCounter1 = 0;
}
delay(50);
}
lastButtonState2 = buttonState2;
if(buttonPushCounter2 < 3) {
int counter = 30 + (40 * buttonPushCounter2);
tft.drawNumber(buttonPushCounter1,counter,40,7);
}
}
Kluczową koncepcją przy tym pomiarze jest fakt, że objętość wydychanego powietrza, nie jest taka sama jak objętość, którą do powietrza wciągnęliśmy przy oddechu. Jest modyfikowany przez fizjologię płuc i należy obliczyć wiele czynników, aby ustalić prawdziwą ilość tlenu, którą z powietrza pobierają nasze płuca. Oprogramowanie musi najpierw uwzględnić wagę użytkownika - podaje się ją obsługując interfejs za pomocą dwóch przycisków dołączonych do modułu TTGO. VO2max jest mierzone w cm³/min/kg. Na ekranie modułu pojawiają się trzy pola. Naciskanie dolnego przycisku zwiększa wagę - cyfrę w danym polu, a drugi przycisk pozwala przejść do kolejnego pola. Ta część programu realizowana jest w funkcji wtRead() (listing 1). Jest ona uruchamiana w konfiguracyjnej części skryptu (funkcja void setup()) w pętli czekającej, na naciśniecie drugiego przycisku po raz czwarty:
Po wprowadzeniu wagi inicjowane jest sprawdzanie cyklu oddechowego w celu pomiaru całkowitej objętości na minutę. Pomiar realizowany jest co 30 sekund. Można go zresetować za pomocą dolnego przycisku w dowolnym momencie podczas całego procesu, aby ponownie uruchomić 30-sekundowe zliczanie oddechów. Pojawi się nowy ekran z zebraną do tej pory objętością w próbce i zegarem odliczającym 30 sekund. Większość komercyjnych maszyn mierzy te parametry przez minutę, ale to dosyć długo, jak na doraźne pomiary np. w czasie ćwiczeń. Pomiędzy oddechami sprawdzane są poziomy tlenu i CO2 w wydychanym powietrzu. Wyniki tych pomiarów umieszczane są w macierzy, która służy do obliczania średniej kroczącej. Temperatura i wilgotność są również próbkowane z czujnika CO2.
Pod koniec czasu próbkowania funkcja goFigure() (listing 1) oblicza VO2max i porównuje je z poprzednimi próbkami i wybiera wartość maksymalną, którą prezentuje na ekranie. Objętość wydychanego gazu jest kompensowana na podstawie skorygowanych objętości wydychanego CO2 i O2 oraz temperatury, ciśnienia i wilgotności wydychanych gazów. W urządzeniu nie ma sensora ciśnienia atmosferycznego - wykorzystane jest ciśnienia na poziomie morza, więc jeśli stosujemy sensor np. wysoko w górach, pomiary mogą nie być dokładne.
Moduł bazuje na układzie ESP32, zatem możliwe jest użycie wbudowanych w niego interfejsów bezprzewodowych do komunikacji. Łatwo jest sobie wyobrazić, że np. z odpowiednią aplikacją na smartfona, układ mógłby łączyć się z telefonem poprzez Bluetooth, aby tam wyświetlać dane z pomiarów i wyliczony pułap tlenowy.
Podsumowanie
Większość komercyjnych urządzeń, takich jak to, jest testowane przy użyciu znormalizowanych mieszanek gazów w celu sprawdzenia dokładności ich czujników. Autorka nie testowała systemu w ten sposób, a bardziej martwiła się o dokładność pomiarów objętości z rurki Venturiego. Podczas konstruowania spirometru sprawdziła ona ten element z dość dużym przepływem (15 l/min) i stwierdziła, że pomiar jest dość dokładny, ale komercyjne laboratoria ustandaryzowały swoje obliczenia objętości na pomiarach objętości ok. 1 litra. Powstał tego rodzaju kalibrator, bazujący na dużej strzykawce i elementach z druku 3D. Zmierzona dokładność takiego pomiaru wynosi ±8%, co jest raczej dobrą dokładnością, jak na hobbystyczną konstrukcję. Niestety, co do wyznaczania samego VO2max autorka nie miała okazji porównać swojej konstrukcji z urządzeniem komercyjnym.
Samo korzystanie z układu jest proste. Wystarczy zrozumieć, co daje nam ten pomiar. Zasada jest prosta - jesteś silnikiem, który spala tlen i chcesz zwiększyć obroty silnika do czerwonej linii, a następnie zmierzyć, ile tlenu spalasz na minutę na kilogram masy swojego ciała. Prostota tego przenośnego urządzenia polega na tym, że można uprawiać swój ulubiony, męczący sport - bieganie, jazdę na rowerze itp. i używać tego instrumentu, gdy zbliża się koniec naszej wydolności. Pozwala to sprawdzać VO2max. Można dodatkowo zamontować to urządzenie na zestawie okularów ochronnych, jak zwykłą fajkę do nurkowania, jeśli to wygodniejsze w danym zastosowaniu.
Jeśli chodzi o samo fizjologiczne znaczenie VO2max, to istnieją ogromne ilości materiałów w Internecie i literaturze fachowej, ale tematyka zdrowia wykracza poza nasz artykuł - skupiamy się na elektronice, a reszty dowiedzieć można się z innych źródeł, skupiających się na tematyce ludzkiej fizjologii.
Nikodem Czechowski, EP
Bibliografia: