Forum: Mikrocontroller und Digitale Elektronik Spirometer mit Arduino und Drucksensor MPX5010


von Christoph E. (stoppi)



Lesenswert?

Hallo!

Ein Projekt habe ich noch in der Warteschleife und zwar ein 
Strömungsmessgerät, welches dann als Spirometer zur Bestimmung des 
Lungenvolumens dienen soll. Als Sensor kommt der MPX5010 zum Einsatz. 
Dieser besitzt zwei Druckeingänge, um den Differenzdruck messen zu 
können. Die Empfindlichkeit beträgt 0.45V/kPa. Ein erster Funktionstest 
verlief erfolgreich. Konnte durch Einsaugen schön Spannungen bis 4.5V 
erzielen bei 5V Versorgungsspannung.

Zur Messung des Lungenvolumens muss natürlich der aktuelle Volumsfluss 
dV/dt bekannt sein. Diesen könnte ich mit einem gewöhnlichen 
Strömungsmessgerät basierend auf einem Schaufelrad bestimmen nur ist 
dies mMn viel zu ungenau, da sich zum Beispiel das Schaufelrad aufgrund 
der Trägheit noch weiterdreht, auch wenn keine Strömung mehr vorliegt. 
Deshalb habe ich mich für die Druckmessung entschieden. Der Gesamtdruck 
besteht ja aus statischen, dynamischen und Schweredruck 
(Bernoulligleichung). Die Summe der drei Drücke ist entlang eines 
Strömungspfades konstant. Gehe ich von einer Höhendifferenz h = 0 aus, 
so fällt der Schweredruck weg. Übrig bleibt die Summe aus statischen und 
dynamischen Druck, also die Gleichung

 p_stat_1 + 0.5  ro  v_1² = p_stat_2 + 0.5  ro  v_2²

Nun messe ich einen statischen Druck außerhalb des Spirometerrohres, wo 
v_1 = 0 gilt. Daraus folgt für die Gleichung:

 p_stat_1 = p_stat_2 + 0.5  ro  v_2²

Umgeformt nach v_2 ergibt sich der Ausdruck:

 v_2 = Wurzel[2 * (p_stat_1 - p_stat_2) / ro]

Die Druckdifferent p_stat_1 - p_stat_2 wird eben mit dem MPX5010 
gemessen. Dessen Ausgangsspannung hat einen geringen (ca. 0.2V) offset, 
welcher von der ausgegebenen Spannung abgezogen werden muss. Die 
Empfindlichkeit beträgt wie oben erwähnt 0.45V/kPa.

Daraus folgt die Beziehung:

 p_stat_1 - p_stat_2 = 1000 * [(U_out - U_offset) / 0.45]

Eingesetzt in die obige Gleichung für v_2 ergibt sich der finale 
Ausdruck

 v_2 = Wurzel[(2000 / (0.45 * ro)) * (U_out - U_offset)]

mit ro = Luftdiche = ca. 1.25 kg/m³

Aus v_2 und dem Strömungsquerschnitt A_2 ergibt sich der momentane 
Volumsfluss dV/dt = A_2 * v_2.

Für das innerhalb der Zeit dt durchströmende Volumen dV gilt dann:

 dV = A_2  v_2  dt

Diese Volumselemente müssen im Arduinoprogramm nur noch aufsummiert 
werden, um das Lungenvolumen V zu erhalten. Als Zeitschrittweite werde 
ich dt = ca. 1ms wählen.

Der Sensor um ca. 14 Euro ist bereits aus China eingetroffen. Als 
nächstes werde ich mich um den Bau der Venturidüse kümmern... ;)

von Christoph E. (stoppi)



Lesenswert?

So, nachdem heute der 4mm-Schlauchverbinder angekommen ist, konnte ich 
die Venturidüse fertigstellen. Der Spannungsoffset beträgt bei 5V 
Versorgung rund 0.2V. Wenn ich durchpuste steigt die Spannung auf ca. 
0.5V an. Das ist zwar nicht die Welt aber mit der 5mV-Auflösung vom 
Arduino geht das schon einigermaßen in Ordnung. Verstärker werde ich 
daher wohl keinen zusätzlich anschließen...

von Christoph E. (stoppi)



Lesenswert?

Das Spirometer ist fertig und hat die Feuertaufe bestanden...

