Hello everybody!
I'm working on a vehicle controller, witch includes a spedometer/odometer, but the results i'm getting are not what i'm expecting.
Ive been pulling my hair since i noticed the error, but i cannot find the reason, so i'm hoping that you guys and gals can help me.
I'm using a online speed calculator, found HERE:
and i'm using https://www.tinkercad.com to emulate my hardware.
So instead of the hall trigger for wheel rotation detection, i'm using a function generator, outputting a sine wave of X Hz.
When i set the function generator to 1 Hz, the "measured" speed is 7.20 km/h while the online speed calculator says it should be 7.6104 km/h, given a wheel circumference of 2114mm.
As i increase the function generator frequency, the error grows by 0,4104 * frequency.
So the measured speed at 5Hz is 36,0km/h, but should be 38,052, a difference of 2.052km/h
At 8Hz, measured speed is 57,6km/h, should be 60,8832km/h, with a difference of 3,2832km/h
Just to show how i'm calculating things:
distance_travelled = wheelCirqumference_in_cm * current_Hz
I then enter distance_travelled in the online calculator above, chose length=cm, time = 1 second and hit calculate.
The actual precision of the spedometer isn't really a deal-breaker for my project, but my autistic side demands at least a reason for this error, if not a solution..
There are 3 functions that are involved;
the "speedISR" witch gets called by the interrupt,
the "doSpeedCalc" which should get triggered when the number of rotations exceeds the minimum count (think of it as debounce), and finally
the "printSpeed" function, to display the current (=most recently calculated values of) speed and distance.
// definitions (should be all of them)
uint16_t rotCount = 0;
uint32_t rotTime = 0;
uint8_t numRotToMeasure = 3;
uint32_t odometer = 0;
float speed = 0.0;
float tripLength = 0.0;
uint32_t lastSpdRep = 0;
uint32_t spdRepInterval = 1500;
uint32_t cirq = 2114; // mm
uint32_t NOW = 0;
#define spdPin 2
bool checkElapsed(uint32_t last, uint32_t limit) { // Returns true if now - last is more than limit.
bool result = false;
if (NOW - last > limit) {
result = true;
}
return result;
}
void setup() {
pinMode(SpdPin, INPUT);
attachInterrupt(digitalPinToInterrupt(SpdPin), speedISR, RISING);
}
void loop() {
NOW = millis();
doSpeedCalc();
}
void speedISR() {
if (!rotTime) {
// if (!rotCount) {
rotTime = NOW; // NOW = millis();
}
else {
rotCount++;
}
odometer++;
}
void doSpeedCalc(void) {
if (rotCount) { // speed timeout, in case speed is too low to be meaningful..
if (checkElapsed(rotTime,(3000 * rotCount))) {
rotCount = 0;
rotTime = 0;
speed = 0.0;
}
}
if (rotCount >= numRotToMeasure) {
uint32_t elapsedTime = 0;
uint32_t distance = (cirq * (rotCount));
elapsedTime = (NOW - rotTime);
// speed = distance / time
speed = (distance / elapsedTime) * 3.6; // speed = (mm/mS) * 3.6 (to convert to km/h)
rotCount = 0;
rotTime = 0;
}
if (checkElapsed(lastSpdRep,spdRepInterval)) {
lastSpdRep = NOW;
printSpeed();
}
}
void printSpeed(void) {
tripLength = (odometer * cirq) / 1000.0;
writeVarSerial(STR_SPD_SPEED,speed,STR_SPD_KMH);
printLongVarLCD(STR_SPD_SPEED,speed,STR_SPD_KMH);
if (tripLength > 1000) {
tripLength = tripLength / 1000.0;
writeVarSerial(STR_SPD_ODO,tripLength,STR_SPD_KM);
printLongVarLCD2(STR_SPD_ODO,tripLength,STR_SPD_KM);
}
else {
writeVarSerial(STR_SPD_ODO,tripLength,STR_SPD_M);
printLongVarLCD2(STR_SPD_ODO,tripLength,STR_SPD_M);
}
}
There are some macro´s in the code above, as well as strings defined elsewhere but i belive you can easily spot the macros and guesstimate their functions.
And since theyre not the source of the frustration here, i have chosen not to include them.