Bike trainer logger
Retrieve data from speed and cadence sensor in a bike trainer. Display info in LCD screen and log in a SD Card
Components and supplies
Wemos D1 Mini
Alphanumeric LCD, 16 x 2
SPI micro SD card- mini TF reader module
Trimmer Potentiometer, 10 kohm
Arduino Nano R3
magnetic N.O. switch
Project description
Code
Trainer.ino
arduino
Initial version of the software
1/* Cimanes 30/04/2019 2 * 3 * Receive speed and cadence signals from a bike trainer 4 * Use one "attachinterrupt" for speed singal. 5 * The "attachinterrupt" will trigger the speed calculations. 6 * Cadence is not triggered with an attach interrupt, as it was causing unstable behavior. 7 * Process the signal as a cycling computer (speed, cadence, pedals, distance, time, average speed/cadence) 8 * Serial print/plot the results 9 * Display results in LCD display 10 * Save results in a file on a SD card (Trainer.log). 11 * 12 * Original software has been designed to work with a "Tacx Fortius" bike trainer. 13 * Digital inputs are configured as Input Pullup. Cadence signal is sampled in parallel to the Arduino and to the Fortius. 14 * Note: the Fortius cadence sensor uses voltage (0 VDC = constant) and (-5 VDC = pulses). 15 * 16 * SD card attached to SPI bus as follows: 17 * MOSI - pin 11 (UNO & NANO) / pin 51 (MEGA) 18 * MISO - pin 12 (UNO & NANO) / pin 50 (MEGA) 19 * CLK - pin 13 (UNO & NANO) / pin 52 (MEGA) 20 * CS or SS - pin 10 (UNO & NANO) / pin 53 (MEGA) / pin 4 (Ethernet Shield) 21 * 22 * MISO (Master In Slave Out) - The Slave line for sending data to the master, 23 * MOSI (Master Out Slave In) - The Master line for sending data to the peripherals, 24 * SCK / CLK (Serial Clock) - The clock pulses which synchronize data transmission generated by the master and one line specific for every device: 25 * SS (Slave Select) - the pin on each device that the master can use to enable and disable specific devices. 26 * 27 * On the Ethernet Shield, CS is pin 4. It's set as an output by default. 28 * Note that even if it's not used as the CS pin, the hardware SS pin (10 on most Arduino boards, 53 on the Mega) 29 * must be left as an output or the SD library functions will not work. 30 * 31 * LCD connection (LCD 1602 used): 32 * {VSS VDD V0 RS RW E D0 D1 D2 D3 D4 D5 D6 D7 A K } 33 * {GND +5V POT 23 GND 25 - - - - 27 22 24 26 +5V GND} --> MEGA board 34 * {GND +5V POT 4 GND 5 - - - - 6 7 8 9 +5V GND} --> NANO board 35 */ 36 37#include <LiquidCrystal.h> // LCD library 38// LCD connection RS E D4 D5 D6 D7 39 LiquidCrystal lcd(4, 5, 6, 7, 8, 9); // --> for NANO 40// LiquidCrystal lcd(23, 25, 27, 22, 24, 26); // --> (optional) for MEGA. Other options valid too 41 42#include <SPI.h> // Library for SPI communication with SD card 43#include <SD.h> // SD card library 44 File myFile; 45 46const byte SSpin = 10 ; // (MEGA = 53; NANO = 10). Pin for "Save Select"; digital input 47const byte logpin = 0 ; // (MEGA = 4 ; NANO = 0). Pin for "log save"; digital input 48const byte cadpin = 3 ; // Pin for cadence pulse; digital input 49 50const byte Dspd = 2 ; // Max speed difference between consecutive readings (km/h) 51const float wheel = 2.09 ; // wheel length in cms 52const int DTspd = 1500 ; // Max allowed time delay between speed pulses 53const int DTspdmin = 100 ; // Min time delay between speed pulses 54const int DTcad = 3000 ; // Max allowed time delay between cadence pulses 55const int DTcadmin = 350 ; // Min time delay between cadence pulses 56const int DTprint = 2000 ; // Time delay for serial print refresh 57const int DTlog = 2000 ; // Time delay for data-logger in SD card file; recommended DTlog >= DTprint for accuracy on average readings. 58const int DTdisp1 = 1800 ; // Time delay for LCD main screen refresh 59const int DTdisp2 = 10000 ; // Time delay for LCD second screen refresh 60 61unsigned long t = 0 ; // Current time in miliseconds 62unsigned long t_c = 500 ; // Current "pedalling" time (Cadence > 0). 63unsigned long t_s = 100 ; // Current "cycling" time (Speed > 0). 64unsigned long tspd = 0 ; // Time reference in miliseconds for cadence calculation 65unsigned long tcad = 0 ; // Time reference in miliseconds for cadence calculation 66unsigned long tprint = 0 ; // Time reference in miliseconds for signal print 67unsigned long tdisp1 = 0 ; // Time reference in miliseconds for LCD refresh 68unsigned long tdisp2 = 0 ; // Time reference in miliseconds for LCD screen shift 69unsigned long tlog = 0 ; // Time reference in miliseconds for data-logger 70 71unsigned int Turn = 0 ; // Number of pulses from the speed sensor 72unsigned int Pedal = 0 ; // Number of pedals 73unsigned int Pedal0 = 0 ; // Number of pedals (reference) 74float Speed = 0 ; // Speed (km/h) 75float Speed0 = 0 ; // Speed reference for filter 76byte Cadence = 0 ; // Cadence (rpm) 77byte Cadence0 = 0 ; // Cadence reference for filter 78byte Dcad = 4 ; // Max cadence difference 79 80float flMin = 0 ; // Time (floating minutes) in movement (speed >0) 81byte Min = 0 ; // Time (minutes) in movement (speed > 0) 82byte Sec = 0 ; // Time (seconds) in movement (speed > 0) 83float Dist = 0 ; // Distance (km) 84float Avspd = 0 ; // Average speed (km/h) 85byte Avcad = 0 ; // Average cadence (pedals / min) 86 87void setup() { 88 pinMode(2, INPUT_PULLUP) ; // Attach interrupt for speed detection 89 pinMode(cadpin, INPUT_PULLUP) ; // Pin: input pulse for cadence detection 90 pinMode(logpin, INPUT_PULLUP) ; // Digital input to save data-log file 91 pinMode(SSpin, OUTPUT) ; // Slave Select pin for SPI communication 92 pinMode(LED_BUILTIN, OUTPUT) ; 93 digitalWrite(LED_BUILTIN, LOW) ; // turn the LED off by making the voltage LOW (I don't like it blinking... :-) ) 94 attachInterrupt(digitalPinToInterrupt(2),Spd_calc,FALLING); 95 96// Initiate LCD display, Serial comm. and SD Card comm.: 97 lcd.begin(16, 2); // 16 characters; 2 lines 98 Serial.begin (9600); 99 100 lcd.clear(); 101 lcd.setCursor(0,0); 102 lcd.print("SD INITIALIZE..."); 103 delay(2000); 104 105 if (!SD.begin(SSpin)) { 106 lcd.setCursor(0,0); 107 lcd.print("SD INIT. FAILED "); 108 delay(5000); 109 return; 110 } 111 lcd.setCursor(0,0); 112 lcd.print(" SD INIT. DONE "); 113 delay(2000); 114 115// Open file "Trainer.log" to save data: 116 myFile = SD.open("Trainer.log", FILE_WRITE); // Open the file 117 118 if(myFile) { // if the file oens, display an "OK" message: 119 lcd.setCursor(0,0); 120 lcd.print(" FILE OPEN: "); 121 lcd.setCursor(0,1); 122 lcd.print(" TRAINER.LOG "); 123 delay(2000); 124 lcd.clear(); 125 } 126 else { // if the file didn't open, display an error message: 127 lcd.setCursor(0,0); 128 lcd.print(" FILE ERROR: "); 129 lcd.setCursor(0,1); 130 lcd.print(" TRAINER.LOG "); 131 delay(5000); 132 lcd.clear(); 133 } 134 135// Print the header in the data-log file: 136 myFile.println("Min" + String("\ ") + "Speed" + String("\ ") + "Cadence" + String("\ ") + "Av_Speed" 137 + String("\ ") + "Av_Cadence" + String("\ ") + "Distance" + String("\ ") + "Pedals"); 138 139 for (int i=0; i<3; i++) { // Initial display on LCD 140 lcd.setCursor(4,0); 141 lcd.print("CIMANES"); 142 lcd.setCursor(1,1); 143 lcd.print("START TRAINING"); 144 delay(800); 145 lcd.clear(); 146 delay(200); 147 } 148} 149 150void loop() { 151// Enable line #153 [t = millis();] to maintain LCD and print alive while Speed = 0; 152// Disable line #153 [t = millis();] to freeze print and LCD while Speed = 0; 153 t = millis(); // Time ellapsed since start 154 if (!digitalRead(cadpin) and t - tcad > DTcadmin) Cad_calc(); // Cadence calculation upon cadence pulse 155 if (t - tprint > DTprint) Print() ; // Check timer for "print" refresh 156 if (t - tdisp1 > DTdisp1) Disp() ; // Check timer for LD refresh 157 if (t - tlog > DTlog ) Log() ; // Check timer for data-logger. 158 if (!digitalRead(logpin)) { 159 myFile.close(); 160 lcd.clear(); 161 lcd.setCursor(2,0); 162 lcd.print("FILE SAVED"); 163 delay(2000); 164 lcd.clear(); 165 } 166} 167 168void Spd_calc() { 169 t = millis(); // Refresh time 170// if ((t - tspd) > DTspdmin) { // Filter needed???? **************** 171 Speed = (wheel) * 3600 / (t - tspd); // Calculate the raw speed (wheel(209 cm) * 3.6 = 752.4) 172 Speed = constrain(Speed, Speed0 - Dspd, Speed0 + Dspd); // Constrain speed incremental 173 174 if (t - tspd < DTspd) t_s = t_s + (t - tspd); // Increase time counter for average speed 175 Speed0 = Speed; // Refresh Speed reference for filter 176 tspd = t; // Refresh time reference for Speed calculation 177 Turn++; // Increase number of wheel turns 178} 179 180void Cad_calc() { 181 t = millis(); // Refresh time 182 if (Cadence0 < 65) Dcad = 15; 183 else Dcad = 4; 184 Pedal++; // Increment pedals upon cadence pulse 185 Cadence = byte((Pedal - Pedal0) * 60000 / (t - tcad)); // Calculate the raw cadence (include the "lost" pedals) 186 Cadence = constrain(Cadence, max(0, Cadence0 - Dcad), Cadence0 + Dcad); 187 188 if(t - tcad < DTcad) t_c = t_c + (t - tcad); // Increase time counter for average cadence 189 tcad = t; // Refresh cadence signal timer 190 Pedal0 = Pedal; // Refresh Pedal reference 191 Cadence0 = Cadence; // Refresh Cadence reference for filter 192} 193 194void Print() { 195// Force Speed and cadence to "0" when no pulses are detected for the pre-selected time delay: 196 if (t - tspd > DTspd) Speed = 0; 197 if (t - tcad > DTcad) Cadence = 0; 198 199// Calculate Timers and average values 200 flMin = float(t_s) / 60000; // Time (floating minutes) in movement (speed >0) 201 Min = flMin ; // Time (minutes) in movement (speed > 0) 202 Sec = 60 * (flMin - Min); // Time (seconds) in movement (speed > 0) 203 Dist = Turn * wheel / 1000 ; // Distance (km) 204 if (Dist < 0,1) Avspd = 0; 205 else Avspd = Dist * 3600000 / t_s ; // Average speed (km/h) 206 if (t_c < 5000) Avcad = Cadence; 207 else Avcad = byte(Pedal * 60000 / t_c) ; // Average cadence (pedals / min) 208 209 Serial.print("S:"); 210 Serial.print(Speed,1); 211 Serial.print(" C:"); 212 Serial.println(Cadence); 213// Additional available plots (can be added to the previous command: 214// Serial.print(" AS:"); 215// Serial.print(Avspd); 216// Serial.print(" D:"); 217// Serial.print(Dist); 218// Serial.print(" T:"); 219// Serial.print(Turn); 220// Serial.print(" T:"); 221// Serial.print(flMin,1); 222// Serial.print(" P:"); 223// Serial.print(Pedal/100); 224// Serial.print(" AC:"); 225// Serial.print(Avcad); 226// Serial.print(" t:"); 227// Serial.println(t); 228 229tprint = t; 230 if (!digitalRead(cadpin) and (t - tcad > DTcadmin)) Pedal++; 231} 232 233void Disp() { 234// Check if the "shift screen" pushbutton is pressed (digital input pint 7) 235 236 if (t - tdisp2 > DTdisp2) { 237 lcd.setCursor(0, 0); 238 lcd.print("AS T : "); 239 lcd.setCursor(3, 0); 240 lcd.print(Avspd, 1); 241 lcd.setCursor(11, 0); 242 lcd.print(Min); 243 lcd.setCursor(14, 0); 244 lcd.print(Sec); 245 lcd.setCursor(0, 1); 246 lcd.print("AC P D "); 247 lcd.setCursor(2, 1); 248 lcd.print(Avcad); 249 lcd.setCursor(6, 1); 250 lcd.print(Pedal); 251 lcd.setCursor(12, 1); 252 lcd.print(Dist,1); 253 tdisp1 = t; 254 tdisp2 = t; 255 } 256 257 else { 258 lcd.setCursor(0, 0); 259 lcd.print(" "); 260 lcd.setCursor(0, 0); 261 lcd.print("S T : "); 262 lcd.setCursor(0, 1); 263 lcd.print(" "); 264 lcd.setCursor(0, 1); 265 lcd.print("D C "); 266 lcd.setCursor(2, 0); 267 lcd.print(Speed, 1); 268 lcd.setCursor(10, 0); 269 lcd.print(Min); 270 lcd.setCursor(13,0); 271 lcd.print(Sec); 272 lcd.setCursor(2, 1); 273 lcd.print(Dist,1); 274 lcd.setCursor(10, 1); 275 lcd.print(Cadence); 276 tdisp1 = t; 277 } 278 if (!digitalRead(cadpin) and (t - tcad > DTcadmin)) Pedal++; 279} 280 281void Log() { 282 myFile.print(flMin); 283 myFile.print("\ "); 284 myFile.print(Speed,1); 285 myFile.print("\ "); 286 myFile.print(Cadence); 287 myFile.print("\ "); 288 myFile.print(Avspd); 289 myFile.print("\ "); 290 myFile.print(Avcad); 291 myFile.print("\ "); 292 myFile.print(Dist); 293 myFile.print("\ "); 294 myFile.println(Pedal); 295 tlog = t; 296 if (!digitalRead(cadpin) and (t - tcad > DTcadmin)) Pedal++; 297} 298
Trainer.ino
arduino
Initial version of the software
1/* Cimanes 30/04/2019 2 * 3 * Receive speed and cadence signals from a bike trainer 4 * Use one "attachinterrupt" for speed singal. 5 * The "attachinterrupt" will trigger the speed calculations. 6 * Cadence is not triggered with an attach interrupt, as it was causing unstable behavior. 7 * Process the signal as a cycling computer (speed, cadence, pedals, distance, time, average speed/cadence) 8 * Serial print/plot the results 9 * Display results in LCD display 10 * Save results in a file on a SD card (Trainer.log). 11 * 12 * Original software has been designed to work with a "Tacx Fortius" bike trainer. 13 * Digital inputs are configured as Input Pullup. Cadence signal is sampled in parallel to the Arduino and to the Fortius. 14 * Note: the Fortius cadence sensor uses voltage (0 VDC = constant) and (-5 VDC = pulses). 15 * 16 * SD card attached to SPI bus as follows: 17 * MOSI - pin 11 (UNO & NANO) / pin 51 (MEGA) 18 * MISO - pin 12 (UNO & NANO) / pin 50 (MEGA) 19 * CLK - pin 13 (UNO & NANO) / pin 52 (MEGA) 20 * CS or SS - pin 10 (UNO & NANO) / pin 53 (MEGA) / pin 4 (Ethernet Shield) 21 * 22 * MISO (Master In Slave Out) - The Slave line for sending data to the master, 23 * MOSI (Master Out Slave In) - The Master line for sending data to the peripherals, 24 * SCK / CLK (Serial Clock) - The clock pulses which synchronize data transmission generated by the master and one line specific for every device: 25 * SS (Slave Select) - the pin on each device that the master can use to enable and disable specific devices. 26 * 27 * On the Ethernet Shield, CS is pin 4. It's set as an output by default. 28 * Note that even if it's not used as the CS pin, the hardware SS pin (10 on most Arduino boards, 53 on the Mega) 29 * must be left as an output or the SD library functions will not work. 30 * 31 * LCD connection (LCD 1602 used): 32 * {VSS VDD V0 RS RW E D0 D1 D2 D3 D4 D5 D6 D7 A K } 33 * {GND +5V POT 23 GND 25 - - - - 27 22 24 26 +5V GND} --> MEGA board 34 * {GND +5V POT 4 GND 5 - - - - 6 7 8 9 +5V GND} --> NANO board 35 */ 36 37#include <LiquidCrystal.h> // LCD library 38// LCD connection RS E D4 D5 D6 D7 39 LiquidCrystal lcd(4, 5, 6, 7, 8, 9); // --> for NANO 40// LiquidCrystal lcd(23, 25, 27, 22, 24, 26); // --> (optional) for MEGA. Other options valid too 41 42#include <SPI.h> // Library for SPI communication with SD card 43#include <SD.h> // SD card library 44 File myFile; 45 46const byte SSpin = 10 ; // (MEGA = 53; NANO = 10). Pin for "Save Select"; digital input 47const byte logpin = 0 ; // (MEGA = 4 ; NANO = 0). Pin for "log save"; digital input 48const byte cadpin = 3 ; // Pin for cadence pulse; digital input 49 50const byte Dspd = 2 ; // Max speed difference between consecutive readings (km/h) 51const float wheel = 2.09 ; // wheel length in cms 52const int DTspd = 1500 ; // Max allowed time delay between speed pulses 53const int DTspdmin = 100 ; // Min time delay between speed pulses 54const int DTcad = 3000 ; // Max allowed time delay between cadence pulses 55const int DTcadmin = 350 ; // Min time delay between cadence pulses 56const int DTprint = 2000 ; // Time delay for serial print refresh 57const int DTlog = 2000 ; // Time delay for data-logger in SD card file; recommended DTlog >= DTprint for accuracy on average readings. 58const int DTdisp1 = 1800 ; // Time delay for LCD main screen refresh 59const int DTdisp2 = 10000 ; // Time delay for LCD second screen refresh 60 61unsigned long t = 0 ; // Current time in miliseconds 62unsigned long t_c = 500 ; // Current "pedalling" time (Cadence > 0). 63unsigned long t_s = 100 ; // Current "cycling" time (Speed > 0). 64unsigned long tspd = 0 ; // Time reference in miliseconds for cadence calculation 65unsigned long tcad = 0 ; // Time reference in miliseconds for cadence calculation 66unsigned long tprint = 0 ; // Time reference in miliseconds for signal print 67unsigned long tdisp1 = 0 ; // Time reference in miliseconds for LCD refresh 68unsigned long tdisp2 = 0 ; // Time reference in miliseconds for LCD screen shift 69unsigned long tlog = 0 ; // Time reference in miliseconds for data-logger 70 71unsigned int Turn = 0 ; // Number of pulses from the speed sensor 72unsigned int Pedal = 0 ; // Number of pedals 73unsigned int Pedal0 = 0 ; // Number of pedals (reference) 74float Speed = 0 ; // Speed (km/h) 75float Speed0 = 0 ; // Speed reference for filter 76byte Cadence = 0 ; // Cadence (rpm) 77byte Cadence0 = 0 ; // Cadence reference for filter 78byte Dcad = 4 ; // Max cadence difference 79 80float flMin = 0 ; // Time (floating minutes) in movement (speed >0) 81byte Min = 0 ; // Time (minutes) in movement (speed > 0) 82byte Sec = 0 ; // Time (seconds) in movement (speed > 0) 83float Dist = 0 ; // Distance (km) 84float Avspd = 0 ; // Average speed (km/h) 85byte Avcad = 0 ; // Average cadence (pedals / min) 86 87void setup() { 88 pinMode(2, INPUT_PULLUP) ; // Attach interrupt for speed detection 89 pinMode(cadpin, INPUT_PULLUP) ; // Pin: input pulse for cadence detection 90 pinMode(logpin, INPUT_PULLUP) ; // Digital input to save data-log file 91 pinMode(SSpin, OUTPUT) ; // Slave Select pin for SPI communication 92 pinMode(LED_BUILTIN, OUTPUT) ; 93 digitalWrite(LED_BUILTIN, LOW) ; // turn the LED off by making the voltage LOW (I don't like it blinking... :-) ) 94 attachInterrupt(digitalPinToInterrupt(2),Spd_calc,FALLING); 95 96// Initiate LCD display, Serial comm. and SD Card comm.: 97 lcd.begin(16, 2); // 16 characters; 2 lines 98 Serial.begin (9600); 99 100 lcd.clear(); 101 lcd.setCursor(0,0); 102 lcd.print("SD INITIALIZE..."); 103 delay(2000); 104 105 if (!SD.begin(SSpin)) { 106 lcd.setCursor(0,0); 107 lcd.print("SD INIT. FAILED "); 108 delay(5000); 109 return; 110 } 111 lcd.setCursor(0,0); 112 lcd.print(" SD INIT. DONE "); 113 delay(2000); 114 115// Open file "Trainer.log" to save data: 116 myFile = SD.open("Trainer.log", FILE_WRITE); // Open the file 117 118 if(myFile) { // if the file oens, display an "OK" message: 119 lcd.setCursor(0,0); 120 lcd.print(" FILE OPEN: "); 121 lcd.setCursor(0,1); 122 lcd.print(" TRAINER.LOG "); 123 delay(2000); 124 lcd.clear(); 125 } 126 else { // if the file didn't open, display an error message: 127 lcd.setCursor(0,0); 128 lcd.print(" FILE ERROR: "); 129 lcd.setCursor(0,1); 130 lcd.print(" TRAINER.LOG "); 131 delay(5000); 132 lcd.clear(); 133 } 134 135// Print the header in the data-log file: 136 myFile.println("Min" + String("\ ") + "Speed" + String("\ ") + "Cadence" + String("\ ") + "Av_Speed" 137 + String("\ ") + "Av_Cadence" + String("\ ") + "Distance" + String("\ ") + "Pedals"); 138 139 for (int i=0; i<3; i++) { // Initial display on LCD 140 lcd.setCursor(4,0); 141 lcd.print("CIMANES"); 142 lcd.setCursor(1,1); 143 lcd.print("START TRAINING"); 144 delay(800); 145 lcd.clear(); 146 delay(200); 147 } 148} 149 150void loop() { 151// Enable line #153 [t = millis();] to maintain LCD and print alive while Speed = 0; 152// Disable line #153 [t = millis();] to freeze print and LCD while Speed = 0; 153 t = millis(); // Time ellapsed since start 154 if (!digitalRead(cadpin) and t - tcad > DTcadmin) Cad_calc(); // Cadence calculation upon cadence pulse 155 if (t - tprint > DTprint) Print() ; // Check timer for "print" refresh 156 if (t - tdisp1 > DTdisp1) Disp() ; // Check timer for LD refresh 157 if (t - tlog > DTlog ) Log() ; // Check timer for data-logger. 158 if (!digitalRead(logpin)) { 159 myFile.close(); 160 lcd.clear(); 161 lcd.setCursor(2,0); 162 lcd.print("FILE SAVED"); 163 delay(2000); 164 lcd.clear(); 165 } 166} 167 168void Spd_calc() { 169 t = millis(); // Refresh time 170// if ((t - tspd) > DTspdmin) { // Filter needed???? **************** 171 Speed = (wheel) * 3600 / (t - tspd); // Calculate the raw speed (wheel(209 cm) * 3.6 = 752.4) 172 Speed = constrain(Speed, Speed0 - Dspd, Speed0 + Dspd); // Constrain speed incremental 173 174 if (t - tspd < DTspd) t_s = t_s + (t - tspd); // Increase time counter for average speed 175 Speed0 = Speed; // Refresh Speed reference for filter 176 tspd = t; // Refresh time reference for Speed calculation 177 Turn++; // Increase number of wheel turns 178} 179 180void Cad_calc() { 181 t = millis(); // Refresh time 182 if (Cadence0 < 65) Dcad = 15; 183 else Dcad = 4; 184 Pedal++; // Increment pedals upon cadence pulse 185 Cadence = byte((Pedal - Pedal0) * 60000 / (t - tcad)); // Calculate the raw cadence (include the "lost" pedals) 186 Cadence = constrain(Cadence, max(0, Cadence0 - Dcad), Cadence0 + Dcad); 187 188 if(t - tcad < DTcad) t_c = t_c + (t - tcad); // Increase time counter for average cadence 189 tcad = t; // Refresh cadence signal timer 190 Pedal0 = Pedal; // Refresh Pedal reference 191 Cadence0 = Cadence; // Refresh Cadence reference for filter 192} 193 194void Print() { 195// Force Speed and cadence to "0" when no pulses are detected for the pre-selected time delay: 196 if (t - tspd > DTspd) Speed = 0; 197 if (t - tcad > DTcad) Cadence = 0; 198 199// Calculate Timers and average values 200 flMin = float(t_s) / 60000; // Time (floating minutes) in movement (speed >0) 201 Min = flMin ; // Time (minutes) in movement (speed > 0) 202 Sec = 60 * (flMin - Min); // Time (seconds) in movement (speed > 0) 203 Dist = Turn * wheel / 1000 ; // Distance (km) 204 if (Dist < 0,1) Avspd = 0; 205 else Avspd = Dist * 3600000 / t_s ; // Average speed (km/h) 206 if (t_c < 5000) Avcad = Cadence; 207 else Avcad = byte(Pedal * 60000 / t_c) ; // Average cadence (pedals / min) 208 209 Serial.print("S:"); 210 Serial.print(Speed,1); 211 Serial.print(" C:"); 212 Serial.println(Cadence); 213// Additional available plots (can be added to the previous command: 214// Serial.print(" AS:"); 215// Serial.print(Avspd); 216// Serial.print(" D:"); 217// Serial.print(Dist); 218// Serial.print(" T:"); 219// Serial.print(Turn); 220// Serial.print(" T:"); 221// Serial.print(flMin,1); 222// Serial.print(" P:"); 223// Serial.print(Pedal/100); 224// Serial.print(" AC:"); 225// Serial.print(Avcad); 226// Serial.print(" t:"); 227// Serial.println(t); 228 229tprint = t; 230 if (!digitalRead(cadpin) and (t - tcad > DTcadmin)) Pedal++; 231} 232 233void Disp() { 234// Check if the "shift screen" pushbutton is pressed (digital input pint 7) 235 236 if (t - tdisp2 > DTdisp2) { 237 lcd.setCursor(0, 0); 238 lcd.print("AS T : "); 239 lcd.setCursor(3, 0); 240 lcd.print(Avspd, 1); 241 lcd.setCursor(11, 0); 242 lcd.print(Min); 243 lcd.setCursor(14, 0); 244 lcd.print(Sec); 245 lcd.setCursor(0, 1); 246 lcd.print("AC P D "); 247 lcd.setCursor(2, 1); 248 lcd.print(Avcad); 249 lcd.setCursor(6, 1); 250 lcd.print(Pedal); 251 lcd.setCursor(12, 1); 252 lcd.print(Dist,1); 253 tdisp1 = t; 254 tdisp2 = t; 255 } 256 257 else { 258 lcd.setCursor(0, 0); 259 lcd.print(" "); 260 lcd.setCursor(0, 0); 261 lcd.print("S T : "); 262 lcd.setCursor(0, 1); 263 lcd.print(" "); 264 lcd.setCursor(0, 1); 265 lcd.print("D C "); 266 lcd.setCursor(2, 0); 267 lcd.print(Speed, 1); 268 lcd.setCursor(10, 0); 269 lcd.print(Min); 270 lcd.setCursor(13,0); 271 lcd.print(Sec); 272 lcd.setCursor(2, 1); 273 lcd.print(Dist,1); 274 lcd.setCursor(10, 1); 275 lcd.print(Cadence); 276 tdisp1 = t; 277 } 278 if (!digitalRead(cadpin) and (t - tcad > DTcadmin)) Pedal++; 279} 280 281void Log() { 282 myFile.print(flMin); 283 myFile.print("\ "); 284 myFile.print(Speed,1); 285 myFile.print("\ "); 286 myFile.print(Cadence); 287 myFile.print("\ "); 288 myFile.print(Avspd); 289 myFile.print("\ "); 290 myFile.print(Avcad); 291 myFile.print("\ "); 292 myFile.print(Dist); 293 myFile.print("\ "); 294 myFile.println(Pedal); 295 tlog = t; 296 if (!digitalRead(cadpin) and (t - tcad > DTcadmin)) Pedal++; 297} 298
Downloadable files
Fritzing project with schematics
Fritzing project with schematics
Trainer_schematic
Connections between arduino, sensors, LCD display and SD card
Trainer_schematic
Fritzing project with schematics
Fritzing project with schematics
Documentation
Trainer V 5.0
Latest revision (including optional Arduino / Wemos D1 mini and additional options)
Trainer V 5.0
Trainer V 5.0
Latest revision (including optional Arduino / Wemos D1 mini and additional options)
Trainer V 5.0
Comments
Only logged in users can leave comments