Weil ich nicht genau weiß, wie sich die Strömungsgeschwindigkeit im Rohr 
radial verteilt (Stichwort Gesetz von Hagen-Poiseuille) und wohl zum 
Rand hin wo gemessen wird abnimmt, habe ich noch einen Korrekturfaktor k 
in die Berechnung der Geschwindigkeit eingebaut. Bekomme aber eigentlich 
sehr vernünftige Messwerte (um die 2 Liter ohne in der Lunge 
verbleibendes Restvolumen).
1
// =============================================================
2
// Programm zur Messung des Lungenvolumen mit dem Sensor MPX5010
3
// =============================================================
4
5
#include <LiquidCrystal_I2C.h>
6
#include <Wire.h>
7
8
LiquidCrystal_I2C lcd(0x27,16,2);  // ACHTUNG: set the LCD address to 0x20 or 0x27 for a 16 chars and 2 line display!!!
9
10
// Anschlüsse Display:
11
// ===================
12
// GND - GND
13
// VCC - 5V
14
// SDA - ANALOG Pin 4
15
// SCL - ANALOG Pin 5
16
17
// Anschlüsse Drucksensor:
18
// =======================
19
// GND - GND
20
// VCC - 5V
21
// Signal - Analog Pin 0
22
23
24
int sensorPin = A0;
25
int pin_start = 12;     // Pin für Startknopf
26
int i;
27
long t_start,t_end;     // Variablen zur Bestimmung der Zeitschrittweite dt
28
29
float U_sensor, U_offset;
30
float v, A, Volumsfluss;
31
float Lungenvolumen, dt;
32
float k;                // Korrekturfaktor
33
34
35
// =========================
36
// ======== SETUP ==========
37
// =========================
38
39
void setup()
40
   {
41
    Serial.begin(9600);
42
43
    pinMode(pin_start, INPUT);           // start-pin für den Beginn der Messung
44
45
    lcd.begin();        // initialize the lcd
46
    lcd.backlight();
47
        
48
    // Print a message to the LCD.
49
    lcd.setCursor(0,0);
50
    lcd.print("Spirometer");
51
52
    delay(4000);
53
54
    lcd.setCursor(0,0);
55
    lcd.print("          ");
56
    lcd.setCursor(0,0);
57
    lcd.print("press button &");
58
    lcd.setCursor(0,1);
59
    lcd.print("blow then.....");
60
     
61
    
62
    U_offset = (5.0 / 1023) * analogRead(sensorPin);   // Bestimmung des sensor-offsets in Volt
63
    
64
    A = (0.024*0.024) * 3.141592654;                   // Querschnittsfläche des Strömungsrohrs in dm² mit Radius r = 0.024 dm
65
66
    dt = 0.0011605;         // zeitliche Schrittweite dt, genau bestimmt mittels millis()
67
68
    k = 1.4;                // Korrekturfaktor
69
70
   }
71
72
73
// =================================
74
// ======== HAUPTSCHLEIFE ==========
75
// =================================
76
77
void loop()
78
   {
79
    Lungenvolumen = 0.0;
80
81
    while(digitalRead(pin_start) == HIGH)    // Wartet bis Startknopf gedrückt
82
83
    lcd.setCursor(0,0);
84
    lcd.print("blow now        ");
85
    lcd.setCursor(0,1);
86
    lcd.print("                ");
87
88
    //t_start = millis();           // Startzeit für die Bestimmung von dt
89
90
91
    for(i = 0; i < 10000; i++)      // insgesamt 10000*0.001 = 10 sek Abfrage der Sensorwerte
92
       {
93
        // Einlesen des Spannungswerts des Sensors MPX5010
94
        
95
        U_sensor = (5.0 / 1023) * analogRead(sensorPin);   // eingelesener Sensorwert in Volt
96
97
        // Berechnung der Geschwindigkeit in dm/sek
98
99
        if(U_sensor - U_offset > 0.005)      // Abfrage um Werte < Schwelle als 0 zu werten
100
           {      
101
            v = k * 10.0 * sqrt((2000/(0.45 * 1.25))*(U_sensor - U_offset));     // Berechnung der Strömungsgeschwindigkeit in dm/sek; 0.45 V/kPa = Sensibilität des Sensors; 1.25 kg/m³ = Luftdichte
102
           }
103
        else
104
           {
105
            v = 0.0;
106
           }
107
108
        Volumsfluss = A * v;     // Volumsfluss V/t in Liter/sek
109
110
        Lungenvolumen = Lungenvolumen + Volumsfluss * dt;   // Aufsummierung der einzelnen Teilvolumina
111
112
        delay(1);     // 1 ms Verzögerung
113
       
114
       }
115
116
    /*
117
    t_end = millis();     // Endzeit für die Bestimmung von dt
118
119
    Serial.println(t_start);
120
    Serial.println(t_end);
121
    Serial.print("dt = ");
122
    Serial.println((t_end - t_start)/10000.0,4);
123
    */
124
     
125
    lcd.setCursor(0,0);
126
    lcd.print("V =             ");
127
    lcd.setCursor(4,0);
128
    lcd.print(Lungenvolumen,2);
129
    lcd.setCursor(9,0);
130
    lcd.print("Liter");
131
132
    delay(2000);
133
134
    lcd.setCursor(0,1);
135
    lcd.print("button to start");
136
      
137
   }

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.