Mit einem Arduino lässt sich sogar die beim Fahrradfahren aufgebrachte Leistung P (= Energie pro Sekunde) bestimmen. Hierfür benötigt man sog. Dehnmessstreifen. Das sind Widerstände, welche ihren Wert je nach Dehnung des Streifens verändern. Angeordnet sind insgesamt 4 Stück in Form einer Vollbrücke. Die Brückenspannung wird dann mittels Operationsverstärker verstärkt (konkret 330-fach) und dann mit dem Arduino an einem analogen Eingang gemessen.
Bei stärkerer Belastung der Kurbel dehnen bzw. stauchen sich die Streifen mehr und die Ausgangsspannung steigt. Um zu wissen, welche Ausgangsspannung welcher Kraft entspricht, muss man die Leistungsmesskurbel natürlich zuerst mit definierten Gewichten kalibrieren.
Die Zeitspanne für eine vollständige Umdrehung wird mit einem sog. Gyrosensor (welcher die Winkelgeschwindigkeit misst) ermittelt. Hier kommt das Modul MPU6050 zum Einsatz. Über Integration der Winkelgeschwindigkeit erhält man den aktuellen Winkel. Die während einer Umdrehung wirkenden Kräfte werden gemittelt. Wurde ein Winkel von 360° zurückgelegt (= vollständige Umdrehung), wird mittels der Zeit t für diese Umdrehung die mittlere Leistung P wie folgt berechnet:
P = 2 · F · 2 · π · Kurbelradius r / t. Der Faktor 2 kommt dadurch zustande, dass ja (gleiche) Arbeit an beiden Kurbelarmen verrichtet wird.
Der Wert für P wird sodann mittels NRF24L01-Funkmodul an den Empfänger am Lenker gesendet. Dieser steuert dann ein 16 x 2 Display an, wobei momentane Leistung und Kurbelumdrehungszahl (in rpm) angezeigt werden.
Arduino-Codes für Sender und Empfänger:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
// Sender-Programm // =============== #include <SPI.h> #include "RF24.h" #include "Wire.h" #include "I2Cdev.h" // I2Cdev and MPU6050 must be installed as libraries #include "MPU6050.h" // class default I2C address is 0x68 = AD0 low #include <math.h> MPU6050 accelgyro; int16_t ax, ay, az; // Beschleunigungswerte in x-,y- und z-Richtung des MPU6050-Sensors int16_t gx, gy, gz; // Winkelgeschwindigkeitswerte in x-,y- und z-Richtung des MPU6050-Sensors float data[2]; // per Funk übertragenes Datenarray für Leistung P, Umdrehungszeit tau etc. int sensorPin = A0; // select the input pin for the force measurement float Winkel_neu, Winkel_alt; // aktueller und alter Neigungswinkel float gz_alt, gz_neu; // aktuelle und alte Winkelgeschwindigkeit float time_alt, time_neu; // aktuelle und alte Zeit float t_Umdrehung_Start; // Startzeit einer Umdrehung float t_Umdrehung_Ende; // Endzeit einer Umdrehung float t_Umdrehung; // Zeit für eine vollständige Umdrehung float v; // Mittlere Pedalgeschwindigkeit float r; // Kurbellänge int n; // Anzahl der Kraftmessungen während einer Umdrehung float F; // Mittelwert der während einer Umdrehung wirkenden Kraft float k; // Kalibrierfaktor bzgl. welcher Zahlenwert [0,1023] welcher Kraft in Newton entspricht int offset; // offset der Eingangsspannung noch ohne Belastung, also bei F = 0 float P; // mittlere Leistung P // Funkmodul NRF24L01 mit Arduino-Pins verbinden: // SCK -> 13 // MISO -> 12 // MOSI -> 11 // CSN -> 10 // CE -> 9 // SPI-Bus Pins 9 und 10 // ============================================================== const uint64_t pipe = 0xE8E8F0F0E1LL; // Adresse des Übertragungskanals des NRF24L01 RF24 radio(9,10); // ====================== // ======== SETUP ======= // ====================== void setup() { radio.begin(); radio.openWritingPipe(pipe); // Sende-Kanal öffnen // join I2C bus (I2Cdev library doesn't do this automatically) Wire.begin(); // initialize serial communication Serial.begin(115200); // initialize device accelgyro.initialize(); // ===================================================================================== // read raw accel/gyro measurements from device // Ausgabewerte-Acc: Auflösung 2g: 16384/g Auflösung 4g: 8192/g // Ausgabewerte-Gyro: Auflösung 250°/s: 131/°/s ; 500°/s: 65.5/°/s ; 2000°/s: 16.375/°/s // ===================================================================================== //Sensor output scaling (2g,4g,8g,16g) accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_8); // Sensor konkret auf 8g eingestellt //Sensor output scaling (250°/s,500°/s,2000°/s) accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_500); // Sensor konkret auf 500°/s eingestellt // verify connection //Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed"); time_alt = 0.0; Winkel_alt = 0.0; gz_alt = 0.0; r = 0.175; // Kurbellänge in m k = 292.0; // Kalibrierfaktor in Newton/Volt offset = 0.0; // offset ohne Belastung for (int i = 0; i < 5; i++) { offset = offset + analogRead(sensorPin); // Ermittlung der mittleren (5 Messungen) offset-Spannung noch ohne Belastung } offset = offset / 5.0; data[0] = 5000.0 * analogRead(sensorPin) / 1024.0; // einmalige Übergabe des Spannungswerts in mV ohne Belastung! /* Serial.print(data[0]); Serial.print(" "); Serial.println(data[1]); */ radio.write(data, 8); // ACHTUNG: Adresse (data) und Länge (pro float 4 byte, d.h. für 2 Zahlen 8 eintragen) der zu sendenden Daten! delay(2000); } // ============================== // ======== HAUPTSCHLEIFE ======= // ============================== void loop() { n = 0; // Zählvariable auf 0 gesetzt F = 0; // Kraftmittelwert wird auf 0 gesetzt t_Umdrehung_Start = micros(); // Ermittlung der Startzeit einer Umdrehung do { accelgyro.getRotation(&gx, &gy, &gz); // Einlesen der aktuellen Winkelgeschwindigkeiten // accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz); // Einlesen der aktuellen Beschleunigungen und Winkelgeschwindigkeiten gz_neu = -gz; // neue Winkelgeschwindigkeit // Berechnung des neuen Winkel mittels altem Winkel und dem Mittelwert aus alter und neuer Winkelgeschwindigkeit: // ============================================================================================================== time_neu = micros(); // aktuelle Laufzeit des Programms in µs Winkel_neu = Winkel_alt + 0.5 * ((gz_alt + gz_neu) / 65.5) * ((time_neu - time_alt) / 1000000.0); if (Winkel_neu < 0) // Neustart bei negativen Winkel { Winkel_neu = 0.0; t_Umdrehung_Start = micros(); n = 0; // Zählvariable auf 0 gesetzt F = 0; // Kraftmittelwert wird auf 0 gesetzt } F = F + k * (5.0 * (analogRead(sensorPin) - offset) / 1023.0); // Integration über alle während einer Umdrehung wirkenden Kräfte; Faktor k = Newton/Volt ! /* Serial.print(Winkel_neu,0); Serial.print(" "); Serial.println(F/n,1); */ /* data[0] = Winkel_neu; data[1] = F / n; */ radio.write(data, 8); // ACHTUNG: Adresse (data) und Länge (pro float 4 byte, d.h. für 2 Zahlen 8 eintragen) der zu sendenden Daten! // Werteübergabe // ============= gz_alt = gz_neu; time_alt = time_neu; Winkel_alt = Winkel_neu; n = n + 1; // Anzahl der Messungen um 1 erhöht } while (Winkel_neu < 360); // Ausstieg aus der Schleife, wenn der Winkel > 360°, sprich bei einer vollen Umdrehung // ============================ // == Vollständige Umdrehung == // ============================ t_Umdrehung_Ende = micros(); // Ermittlung der Endzeit einer Umdrehung Winkel_alt = Winkel_alt - 360.0; // Reduzierung des Winkels auf das Intervall [0,360] F = F / n; // Berechnung der mittleren Kraft während einer Umdrehung t_Umdrehung = (t_Umdrehung_Ende - t_Umdrehung_Start) / 1000000.0; // Berechnung der Umlaufszeit in Sekunden v = 2.0 * r * 3.141592654 / t_Umdrehung; // Berechnung der mittleren Pedalgeschwindigkeit; P = 2.0 * F * v; // Berechnung der mittleren Leistung P // ========================= // Datenübertragung per Funk // ========================= data[0] = P; data[1] = t_Umdrehung; /* Serial.print(data[0]); Serial.print(" "); Serial.println(data[1]); */ radio.write(data, 8); // ACHTUNG: Adresse (data) und Länge (pro float 4 byte, d.h. für 2 Zahlen 8 eintragen) der zu sendenden Daten! } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
// Empfänger-Programm // ================== #include <SPI.h> #include "RF24.h" #include <LiquidCrystal_I2C.h> #include <Wire.h> LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display. ACHTUNG: Adresse kann auch 0x3F sein !!! // Anschlüsse: // GND - GND // VCC - 5V // SDA - ANALOG Pin 4 // SCL - ANALOG pin 5 const uint64_t pipe = 0xE8E8F0F0E1LL; bool done; float message[2]; // Funkmodul NRF24L01 mit Arduino-Pins verbinden: // SCK -> 13 // MISO -> 12 // MOSI -> 11 // CSN -> 10 // CE -> 9 // SPI-Bus Pins 9 und 10 // ============================================================== RF24 radio(9,10); // =========================== // ========== SETUP ========== // =========================== void setup() { Serial.begin(9600); radio.begin(); radio.openReadingPipe(1, pipe); radio.startListening(); lcd.init(); // initialize the lcd lcd.backlight(); lcd.setCursor(0,0); lcd.print("P:"); lcd.setCursor(0,1); lcd.print("rpm:"); } // =================================== // ========== HAUPTSCHLEIFE ========== // =================================== void loop() { if (radio.available()) { done = false; while (!done) { done = radio.read(message, 8); // ACHTUNG: Für jeden übertragenen Integerwert 4 Byte! } } Serial.print(message[0],0); Serial.print(" "); Serial.println(60/message[1],0); lcd.setCursor(3,0); lcd.print(" "); lcd.setCursor(3,0); lcd.print(message[0],0); lcd.print(" W"); lcd.setCursor(5,1); lcd.print(" "); lcd.setCursor(5,1); lcd.print(60/message[1],0); } |