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:
// 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!
}
// 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);
}
