Hello, I’m very new to programming so bare with me if what I’m saying is wrong in anyway.
In University we were tasked with calculating CdA for a cyclist in real-time and displaying this on an LCD screen however this proved to be quite difficult as it obviously involves a number of sensors all of which are coded uniquely to perform that function. The goal of the project was to solve the equation below:
CdA = (WTotal – (WRR + WPE + WKE) x2 / pair x V^2 x v)
CdA = (W – (Crr x m x g x v) + (s x m x g x v) + (m x a x v) x2 / pair x V^2 x v)
• Crr = Rolling resistance co-efficient = 7W
• m = Total mass of rider + bike (kg) = 87kg
• g = Gravitational acceleration = 9.81 (m/s)
• v = Speed (m/s) = refer to code
• s = Slope = 0
• a = Acceleration = ?
• p = Density of air (kg/m^2) = 1.225
• V = Wind speed (m/s) = refer to code
• CdA = Drag co-efficient times the area – this is what is needed to be solved and displayed
Assumptions have been made for some factors (g= 9.81, s=0, p = 1.225, Wtotal (took an average for this value due to budget constraints in buying a power meter taking it as around 250W) Also, the bike specs gave us values for Crr = 7W , m = 87kg )
acceleration is still to be worked out which I’m confused about, can the code work this out using speed and time?
Also, wind speed has been tested with the code below using a pitot tube which has given me good values:
//Routine for calculating the velocity from
//a pitot tube and MPXV7002DP pressure differential sensor
float V_0 = 5.0; // supply voltage to the pressure sensor
float rho = 1.204; // density of air
// parameters for averaging and offset
int offset = 0;
int offset_size = 10;
int veloc_mean_size = 20;
int zero_span = 2;
// setup and calculate offset
void setup() {
Serial.begin(9600);
for (int ii=0;ii<offset_size;ii++){
offset += analogRead(A0)-(1023/2);
}
offset /= offset_size;
}
void loop() {
float adc_avg = 0; float veloc = 0.0;
// average a few ADC readings for stability
for (int ii=0;ii<veloc_mean_size;ii++){
adc_avg+= analogRead(A0)-offset;
}
adc_avg/=veloc_mean_size;
// make sure if the ADC reads below 512, then we equate it to a negative velocity
if (adc_avg>512-zero_span and adc_avg<512+zero_span){
} else{
if (adc_avg<512){
veloc = -sqrt((-10000.0*((adc_avg/1023.0)-0.5))/rho);
} else{
veloc = sqrt((10000.0*((adc_avg/1023.0)-0.5))/rho);
}
}
Serial.println(veloc); // print velocity
delay(1000); // delay for stability
}
The ground speed in m/s uses the following code, using a hall effect with a magnet which measures the rpm and m/s of the spinning wheel. Again, this works fine individually, this code was modified slightly from another one on this form:
// Configuration constants:
const byte RevSensePin = 2;
const float WheelRadiusInMeters = 0.07;
const unsigned long DisplayIntervalMillis = 1000; // Update once per second
const unsigned long MaxRevTimeMicros = 2000000UL; // >2 seconds per revolution counts as 0 RPM
// Variables used in the ISR and in the main code must be 'volatile'
volatile unsigned long RevSenseTimeMicros = 0; // Time that the rising edge was sensed
volatile unsigned long RevTimeMicros = 0; // Microseconds between consecutive pulses
// Useful constants:
const unsigned long SixtySecondsInMicros = 60000000UL;
const float WheelCircumferenceInMeters = TWO_PI * WheelRadiusInMeters;
void setup()
{
Serial.begin(9600);
pinMode(RevSensePin, INPUT);
attachInterrupt(digitalPinToInterrupt(RevSensePin), RevSenseISR, RISING);
}
void RevSenseISR()
{
static unsigned long revSensePreviousMicros = 0; // 'static' to retain value between calls
RevSenseTimeMicros = micros();
RevTimeMicros = RevSenseTimeMicros - revSensePreviousMicros; // Time for last revolution
revSensePreviousMicros = RevSenseTimeMicros;
}
void loop()
{
static unsigned previousRPM;
// Only update the display once per DisplayIntervalMillis
unsigned long currentMillis = millis();
static unsigned long previousMillis = 0;
if (currentMillis - previousMillis >= DisplayIntervalMillis)
{
previousMillis += DisplayIntervalMillis;
// With interrupts disabled, make local copies of volatile variables
// This is so the ISR can't change them while we read them
noInterrupts();
unsigned long revSenseTimeMicros = RevSenseTimeMicros; // Time that the last rising edge was sensed
unsigned long revTimeMicros = RevTimeMicros; // Microseconds between consecutive pulses
interrupts();
// Calculate RPM
unsigned newRPM;
if (micros() - revSenseTimeMicros > MaxRevTimeMicros)
newRPM = 0; // Going so slow we're essentially stopped
else
newRPM = SixtySecondsInMicros / revTimeMicros;
// No need to update the display unless the RPM value has changed
if (newRPM != previousRPM)
{
previousRPM = newRPM;
displayRPM(newRPM);
}
}
}
void displayRPM(unsigned RPM)
{
float metersPerMinute = RPM * WheelCircumferenceInMeters;
Serial.print("RPM = "); //print the word "RPM".
Serial.print(RPM); // print the rpm value.
Serial.print("\t\t Linear Speed = ");
Serial.print(metersPerMinute/60); //print the linear velocity value.
Serial.println(" m/s");
}
So, the task is to combine these two codes together and solve the equation to display the CdA value using all of the values that have been given from specs, assumed or worked out with using the codes and sensors above.
I understand this is a big task but any help on even how I’d go about doing this or an example of the codes combined would be greatly appreciated. Thank you.